/* * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 */ #ifdef HAVE_CONFIG_H # include #endif #include "ecore_x_private.h" #include "ecore_x_randr.h" #define Ecore_X_Randr_None 0 #define Ecore_X_Randr_Unset -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 RRandR >= 1.2. * @param win select this window's properties for RandRR 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 EINA_TRUE will be returned. Else EINA_FALSE is returned. */ 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. 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 0, current aspect is assumed. * @param h_mm height in mm the screen should be set to. If 0, current aspect is assumed. * @return EINA_TRUE if request was successfully sent or screen is already in * requested size, 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)))) strncpy(ret[i]->name, res->modes[i].name, res->modes[i].nameLength); 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 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; if (!(ret->name = strndup(res->modes[i].name, res->modes[i].nameLength))) { ret->name = NULL; ret->nameLength = 0; } else ret->nameLength = res->modes[i].nameLength; 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 * 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 } 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 EINA_TRUE if position could be 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 * NULL CRTC will be disabled. * @param noutputs number of outputs in array to be used. Use * Ecore_X_Randr_Unset (or -1) to use currently used outputs. * @para mode XID of the mode to be set. If set to 0 the CRTC will be disabled. * If set to -1 the call will fail. * @return EINA_TRUE if mode setting was successfull. Else EINA_FALSE */ 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 clone) { #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, clone) && (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)) && (clone_crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, clone))) { 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, clone, 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 EINA_TRUE if the configuration alteration was successful, else * EINA_FALSE */ 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 == 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. * @crtc_r1 the CRTC to be positioned. * @crtc_r2 the CRTC the position should be relative to * @position the relation between the crtcs * @aligment in case CRTCs size differ, aligns CRTC1 accordingly at CRTC2's * borders * @return EINA_TRUE if crtc could be successfully positioned. 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 } 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. * @root window that this information should be queried for. * @output the output which's clones we concern * @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 * @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 bewow command is correct, but due to a bug in libXrandr * it doesn't work. Therefor we stick with strlen(). * Replace the line below with the following once * libXrandr >= git revision '25d793ab4ec111658e541c94eba4893a81d6a3b7'. * is shipped and standard. * * *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 * @w width of given mode in px * @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 * @output the XID of the output * @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 == NULL) || !_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 neccessary 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 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[ncrtc]; Eina_Bool ret = EINA_TRUE; int i, cw, ch, w_max, h_max, nw, nh; 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) || ((crtc_info[i]->x + crtc_info[i]->width + dx) > w_max) || ((crtc_info[i]->y + dy) < 0) || ((crtc_info[i]->y + crtc_info[i]->height + dy) > h_max) ) goto _ecore_x_randr_move_crtcs_fail_free_crtc_info; nw = MAX((crtc_info[i]->x + crtc_info[i]->width + dx), nw); nh = MAX((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; i++) { if (!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) 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++) { 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 ((crtc_info->x + crtc_info->width) > w_n) w_n = (crtc_info->x + crtc_info->width); if ((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); } fprintf(stderr, "E_RANDR: babam, resize! Trying to move all CRTCs with dx %d and dy %d", dx_min, dy_min); 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 }