From 8e62eb9519e37b22622ac198dbf30a78207916b2 Mon Sep 17 00:00:00 2001 From: Christopher Michael Date: Tue, 29 Jan 2013 14:48:14 +0000 Subject: [PATCH] Implement & fix ecore_x_randr code. NB: All functions which are in the Ecore_X header have now been implemented except for 2. NB: No support yet for the RandR 1.4 functions. Signed-off-by: Christopher Michael SVN revision: 83439 --- src/lib/ecore_x/xlib/ecore_x_randr.c | 3243 ++++++++++++++++++++++++++ 1 file changed, 3243 insertions(+) create mode 100644 src/lib/ecore_x/xlib/ecore_x_randr.c diff --git a/src/lib/ecore_x/xlib/ecore_x_randr.c b/src/lib/ecore_x/xlib/ecore_x_randr.c new file mode 100644 index 0000000000..cf2e085402 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_randr.c @@ -0,0 +1,3243 @@ + #ifdef HAVE_CONFIG_H +# include +#endif + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" + +/* NB: FIXME: + * + * A lot of this code uses XRRGetScreenInfo and then calls + * XRRFreeScreenConfigInfo. Typically this is not an Unheard of thing to do, + * however this process of getting config and freeing config does force a + * round-trip to the X server */ + +/* local variables */ +static Eina_Bool _randr_avail = EINA_FALSE; + +#ifdef ECORE_XRANDR + +# define RANDR_VERSION_1_1 ((1 << 16) | 1) +# define RANDR_VERSION_1_2 ((1 << 16) | 2) +# define RANDR_VERSION_1_3 ((1 << 16) | 3) +# define RANDR_VERSION_1_4 ((1 << 16) | 4) + +# define RANDR_EDID_VERSION_1_3 ((1 << 8) | 3) +# define RANDR_EDID_VERSION_MAJOR 0x12 +# define RANDR_EDID_VERSION_MINOR 0x13 + +# define RANDR_EDID_MANUFACTURER 0x08 +# define RANDR_EDID_BLOCK 0x36 + +typedef enum _Ecore_X_Randr_Edid_Aspect_Ratio_Preferred +{ + RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3 = 0x00, + RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9 = 0x01, + RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10 = 0x02, + RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4 = 0x03, + RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9 = 0x04 +} Ecore_X_Randr_Edid_Aspect_Ratio_Preferred; + +static int _randr_major, _randr_minor, _randr_version; + +XRRScreenResources *(*_ecore_x_randr_screen_resources_get)(Display *disp, Window win); + +#endif + +/* local functions */ +void +_ecore_x_randr_init(void) +{ +#ifdef ECORE_XRANDR + _randr_major = 1; + _randr_minor = 3; + _randr_version = 0; + + /* try to query the randr extenstion version */ + if (XRRQueryVersion(_ecore_x_disp, &_randr_major, &_randr_minor)) + { + _randr_version = (_randr_major << 16) | _randr_minor; + + if (_randr_version >= RANDR_VERSION_1_3) + _ecore_x_randr_screen_resources_get = XRRGetScreenResourcesCurrent; + else if (_randr_version == RANDR_VERSION_1_2) + _ecore_x_randr_screen_resources_get = XRRGetScreenResources; + + _randr_avail = EINA_TRUE; + } +#endif +} + +/* public functions */ +EAPI int +ecore_x_randr_version_get(void) +{ +#ifdef ECORE_XRANDR + if (_randr_avail) return _randr_version; +#endif + return -1; +} + +EAPI Eina_Bool +ecore_x_randr_query(void) +{ + return _randr_avail; +} + +/*************************************** + * API Functions for RandR version 1.1 * + ***************************************/ + +/* + * @param root window which's primary output will be queried + */ +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_screen_primary_output_orientations_get(Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + Rotation ret = 0, crot = 0; + + /* get the rotations available from XRandr */ + ret = XRRRotations(_ecore_x_disp, + XRRRootToScreen(_ecore_x_disp, root), &crot); + + return ret; +#else + return 0; +#endif +} + +/* + * @param root window which's primary output will be queried + * @return the current orientation of the root window's screen primary output + */ +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_screen_primary_output_orientation_get(Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + Rotation ret = 0; + + /* get the current rotation available from XRandr */ + XRRRotations(_ecore_x_disp, + XRRRootToScreen(_ecore_x_disp, root), &ret); + + return ret; +#else + return 0; +#endif +} + +/* + * @brief Sets a given screen's primary output's orientation. + * + * @param root Window which's screen's primary output will be queried. + * @param orientation orientation which should be set for the root window's + * screen primary output. + * @return @c EINA_TRUE if the primary output's orientation could be + * successfully altered. + */ +EAPI Eina_Bool +ecore_x_randr_screen_primary_output_orientation_set(Ecore_X_Window root, Ecore_X_Randr_Orientation orient) +{ +#ifdef ECORE_XRANDR + Eina_Bool ret = EINA_FALSE; + Rotation crot = 0; + XRRScreenConfiguration *cfg = NULL; + int id = 0; + + /* try to get the screen config from XRandr */ + if (!(cfg = XRRGetScreenInfo(_ecore_x_disp, root))) + return EINA_FALSE; + + /* get the screen's current size id */ + id = XRRConfigCurrentConfiguration(cfg, &crot); + + /* attempt to set the new orientation */ + if (!XRRSetScreenConfig(_ecore_x_disp, cfg, root, id, orient, CurrentTime)) + ret = EINA_TRUE; + + /* free any returned screen config */ + if (cfg) XRRFreeScreenConfigInfo(cfg); + + return ret; +#else + return EINA_FALSE; +#endif +} + +/* + * @brief gets a screen's primary output's possible sizes + * @param root window which's primary output will be queried + * @param num number of sizes reported as supported by the screen's primary output + * @return an array of sizes reported as supported by the screen's primary output or - if query failed - NULL + */ +EAPI Ecore_X_Randr_Screen_Size_MM * +ecore_x_randr_screen_primary_output_sizes_get(Ecore_X_Window root, int *num) +{ + if (num) *num = 0; +#ifdef ECORE_XRANDR + Ecore_X_Randr_Screen_Size_MM *ret = NULL; + XRRScreenSize *sizes; + int n = 0, i = 0; + + /* retrieve the number of sizes from X, and the sizes themselves. + * + * NB: don't have to free the returned sizes */ + sizes = XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n); + if (!sizes) return NULL; + if (n <= 0) return NULL; + + /* try to allocate our structure for these sizes */ + if (!(ret = calloc(n, sizeof(Ecore_X_Randr_Screen_Size_MM)))) + return NULL; + + if (num) *num = n; + + /* fill in our allocated structure with the screen sizes */ + for (i = 0; i < n; i++) + { + ret[i].width = sizes[i].width; + ret[i].height = sizes[i].height; + ret[i].width_mm = sizes[i].mwidth; + ret[i].height_mm = sizes[i].mheight; + } + + return ret; +#else + return NULL; +#endif +} + +EAPI void +ecore_x_randr_screen_primary_output_current_size_get(Ecore_X_Window root, int *w, int *h, int *w_mm, int *h_mm, int *size_index) +{ +#ifdef ECORE_XRANDR + XRRScreenConfiguration *cfg = NULL; + + /* try to get the screen config from XRandr */ + if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root))) + { + XRRScreenSize *sizes; + Rotation crot = 0; + int n = 0; + + /* retrieve the number of sizes from X, and the sizes themselves. + * + * NB: don't have to free the returned sizes */ + sizes = + XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n); + if ((sizes) && (n > 0)) + { + int idx = 0; + + /* get the index of the current configuration */ + idx = XRRConfigCurrentConfiguration(cfg, &crot); + + /* if the index is valid, then fill in the return variables with + * the size information for this index */ + if ((idx < n) && (idx >= 0)) + { + if (w) *w = sizes[idx].width; + if (h) *h = sizes[idx].height; + if (w_mm) *w_mm = sizes[idx].mwidth; + if (h_mm) *h_mm = sizes[idx].mheight; + if (size_index) *size_index = idx; + } + } + + /* free the returned screen config */ + XRRFreeScreenConfigInfo(cfg); + } +#endif +} + +/* + * @brief Sets a given screen's primary output size, but disables all other + * outputs at the same time. + * + * @param root Window which's primary output will be queried. + * @param size_index Within the list of sizes reported as supported by the root + * window's screen primary output. + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure due to e.g. + * invalid times. + */ +EAPI Eina_Bool +ecore_x_randr_screen_primary_output_size_set(Ecore_X_Window root, int size_index) +{ +#ifdef ECORE_XRANDR + Eina_Bool ret = EINA_FALSE; + int n = 0; + + /* check for valid size index first */ + if (size_index < 0) return EINA_FALSE; + + /* get the number of sizes from XRandr */ + XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n); + + /* make sure the requested index is below the number returned from randr */ + if (size_index < n) + { + XRRScreenConfiguration *cfg = NULL; + + /* try to get the screen config from XRandr */ + if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root))) + { + /* try to set the new screen config + * + * NB: Returns Success (0) if it works */ + if (!XRRSetScreenConfig(_ecore_x_disp, cfg, root, size_index, + ECORE_X_RANDR_ORIENTATION_ROT_0, + CurrentTime)) + { + ret = EINA_TRUE; + } + + /* free the returned screen config */ + XRRFreeScreenConfigInfo(cfg); + } + } + + return ret; +#else + return EINA_FALSE; +#endif +} + +/* + * @param root window which's primary output will be queried + * @return currently used refresh rate or - if request failed or RandRR is not available - 0.0 + */ +EAPI Ecore_X_Randr_Refresh_Rate +ecore_x_randr_screen_primary_output_current_refresh_rate_get(Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + XRRScreenConfiguration *cfg = NULL; + + /* try to get the screen config from XRandr */ + if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root))) + { + Ecore_X_Randr_Refresh_Rate ret = 0.0; + + /* try to get the current refresh rate */ + ret = XRRConfigCurrentRate(cfg); + + /* free the returned screen config */ + XRRFreeScreenConfigInfo(cfg); + + return ret; + } +#endif + return 0.0; +} + +/* + * @param root window which's primary output will be queried + * @param size_index referencing the size to query valid refresh rates for + * @return currently used refresh rate or - if request failed or RandRR is not available - NULL + */ +EAPI Ecore_X_Randr_Refresh_Rate * +ecore_x_randr_screen_primary_output_refresh_rates_get(Ecore_X_Window root, int size_index, int *num) +{ +#ifdef ECORE_XRANDR + Ecore_X_Randr_Refresh_Rate *rates = NULL; + int n = 0; + + /* try to get the refresh rates for this screen */ + if ((rates = XRRRates(_ecore_x_disp, + XRRRootToScreen(_ecore_x_disp, root), size_index, &n))) + { + Ecore_X_Randr_Refresh_Rate *ret = NULL; + + /* try to allocate space for the return */ + if ((ret = malloc(n * sizeof(Ecore_X_Randr_Refresh_Rate)))) + { + int i = 0; + + /* fill in our return values */ + for (i = 0; i < n; i++) + ret[i] = rates[i]; + + if (num) *num = n; + + return ret; + } + } +#endif + return NULL; +} + +/* + * @brief Sets the current primary output's refresh rate. + * + * @param root Window which's primary output will be queried. + * @param size_index Referencing the size to be set. + * @param rate The refresh rate to be set. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_screen_primary_output_refresh_rate_set(Ecore_X_Window root, int size_index, Ecore_X_Randr_Refresh_Rate rate) +{ +#ifdef ECORE_XRANDR + if (_randr_version >= RANDR_VERSION_1_1) + { + XRRScreenConfiguration *cfg = NULL; + + /* try to get the screen config from XRandr */ + if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root))) + { + Eina_Bool ret = EINA_FALSE; + Rotation rot = 0; + + /* get the current rotation */ + XRRConfigRotations(cfg, &rot); + + /* try to set the new screen config + * + * NB: Returns Success (0) if it works */ + if (!XRRSetScreenConfigAndRate(_ecore_x_disp, cfg, root, + size_index, rot, rate, CurrentTime)) + { + ret = EINA_TRUE; + } + + /* free the returned screen config */ + XRRFreeScreenConfigInfo(cfg); + + return ret; + } + } +#endif + return EINA_FALSE; +} + +/*************************************** + * API Functions for RandR version 1.2 * + ***************************************/ + +/** + * @brief Enable event selection. This enables basic interaction with + * output/crtc events and requires RandR >= 1.2. + * + * @param win Select this window's properties for RandR events. + * @param on Enable/disable selecting. + */ +EAPI void +ecore_x_randr_events_select(Ecore_X_Window win, Eina_Bool on) +{ +#ifdef ECORE_XRANDR + int mask = 0; + + if (on) + { + mask = RRScreenChangeNotifyMask; + if (_randr_version >= RANDR_VERSION_1_2) + mask |= (RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | + RROutputPropertyNotifyMask); + } + + /* tell randr what events we want to listen to for this window */ + XRRSelectInput(_ecore_x_disp, win, mask); +#endif +} + +/* + * @param w width of screen in px + * @param h height of screen in px + */ +EAPI void +ecore_x_randr_screen_current_size_get(Ecore_X_Window root, int *w, int *h, int *w_mm, int *h_mm) +{ +#ifdef ECORE_XRANDR + if (_randr_version >= RANDR_VERSION_1_2) + { + int scr = 0; + + /* get the screen number */ + scr = XRRRootToScreen(_ecore_x_disp, root); + + if (w) *w = DisplayWidth(_ecore_x_disp, scr); + if (h) *h = DisplayHeight(_ecore_x_disp, scr); + if (w_mm) *w_mm = DisplayWidthMM(_ecore_x_disp, scr); + if (h_mm) *h_mm = DisplayHeightMM(_ecore_x_disp, scr); + } +#endif +} + +/* + * @param root window which's screen will be queried + * @param wmin minimum width the screen can be set to + * @param hmin minimum height the screen can be set to + * @param wmax maximum width the screen can be set to + * @param hmax maximum height the screen can be set to + */ +EAPI void +ecore_x_randr_screen_size_range_get(Ecore_X_Window root, int *wmin, int *hmin, int *wmax, int *hmax) +{ +#ifdef ECORE_XRANDR + if (_randr_version >= RANDR_VERSION_1_2) + { + int swmin = 0, shmin = 0, swmax = 0, shmax = 0; + + /* try to get the screen size range from XRandr + * + * NB: returns 1 on success */ + if ((XRRGetScreenSizeRange(_ecore_x_disp, root, &swmin, &shmin, + &swmax, &shmax))) + { + /* fill in the return variables */ + if (wmin) *wmin = swmin; + if (hmin) *hmin = shmin; + if (wmax) *wmax = swmax; + if (hmax) *hmax = shmax; + } + } +#endif +} + +/** + * @brief removes unused screen space. The most upper left CRTC is set to 0x0 + * and all other CRTCs dx,dy respectively. + * @param root the window's screen which will be reset. + */ +EAPI void +ecore_x_randr_screen_reset(Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + Ecore_X_Randr_Crtc crtcs[res->ncrtc]; + int i = 0, nenabled = 0; + int nw = 0, nh = 0; + int dx = 100000, dy = 100000; + + for (i = 0; i < res->ncrtc; i++) + { + XRRCrtcInfo *info = NULL; + + /* try to get the crtc info from Xrandr */ + if (!(info = XRRGetCrtcInfo(_ecore_x_disp, res, res->crtcs[i]))) + continue; + + /* safety check */ + if ((info->mode <= 0) || (info->noutput == 0)) + { + /* free the crtc info */ + XRRFreeCrtcInfo(info); + + continue; + } + + crtcs[nenabled++] = res->crtcs[i]; + + if ((int)(info->x + info->width) > nw) + nw = (info->x + info->width); + + if ((int)(info->y + info->height) > nh) + nh = (info->y + info->height); + + if (info->x < dx) dx = info->x; + if (info->y < dy) dy = info->y; + + /* free the crtc info */ + XRRFreeCrtcInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + if ((dx > 0) || (dy > 0)) + { + if (ecore_x_randr_move_crtcs(root, crtcs, nenabled, -dx, -dy)) + { + nw -= dx; + nh -= dy; + } + } + + ecore_x_randr_screen_current_size_set(root, nw, nh, -1, -1); + } +#endif +} + +/* + * @param root Window which's screen's size should be set. If invalid (e.g. + * @c NULL) no action is taken. + * @param w Width in px the screen should be set to. If out of valid + * boundaries, current value is assumed. + * @param h Height in px the screen should be set to. If out of valid + * boundaries, current value is assumed. + * @param w_mm Width in mm the screen should be set to. If @c 0, current + * aspect is assumed. + * @param h_mm Height in mm the screen should be set to. If @c 0, current + * aspect is assumed. + * @return @c EINA_TRUE if request was successfully sent or screen is already + * in requested size, @c EINA_FALSE if parameters are invalid. + */ +EAPI Eina_Bool +ecore_x_randr_screen_current_size_set(Ecore_X_Window root, int w, int h, int w_mm, int h_mm) +{ +#ifdef ECORE_XRANDR + if (_randr_version >= RANDR_VERSION_1_2) + { + int cw = 0, ch = 0, cwmm = 0, chmm = 0; + int wmin = 0, hmin = 0, wmax = 0, hmax = 0; + + /* get the current screen size */ + ecore_x_randr_screen_current_size_get(root, &cw, &ch, &cwmm, &chmm); + + /* compare to the values passed in. if there are no changes, get out */ + if ((w == cw) && (h == ch) && (w_mm == cwmm) && (h_mm == chmm)) + return EINA_TRUE; + + /* get the current size range */ + ecore_x_randr_screen_size_range_get(root, &wmin, &hmin, &wmax, &hmax); + + /* compare to the values passed in. make sure they are within range */ + if ((w != 0) && ((w < wmin) || (w > wmax))) return EINA_FALSE; + if ((h != 0) && ((h < hmin) || (h > hmax))) return EINA_FALSE; + + /* safety check some values */ + if (w <= 0) w = cw; + if (h <= 0) h = ch; + if (w_mm <= 0) + w_mm = (int)(((double)(cwmm / (double)cw)) * (double)w); + if (h_mm <= 0) + h_mm = (int)(((double)(chmm / (double)ch)) * (double)h); + + /* tell XRandr to set screen size */ + XRRSetScreenSize(_ecore_x_disp, root, w, h, w_mm, h_mm); + + return EINA_TRUE; + } +#endif + return EINA_FALSE; +} + +/* + * @brief get detailed information for all modes related to a root window's screen + * @param root window which's screen's ressources are queried + * @param num number of modes returned + * @return modes' information + */ +EAPI Ecore_X_Randr_Mode_Info ** +ecore_x_randr_modes_info_get(Ecore_X_Window root, int *num) +{ + if (num) *num = 0; +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + Ecore_X_Randr_Mode_Info **ret = NULL; + + /* try to allocate space for our return variable */ + if ((ret = (Ecore_X_Randr_Mode_Info **) + malloc(res->nmode * sizeof(Ecore_X_Randr_Mode_Info *)))) + { + int i = 0; + + /* loop through all the modes and assign to our return var */ + for (i = 0; i < res->nmode; i++) + { + if ((ret[i] = malloc(sizeof(Ecore_X_Randr_Mode_Info)))) + { + ret[i]->xid = res->modes[i].id; + ret[i]->width = res->modes[i].width; + ret[i]->height = res->modes[i].height; + ret[i]->dotClock = res->modes[i].dotClock; + ret[i]->hSyncStart = res->modes[i].hSyncStart; + ret[i]->hSyncEnd = res->modes[i].hSyncEnd; + ret[i]->hTotal = res->modes[i].hTotal; + ret[i]->hSkew = res->modes[i].hSkew; + ret[i]->vSyncStart = res->modes[i].vSyncStart; + ret[i]->vSyncEnd = res->modes[i].vSyncEnd; + ret[i]->vTotal = res->modes[i].vTotal; + if ((ret[i]->name = + (malloc(res->modes[i].nameLength + 1)))) + strncpy(ret[i]->name, res->modes[i].name, + (res->modes[i].nameLength + 1)); + else + ret[i]->name = NULL; + + ret[i]->nameLength = res->modes[i].nameLength; + ret[i]->modeFlags = res->modes[i].modeFlags; + } + else + { + while (i > 0) + free(ret[--i]); + free(ret); + ret = NULL; + break; + } + } + } + + /* set the returned number of modes */ + if ((ret) && (num)) *num = res->nmode; + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return NULL; +} + +/* + * @brief Add a mode to a display. + * + * @param root Window to which's screen's ressources are added. + * @param mode_info + * @return Ecore_X_Randr_Mode of the added mode. Ecore_X_Randr_None if mode + * adding failed. + * @since 1.2.0 + */ +EAPI Ecore_X_Randr_Mode +ecore_x_randr_mode_info_add(Ecore_X_Window root, Ecore_X_Randr_Mode_Info *mode_info) +{ +#ifdef ECORE_XRANDR + if (_randr_version >= RANDR_VERSION_1_2) + { + Ecore_X_Randr_Mode mode = 0; + + /* if we have valid mode_info from the user, then ask XRandr to + * create the new mode using that as base */ + if (mode_info) + mode = XRRCreateMode(_ecore_x_disp, root, (XRRModeInfo *)mode_info); + + return mode; + } +#endif + return 0; +} + +/* + * @brief Delete a mode from the display. + * + * @param mode_info + * @since 1.2.0 + */ +EAPI void +ecore_x_randr_mode_del(Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + if (_randr_version >= RANDR_VERSION_1_2) + XRRDestroyMode(_ecore_x_disp, mode); +#endif +} + +/* + * @brief get detailed information for a given mode id + * @param root window which's screen's ressources are queried + * @param mode the XID which identifies the mode of interest + * @return mode's detailed information + */ +EAPI Ecore_X_Randr_Mode_Info * +ecore_x_randr_mode_info_get(Ecore_X_Window root, Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + Ecore_X_Randr_Mode_Info *ret = NULL; + int i = 0; + + /* loop the mode informations and find the one we want */ + for (i = 0; i < res->nmode; i++) + { + /* compare mode ids */ + if (res->modes[i].id != mode) continue; + + /* try to allocate our return mode information structure */ + if (!(ret = malloc(sizeof(Ecore_X_Randr_Mode_Info)))) + break; + + /* copy the mode information into our return structure */ + ret->xid = res->modes[i].id; + ret->width = res->modes[i].width; + ret->height = res->modes[i].height; + ret->dotClock = res->modes[i].dotClock; + ret->hSyncStart = res->modes[i].hSyncStart; + ret->hSyncEnd = res->modes[i].hSyncEnd; + ret->hTotal = res->modes[i].hTotal; + ret->hSkew = res->modes[i].hSkew; + ret->vSyncStart = res->modes[i].vSyncStart; + ret->vSyncEnd = res->modes[i].vSyncEnd; + ret->vTotal = res->modes[i].vTotal; + ret->modeFlags = res->modes[i].modeFlags; + ret->name = NULL; + ret->nameLength = 0; + if (res->modes[i].nameLength > 0) + { + ret->nameLength = res->modes[i].nameLength; + if ((ret->name = malloc(res->modes[i].nameLength + 1))) + strncpy(ret->name, res->modes[i].name, + (res->modes[i].nameLength + 1)); + } + break; + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return NULL; +} + +/* + * @brief Free detailed mode information. The pointer handed in will be set to + * @c NULL after freeing the memory. + * + * @param mode_info The mode information that should be freed. + */ +EAPI void +ecore_x_randr_mode_info_free(Ecore_X_Randr_Mode_Info *mode_info) +{ +#ifdef ECORE_XRANDR + if (_randr_version >= RANDR_VERSION_1_2) + { + if (mode_info) + { + if (mode_info->name) free(mode_info->name); + free(mode_info); + mode_info = NULL; + } + } +#endif +} + +/* + * @brief Get all known CRTCs related to a root window's screen. + * + * @param root Window which's screen's ressources are queried. + * @param num Number of CRTCs returned. + * @return CRTC IDs. + */ +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_crtcs_get(Ecore_X_Window root, int *num) +{ + if (num) *num = 0; +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + Ecore_X_Randr_Crtc *ret = NULL; + + /* try to allocate space for our return variable */ + if ((ret = malloc(res->ncrtc * sizeof(Ecore_X_Randr_Crtc)))) + { + int i = 0; + + if (num) *num = res->ncrtc; + + /* copy the crtc information into our return variable */ + for (i = 0; i < res->ncrtc; i++) + ret[i] = res->crtcs[i]; + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return NULL; +} + +EAPI Ecore_X_Randr_Output * +ecore_x_randr_outputs_get(Ecore_X_Window root, int *num) +{ + if (num) *num = 0; +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + Ecore_X_Randr_Output *ret = NULL; + + /* try to allocate space for our return variable */ + if ((ret = malloc(res->noutput * sizeof(Ecore_X_Randr_Output)))) + { + int i = 0; + + if (num) *num = res->noutput; + + /* copy the output information into our return variable */ + for (i = 0; i < res->noutput; i++) + ret[i] = res->outputs[i]; + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return NULL; +} + +/* + * @brief Get the outputs, which display a certain window. + * + * @param window Window the displaying outputs shall be found for + * @param num The number of outputs displaying the window + * @return Array of outputs that display a certain window. @c NULL if no + * outputs was found that displays the specified window. + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_window_outputs_get(Ecore_X_Window window, int *num) +{ + if (num) *num = 0; +#ifdef ECORE_XRANDR + Ecore_X_Window root; + Ecore_X_Randr_Crtc *crtcs = NULL; + int ncrtcs = 0; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + /* grab this windows root window */ + root = ecore_x_window_root_get(window); + + /* get the crtcs from xrandr */ + if ((crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs))) + { + XRRScreenResources *res = NULL; + Ecore_X_Randr_Output *ret = NULL; + + /* try to get the screen resources from Xrandr + * + * NB: We do this ONCE here as we reuse it for every crtc. + * NB: The old code used to loop and fetch the screen resources on + * every crtc */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + Ecore_X_Randr_Output *tret = NULL; + int i = 0, nret = 0; + + /* for each crtc, get it's outputs */ + for (i = 0, nret = 0; i < ncrtcs; i++) + { + XRRCrtcInfo *crtc = NULL; + + /* try to get the crtc info for this crtc */ + if (!(crtc = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i]))) + continue; + + /* try to reallocate our return variable */ + if ((tret = realloc(ret, ((nret + crtc->noutput) * + sizeof(Ecore_X_Randr_Output))))) + { + ret = tret; + memcpy(&ret[nret], crtc->outputs, + (crtc->noutput * sizeof(Ecore_X_Randr_Output))); + nret += crtc->noutput; + } + + /* free the crtc info */ + XRRFreeCrtcInfo(crtc); + } + + if (num) *num = nret; + + /* free the resources */ + XRRFreeScreenResources(res); + } + + /* free any allocated crtcs from the get function */ + free(crtcs); + + return ret; + } +#endif + return NULL; +} + +/* + * @deprecated bad naming. Use ecore_x_randr_window_outputs_get instead. + * @brief Get the outputs, which display a certain window. + * + * @param window Window the displaying outputs shall be found for. + * @param num The number of outputs displaying the window. + * @return Array of outputs that display a certain window. @c NULL if no + * outputs was found that displays the specified window. + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_current_output_get(Ecore_X_Window window, int *num) +{ + return ecore_x_randr_window_outputs_get(window, num); +} + +/* + * @brief get the CRTCs, which display a certain window + * @param window window the displaying crtcs shall be found for + * @param num the number of crtcs displaying the window + * @return Array of crtcs that display a certain window. @c NULL if no crtcs + * was found that displays the specified window. + * @since 1.2.0 + */ +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_window_crtcs_get(Ecore_X_Window window, int *num) +{ + if (num) *num = 0; +#ifdef ECORE_XRANDR + Ecore_X_Window root; + Ecore_X_Randr_Crtc *crtcs = NULL; + int ncrtcs = 0; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + /* grab this windows root window */ + root = ecore_x_window_root_get(window); + + /* get the crtcs from xrandr */ + if ((crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs))) + { + XRRScreenResources *res = NULL; + Ecore_X_Randr_Crtc *ret = NULL; + + /* make sure we can allocate our return variable */ + if (!(ret = calloc(1, ncrtcs * sizeof(Ecore_X_Randr_Crtc)))) + { + free(crtcs); + return NULL; + } + + /* try to get the screen resources from Xrandr + * + * NB: We do this ONCE here as we reuse it for every crtc. + * NB: The old code used to loop and fetch the screen resources on + * every crtc */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + Window tw; + Eina_Rectangle wrect, crect; + int i = 0, nret = 0; + + /* get the geometry of this window */ + ecore_x_window_geometry_get(window, &wrect.x, &wrect.y, + &wrect.w, &wrect.h); + + /* translate coordinates relative to root window */ + XTranslateCoordinates(_ecore_x_disp, window, root, + 0, 0, &wrect.x, &wrect.y, &tw); + + for (i = 0; i < ncrtcs; i++) + { + XRRCrtcInfo *info = NULL; + + /* try to get crtc info */ + if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i]))) + { + /* check if crtc is enabled */ + if (info->mode != 0) + { + /* enabled. get geometry */ + crect.x = info->x; + crect.y = info->y; + crect.w = info->width; + crect.h = info->height; + + /* check intersection with window */ + if (eina_rectangles_intersect(&wrect, &crect)) + { + /* add if intersect */ + ret[nret] = crtcs[i]; + nret++; + } + } + + /* free the crtc info */ + XRRFreeCrtcInfo(info); + } + } + + /* free the resources */ + XRRFreeScreenResources(res); + + if (num) *num = nret; + } + + free(crtcs); + + return ret; + } +#endif + return NULL; +} + +/* + * @deprecated bad naming. Use ecore_x_randr_window_crtcs_get instead. + * @brief get the CRTCs, which display a certain window + * @param window window the displaying crtcs shall be found for + * @param num the number of crtcs displaying the window + * @return Array of crtcs that display a certain window. @c NULL if no crtcs + * was found that displays the specified window. + */ +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_current_crtc_get(Ecore_X_Window window, int *num) +{ + return ecore_x_randr_window_crtcs_get(window, num); +} + +/* + * @brief get a CRTC's outputs. + * @param root the root window which's screen will be queried + * @param num number of outputs referenced by given CRTC + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_crtc_outputs_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *num) +{ + if (num) *num = 0; +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRRCrtcInfo *info = NULL; + Ecore_X_Randr_Output *ret = NULL; + + /* try to get crtc info */ + if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + /* try to allocate our return struct */ + if ((ret = malloc(info->noutput * sizeof(Ecore_X_Randr_Output)))) + { + int i = 0; + + /* loop the outputs on this crtc */ + for (i = 0; i < info->noutput; i++) + ret[i] = info->outputs[i]; + + if (num) *num = info->noutput; + } + + /* free the crtc info */ + XRRFreeCrtcInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return NULL; +} + +/* + * @brief get a CRTC's possible outputs. + * @param root the root window which's screen will be queried + * @param num number of possible outputs referenced by given CRTC + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_crtc_possible_outputs_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *num) +{ + if (num) *num = 0; +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRRCrtcInfo *info = NULL; + Ecore_X_Randr_Output *ret = NULL; + + /* try to get crtc info */ + if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + /* try to allocate our return struct */ + if ((ret = malloc(info->npossible * sizeof(Ecore_X_Randr_Output)))) + { + int i = 0; + + /* loop the outputs on this crtc */ + for (i = 0; i < info->npossible; i++) + ret[i] = info->possible[i]; + + if (num) *num = info->npossible; + } + + /* free the crtc info */ + XRRFreeCrtcInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return NULL; +} + +EAPI void +ecore_x_randr_crtc_geometry_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRRCrtcInfo *info = NULL; + + /* try to get crtc info */ + if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + if (x) *x = info->x; + if (y) *y = info->y; + if (w) *w = info->width; + if (h) *h = info->height; + + /* free the crtc info */ + XRRFreeCrtcInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + } +#endif +} + +EAPI void +ecore_x_randr_crtc_pos_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y) +{ +#ifdef ECORE_XRANDR + if (_randr_version < RANDR_VERSION_1_2) return; + + ecore_x_randr_crtc_geometry_get(root, crtc, x, y, NULL, NULL); +#endif +} + +/* + * @brief Sets the position of given CRTC within root window's screen. + * + * @param root The window's screen to be queried. + * @param crtc The CRTC which's position within the mentioned screen is to be + * altered. + * @param x Position on the x-axis (0 == left) of the screen. if x < 0 current + * value will be kept. + * @param y Position on the y-ayis (0 == top) of the screen. if y < 0, current + * value will be kept. + * @return @c EINA_TRUE if position could successfully be altered. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_pos_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int x, int y) +{ +#ifdef ECORE_XRANDR + int cx = 0, cy = 0, cw = 0, ch = 0; + int sw = 0, sh = 0, nw = 0, nh = 0; + + if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE; + + /* grab the current crtc geometry */ + ecore_x_randr_crtc_geometry_get(root, crtc, &cx, &cy, &cw, &ch); + + /* grab the current screen geometry */ + ecore_x_randr_screen_current_size_get(root, &sw, &sh, NULL, NULL); + + /* safety check some values */ + if (x < 0) x = cx; + if (y < 0) y = cy; + if ((x + cw) > sw) nw = (x + cw); + if ((y + ch) > sh) nh = (y + ch); + + if ((nw > 0) && (nh > 0)) + { + /* try to update the current screen geometry */ + if (!ecore_x_randr_screen_current_size_set(root, nw, nh, 0, 0)) + return EINA_FALSE; + } + + /* try to set the new crtc position */ + return ecore_x_randr_crtc_settings_set(root, crtc, NULL, -1, x, y, -1, -1); +#endif + return EINA_FALSE; +} + +/** + * @brief Get the current set mode of a given CRTC + * @param root the window's screen to be queried + * @param crtc the CRTC which's should be queried + * @return currently set mode or - in case parameters are invalid - + * Ecore_X_Randr_Unset + */ +EAPI Ecore_X_Randr_Mode +ecore_x_randr_crtc_mode_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return -1; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRRCrtcInfo *info = NULL; + Ecore_X_Randr_Mode ret = -1; + + /* try to get crtc info */ + if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + /* get the mode */ + ret = info->mode; + + /* free the crtc info */ + XRRFreeCrtcInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return -1; +} + +/** + * @brief Sets a mode for a CRTC and the outputs attached to it. + * + * @param root The window's screen to be queried. + * @param crtc The CRTC which shall be set. + * @param outputs Array of outputs which have to be compatible with the mode. + * If @c NULL, CRTC will be disabled. + * @param noutputs Number of outputs in array to be used. Use + * Ecore_X_Randr_Unset (or @c -1) to use currently used outputs. + * @param mode XID of the mode to be set. If set to @c 0 the CRTC will be + * disabled. If set to @c -1 the call will fail. + * @return @c EINA_TRUE if mode setting was successful, @c EINA_FALSE + * otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_mode_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, Ecore_X_Randr_Output *outputs, int noutputs, Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE; + + return ecore_x_randr_crtc_settings_set(root, crtc, outputs, noutputs, + -1, -1, mode, -1); +#endif + return EINA_FALSE; +} + +EAPI void +ecore_x_randr_crtc_size_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *w, int *h) +{ +#ifdef ECORE_XRANDR + if (_randr_version < RANDR_VERSION_1_2) return; + ecore_x_randr_crtc_geometry_get(root, crtc, NULL, NULL, w, h); +#endif +} + +EAPI Ecore_X_Randr_Refresh_Rate +ecore_x_randr_crtc_refresh_rate_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc EINA_UNUSED, Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return 0.0; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + int i = 0; + double ret = 0.0; + + for (i = 0; i < res->nmode; i++) + { + if (res->modes[i].id == mode) + { + if ((res->modes[i].hTotal) && (res->modes[i].vTotal)) + { + ret = ((double)res->modes[i].dotClock / + ((double)res->modes[i].hTotal * + (double)res->modes[i].vTotal)); + } + break; + } + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return 0.0; +} + +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_crtc_orientations_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return 0; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRRCrtcInfo *info = NULL; + Ecore_X_Randr_Orientation ret = 0; + + /* try to get crtc info */ + if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + /* get the mode */ + ret = info->rotations; + + /* free the crtc info */ + XRRFreeCrtcInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return 0; +} + +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_crtc_orientation_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return 0; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRRCrtcInfo *info = NULL; + Ecore_X_Randr_Orientation ret = 0; + + /* try to get crtc info */ + if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + /* get the mode */ + ret = info->rotation; + + /* free the crtc info */ + XRRFreeCrtcInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return 0; +} + +EAPI Eina_Bool +ecore_x_randr_crtc_orientation_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, const Ecore_X_Randr_Orientation orientation) +{ +#ifdef ECORE_XRANDR + if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE; + + if (orientation != 0) + return ecore_x_randr_crtc_settings_set(root, crtc, NULL, + -1, -1, -1, -1, orientation); +#endif + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_randr_crtc_clone_set(Ecore_X_Window root, Ecore_X_Randr_Crtc original, Ecore_X_Randr_Crtc cln) +{ +#ifdef ECORE_XRANDR + Eina_Bool ret = EINA_FALSE; + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRRCrtcInfo *info = NULL; + Ecore_X_Randr_Orientation orig_orient = 0; + Ecore_X_Randr_Mode orig_mode = -1; + int ox = 0, oy = 0; + + /* try to get crtc info for original crtc */ + if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, original))) + { + ox = info->x; + oy = info->y; + orig_orient = info->rotation; + orig_mode = info->mode; + + /* free the crtc info */ + XRRFreeCrtcInfo(info); + } + + ret = ecore_x_randr_crtc_settings_set(root, cln, NULL, -1, ox, oy, + orig_mode, orig_orient); + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return EINA_FALSE; +} + +/** + * @brief Sets the demanded parameters for a given CRTC. Note that the CRTC is + * auto enabled in it's preferred mode, when it was disabled before. + * + * @param root The root window which's default display will be queried. + * @param crtc The CRTC which's configuration should be altered. + * @param outputs An array of outputs, that should display this CRTC's content. + * @param noutputs Number of outputs in the array of outputs. If set to + * Ecore_X_Randr_Unset, current outputs and number of outputs will be used. + * If set to Ecore_X_Randr_None, CRTC will be disabled. + * @param x New x coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current x + * corrdinate will be assumed. + * @param y New y coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current y + * corrdinate will be assumed. + * @param mode The new mode to be set. If Ecore_X_Randr_None is passed, the + * CRTC will be disabled. If Ecore_X_Randr_Unset is passed, the current mode is + * assumed. + * @param orientation The new orientation to be set. If Ecore_X_Randr_Unset is + * used, the current mode is assumed. + * @return @c EINA_TRUE if the configuration alteration was successful, + * @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_settings_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, Ecore_X_Randr_Output *outputs, int noutputs, int x, int y, Ecore_X_Randr_Mode mode, Ecore_X_Randr_Orientation orientation) +{ +#ifdef ECORE_XRANDR + Eina_Bool ret = EINA_FALSE; + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRRCrtcInfo *info = NULL; + + /* try to get crtc info for original crtc */ + if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + if ((mode == 0) || (noutputs == 0)) + outputs = NULL; + else if (noutputs == -1) + { + outputs = (Ecore_X_Randr_Output *)info->outputs; + noutputs = info->noutput; + } + + /* safety check some values */ + if ((int)mode == -1) mode = info->mode; + if ((int)orientation == -1) orientation = info->rotation; + if (x < 0) x = info->x; + if (y < 0) y = info->y; + + /* try to set the crtc config */ + if (!XRRSetCrtcConfig(_ecore_x_disp, res, crtc, CurrentTime, + x, y, mode, orientation, + (RROutput *)outputs, noutputs)) + ret = EINA_TRUE; + + /* free the crtc info */ + XRRFreeCrtcInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return EINA_FALSE; +} + +/** + * @brief Sets a CRTC relative to another one. + * + * @param root The root window which's default display will be set. + * @param crtc_r1 The CRTC to be positioned. + * @param crtc_r2 The CRTC the position should be relative to. + * @param policy The relation between the crtcs. + * @param alignment In case CRTCs size differ, aligns CRTC1 accordingly at + * CRTC2's borders. + * @return @c EINA_TRUE if crtc could be successfully positioned, @c EINA_FALSE + * if repositioning failed or if position of new crtc would be out of given + * screen's min/max bounds. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_pos_relative_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc_r1, Ecore_X_Randr_Crtc crtc_r2, Ecore_X_Randr_Output_Policy policy, Ecore_X_Randr_Relative_Alignment alignment) +{ +#ifdef ECORE_XRANDR + Eina_Rectangle r1, r2; + int mw = 0, mh = 0, sw = 0, sh = 0; + int nx = 0, ny = 0; + + if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE; + + /* check each crtc has a valid mode */ + if (ecore_x_randr_crtc_mode_get(root, crtc_r1) == 0) return EINA_FALSE; + if (ecore_x_randr_crtc_mode_get(root, crtc_r2) == 0) return EINA_FALSE; + + /* get the geometry of each crtc */ + ecore_x_randr_crtc_geometry_get(root, crtc_r1, &r1.x, &r1.y, &r1.w, &r1.h); + ecore_x_randr_crtc_geometry_get(root, crtc_r2, &r2.x, &r2.y, &r2.w, &r2.h); + + /* get the geometry of the screen */ + ecore_x_randr_screen_size_range_get(root, NULL, NULL, &mw, &mh); + ecore_x_randr_screen_current_size_get(root, &sw, &sh, NULL, NULL); + + switch (policy) + { + case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT: + nx = (r2.x + r2.w); + + switch (alignment) + { + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE: + ny = -1; + break; + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL: + ny = ((int)(((double)r2.h / 2.0) + r2.y - ((double)r1.h / 2.0))); + break; + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR: + ny = ((int)((double)sh / 2.0) - ((double)r1.h / 2.0)); + break; + } + + break; + case ECORE_X_RANDR_OUTPUT_POLICY_LEFT: + nx = (r2.x - r1.w); + + switch (alignment) + { + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE: + ny = -1; + break; + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL: + ny = ((int)(((double)r2.h / 2.0) + r2.y - ((double)r1.h / 2.0))); + break; + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR: + ny = ((int)((double)sh / 2.0) - ((double)r1.h / 2.0)); + break; + } + + break; + case ECORE_X_RANDR_OUTPUT_POLICY_BELOW: + ny = (r2.y + r2.h); + + switch (alignment) + { + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE: + nx = -1; + break; + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL: + nx = ((int)((((double)r2.x + (double)r2.w) / 2.0) - + ((double)r1.w / 2.0))); + break; + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR: + nx = ((int)((double)sw / 2.0)); + break; + } + + break; + case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE: + ny = (r2.y - r1.h); + + switch (alignment) + { + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE: + nx = -1; + break; + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL: + nx = ((int)((((double)r2.x + (double)r2.w) / 2.0) - + ((double)r1.w / 2.0))); + break; + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR: + nx = ((int)((double)sw / 2.0)); + break; + } + + break; + case ECORE_X_RANDR_OUTPUT_POLICY_CLONE: + return ecore_x_randr_crtc_pos_set(root, crtc_r1, r2.x, r2.y); + break; + case ECORE_X_RANDR_OUTPUT_POLICY_NONE: + break; + default: + return EINA_FALSE; + } + + if ((nx == r1.x) && (ny == r1.y)) return EINA_TRUE; + if (((ny + r1.h) > mh) || ((nx + r1.w) > mw)) return EINA_FALSE; + + return ecore_x_randr_crtc_pos_set(root, crtc_r1, nx, ny); +#else + return EINA_FALSE; +#endif +} + +/* + * @brief Add given mode to given output. + * + * @param output The output the mode is added to. + * @param mode The mode added to the output. + * @return @c EINA_FALSE if output or mode equal Ecore_X_Randr_None, else + * @c EINA_TRUE. + * Additionally, if xcb backend is used, the success of the addition is + * reported back directly. + * @since 1.2.0 + */ +EAPI Eina_Bool +ecore_x_randr_output_mode_add(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE; + + if ((output) && (mode)) + { + /* add this mode to output + * + * NB: This XRR function returns void so we have to assume it worked */ + XRRAddOutputMode(_ecore_x_disp, output, mode); + + return EINA_TRUE; + } +#endif + return EINA_FALSE; +} + +/* + * @brief delete given mode from given output + * @param output the output the mode is removed from + * @param mode the mode removed from the output + * @since 1.2.0 + */ +EAPI void +ecore_x_randr_output_mode_del(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + if (_randr_version < RANDR_VERSION_1_2) return; + + if ((!output) || (!mode)) return; + + XRRDeleteOutputMode(_ecore_x_disp, output, mode); +#endif +} + +EAPI Ecore_X_Randr_Mode * +ecore_x_randr_output_modes_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num, int *npreferred) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRROutputInfo *info = NULL; + Ecore_X_Randr_Mode *modes = NULL; + + /* try to get output info */ + if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + if ((modes = malloc(info->nmode * sizeof(Ecore_X_Randr_Mode)))) + { + int i = 0; + + for (i = 0; i < info->nmode; i++) + modes[i] = info->modes[i]; + + if (num) *num = info->nmode; + if (npreferred) *npreferred = info->npreferred; + } + + /* free the output info */ + XRRFreeOutputInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return modes; + } +#endif + return NULL; +} + +/** + * @brief gets the the outputs which might be used simultenously on the same + * CRTC. + * @param root window that this information should be queried for. + * @param output the output which's clones we concern + * @param num number of possible clones + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_output_clones_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRROutputInfo *info = NULL; + Ecore_X_Randr_Output *outputs = NULL; + + /* try to get output info */ + if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + /* try to allocate space for output return */ + if ((outputs = malloc(info->nclone * sizeof(Ecore_X_Randr_Output)))) + { + int i = 0; + + for (i = 0; i < info->nclone; i++) + outputs[i] = info->clones[i]; + + if (num) *num = info->nclone; + } + + /* free the output info */ + XRRFreeOutputInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return outputs; + } +#endif + return NULL; +} + +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_output_possible_crtcs_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return 0; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRROutputInfo *info = NULL; + Ecore_X_Randr_Crtc *crtcs = NULL; + + /* try to get output info */ + if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + /* try to allocate space for the return crtcs */ + if ((crtcs = malloc(info->ncrtc * sizeof(Ecore_X_Randr_Crtc)))) + { + int i = 0; + + for (i = 0; i < info->ncrtc; i++) + crtcs[i] = info->crtcs[i]; + + if (num) *num = info->ncrtc; + } + + /* free the output info */ + XRRFreeOutputInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return crtcs; + } +#endif + return NULL; +} + +EAPI Ecore_X_Randr_Crtc +ecore_x_randr_output_crtc_get(Ecore_X_Window root, Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return 0; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRROutputInfo *info = NULL; + Ecore_X_Randr_Crtc ret = 0; + + /* try to get output info */ + if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + ret = info->crtc; + + /* free the output info */ + XRRFreeOutputInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return 0; +} + +/** + * @brief gets the given output's name as reported by X + * @param root the window which's screen will be queried + * @param output The output for which the name will be reported. + * @param len length of returned c-string. + * @return name of the output as reported by X + */ +EAPI char * +ecore_x_randr_output_name_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *len) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return 0; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRROutputInfo *info = NULL; + char *ret = NULL; + + /* try to get output info */ + if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + if (info->name) + { + /* FIXME: TODO: NB: + * + * Old randr code says there is an xrandr bug here with + * nameLen. Test This !!! + * + */ + ret = strdup(info->name); + if (len) *len = info->nameLen; + } + + /* free the output info */ + XRRFreeOutputInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return NULL; +} + +EAPI int +ecore_x_randr_crtc_gamma_ramp_size_get(Ecore_X_Randr_Crtc crtc) +{ + /* TODO: !!! */ + return 0; +} + +EAPI Ecore_X_Randr_Crtc_Gamma ** +ecore_x_randr_crtc_gamma_ramps_get(Ecore_X_Randr_Crtc crtc) +{ + /* TODO: !!! */ + return NULL; +} + +EAPI Eina_Bool +ecore_x_randr_crtc_gamma_ramps_set(Ecore_X_Randr_Crtc crtc, const Ecore_X_Randr_Crtc_Gamma *red, const Ecore_X_Randr_Crtc_Gamma *green, const Ecore_X_Randr_Crtc_Gamma *blue) +{ + /* TODO: !!! */ + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_randr_move_all_crtcs_but(Ecore_X_Window root, const Ecore_X_Randr_Crtc *not_moved, int nnot_moved, int dx, int dy) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + Eina_Bool ret = EINA_FALSE; + + if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE; + + if ((nnot_moved <= 0) || (!not_moved)) return EINA_FALSE; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + Ecore_X_Randr_Crtc *crtcs = NULL; + int n = 0; + + n = (res->ncrtc - nnot_moved); + + /* try to allocate space for a list of crtcs */ + if ((crtcs = malloc(n * sizeof(Ecore_X_Randr_Crtc)))) + { + int i = 0, j = 0, k = 0; + + for (i = 0, k = 0; (i < res->ncrtc) && (k < n); i++) + { + for (j = 0; j < nnot_moved; j++) + { + if (res->crtcs[i] == not_moved[j]) + break; + } + + if (j == nnot_moved) crtcs[k++] = res->crtcs[i]; + } + } + + /* free the resources */ + XRRFreeScreenResources(res); + + /* actually move the crtcs */ + ret = ecore_x_randr_move_crtcs(root, crtcs, n, dx, dy); + free(crtcs); + + return ret; + } +#endif + return EINA_FALSE; +} + +/* + * @brief Move given CRTCs belonging to the given root window's screen dx/dy + * pixels relative to their current position. The screen size will be + * automatically adjusted if necessary and possible. + * + * @param root Window which's screen's resources are used. + * @param crtcs List of CRTCs to be moved. + * @param ncrtc Number of CRTCs in array. + * @param dx Amount of pixels the CRTCs should be moved in x direction. + * @param dy Amount of pixels the CRTCs should be moved in y direction. + * @return @c EINA_TRUE if all crtcs could be moved successfully. + */ +EAPI Eina_Bool +ecore_x_randr_move_crtcs(Ecore_X_Window root, const Ecore_X_Randr_Crtc *crtcs, int ncrtc, int dx, int dy) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + XRRCrtcInfo **info = NULL; + int i = 0; + + if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + Eina_Bool ret = EINA_TRUE; + int mw = 0, mh = 0, sw = 0, sh = 0; + int nw = 0, nh = 0; + + info = alloca(ncrtc * sizeof(XRRCrtcInfo *)); + memset(info, 0, ncrtc * sizeof(XRRCrtcInfo)); + + ecore_x_randr_screen_size_range_get(root, NULL, NULL, &mw, &mh); + ecore_x_randr_screen_current_size_get(root, &sw, &sh, NULL, NULL); + nw = sw; + nh = sh; + + for (i = 0; i < ncrtc; i++) + { + /* try to get crtc info for original crtc */ + if ((info[i] = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i]))) + { + if (((info[i]->x + dx) < 0) || ((info[i]->y + dy < 0)) || + ((int)(info[i]->x + info[i]->width) > mw) || + ((int)(info[i]->y + info[i]->height) > mh)) + { + goto err; + } + + nw = MAX(((int)(info[i]->x + info[i]->width) + dx), nw); + nh = MAX(((int)(info[i]->y + info[i]->height) + dy), nh); + } + } + + /* resize the screen if we need to */ + if (!(((nw > sw) || (nh > sh)) || + ecore_x_randr_screen_current_size_set(root, nw, nh, -1, -1))) + goto err; + + /* actually move the crtcs */ + for (i = 0; ((i < ncrtc) && info[i]); i++) + { + if (!ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, -1, + (info[i]->x + dx), + (info[i]->y + dy), + info[i]->mode, + info[i]->rotation)) + { + ret = EINA_FALSE; + break; + } + } + + if (i < ncrtc) + { + /* something went wrong somewhere. move everything back */ + while (i-- >= 0) + { + if (info[i]) + ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, -1, + (info[i]->x - dx), + (info[i]->y - dy), + info[i]->mode, + info[i]->rotation); + } + } + + /* cleanup */ + for (i = 0; i < ncrtc; i++) + if (info[i]) XRRFreeCrtcInfo(info[i]); + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } + +err: + while (i-- > 0) + { + /* free the crtc info */ + if (info[i]) XRRFreeCrtcInfo(info[i]); + } + + /* free the resources */ + if (res) XRRFreeScreenResources(res); +#endif + return EINA_FALSE; +} + +/** + * @brief gets the width and hight of a given mode + * @param mode the mode which's size is to be looked up + * @param w width of given mode in px + * @param h height of given mode in px + */ +EAPI void +ecore_x_randr_mode_size_get(Ecore_X_Window root, Ecore_X_Randr_Mode mode, int *w, int *h) +{ +#ifdef ECORE_XRANDR + if (_randr_version < RANDR_VERSION_1_2) return; + + if ((mode != 0) && ((w) || (h))) + { + XRRScreenResources *res = NULL; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + int i = 0; + + for (i = 0; i < res->nmode; i++) + { + if (res->modes[i].id == mode) + { + if (w) *w = res->modes[i].width; + if (h) *h = res->modes[i].height; + break; + } + } + + /* free the resources */ + XRRFreeScreenResources(res); + } + } +#endif +} + +EAPI Ecore_X_Randr_Connection_Status +ecore_x_randr_output_connection_status_get(Ecore_X_Window root, Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) + return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRROutputInfo *info = NULL; + Ecore_X_Randr_Connection_Status ret = + ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN; + + /* try to get output info */ + if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + ret = info->connection; + + /* free the output info */ + XRRFreeOutputInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN; +} + +EAPI void +ecore_x_randr_output_size_mm_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *w, int *h) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) return; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRROutputInfo *info = NULL; + + /* try to get output info */ + if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + if (w) *w = info->mm_width; + if (h) *h = info->mm_height; + + /* free the output info */ + XRRFreeOutputInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + } +#endif +} + +EAPI Eina_Bool +ecore_x_randr_output_crtc_set(Ecore_X_Window root, Ecore_X_Randr_Output output, const Ecore_X_Randr_Crtc crtc) +{ + /* TODO: !! */ + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_randr_output_backlight_available(void) +{ +#ifdef ECORE_XRANDR + Atom backlight = None; + + /* check for new backlight property */ + if ((backlight = XInternAtom(_ecore_x_disp, RR_PROPERTY_BACKLIGHT, True))) + return EINA_TRUE; + + /* check for legacy backlight property */ + if ((backlight = XInternAtom(_ecore_x_disp, "BACKLIGHT", True))) + return EINA_TRUE; +#endif + return EINA_FALSE; +} + +/** + * @brief Set up the backlight level to the given level. + * + * @param root The window's screen which will be set. + * @param level Of the backlight between @c 0 and @c 1. + */ +EAPI void +ecore_x_randr_screen_backlight_level_set(Ecore_X_Window root, double level) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + int i = 0; + + if (_randr_version < RANDR_VERSION_1_3) return; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + /* set the backlight level on each output */ + for (i = 0; i < res->noutput; i++) + ecore_x_randr_output_backlight_level_set(root, res->outputs[i], level); + + /* free the resources */ + XRRFreeScreenResources(res); + } +#endif +} + +EAPI double +ecore_x_randr_output_backlight_level_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + XRRPropertyInfo *info = NULL; + Atom backlight = None, type = None; + unsigned long bytes = 0; + unsigned long items = 0; + unsigned char *prop = NULL; + long val = 0; + int format = 0; + + /* check if "new" backlight is available */ + if (_randr_version >= RANDR_VERSION_1_3) + { + if ((backlight = + XInternAtom(_ecore_x_disp, RR_PROPERTY_BACKLIGHT, True))) + { + XRRGetOutputProperty(_ecore_x_disp, output, backlight, 0, 4, + False, False, None, &type, &format, + &items, &bytes, &prop); + } + } + + if ((!prop) || (items == 0)) + { + /* check legacy backlight property + * + * FIXME: NB: Not sure what randr version we need for the legacy + * backlight property so skip version check */ + if ((backlight = XInternAtom(_ecore_x_disp, "BACKLIGHT", True))) + { + XRRGetOutputProperty(_ecore_x_disp, output, backlight, 0, 4, + False, False, None, &type, &format, + &items, &bytes, &prop); + } + } + + /* safety check */ + if ((type != XA_INTEGER) || (items != 1) || (format != 32)) + { + WRN("Backlight property is not supported on this server or driver"); + return -1; + } + + val = *((long *)prop); + free(prop); + + /* try to get the backlight property value from Xrandr */ + if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, backlight))) + { + double ret = -1; + + if ((info->range) && (info->num_values == 2)) + { + /* convert the current value */ + ret = ((double)(val - info->values[0])) / + ((double)(info->values[1] - info->values[0])); + } + + /* free the info */ + free(info); + + return ret; + } +#endif + return -1; +} + +EAPI Eina_Bool +ecore_x_randr_output_backlight_level_set(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, double level) +{ +#ifdef ECORE_XRANDR + XRRPropertyInfo *info = NULL; + Atom backlight = None; + + /* safety check some input values */ + if ((level < 0) || (level > 1)) + { + ERR("Backlight level should be between 0 and 1"); + return EINA_FALSE; + } + + /* check if "new" backlight is available */ + if (_randr_version >= RANDR_VERSION_1_3) + backlight = XInternAtom(_ecore_x_disp, RR_PROPERTY_BACKLIGHT, True); + + if (!backlight) + backlight = XInternAtom(_ecore_x_disp, "BACKLIGHT", True); + + if (!backlight) + { + WRN("Backlight property is not supported on this server or driver"); + return EINA_FALSE; + } + + /* try to get the output property from Xrandr */ + if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, backlight))) + { + Eina_Bool ret = EINA_FALSE; + + if ((info->range) && (info->num_values == 2)) + { + double min = 0.0, max = 0.0; + long val = 0; + + min = info->values[0]; + max = info->values[1]; + val = (level * (max - min)) + min; + if (val > max) val = max; + if (val < min) val = min; + + /* tell xrandr to change the backlight value */ + XRRChangeOutputProperty(_ecore_x_disp, output, backlight, + XA_INTEGER, 32, PropModeReplace, + (unsigned char *)&val, 1); + + /* send changes to X */ + ecore_x_flush(); + + ret = EINA_TRUE; + } + + /* free the info */ + free(info); + + return ret; + } +#endif + return EINA_FALSE; +} + +/** + * @brief gets the EDID information of an attached output if available. + * Note that this information is not to be compared using ordinary string + * comparison functions, since it includes 0-bytes. + * @param root window this information should be queried from + * @param output the XID of the output + * @param length length of the byte-array. If NULL, request will fail. + */ +EAPI unsigned char * +ecore_x_randr_output_edid_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, unsigned long *length) +{ +#ifdef ECORE_XRANDR + Atom edid = None, type = None; + unsigned char *prop; + int format = 0; + unsigned long nitems = 0, bytes = 0; + + if (_randr_version < RANDR_VERSION_1_2) return NULL; + + if (!length) return NULL; + + /* try to get the edid atom */ + if (!(edid = XInternAtom(_ecore_x_disp, RR_PROPERTY_RANDR_EDID, True))) + return NULL; + + /* get the output property + * + * NB: Returns 0 on success */ + if (!XRRGetOutputProperty(_ecore_x_disp, output, edid, 0, 100, False, False, + AnyPropertyType, &type, &format, &nitems, + &bytes, &prop)) + { + if ((type == XA_INTEGER) && (format == 8)) + { + unsigned char *ret = NULL; + + if ((ret = malloc(nitems * sizeof(unsigned char)))) + { + if (length) *length = nitems; + memcpy(ret, prop, (nitems * sizeof(unsigned char))); + return ret; + } + } + } +#endif + return NULL; +} + +EAPI Ecore_X_Render_Subpixel_Order +ecore_x_randr_output_subpixel_order_get(Ecore_X_Window root, Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + XRRScreenResources *res = NULL; + + if (_randr_version < RANDR_VERSION_1_2) + return ECORE_X_RENDER_SUBPIXEL_ORDER_UNKNOWN; + + /* try to get the screen resources from Xrandr */ + if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root))) + { + XRROutputInfo *info = NULL; + Ecore_X_Render_Subpixel_Order ret = 0; + + /* try to get output info */ + if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + ret = info->subpixel_order; + + /* free the output info */ + XRRFreeOutputInfo(info); + } + + /* free the resources */ + XRRFreeScreenResources(res); + + return ret; + } +#endif + return ECORE_X_RENDER_SUBPIXEL_ORDER_UNKNOWN; +} + +/*************************************** + * API Functions for RandR version 1.3 * + ***************************************/ + +EAPI Ecore_X_Randr_Output * +ecore_x_randr_output_wired_clones_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num) +{ +#ifdef ECORE_XRANDR + Atom clones = None, type = None; + unsigned char *prop; + int format = 0; + unsigned long nitems = 0, bytes = 0; + + /* NB: FIXME: + * + * I am not sure that this code is correct. This needs checking + */ + + if (_randr_version < RANDR_VERSION_1_3) return NULL; + + /* try to get the edid atom */ + if (!(clones = XInternAtom(_ecore_x_disp, RR_PROPERTY_CLONE_LIST, True))) + return NULL; + + /* get the output property + * + * NB: Returns 0 on success */ + if (!XRRGetOutputProperty(_ecore_x_disp, output, clones, 0, 100, False, False, + AnyPropertyType, &type, &format, &nitems, + &bytes, &prop)) + { + if ((type == XA_ATOM) && (nitems >= 1) && (format == 32)) + { + Ecore_X_Randr_Output *ret = NULL; + + if ((ret = malloc(nitems * sizeof(Ecore_X_Randr_Output)))) + { + if (num) *num = nitems; + memcpy(ret, prop, (nitems * sizeof(Ecore_X_Randr_Output))); + return ret; + } + } + } +#endif + return NULL; +} + +EAPI Ecore_X_Randr_Output ** +ecore_x_randr_output_compatibility_list_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num) +{ + /* TODO: (1.3) !! */ + //RR_PROPERTY_COMPATIBILITY_LIST + return NULL; +} + +EAPI Ecore_X_Randr_Signal_Format * +ecore_x_randr_output_signal_formats_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num) +{ +#ifdef ECORE_XRANDR + XRRPropertyInfo *info = NULL; + Atom sig, type; + unsigned long bytes = 0; + unsigned long items = 0; + unsigned char *prop = NULL; + int format = 0; + + if (_randr_version < RANDR_VERSION_1_3) return NULL; + + /* try to get the connector number atom */ + if (!(sig = XInternAtom(_ecore_x_disp, RR_PROPERTY_SIGNAL_FORMAT, True))) + return NULL; + + /* try to get the output property from Xrandr + * + * NB: Returns 0 on success */ + if (XRRGetOutputProperty(_ecore_x_disp, output, sig, 0, 100, + False, False, AnyPropertyType, &type, &format, + &items, &bytes, &prop)) + { + printf("Signal Format property not supported.\n"); + return NULL; + } + + free(prop); + + /* safety check */ + if ((type != XA_ATOM) || (items < 1) || (format != 32)) + return NULL; + + /* try to get the output property from Xrandr */ + if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, sig))) + { + Ecore_X_Randr_Signal_Format *formats = NULL; + + if ((formats = + malloc(info->num_values * sizeof(Ecore_X_Randr_Signal_Format)))) + { + if (num) *num = info->num_values; + memcpy(formats, info->values, + (info->num_values * sizeof(Ecore_X_Randr_Signal_Format))); + } + + /* free the info */ + free(info); + + return formats; + } +#endif + return NULL; +} + +EAPI Eina_Bool +ecore_x_randr_output_signal_format_set(Ecore_X_Window root, Ecore_X_Randr_Output output, Ecore_X_Randr_Signal_Format *signal) +{ + /* TODO: (1.3) !! */ + //RR_PROPERTY_SIGNAL_FORMAT + return EINA_FALSE; +} + +EAPI Ecore_X_Randr_Signal_Property * +ecore_x_randr_output_signal_properties_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num) +{ +#ifdef ECORE_XRANDR + XRRPropertyInfo *info = NULL; + Atom sig, type; + unsigned long bytes = 0; + unsigned long items = 0; + unsigned char *prop = NULL; + int format = 0; + + if (_randr_version < RANDR_VERSION_1_3) return NULL; + + /* try to get the connector number atom */ + if (!(sig = XInternAtom(_ecore_x_disp, RR_PROPERTY_SIGNAL_PROPERTIES, True))) + return NULL; + + /* try to get the output property from Xrandr + * + * NB: Returns 0 on success */ + if (XRRGetOutputProperty(_ecore_x_disp, output, sig, 0, 100, + False, False, AnyPropertyType, &type, &format, + &items, &bytes, &prop)) + { + printf("Signal Properties property not supported.\n"); + return NULL; + } + + free(prop); + + /* safety check */ + if ((type != XA_ATOM) || (items < 1) || (format != 32)) + return NULL; + + /* try to get the output property from Xrandr */ + if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, sig))) + { + Ecore_X_Randr_Signal_Property *props = NULL; + + if ((props = + malloc(info->num_values * sizeof(Ecore_X_Randr_Signal_Property)))) + { + if (num) *num = info->num_values; + memcpy(props, info->values, + (info->num_values * sizeof(Ecore_X_Randr_Signal_Property))); + } + + /* free the info */ + free(info); + + return props; + } +#endif + return NULL; +} + +/* TODO NB: + * + * Document this. + * + * Returns: + * 0 == unknown + * 1 == primary + * 2 == secondary + * 3 == (typically) TV Connector but is driver/hardware dependent + * + */ +EAPI int +ecore_x_randr_output_connector_number_get(Ecore_X_Window root, Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + XRRPropertyInfo *info = NULL; + Atom conn, type; + unsigned long bytes = 0; + unsigned long items = 0; + unsigned char *prop = NULL; + int val = 0, format = 0; + + if (_randr_version < RANDR_VERSION_1_3) return -1; + + /* try to get the connector number atom */ + if (!(conn = XInternAtom(_ecore_x_disp, RR_PROPERTY_CONNECTOR_NUMBER, True))) + return -1; + + /* try to get the output property from Xrandr + * + * NB: Returns 0 on success */ + if (XRRGetOutputProperty(_ecore_x_disp, output, conn, 0, 100, + False, False, AnyPropertyType, &type, &format, + &items, &bytes, &prop)) + { + printf("ConnectionNumber property not supported.\n"); + return -1; + } + + /* safety check */ + if ((type != XA_INTEGER) || (items != 1) || (format != 32)) + return -1; + + val = *((int *)prop); + free(prop); + + /* try to get the output property from Xrandr */ + if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, conn))) + { + int ret = 0; + + /* convert the current value */ + ret = (int)(val - info->values[0]); + + /* free the info */ + free(info); + + return ret; + } +#endif + return -1; +} + +EAPI Ecore_X_Randr_Connector_Type +ecore_x_randr_output_connector_type_get(Ecore_X_Window root, Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + XRRPropertyInfo *info = NULL; + Atom conn, type; + unsigned long bytes = 0; + unsigned long items = 0; + unsigned char *prop = NULL; + int val = 0, format = 0; + + if (_randr_version < RANDR_VERSION_1_3) return -1; + + /* try to get the connector type atom */ + if ((conn = XInternAtom(_ecore_x_disp, RR_PROPERTY_CONNECTOR_NUMBER, True))) + XRRGetOutputProperty(_ecore_x_disp, output, conn, 0, 4, + False, False, AnyPropertyType, &type, &format, + &items, &bytes, &prop); + + if ((!prop) || (items == 0)) + { + /* NB: some butthead drivers (*cough* nouveau *cough*) do not + * implement randr properly. They are not using the connector type + * property of randr, but rather a "subconnector" property */ + if ((conn = XInternAtom(_ecore_x_disp, "subconnector", True))) + XRRGetOutputProperty(_ecore_x_disp, output, conn, 0, 4, + False, False, AnyPropertyType, &type, + &format, &items, &bytes, &prop); + } + + if ((!prop) || (items == 0)) + { + WRN("ConnectorType Property not supported."); + return -1; + } + + /* safety check */ + if ((type != XA_ATOM) || (items != 1) || (format != 32)) + return -1; + + val = *((int *)prop); + free(prop); + + /* try to get the output property from Xrandr */ + if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, conn))) + { + int ret = 0; + + /* convert the current value */ + ret = (int)(val - info->values[0]); + + /* printf("\tReturn Value: %d\n", ret); */ + /* printf("\t\tActual Name: %s\n", */ + /* XGetAtomName(_ecore_x_disp, ((Atom)info->values[ret]))); */ + + /* free the info */ + free(info); + + return ret; + } +#endif + return -1; +} + +EAPI Ecore_X_Randr_Output +ecore_x_randr_primary_output_get(Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + if (_randr_version < RANDR_VERSION_1_3) return 0; + return XRRGetOutputPrimary(_ecore_x_disp, root); +#else + return 0; +#endif +} + +EAPI void +ecore_x_randr_primary_output_set(Ecore_X_Window root, Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + if (_randr_version < RANDR_VERSION_1_3) return; + XRRSetOutputPrimary(_ecore_x_disp, root, output); +#endif +} + +/*************************************** + * API Functions for RandR Edid + ***************************************/ + +EAPI Eina_Bool +ecore_x_randr_edid_has_valid_header(unsigned char *edid, unsigned long edid_length) +{ + const unsigned char header[] = + { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; + + if (!edid) return EINA_FALSE; + if (edid_length < 8) return EINA_FALSE; + if (!memcmp(edid, header, 8)) return EINA_TRUE; + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_randr_edid_info_has_valid_checksum(unsigned char *edid, unsigned long edid_length) +{ + unsigned char *iter = NULL; + char sum = 0; + int i = 0, version = 0; + + if (edid_length < 128) return EINA_FALSE; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE; + + for (i = 0; i < 128; i++) + sum += edid[i]; + + if (sum) return EINA_FALSE; + + /* check extension blocks */ + for (iter = edid; iter < (edid + edid_length); iter += 128) + { + if (iter[0] == 0x02) + { + for (i = 0, sum = 0; i < 128; i++) + sum += iter[i]; + } + } + + if (sum) return EINA_FALSE; + return EINA_TRUE; +} + +EAPI int +ecore_x_randr_edid_version_get(unsigned char *edid, unsigned long edid_length) +{ + if ((edid_length > RANDR_EDID_VERSION_MINOR) && + (ecore_x_randr_edid_has_valid_header(edid, edid_length))) + { + return (edid[RANDR_EDID_VERSION_MAJOR] << 8) | + edid[RANDR_EDID_VERSION_MINOR]; + } + + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; +} + +EAPI char * +ecore_x_randr_edid_manufacturer_name_get(unsigned char *edid, unsigned long edid_length) +{ + if ((edid_length > RANDR_EDID_MANUFACTURER + 1) && + (ecore_x_randr_edid_has_valid_header(edid, edid_length))) + { + unsigned char *x; + char *name; + + if (!(name = malloc(sizeof(char) * 4))) return NULL; + + x = (edid + RANDR_EDID_MANUFACTURER); + name[0] = ((x[0] & 0x7c) >> 2) + '@'; + name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xe0) >> 5) + '@'; + name[2] = (x[1] & 0x1f) + '@'; + name[3] = 0; + + return name; + } + + return NULL; +} + +EAPI char * +ecore_x_randr_edid_display_name_get(unsigned char *edid, unsigned long edid_length) +{ + unsigned char *block = NULL; + int version = 0; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) return NULL; + + for (block = (edid + RANDR_EDID_BLOCK); + block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18) + { + if ((block[0] == 0) && (block[1] == 0)) + { + if (block[3] == 0xfc) + { + char *name, *p; + const char *edid_name; + + edid_name = (const char *)block + 5; + if (!(name = malloc(14))) return NULL; + strncpy(name, edid_name, 13); + name[13] = 0; + + for (p = name; *p; p++) + if ((*p < ' ') || (*p > '~')) *p = 0; + + return name; + } + } + } + + return NULL; +} + +EAPI char * +ecore_x_randr_edid_display_ascii_get(unsigned char *edid, unsigned long edid_length) +{ + unsigned char *block = NULL; + int version = 0; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) return NULL; + + for (block = (edid + RANDR_EDID_BLOCK); + block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18) + { + if ((block[0] == 0) && (block[1] == 0)) + { + if (block[3] == 0xfe) + { + char *ascii = NULL, *p = NULL; + const char *edid_ascii; + + edid_ascii = (const char *)block + 5; + + if (!(ascii = malloc(14))) return NULL; + strncpy(ascii, edid_ascii, 13); + ascii[13] = 0; + for (p = ascii; *p; p++) + if ((*p < ' ') || (*p > '~')) *p = 0; + + return ascii; + } + } + } + + return NULL; +} + +EAPI char * +ecore_x_randr_edid_display_serial_get(unsigned char *edid, unsigned long edid_length) +{ + unsigned char *block = NULL; + int version = 0; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) return NULL; + + for (block = (edid + RANDR_EDID_BLOCK); + block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18) + { + if ((block[0] == 0) && (block[1] == 0)) + { + if (block[3] == 0xff) + { + char *serial = NULL, *p = NULL; + const char *edid_serial; + + edid_serial = (const char *)block + 5; + + if (!(serial = malloc(14))) return NULL; + strncpy(serial, edid_serial, 13); + serial[13] = 0; + for (p = serial; *p; p++) + if ((*p < ' ') || (*p > '~')) *p = 0; + + return serial; + } + } + } + + return NULL; +} + +EAPI int +ecore_x_randr_edid_model_get(unsigned char *edid, unsigned long edid_length) +{ + return ecore_x_randr_edid_manufacturer_model_get(edid, edid_length); +} + +EAPI int +ecore_x_randr_edid_manufacturer_serial_number_get(unsigned char *edid, unsigned long edid_length) +{ + if ((edid_length > RANDR_EDID_MANUFACTURER + 1) && + (ecore_x_randr_edid_has_valid_header(edid, edid_length))) + return (int)(edid[0x0c] + (edid[0x0d] << 8) + + (edid[0x0e] << 16) + (edid[0x0f] << 24)); + + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; +} + +EAPI int +ecore_x_randr_edid_manufacturer_model_get(unsigned char *edid, unsigned long edid_length) +{ + if ((edid_length > RANDR_EDID_MANUFACTURER + 1) && + (ecore_x_randr_edid_has_valid_header(edid, edid_length))) + return (int)(edid[0x0a] + (edid[0x0b] << 8)); + + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; +} + +EAPI Eina_Bool +ecore_x_randr_edid_dpms_available_get(unsigned char *edid, unsigned long edid_length) +{ + int version = 0; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE; + + return !!(edid[0x18] & 0xE0); +} + +EAPI Eina_Bool +ecore_x_randr_edid_dpms_standby_available_get(unsigned char *edid, unsigned long edid_length) +{ + int version = 0; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE; + + if (edid[0x18] & 0xE0) return !!(edid[0x18] & 0x80); + + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_randr_edid_dpms_suspend_available_get(unsigned char *edid, unsigned long edid_length) +{ + int version = 0; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE; + + if (edid[0x18] & 0xE0) return !!(edid[0x18] & 0x40); + + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_randr_edid_dpms_off_available_get(unsigned char *edid, unsigned long edid_length) +{ + int version = 0; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE; + + if (edid[0x18] & 0xE0) return !!(edid[0x18] & 0x20); + + return EINA_FALSE; +} + +EAPI Ecore_X_Randr_Edid_Aspect_Ratio +ecore_x_randr_edid_display_aspect_ratio_preferred_get(unsigned char *edid, unsigned long edid_length) +{ + unsigned char *block = NULL; + int version = 0; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + + for (block = (edid + RANDR_EDID_BLOCK); + block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18) + { + if ((block[0] == 0) && (block[1] == 0)) + { + if ((block[3] == 0xfd) && (block[10] == 0x04)) + { + Ecore_X_Randr_Edid_Aspect_Ratio_Preferred ratio = + (Ecore_X_Randr_Edid_Aspect_Ratio_Preferred)((block[15] & 0xe0) >> 5); + + switch (ratio) + { + case RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3: + return ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3; + case RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9: + return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9; + case RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10: + return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10; + case RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4: + return ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4; + case RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9: + return ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9; + default: + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + } + } + } + } + + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; +} + +EAPI Ecore_X_Randr_Edid_Aspect_Ratio +ecore_x_randr_edid_display_aspect_ratios_get(unsigned char *edid, unsigned long edid_length) +{ + Ecore_X_Randr_Edid_Aspect_Ratio ret; + unsigned char *block = NULL; + int version = 0; + + ret = ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + + for (block = (edid + RANDR_EDID_BLOCK); + block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18) + { + if ((block[0] == 0) && (block[1] == 0)) + { + if ((block[3] == 0xfd) && (block[10] == 0x04)) + { + if (block[14] & 0x80) + ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3; + if (block[14] & 0x40) + ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9; + if (block[14] & 0x20) + ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10; + if (block[14] & 0x10) + ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4; + if (block[14] & 0x08) + ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9; + } + } + } + + return ret; +} + +EAPI Ecore_X_Randr_Edid_Display_Colorscheme +ecore_x_randr_edid_display_colorscheme_get(unsigned char *edid, unsigned long edid_length) +{ + Ecore_X_Randr_Edid_Display_Colorscheme ret; + int version = 0; + + ret = ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + + if (ecore_x_randr_edid_display_type_digital_get(edid, edid_length)) + { + ret = ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_4_4_4; + if (edid[0x18] & 0x10) + ret |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_4_4; + if (edid[0x18] & 0x08) + ret |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_2_2; + } + else + ret = (edid[0x18] & 0x18); + + return ret; +} + +EAPI Eina_Bool +ecore_x_randr_edid_display_type_digital_get(unsigned char *edid, unsigned long edid_length) +{ + int version = 0; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE; + + return !!(edid[0x14] & 0x80); +} + +EAPI Ecore_X_Randr_Edid_Display_Interface_Type +ecore_x_randr_edid_display_interface_type_get(unsigned char *edid, unsigned long edid_length) +{ + Ecore_X_Randr_Edid_Display_Interface_Type type; + int version = 0; + + type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < RANDR_EDID_VERSION_1_3) + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + + type = (edid[0x14] & 0x0f); + if (type > ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT) + type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + + return type; +}