efl/legacy/ecore/src/lib/ecore_x/xlib/ecore_x_randr_12.c

2393 lines
71 KiB
C

/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "ecore_x_private.h"
#include "ecore_x_randr.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define Ecore_X_Randr_None (Ecore_X_Randr_Crtc)0
#define Ecore_X_Randr_Unset (Ecore_X_Randr_Crtc) - 1
#ifdef ECORE_XRANDR
#define RANDR_1_2 ((1 << 16) | 2)
#define RANDR_VALIDATE_ROOT(screen, root) \
((screen = XRRRootToScreen(_ecore_x_disp, root)) != -1)
#define RANDR_CHECK_1_2_RET(ret) if (_randr_version < RANDR_1_2) \
return ret
#define RANDR_PROPERTY_EDID "EDID"
#define RANDR_PROPERTY_BACKLIGHT "Backlight"
#define RANDR_PROPERTY_SIGNAL_FORMAT "SignalFormat"
#define RANDR_PROPERTY_SIGNAL_PROPERTIES "SignalProperties"
#define RANDR_PROPERTY_CONNECTOR_TYPE "ConnectorType"
#define RANDR_PROPERTY_CONNECTOR_NUMBER "ConnectorNumber"
#define RANDR_PROPERTY_COMPATIBILITY_LIST "CompatibilityList"
#define RANDR_PROPERTY_CLONE_LIST "CloneList"
extern XRRScreenResources *(*_ecore_x_randr_get_screen_resources)(Display *
dpy,
Window
window);
extern int _randr_version;
#endif
/**
* @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;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
if (!on)
mask = 0;
else
{
mask = RRScreenChangeNotifyMask;
if (_randr_version >= RANDR_1_2)
mask |= (RRCrtcChangeNotifyMask |
RROutputChangeNotifyMask |
RROutputPropertyNotifyMask);
}
XRRSelectInput(_ecore_x_disp, win, mask);
#endif
}
/**
* @brief Validates a CRTC for a given root window's screen.
*
* @param root The window which's default display will be queried.
* @param crtc The CRTC to be validated.
* @return In case it is found, @c EINA_TRUE will be returned, @c EINA_FALSE
* otherwise.
*/
static inline Eina_Bool
_ecore_x_randr_crtc_validate(Ecore_X_Window root,
Ecore_X_Randr_Crtc crtc)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(EINA_FALSE);
XRRScreenResources *res = NULL;
int i;
Eina_Bool ret = EINA_FALSE;
if ((crtc == Ecore_X_Randr_None) ||
(crtc == Ecore_X_Randr_Unset))
return ret;
if (_ecore_x_randr_root_validate(root) && crtc &&
(res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
{
for (i = 0; i < res->ncrtc; i++)
{
if (res->crtcs[i] == crtc)
{
ret = EINA_TRUE;
break;
}
}
XRRFreeScreenResources(res);
}
return ret;
#else
return EINA_FALSE;
#endif
}
Eina_Bool
_ecore_x_randr_output_validate(Ecore_X_Window root,
Ecore_X_Randr_Output output)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(EINA_FALSE);
Eina_Bool ret = EINA_FALSE;
XRRScreenResources *res = NULL;
int i;
if (_ecore_x_randr_root_validate(root) && output &&
(res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
{
for (i = 0; i < res->noutput; i++)
{
if (res->outputs[i] == output)
{
ret = EINA_TRUE;
break;
}
}
XRRFreeScreenResources(res);
}
return ret;
#else
return EINA_FALSE;
#endif
}
static inline Eina_Bool
_ecore_x_randr_mode_validate(Ecore_X_Window root,
Ecore_X_Randr_Mode mode)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(EINA_FALSE);
Eina_Bool ret = EINA_FALSE;
XRRScreenResources *res = NULL;
int i;
if (_ecore_x_randr_root_validate(root) && mode &&
(res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
{
for (i = 0; i < res->nmode; i++)
{
if (res->modes[i].id == mode)
{
ret = EINA_TRUE;
break;
}
}
XRRFreeScreenResources(res);
}
return ret;
#else
return EINA_FALSE;
#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
RANDR_CHECK_1_2_RET();
Ecore_X_Randr_Screen scr;
if (!RANDR_VALIDATE_ROOT(scr, root))
return;
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
RANDR_CHECK_1_2_RET();
int twmin, thmin, twmax, thmax;
if (XRRGetScreenSizeRange (_ecore_x_disp, root, &twmin, &thmin, &twmax,
&thmax))
{
if (wmin)
*wmin = twmin;
if (hmin)
*hmin = thmin;
if (wmax)
*wmax = twmax;
if (hmax)
*hmax = thmax;
}
#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
RANDR_CHECK_1_2_RET(EINA_FALSE);
Ecore_X_Randr_Screen scr;
int w_c, h_c, w_mm_c, h_mm_c, twmin, thmin, twmax, thmax;
if (!RANDR_VALIDATE_ROOT(scr, root))
return EINA_FALSE;
ecore_x_randr_screen_current_size_get(root, &w_c, &h_c, &w_mm_c, &h_mm_c);
if ((w == w_c) && (h == h_c) && (w_mm_c == w_mm) && (h_mm_c == h_mm))
return EINA_TRUE;
ecore_x_randr_screen_size_range_get(root, &twmin, &thmin, &twmax, &thmax);
if (((w != Ecore_X_Randr_None) &&
((w < twmin) ||
(w > twmax))) ||
((h != Ecore_X_Randr_None) && ((h < thmin) || (h > thmax))))
return EINA_FALSE;
if (w <= 0)
w = DisplayWidth(_ecore_x_disp, scr);
if (h <= 0)
h = DisplayHeight(_ecore_x_disp, scr);
if (w_mm <= 0)
w_mm =
(int)(((double)(DisplayWidthMM(_ecore_x_disp,
scr) /
(double)DisplayWidth(_ecore_x_disp,
scr))) * (double)w);
if (h_mm <= 0)
h_mm =
(int)(((double)(DisplayHeightMM(_ecore_x_disp,
scr) /
(double)DisplayHeight(_ecore_x_disp,
scr))) * (double)h);
XRRSetScreenSize (_ecore_x_disp, root, w, h, w_mm, h_mm);
return EINA_TRUE;
#else
return EINA_FALSE;
#endif
}
/*
* @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)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(NULL);
XRRScreenResources *res = NULL;
Ecore_X_Randr_Mode_Info **ret = NULL;
int i;
if (_ecore_x_randr_root_validate(root) &&
(res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
{
if ((ret =
(Ecore_X_Randr_Mode_Info **)malloc(sizeof(
Ecore_X_Randr_Mode_Info *)
*
res->nmode)))
{
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;
}
}
}
if (ret && num)
*num = res->nmode;
XRRFreeScreenResources(res);
}
return ret;
#else
return NULL;
#endif
}
/*
* @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
RANDR_CHECK_1_2_RET(EINA_FALSE);
Ecore_X_Randr_Mode mode = Ecore_X_Randr_None;
if (_ecore_x_randr_root_validate(root) && mode_info)
mode = XRRCreateMode(_ecore_x_disp, root, (XRRModeInfo*)mode_info);
return mode;
#else
return Ecore_X_Randr_None;
#endif
}
/*
* @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
RANDR_CHECK_1_2_RET();
XRRDestroyMode(_ecore_x_disp, mode);
#else
return;
#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
RANDR_CHECK_1_2_RET(NULL);
XRRScreenResources *res = NULL;
Ecore_X_Randr_Mode_Info *ret = NULL;
int i;
if (_ecore_x_randr_root_validate(root) &&
(res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
{
for (i = 0; i < res->nmode; i++)
{
if ((res->modes[i].id == mode) &&
(ret = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
{
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->name = NULL;
ret->nameLength = 0;
if (res->modes[i].nameLength > 0)
{
ret->nameLength = res->modes[i].nameLength;
ret->name = malloc(res->modes[i].nameLength + 1);
if (ret->name)
memcpy(ret->name, res->modes[i].name,
res->modes[i].nameLength + 1);
}
ret->modeFlags = res->modes[i].modeFlags;
break;
}
}
XRRFreeScreenResources(res);
}
return ret;
#else
return NULL;
#endif
}
/*
* @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
RANDR_CHECK_1_2_RET();
if (!mode_info)
return;
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)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(NULL);
XRRScreenResources *res = NULL;
Ecore_X_Randr_Crtc *ret = NULL;
if (num && root &&
(res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
{
if ((ret = malloc(sizeof(Ecore_X_Randr_Crtc) * res->ncrtc)))
{
memcpy(ret, res->crtcs, (sizeof(Ecore_X_Randr_Crtc) * res->ncrtc));
*num = res->ncrtc;
}
XRRFreeScreenResources(res);
}
return ret;
#else
return NULL;
#endif
}
/*
* @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 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)
{
#ifdef ECORE_XRANDR
Ecore_X_Window root;
Eina_Rectangle w_geo, c_geo;
Ecore_X_Randr_Crtc *crtcs;
Ecore_X_Randr_Mode mode;
Ecore_X_Randr_Output *ret = NULL;
Window tw;
int ncrtcs, i, nret = 0, rx = 0, ry = 0;
if (_randr_version < RANDR_1_2) goto _ecore_x_randr_window_crtcs_get_fail;
ecore_x_window_geometry_get(window,
&w_geo.x, &w_geo.y,
&w_geo.w, &w_geo.h);
root = ecore_x_window_root_get(window);
crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs);
if (!crtcs) goto _ecore_x_randr_window_crtcs_get_fail;
/* now get window RELATIVE to root window - thats what matters. */
XTranslateCoordinates(_ecore_x_disp, window, root, 0, 0, &rx, &ry, &tw);
w_geo.x = rx;
w_geo.y = ry;
for (i = 0, nret = 0; i < ncrtcs; i++)
{
/* if crtc is not enabled, don't bother about it any further */
mode = ecore_x_randr_crtc_mode_get(root, crtcs[i]);
if (mode == Ecore_X_Randr_None) continue;
ecore_x_randr_crtc_geometry_get(root, crtcs[i],
&c_geo.x, &c_geo.y,
&c_geo.w, &c_geo.h);
if (eina_rectangles_intersect(&w_geo, &c_geo))
{
ret = realloc(ret, (sizeof(Ecore_X_Randr_Crtc) * ++nret));
ret[nret] = crtcs[i];
}
}
free(crtcs);
if (num) *num = nret;
return ret;
_ecore_x_randr_window_crtcs_get_fail:
#endif
if (num) *num = 0;
return NULL;
}
EAPI Ecore_X_Randr_Output *
ecore_x_randr_outputs_get(Ecore_X_Window root,
int *num)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(NULL);
XRRScreenResources *res = NULL;
Ecore_X_Randr_Output *ret = NULL;
if (num && root &&
(res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
{
if ((ret = malloc(sizeof(Ecore_X_Randr_Output) * res->noutput)))
{
memcpy(ret, res->outputs,
(sizeof(Ecore_X_Randr_Output) * res->noutput));
if (num)
*num = res->noutput;
}
if (res)
XRRFreeScreenResources(res);
}
return ret;
#else
return NULL;
#endif
}
//Per Crtc
/*
* @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)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(NULL);
XRRScreenResources *res = NULL;
Ecore_X_Randr_Output *ret = NULL;
XRRCrtcInfo *crtc_info = NULL;
if (_ecore_x_randr_crtc_validate(root,
crtc) &&
(res =
_ecore_x_randr_get_screen_resources (_ecore_x_disp,
root)) &&
(crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
{
if ((ret = malloc(sizeof(Ecore_X_Randr_Output) * crtc_info->noutput)))
{
memcpy(ret, crtc_info->outputs,
(sizeof(Ecore_X_Randr_Output) * crtc_info->noutput));
if (num)
*num = crtc_info->noutput;
}
if (crtc_info)
XRRFreeCrtcInfo(crtc_info);
if (res)
XRRFreeScreenResources(res);
}
return ret;
#else
return NULL;
#endif
}
/*
* @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)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(NULL);
XRRScreenResources *res = NULL;
Ecore_X_Randr_Output *ret = NULL;
XRRCrtcInfo *crtc_info = NULL;
if (_ecore_x_randr_crtc_validate(root,
crtc) &&
(res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
{
if ((crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
{
if ((ret =
malloc(sizeof(Ecore_X_Randr_Output) * crtc_info->npossible)))
{
memcpy(ret, crtc_info->possible,
(sizeof(Ecore_X_Randr_Output) * crtc_info->npossible));
if (num)
*num = res->ncrtc;
}
XRRFreeCrtcInfo(crtc_info);
}
XRRFreeScreenResources(res);
}
return ret;
#else
return NULL;
#endif
}
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
RANDR_CHECK_1_2_RET();
XRRScreenResources *res = NULL;
XRRCrtcInfo *crtc_info = NULL;
if (_ecore_x_randr_crtc_validate(root,
crtc) &&
(res =
_ecore_x_randr_get_screen_resources (_ecore_x_disp,
root)) &&
(crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
{
if (x)
*x = crtc_info->x;
if (y)
*y = crtc_info->y;
if (w)
*w = crtc_info->width;
if (h)
*h = crtc_info->height;
XRRFreeCrtcInfo(crtc_info);
XRRFreeScreenResources(res);
}
#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
RANDR_CHECK_1_2_RET(EINA_FALSE);
int w_c, h_c, w_new = 0, h_new = 0;
Eina_Rectangle crtc_geo;
ecore_x_randr_crtc_geometry_get(root,
crtc,
&crtc_geo.x,
&crtc_geo.y,
&crtc_geo.w,
&crtc_geo.h);
ecore_x_randr_screen_current_size_get(root, &w_c, &h_c, NULL, NULL);
if (x < 0)
x = crtc_geo.x;
if (y < 0)
y = crtc_geo.y;
if ((x + crtc_geo.w) > w_c)
w_new = x + crtc_geo.w;
if ((y + crtc_geo.h) > h_c)
h_new = y + crtc_geo.h;
if ((w_new != 0) || (h_new != 0))
if (!ecore_x_randr_screen_current_size_set(root, w_new, h_new, 0, 0))
return EINA_FALSE;
return ecore_x_randr_crtc_settings_set(root,
crtc,
NULL,
Ecore_X_Randr_Unset,
x,
y,
Ecore_X_Randr_Unset,
Ecore_X_Randr_Unset);
#else
return EINA_FALSE;
#endif
}
/**
* @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
RANDR_CHECK_1_2_RET(Ecore_X_Randr_Unset);
XRRScreenResources *res = NULL;
XRRCrtcInfo *crtc_info = NULL;
Ecore_X_Randr_Mode ret = Ecore_X_Randr_Unset;
if (_ecore_x_randr_root_validate(root) &&
_ecore_x_randr_crtc_validate(root,
crtc) &&
(res =
_ecore_x_randr_get_screen_resources(_ecore_x_disp,
root)) &&
(crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
{
ret = crtc_info->mode;
XRRFreeCrtcInfo(crtc_info);
XRRFreeScreenResources(res);
}
return ret;
#else
return Ecore_X_Randr_Unset;
#endif
}
/**
* @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
RANDR_CHECK_1_2_RET(EINA_FALSE);
if (mode == Ecore_X_Randr_Unset)
return EINA_FALSE;
return ecore_x_randr_crtc_settings_set(root,
crtc,
outputs,
noutputs,
Ecore_X_Randr_Unset,
Ecore_X_Randr_Unset,
mode,
Ecore_X_Randr_Unset);
#else
return EINA_FALSE;
#endif
}
EAPI void
ecore_x_randr_crtc_size_get(Ecore_X_Window root,
Ecore_X_Randr_Crtc crtc,
int *w,
int *h)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET();
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,
Ecore_X_Randr_Mode mode)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(0.0);
XRRScreenResources *res = NULL;
XRRCrtcInfo *crtc_info = NULL;
Ecore_X_Randr_Refresh_Rate ret = 0.0;
int i;
if (_ecore_x_randr_crtc_validate(root,
crtc) &&
(res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
{
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;
}
}
if (crtc_info)
XRRFreeCrtcInfo(crtc_info);
if (res)
XRRFreeScreenResources(res);
return ret;
#else
return 0.0;
#endif
}
EAPI Ecore_X_Randr_Orientation
ecore_x_randr_crtc_orientations_get(Ecore_X_Window root,
Ecore_X_Randr_Crtc crtc)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(Ecore_X_Randr_None);
XRRCrtcInfo *crtc_info = NULL;
XRRScreenResources *res = NULL;
Ecore_X_Randr_Orientation ret = Ecore_X_Randr_None;
if (_ecore_x_randr_crtc_validate(root,
crtc) &&
(res =
_ecore_x_randr_get_screen_resources (_ecore_x_disp,
root)) &&
(crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
{
ret = crtc_info->rotations;
}
if (crtc_info)
XRRFreeCrtcInfo(crtc_info);
if (res)
XRRFreeScreenResources(res);
return ret;
#else
return Ecore_X_Randr_None;
#endif
}
EAPI Ecore_X_Randr_Orientation
ecore_x_randr_crtc_orientation_get(Ecore_X_Window root,
Ecore_X_Randr_Crtc crtc)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(Ecore_X_Randr_None);
XRRCrtcInfo *crtc_info = NULL;
XRRScreenResources *res = NULL;
Ecore_X_Randr_Orientation ret = Ecore_X_Randr_None;
if (_ecore_x_randr_crtc_validate(root,
crtc) &&
(res =
_ecore_x_randr_get_screen_resources (_ecore_x_disp,
root)) &&
(crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
{
ret = crtc_info->rotation;
}
if (crtc_info)
XRRFreeCrtcInfo(crtc_info);
if (res)
XRRFreeScreenResources(res);
return ret;
#else
return Ecore_X_Randr_None;
#endif
}
EAPI Eina_Bool
ecore_x_randr_crtc_orientation_set(Ecore_X_Window root,
Ecore_X_Randr_Crtc crtc,
Ecore_X_Randr_Orientation orientation)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(EINA_FALSE);
Eina_Bool ret = EINA_FALSE;
if (orientation != Ecore_X_Randr_None)
{
ret = ecore_x_randr_crtc_settings_set(root,
crtc,
NULL,
Ecore_X_Randr_Unset,
Ecore_X_Randr_Unset,
Ecore_X_Randr_Unset,
Ecore_X_Randr_Unset,
orientation);
}
return ret;
#else
return EINA_FALSE;
#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
RANDR_CHECK_1_2_RET();
ecore_x_randr_crtc_geometry_get(root, crtc, x, y, NULL, NULL);
#endif
}
EAPI Eina_Bool
ecore_x_randr_crtc_clone_set(Ecore_X_Window root,
Ecore_X_Randr_Crtc original,
Ecore_X_Randr_Crtc clon)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(EINA_FALSE);
XRRScreenResources *res = NULL;
XRRCrtcInfo *clone_crtc_info = NULL;
Ecore_X_Randr_Mode original_mode = Ecore_X_Randr_None;
Ecore_X_Randr_Orientation original_orientation = Ecore_X_Randr_None;
Eina_Bool ret = EINA_FALSE;
int x, y;
if (_ecore_x_randr_root_validate(root) &&
_ecore_x_randr_crtc_validate(root,
original) &&
_ecore_x_randr_crtc_validate(root,
clon) &&
(res =
_ecore_x_randr_get_screen_resources (_ecore_x_disp,
root)) &&
(clone_crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, clon)))
{
ecore_x_randr_crtc_geometry_get(root, original, &x, &y, NULL, NULL);
original_mode = ecore_x_randr_crtc_mode_get(root, original);
original_orientation = ecore_x_randr_crtc_orientation_get(root,
original);
ret = ecore_x_randr_crtc_settings_set(root,
clon,
NULL,
Ecore_X_Randr_Unset,
x,
y,
original_mode,
original_orientation);
XRRFreeCrtcInfo(clone_crtc_info);
XRRFreeScreenResources(res);
}
return ret;
#else
return EINA_FALSE;
#endif
}
/**
* @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
RANDR_CHECK_1_2_RET(EINA_FALSE);
XRRScreenResources *res = NULL;
XRRCrtcInfo *crtc_info = NULL;
Eina_Bool ret = EINA_FALSE;
if (_ecore_x_randr_crtc_validate(root,
crtc) &&
(res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
{
if ((crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
{
if ((mode == Ecore_X_Randr_None) ||
(noutputs == Ecore_X_Randr_None))
{
outputs = NULL;
noutputs = 0;
}
else if (noutputs == (int)Ecore_X_Randr_Unset)
{
outputs = (Ecore_X_Randr_Output *)crtc_info->outputs;
noutputs = crtc_info->noutput;
}
if (mode == Ecore_X_Randr_Unset)
mode = crtc_info->mode;
if (x < 0)
x = crtc_info->x;
if (y < 0)
y = crtc_info->y;
if (orientation == Ecore_X_Randr_Unset)
orientation = crtc_info->rotation;
if (!XRRSetCrtcConfig(_ecore_x_disp, res, crtc, CurrentTime,
x, y, mode, orientation, (RROutput *)outputs,
noutputs))
ret = EINA_TRUE;
XRRFreeCrtcInfo(crtc_info);
}
XRRFreeScreenResources(res);
}
return ret;
#else
return EINA_FALSE;
#endif
}
/**
* @brief Sets a CRTC relative to another one.
*
* @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
RANDR_CHECK_1_2_RET(EINA_FALSE);
Eina_Rectangle r1_geo, r2_geo;
int w_max, h_max, cw, ch, x_n = Ecore_X_Randr_Unset, y_n =
Ecore_X_Randr_Unset;
/*
int r1_noutputs, r2_noutputs, r1_nmodes, i, j, outputs_mode_found, mode_w, mode_h;
Ecore_X_Randr_Output *r1_outputs, *r2_outputs, *r2_r1_outputs;
Ecore_X_Randr_Mode *r1_modes, r2_mode, r1_mode;
Eina_Bool ret;
*/
if ((ecore_x_randr_crtc_mode_get(root, crtc_r1) == Ecore_X_Randr_None)
|| (ecore_x_randr_crtc_mode_get(root, crtc_r2) == Ecore_X_Randr_None))
return EINA_FALSE;
if (!_ecore_x_randr_crtc_validate(root, crtc_r1) ||
(!(crtc_r1 != crtc_r2) &&
!_ecore_x_randr_crtc_validate(root, crtc_r2)))
return EINA_FALSE;
ecore_x_randr_crtc_geometry_get(root,
crtc_r1,
&r1_geo.x,
&r1_geo.y,
&r1_geo.w,
&r1_geo.h);
ecore_x_randr_crtc_geometry_get(root,
crtc_r2,
&r2_geo.x,
&r2_geo.y,
&r2_geo.w,
&r2_geo.h);
ecore_x_randr_screen_size_range_get(root, NULL, NULL, &w_max, &h_max);
ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL);
switch (policy)
{
case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT:
//set r1 right of r2
x_n = r2_geo.x + r2_geo.w;
switch (alignment)
{
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
y_n = Ecore_X_Randr_Unset;
break;
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
y_n =
((int)(((double)r2_geo.h /
2.0) + (double)r2_geo.y - ((double)r1_geo.h / 2.0)));
break;
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
y_n = ((int)((double)ch / 2.0) - ((double)r1_geo.h / 2.0));
break;
}
break;
case ECORE_X_RANDR_OUTPUT_POLICY_LEFT:
//set r1 left of r2
x_n = r2_geo.x - r1_geo.w;
switch (alignment)
{
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
y_n = Ecore_X_Randr_Unset;
break;
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
y_n =
((int)(((double)r2_geo.h /
2.0) + r2_geo.y - ((double)r1_geo.h / 2.0)));
break;
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
y_n = ((int)(((double)ch / 2.0) - ((double)r1_geo.h / 2.0)));
break;
}
break;
case ECORE_X_RANDR_OUTPUT_POLICY_BELOW:
//set r1 below r2
y_n = r2_geo.y + r2_geo.h;
switch (alignment)
{
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
x_n = Ecore_X_Randr_Unset;
break;
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
x_n =
((int)((((double)r2_geo.x +
(double)r2_geo.w) / 2.0) - ((double)r1_geo.w / 2.0)));
break;
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
x_n = ((int)((double)cw / 2.0));
break;
}
break;
case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE:
y_n = r2_geo.y - r1_geo.h;
//set r1 above r2
switch (alignment)
{
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
x_n = Ecore_X_Randr_Unset;
break;
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
x_n =
((int)((((double)r2_geo.x +
(double)r2_geo.w) / 2.0) - ((double)r1_geo.w / 2.0)));
break;
case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
x_n = ((int)((double)cw / 2.0));
break;
}
break;
case ECORE_X_RANDR_OUTPUT_POLICY_CLONE:
return ecore_x_randr_crtc_pos_set(root, crtc_r1, r2_geo.x, r2_geo.y);
/* entire cloning (including modesetting)
//all outputs of crtc1 capable of crtc2's current mode?
r2_mode = ecore_x_randr_crtc_mode_get(root, crtc_r2);
if (!(r1_outputs =
ecore_x_randr_crtc_outputs_get(root, crtc_r1,
&r1_noutputs)) ||
(r1_noutputs == 0))
return EINA_FALSE;
for (i = 0, outputs_mode_found = 0; i < r1_noutputs; i++)
{
if (!(r1_modes =
ecore_x_randr_output_modes_get(root, r1_outputs[i],
&r1_nmodes, NULL)))
{
free(r1_outputs);
return EINA_FALSE;
}
for (j = 0; j < r1_nmodes; j++)
{
ecore_x_randr_mode_size_get(root,
r1_modes[j],
&mode_w,
&mode_h);
if ((mode_w == r2_geo.w) && (mode_h == r2_geo.h))
{
r1_mode = r1_modes[j];
++outputs_mode_found;
free(r1_modes);
r1_modes = NULL;
break;
}
}
if (r1_modes)
free(r1_modes);
if (outputs_mode_found <= i)
{
//an output doesn't support the set mode, cancel!
free(r1_outputs);
return EINA_FALSE;
}
}
free (r1_outputs);
//CRTC 1's outputs support a mode of same geometry as CRTC 2.
ret =
(ecore_x_randr_crtc_mode_set(root, crtc_r1, Ecore_X_Randr_None,
Ecore_X_Randr_None,
r1_mode) &&
ecore_x_randr_crtc_pos_set(root, crtc_r1, r2_geo.x, r2_geo.y));
return ret;
*/
/* entire cloning on same CRTC
//all outputs of crtc1 capable of crtc2's current mode?
r2_mode = ecore_x_randr_crtc_mode_get(root, crtc_r2);
if (!(r1_outputs =
ecore_x_randr_crtc_outputs_get(root, crtc_r1,
&r1_noutputs)) ||
(r1_noutputs == 0))
return EINA_FALSE;
for (i = 0, outputs_mode_found = 0; i < r1_noutputs; i++)
{
if (!(r1_modes =
ecore_x_randr_output_modes_get(root, r1_outputs[i],
&r1_nmodes, NULL)))
{
free(r1_outputs);
return EINA_FALSE;
}
for (j = 0; j < r1_nmodes; j++)
{
if (r1_modes[j] == r2_mode)
{
++outputs_mode_found;
free(r1_modes);
r1_modes = NULL;
break;
}
}
if (r1_modes)
free(r1_modes);
if (outputs_mode_found <= i)
{
//an output doesn't support the set mode, cancel!
free(r1_outputs);
return EINA_FALSE;
}
}
//check whether crtc r2 can use all outputs of r1.
if (!(r2_outputs =
ecore_x_randr_crtc_possible_outputs_get(root, crtc_r2,
&r2_noutputs)) ||
(r2_noutputs == 0))
{
free(r1_outputs);
return EINA_FALSE;
}
for (i = 0; i < r1_noutputs; i++)
{
for (j = 0; j < r2_noutputs; )
{
if (r1_outputs[i] == r2_outputs[j])
break;
j++;
}
if (j == r2_noutputs)
{
//didn't find the output!
free (r1_outputs);
free (r2_outputs);
return EINA_FALSE;
}
}
//apparently crtc2 supports all outputs of r1
//TODO: check with the compatible list of outputs (property in RR1.3)
r2_r1_outputs =
malloc(sizeof(Ecore_X_Randr_Output) * (r1_noutputs + r2_noutputs));
for (i = 0; i < r1_noutputs; i++)
{
r2_r1_outputs[i] = r1_outputs[i];
}
free(r1_outputs);
for (; i < r2_noutputs; i++)
{
r2_r1_outputs[i] = r2_outputs[i];
}
free(r2_outputs);
ret =
ecore_x_randr_crtc_mode_set(root, crtc_r2, r2_r1_outputs,
(r1_noutputs + r1_noutputs), r2_mode);
free (r2_r1_outputs);
return ret;
*/
case ECORE_X_RANDR_OUTPUT_POLICY_NONE:
break;
}
if ((x_n == r1_geo.x) && (y_n == r1_geo.x))
return EINA_TRUE;
//out of possible bounds?
if (((y_n + r1_geo.h) > h_max) || ((x_n + r1_geo.w) > w_max))
return EINA_FALSE;
return ecore_x_randr_crtc_pos_set(root, crtc_r1, x_n, y_n);
#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
RANDR_CHECK_1_2_RET(EINA_FALSE);
if ((output == Ecore_X_Randr_None) || (mode == Ecore_X_Randr_None))
return EINA_FALSE;
XRRAddOutputMode(_ecore_x_disp, output, mode);
return EINA_TRUE;
#else
return EINA_FALSE;
#endif
}
/*
* @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
RANDR_CHECK_1_2_RET();
if ((output == Ecore_X_Randr_None) || (mode == Ecore_X_Randr_None))
return;
XRRDeleteOutputMode(_ecore_x_disp, output, mode);
#else
return;
#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
RANDR_CHECK_1_2_RET(NULL);
XRRScreenResources *res = NULL;
XRROutputInfo *output_info = NULL;
Ecore_X_Randr_Mode *modes = NULL;
if ((output != Ecore_X_Randr_None)
&& (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))
&& (output_info =
XRRGetOutputInfo(_ecore_x_disp, res, (RROutput)output)))
{
if ((modes = malloc(sizeof(Ecore_X_Randr_Mode) * output_info->nmode)))
{
memcpy(modes, output_info->modes,
(sizeof(Ecore_X_Randr_Mode) * output_info->nmode));
if (num)
*num = output_info->nmode;
if (npreferred)
*npreferred = output_info->npreferred;
}
}
if (output_info)
XRRFreeOutputInfo(output_info);
if (res)
XRRFreeScreenResources(res);
return modes;
#else
return NULL;
#endif
}
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
RANDR_CHECK_1_2_RET(NULL);
XRRScreenResources *res = NULL;
XRROutputInfo *output_info = NULL;
Ecore_X_Randr_Crtc *crtcs = NULL;
if ((output != Ecore_X_Randr_None))
{
if ((res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
{
if ((output_info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
{
if ((crtcs = malloc(sizeof(Ecore_X_Randr_Crtc) * output_info->ncrtc)))
{
memcpy(crtcs, output_info->crtcs, (sizeof(Ecore_X_Randr_Crtc) * output_info->ncrtc));
if (num) *num = output_info->ncrtc;
}
XRRFreeOutputInfo(output_info);
}
XRRFreeScreenResources(res);
}
}
return crtcs;
#else
return Ecore_X_Randr_None;
#endif
}
/**
* @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
RANDR_CHECK_1_2_RET(NULL);
XRRScreenResources *res = NULL;
XRROutputInfo *output_info = NULL;
Ecore_X_Randr_Output *outputs = NULL;
if ((output != Ecore_X_Randr_None))
{
if ((res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
{
if ((output_info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
{
if ((outputs = malloc(sizeof(Ecore_X_Randr_Output) * output_info->nclone)))
{
memcpy(outputs, output_info->clones, (sizeof(Ecore_X_Randr_Output) * output_info->nclone));
if (num) *num = output_info->nclone;
}
XRRFreeOutputInfo(output_info);
}
XRRFreeScreenResources(res);
}
}
return outputs;
#else
return Ecore_X_Randr_None;
#endif
}
EAPI Ecore_X_Randr_Crtc
ecore_x_randr_output_crtc_get(Ecore_X_Window root,
Ecore_X_Randr_Output output)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(Ecore_X_Randr_None);
XRRScreenResources *res = NULL;
XRROutputInfo *output_info = NULL;
Ecore_X_Randr_Crtc ret = Ecore_X_Randr_None;
if ((output != Ecore_X_Randr_None))
{
if ((res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
{
if ((output_info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
{
ret = output_info->crtc;
XRRFreeOutputInfo(output_info);
}
XRRFreeScreenResources(res);
}
}
return ret;
#else
return Ecore_X_Randr_None;
#endif
}
/**
* @brief gets the given output's name as reported by X
* @param root the window which's screen will be queried
* @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
RANDR_CHECK_1_2_RET(NULL);
XRRScreenResources *res = NULL;
XRROutputInfo *output_info = NULL;
char *ret = NULL;
if ((output != Ecore_X_Randr_None)
&& (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))
&& (output_info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
{
/*
* Actually the below command is correct, but due to a bug in libXrandr
* it doesn't work. Therefore we stick with strlen().
* Replace the line below with the following once this bug is
* fixed within libXrandr.
*
* *len = output_info->nameLen;
*
*/
if ((ret = strdup(output_info->name)) && len)
*len = strlen(ret);
XRRFreeOutputInfo(output_info);
}
if (res)
XRRFreeScreenResources(res);
return ret;
#else
return NULL;
#endif
}
/**
* @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
RANDR_CHECK_1_2_RET();
XRRScreenResources *res = NULL;
int i;
if ((mode != Ecore_X_Randr_None)
&& (w || h)
&& (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
{
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;
}
}
}
if (res)
XRRFreeScreenResources(res);
#endif
}
/**
* @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,
Ecore_X_Randr_Output output,
unsigned long *length)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(NULL);
Atom name = XInternAtom (_ecore_x_disp, RANDR_PROPERTY_EDID, False);
unsigned char *prop_data, *ret = NULL;
int actual_format;
unsigned long nitems, bytes_after;
Atom actual_type;
if (!length || !_ecore_x_randr_output_validate(root, output))
return NULL;
if (XRRGetOutputProperty (_ecore_x_disp, output, name,
0, 100, False, False,
AnyPropertyType,
&actual_type, &actual_format,
&nitems, &bytes_after, &prop_data) == Success)
{
if (actual_type == XA_INTEGER && actual_format == 8)
{
if ((ret = malloc(nitems * sizeof(unsigned char))))
{
if (length &&
(memcpy(ret, prop_data, (nitems * sizeof(unsigned char)))))
*length = nitems;
return ret;
}
}
}
return NULL;
#else
return NULL;
#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
RANDR_CHECK_1_2_RET(ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN);
XRRScreenResources *res = NULL;
XRROutputInfo *output_info = NULL;
Ecore_X_Randr_Connection_Status ret =
ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
if ((output != Ecore_X_Randr_None)
&& (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))
&& (output_info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
{
ret = output_info->connection;
}
if (output_info)
XRRFreeOutputInfo(output_info);
if (res)
XRRFreeScreenResources(res);
return ret;
#else
return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
#endif
}
EAPI void
ecore_x_randr_output_size_mm_get(Ecore_X_Window root,
Ecore_X_Randr_Output output,
int *w_mm,
int *h_mm)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET();
XRRScreenResources *res = NULL;
XRROutputInfo *output_info = NULL;
if ((output != Ecore_X_Randr_None)
&& (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
{
if ((output_info =
XRRGetOutputInfo(_ecore_x_disp, res, (RROutput)output)))
{
if (w_mm)
*w_mm = output_info->mm_width;
if (h_mm)
*h_mm = output_info->mm_height;
XRRFreeOutputInfo(output_info);
}
XRRFreeScreenResources(res);
}
#endif
}
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
Ecore_X_Randr_Crtc *crtcs_to_be_moved = NULL;
XRRScreenResources *res = NULL;
int i, j, k, n;
Eina_Bool ret;
if ((nnot_moved <= 0) || (!not_moved)
|| !_ecore_x_randr_root_validate(root)
|| !(res =
_ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
return EINA_FALSE;
n = (res->ncrtc - nnot_moved);
if ((crtcs_to_be_moved = malloc(sizeof(Ecore_X_Randr_Crtc) * n)))
{
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[i] is not in the 'not to move'-list
crtcs_to_be_moved[k++] = res->crtcs[i];
}
}
XRRFreeScreenResources(res);
ret = ecore_x_randr_move_crtcs(root, crtcs_to_be_moved, n, dx, dy);
free(crtcs_to_be_moved);
return ret;
#else
return EINA_FALSE;
#endif
}
/*
* @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
RANDR_CHECK_1_2_RET(EINA_FALSE);
XRRScreenResources *res = NULL;
XRRCrtcInfo **crtc_info = NULL;
Eina_Bool ret = EINA_TRUE;
int i, cw, ch, w_max, h_max, nw, nh;
crtc_info = alloca(sizeof(XRRCrtcInfo *) * ncrtc);
memset(crtc_info, 0, sizeof(XRRCrtcInfo *) * ncrtc);
if (_ecore_x_randr_root_validate(root)
&& (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
{
ecore_x_randr_screen_size_range_get(root, NULL, NULL, &w_max, &h_max);
ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL);
nw = cw;
nh = ch;
for (i = 0;
(i < ncrtc) &&
(crtc_info[i] = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i]));
i++)
{
if (((crtc_info[i]->x + dx) < 0) ||
((int)(crtc_info[i]->x + crtc_info[i]->width + dx) > w_max)
|| ((crtc_info[i]->y + dy) < 0) ||
((int)(crtc_info[i]->y + crtc_info[i]->height + dy) > h_max)
)
goto _ecore_x_randr_move_crtcs_fail_free_crtc_info;
nw = MAX((int)(crtc_info[i]->x + crtc_info[i]->width + dx), nw);
nh = MAX((int)(crtc_info[i]->y + crtc_info[i]->height + dy), nh);
}
//not out of bounds
//resize if necessary
if (!(((nw > cw) ||
(nh > ch)) ||
ecore_x_randr_screen_current_size_set(root, nw, nh,
Ecore_X_Randr_Unset,
Ecore_X_Randr_Unset)))
goto _ecore_x_randr_move_crtcs_fail_free_crtc_info;
//actually move all the crtcs, keep their rotation and mode.
for (i = 0; (i < ncrtc) && crtc_info[i]; i++)
{
if ((crtc_info[i]) &&
(!ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL,
Ecore_X_Randr_Unset,
(crtc_info[i]->x + dx),
(crtc_info[i]->y + dy),
crtc_info[i]->mode,
crtc_info[i]->rotation)))
{
ret = EINA_FALSE;
break;
}
}
if (i < ncrtc)
{
//something went wrong, let's try to move the already moved crtcs
//back.
while ((i--) >= 0)
{
if (crtc_info[i])
ecore_x_randr_crtc_settings_set(root,
crtcs[i],
NULL,
Ecore_X_Randr_Unset,
(crtc_info[i]->x - dx),
(crtc_info[i]->y - dy),
crtc_info[i]->mode,
crtc_info[i]->rotation);
}
}
for (i = 0; i < ncrtc; i++)
{
if (crtc_info[i]) XRRFreeCrtcInfo(crtc_info[i]);
}
}
XRRFreeScreenResources(res);
return ret;
_ecore_x_randr_move_crtcs_fail_free_crtc_info:
while (i-- > 0)
XRRFreeCrtcInfo(crtc_info[i]);
XRRFreeScreenResources(res);
return EINA_FALSE;
#else
return EINA_FALSE;
#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
XRRCrtcInfo *crtc_info = NULL;
XRRScreenResources *res = NULL;
//the 100000 are just a random huge number.
int i, dx_min = 100000, dy_min = 100000, w_n = 0, h_n = 0, nenabled_crtcs = 0;
if (!_ecore_x_randr_root_validate(root) ||
!(res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
return;
Ecore_X_Randr_Crtc enabled_crtcs[res->ncrtc];
for (i = 0; i < res->ncrtc; i++)
{
if (!(crtc_info =
XRRGetCrtcInfo(_ecore_x_disp, res,
res->crtcs[i])) ||
(crtc_info->mode == Ecore_X_Randr_None) ||
(crtc_info->mode == Ecore_X_Randr_Unset)
|| ((crtc_info->noutput == 0)))
continue;
enabled_crtcs[nenabled_crtcs++] = res->crtcs[i];
if ((int)(crtc_info->x + crtc_info->width) > w_n)
w_n = (crtc_info->x + crtc_info->width);
if ((int)(crtc_info->y + crtc_info->height) > h_n)
h_n = (crtc_info->y + crtc_info->height);
if (crtc_info->x < dx_min)
dx_min = crtc_info->x;
if (crtc_info->y < dy_min)
dy_min = crtc_info->y;
XRRFreeCrtcInfo(crtc_info);
}
if ((dx_min > 0) || (dy_min > 0))
{
if (ecore_x_randr_move_crtcs(root, enabled_crtcs, nenabled_crtcs, -dx_min, -dy_min))
{
w_n -= dx_min;
h_n -= dy_min;
}
}
ecore_x_randr_screen_current_size_set(root,
w_n,
h_n,
Ecore_X_Randr_Unset,
Ecore_X_Randr_Unset);
#endif
}
/**
* @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
RANDR_CHECK_1_2_RET();
Atom _backlight;
XRRScreenResources *resources = NULL;
Ecore_X_Randr_Output output;
int o;
if ((level < 0) || (level > 1))
{
ERR("Wrong value for the backlight level. It should be between 0 and 1.");
return;
}
/*
* To make sure that the _backlight atomic property still exists.
*/
_backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True);
if (_backlight == None)
{
WRN("Backlight setting is not supported on this server or driver");
return;
}
/* get the ressources */
resources = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root);
if (!resources) return;
for (o = 0; o < resources->noutput; o++)
{
output = resources->outputs[o];
if (ecore_x_randr_output_backlight_level_get(root, output) >= 0)
{
ecore_x_randr_output_backlight_level_set(root, output, level);
}
}
XRRFreeScreenResources(resources);
#endif
}
/*
* @brief Check if a backlight is available.
* @return Whether a backlight is available.
*/
EAPI Eina_Bool
ecore_x_randr_output_backlight_available(void)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(-1);
Atom _backlight;
_backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True);
return (_backlight == None) ? EINA_FALSE : EINA_TRUE;
#endif
return EINA_FALSE;
}
/*
* @brief Get the backlight level of the given output.
*
* @param root Window which's screen should be queried.
* @param output From which the backlight level should be retrieved.
* @return The backlight level.
*/
EAPI double
ecore_x_randr_output_backlight_level_get(Ecore_X_Window root,
Ecore_X_Randr_Output output)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(-1);
Atom actual_type;
Atom _backlight;
XRRPropertyInfo *info = NULL;
double dvalue;
int actual_format;
long value, max, min;
unsigned long nitems;
unsigned long bytes_after;
unsigned char *prop = NULL;
/* set backlight variable if not already done */
_backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True);
if (_backlight == None)
{
ERR("Backlight property is not suppported on this server or driver");
return -1;
}
if (!_ecore_x_randr_output_validate(root, output))
{
ERR("Invalid output");
return -1;
}
if (XRRGetOutputProperty(_ecore_x_disp, output, _backlight,
0, 4, False, False, None,
&actual_type, &actual_format,
&nitems, &bytes_after, &prop) != Success)
{
WRN("Backlight not supported on this output");
return -1;
}
if ((actual_type != XA_INTEGER) || (nitems != 1) || (actual_format != 32)) return -1;
value = *((long *)prop);
free (prop);
/* I have the current value of the backlight */
/* Now retrieve the min and max intensities of the output */
info = XRRQueryOutputProperty(_ecore_x_disp, output, _backlight);
if (info)
{
dvalue = -1;
if ((info->range) && (info->num_values == 2))
{
/* finally convert the current value in the interval [0..1] */
min = info->values[0];
max = info->values[1];
dvalue = ((double)(value - min)) / ((double)(max - min));
}
free(info);
return dvalue;
}
#endif
return -1;
}
/*
* @brief Set the backlight level of a given output.
*
* @param root Window which's screen should be queried.
* @param output That should be set.
* @param level For which the backlight should be set.
* @return @c EINA_TRUE in case of success.
*/
EAPI Eina_Bool
ecore_x_randr_output_backlight_level_set(Ecore_X_Window root,
Ecore_X_Randr_Output output,
double level)
{
#ifdef ECORE_XRANDR
RANDR_CHECK_1_2_RET(EINA_FALSE);
Atom _backlight;
XRRPropertyInfo *info = NULL;
double min, max, tmp;
long new;
if ((level < 0) || (level > 1))
{
ERR("Backlight level should be between 0 and 1");
return EINA_FALSE;
}
if (!_ecore_x_randr_output_validate(root, output))
{
ERR("Wrong output value");
return EINA_FALSE;
}
_backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True);
if (_backlight == None)
{
WRN("Backlight property is not suppported on this server or driver");
return EINA_FALSE;
}
info = XRRQueryOutputProperty(_ecore_x_disp, output, _backlight);
if (info)
{
if ((info->range) && (info->num_values == 2))
{
min = info->values[0];
max = info->values[1];
tmp = (level * (max - min)) + min;
new = tmp;
if (new > max) new = max;
if (new < min) new = min;
XRRChangeOutputProperty(_ecore_x_disp, output, _backlight, XA_INTEGER, 32,
PropModeReplace, (unsigned char *)&new, 1);
XFlush(_ecore_x_disp);
}
free(info);
return EINA_TRUE;
}
#endif
return EINA_FALSE;
}
/*
* @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)
{
#ifdef ECORE_XRANDR
Ecore_X_Window root;
Ecore_X_Randr_Crtc *crtcs;
Ecore_X_Randr_Output *outputs, *ret = NULL;
int ncrtcs, noutputs, i, nret = 0;
if (_randr_version < RANDR_1_2) goto _ecore_x_randr_current_output_get_fail;
root = ecore_x_window_root_get(window);
if (!(crtcs = ecore_x_randr_window_crtcs_get(window, &ncrtcs)))
goto _ecore_x_randr_current_output_get_fail;
for (i = 0, nret = 0; i < ncrtcs; i++)
{
outputs = ecore_x_randr_crtc_outputs_get(root, crtcs[i],
&noutputs);
if (!outputs)
goto _ecore_x_randr_current_output_get_fail_free;
nret += noutputs;
ret = realloc(ret, (nret * sizeof(Ecore_X_Randr_Output)));
memcpy(&ret[nret], outputs, (noutputs * sizeof(Ecore_X_Randr_Output)));
free(outputs);
}
free(crtcs);
if (num)
*num = nret;
return ret;
_ecore_x_randr_current_output_get_fail_free:
free(outputs);
free(crtcs);
free(ret);
_ecore_x_randr_current_output_get_fail:
#endif
if (num) *num = 0;
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);
}