03da85020cc90371cc98300179364b4d99202a3b
[platform/upstream/efl.git] / src / lib / ecore_x / xlib / ecore_x_randr.c
1  #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include "Ecore.h"
6 #include "ecore_x_private.h"
7 #include "Ecore_X.h"
8
9 /* NB: FIXME:
10  * 
11  * A lot of this code uses XRRGetScreenInfo and then calls 
12  * XRRFreeScreenConfigInfo. Typically this is not an Unheard of thing to do, 
13  * however this process of getting config and freeing config does force a 
14  * round-trip to the X server */
15
16 /* local variables */
17 static Eina_Bool _randr_avail = EINA_FALSE;
18
19 static Ecore_X_Atom connector_type = 0;
20 static Ecore_X_Atom connector_number = 0;
21
22 #ifdef ECORE_XRANDR
23
24 # define RANDR_VERSION_1_1 ((1 << 16) | 1)
25 # define RANDR_VERSION_1_2 ((1 << 16) | 2)
26 # define RANDR_VERSION_1_3 ((1 << 16) | 3)
27 # define RANDR_VERSION_1_4 ((1 << 16) | 4)
28
29 # define RANDR_EDID_VERSION_1_3 ((1 << 8) | 3)
30 # define RANDR_EDID_VERSION_MAJOR 0x12
31 # define RANDR_EDID_VERSION_MINOR 0x13
32
33 # define RANDR_EDID_MANUFACTURER 0x08
34 # define RANDR_EDID_BLOCK 0x36
35
36 typedef enum _Ecore_X_Randr_Edid_Aspect_Ratio_Preferred 
37 {
38    RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3 = 0x00,
39      RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9 = 0x01,
40      RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10 = 0x02,
41      RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4 = 0x03,
42      RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9 = 0x04
43 } Ecore_X_Randr_Edid_Aspect_Ratio_Preferred;
44
45 static int _randr_major, _randr_minor, _randr_version;
46
47 XRRScreenResources *(*_ecore_x_randr_screen_resources_get)(Display *disp, Window win);
48
49 #endif
50
51 /* local functions */
52 void 
53 _ecore_x_randr_init(void)
54 {
55 #ifdef ECORE_XRANDR
56    _randr_major = 1;
57    _randr_minor = 4;
58    _randr_version = 0;
59
60    /* try to query the randr extenstion version */
61    if (XRRQueryVersion(_ecore_x_disp, &_randr_major, &_randr_minor))
62      {
63         _randr_version = (_randr_major << 16) | _randr_minor;
64
65         if (_randr_version >= RANDR_VERSION_1_3)
66           _ecore_x_randr_screen_resources_get = XRRGetScreenResourcesCurrent;
67         else if (_randr_version == RANDR_VERSION_1_2)
68           _ecore_x_randr_screen_resources_get = XRRGetScreenResources;
69
70         _randr_avail = EINA_TRUE;
71
72         connector_type = ecore_x_atom_get(RR_PROPERTY_CONNECTOR_TYPE);
73         connector_number = ecore_x_atom_get(RR_PROPERTY_CONNECTOR_NUMBER);
74      }
75 #endif
76 }
77
78 /* public functions */
79 EAPI int 
80 ecore_x_randr_version_get(void)
81 {
82 #ifdef ECORE_XRANDR
83    if (_randr_avail) return _randr_version;
84 #endif
85    return -1;
86 }
87
88 EAPI Eina_Bool 
89 ecore_x_randr_query(void)
90 {
91    return _randr_avail;
92 }
93
94 /**
95  * @brief This function returns the current config timestamp from 
96  * XRRScreenConfiguration.
97  * 
98  * @param root root window to query screen configuration from
99  * 
100  * @returns The screen configuration timestamp
101  * 
102  * @since 1.8
103  */
104 EAPI Ecore_X_Time 
105 ecore_x_randr_config_timestamp_get(Ecore_X_Window root)
106 {
107    Ecore_X_Time timestamp = 0;
108
109 #ifdef ECORE_XRANDR
110    XRRScreenConfiguration *cfg;
111
112    /* try to get the screen configuration from Xrandr */
113    if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
114      {
115         Time tm;
116
117         XRRConfigTimes(cfg, &tm);
118
119         timestamp = (Ecore_X_Time)tm;
120
121         /* free any returned screen config */
122         if (cfg) XRRFreeScreenConfigInfo(cfg);
123      }
124 #endif
125
126    return timestamp;
127 }
128
129 /***************************************
130  * API Functions for RandR version 1.1 *
131  ***************************************/
132
133 /*
134  * @param root window which's primary output will be queried
135  */
136 EAPI Ecore_X_Randr_Orientation 
137 ecore_x_randr_screen_primary_output_orientations_get(Ecore_X_Window root)
138 {
139 #ifdef ECORE_XRANDR
140    Rotation ret = 0, crot = 0;
141
142    /* get the rotations available from XRandr */
143    ret = XRRRotations(_ecore_x_disp, 
144                       XRRRootToScreen(_ecore_x_disp, root), &crot);
145
146    return ret;
147 #else
148    return 0;
149 #endif
150 }
151
152 /*
153  * @param root window which's primary output will be queried
154  * @return the current orientation of the root window's screen primary output
155  */
156 EAPI Ecore_X_Randr_Orientation 
157 ecore_x_randr_screen_primary_output_orientation_get(Ecore_X_Window root)
158 {
159 #ifdef ECORE_XRANDR
160    Rotation ret = 0;
161
162    /* get the current rotation available from XRandr */
163    XRRRotations(_ecore_x_disp, 
164                 XRRRootToScreen(_ecore_x_disp, root), &ret);
165
166    return ret;
167 #else
168    return 0;
169 #endif
170 }
171
172 /*
173  * @brief Sets a given screen's primary output's orientation.
174  *
175  * @param root Window which's screen's primary output will be queried.
176  * @param orientation orientation which should be set for the root window's
177  * screen primary output.
178  * @return @c EINA_TRUE if the primary output's orientation could be
179  * successfully altered.
180  */
181 EAPI Eina_Bool 
182 ecore_x_randr_screen_primary_output_orientation_set(Ecore_X_Window root, Ecore_X_Randr_Orientation orient)
183 {
184 #ifdef ECORE_XRANDR
185    Eina_Bool ret = EINA_FALSE;
186    Rotation crot = 0;
187    XRRScreenConfiguration *cfg = NULL;
188    int id = 0;
189
190    /* try to get the screen config from XRandr */
191    if (!(cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
192      return EINA_FALSE;
193
194    /* get the screen's current size id */
195    id = XRRConfigCurrentConfiguration(cfg, &crot);
196
197    /* attempt to set the new orientation */
198    if (!XRRSetScreenConfig(_ecore_x_disp, cfg, root, id, orient, CurrentTime))
199      ret = EINA_TRUE;
200
201    /* free any returned screen config */
202    if (cfg) XRRFreeScreenConfigInfo(cfg);
203
204    return ret;
205 #else
206    return EINA_FALSE;
207 #endif
208 }
209
210 /*
211  * @brief gets a screen's primary output's possible sizes
212  * @param root window which's primary output will be queried
213  * @param num number of sizes reported as supported by the screen's primary output
214  * @return an array of sizes reported as supported by the screen's primary output or - if query failed - NULL
215  */
216 EAPI Ecore_X_Randr_Screen_Size_MM *
217 ecore_x_randr_screen_primary_output_sizes_get(Ecore_X_Window root, int *num)
218 {
219    if (num) *num = 0;
220 #ifdef ECORE_XRANDR
221    Ecore_X_Randr_Screen_Size_MM *ret = NULL;
222    XRRScreenSize *sizes;
223    int n = 0, i = 0;
224
225    /* retrieve the number of sizes from X, and the sizes themselves.
226     * 
227     * NB: don't have to free the returned sizes */
228    sizes = XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n);
229    if (!sizes) return NULL;
230    if (n <= 0) return NULL;
231
232    /* try to allocate our structure for these sizes */
233    if (!(ret = calloc(n, sizeof(Ecore_X_Randr_Screen_Size_MM))))
234      return NULL;
235
236    if (num) *num = n;
237
238    /* fill in our allocated structure with the screen sizes */
239    for (i = 0; i < n; i++)
240      {
241         ret[i].width = sizes[i].width;
242         ret[i].height = sizes[i].height;
243         ret[i].width_mm = sizes[i].mwidth;
244         ret[i].height_mm = sizes[i].mheight;
245      }
246
247    return ret;
248 #else
249    return NULL;
250 #endif
251 }
252
253 EAPI void 
254 ecore_x_randr_screen_primary_output_current_size_get(Ecore_X_Window root, int *w, int *h, int *w_mm, int *h_mm, int *size_index)
255 {
256 #ifdef ECORE_XRANDR
257    XRRScreenConfiguration *cfg = NULL;
258
259    /* try to get the screen config from XRandr */
260    if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
261      {
262         XRRScreenSize *sizes;
263         Rotation crot = 0;
264         int n = 0;
265
266         /* retrieve the number of sizes from X, and the sizes themselves.
267          * 
268          * NB: don't have to free the returned sizes */
269         sizes = 
270           XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n);
271         if ((sizes) && (n > 0))
272           {
273              int idx = 0;
274
275              /* get the index of the current configuration */
276              idx = XRRConfigCurrentConfiguration(cfg, &crot);
277
278              /* if the index is valid, then fill in the return variables with 
279               * the size information for this index */
280              if ((idx < n) && (idx >= 0))
281                {
282                   if (w) *w = sizes[idx].width;
283                   if (h) *h = sizes[idx].height;
284                   if (w_mm) *w_mm = sizes[idx].mwidth;
285                   if (h_mm) *h_mm = sizes[idx].mheight;
286                   if (size_index) *size_index = idx;
287                }
288           }
289
290         /* free the returned screen config */
291         XRRFreeScreenConfigInfo(cfg);
292      }
293 #endif
294 }
295
296 /*
297  * @brief Sets a given screen's primary output size, but disables all other
298  * outputs at the same time.
299  *
300  * @param root Window which's primary output will be queried.
301  * @param size_index Within the list of sizes reported as supported by the root
302  * window's screen primary output.
303  * @return @c EINA_TRUE on success, @c EINA_FALSE on failure due to e.g.
304  * invalid times.
305  */
306 EAPI Eina_Bool 
307 ecore_x_randr_screen_primary_output_size_set(Ecore_X_Window root, int size_index)
308 {
309 #ifdef ECORE_XRANDR
310    Eina_Bool ret = EINA_FALSE;
311    int n = 0;
312
313    /* check for valid size index first */
314    if (size_index < 0) return EINA_FALSE;
315
316    /* get the number of sizes from XRandr */
317    XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n);
318
319    /* make sure the requested index is below the number returned from randr */
320    if (size_index < n)
321      {
322         XRRScreenConfiguration *cfg = NULL;
323
324         /* try to get the screen config from XRandr */
325         if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
326           {
327              /* try to set the new screen config
328               * 
329               * NB: Returns Success (0) if it works */
330              if (!XRRSetScreenConfig(_ecore_x_disp, cfg, root, size_index, 
331                                       ECORE_X_RANDR_ORIENTATION_ROT_0, 
332                                       CurrentTime))
333                {
334                   ret = EINA_TRUE;
335                }
336
337              /* free the returned screen config */
338              XRRFreeScreenConfigInfo(cfg);
339           }
340      }
341
342    return ret;
343 #else
344    return EINA_FALSE;
345 #endif
346 }
347
348 /*
349  * @param root window which's primary output will be queried
350  * @return currently used refresh rate or - if request failed or RandRR is not available - 0.0
351  */
352 EAPI Ecore_X_Randr_Refresh_Rate 
353 ecore_x_randr_screen_primary_output_current_refresh_rate_get(Ecore_X_Window root)
354 {
355 #ifdef ECORE_XRANDR
356    XRRScreenConfiguration *cfg = NULL;
357
358    /* try to get the screen config from XRandr */
359    if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
360      {
361         Ecore_X_Randr_Refresh_Rate ret = 0.0;
362
363         /* try to get the current refresh rate */
364         ret = XRRConfigCurrentRate(cfg);
365
366         /* free the returned screen config */
367         XRRFreeScreenConfigInfo(cfg);
368
369         return ret;
370      }
371 #endif
372    return 0.0;
373 }
374
375 /*
376  * @param root window which's primary output will be queried
377  * @param size_index referencing the size to query valid refresh rates for
378  * @return currently used refresh rate or - if request failed or RandRR is not available - NULL
379  */
380 EAPI Ecore_X_Randr_Refresh_Rate *
381 ecore_x_randr_screen_primary_output_refresh_rates_get(Ecore_X_Window root, int size_index, int *num)
382 {
383 #ifdef ECORE_XRANDR
384    Ecore_X_Randr_Refresh_Rate *rates = NULL;
385    int n = 0;
386
387    /* try to get the refresh rates for this screen */
388    if ((rates = XRRRates(_ecore_x_disp, 
389                          XRRRootToScreen(_ecore_x_disp, root), size_index, &n)))
390      {
391         Ecore_X_Randr_Refresh_Rate *ret = NULL;
392
393         if (n == 0) return NULL;
394
395         /* try to allocate space for the return */
396         if ((ret = malloc(n * sizeof(Ecore_X_Randr_Refresh_Rate))))
397           {
398              int i = 0;
399
400              /* fill in our return values */
401              for (i = 0; i < n; i++)
402                ret[i] = rates[i];
403
404              if (num) *num = n;
405
406              return ret;
407           }
408      }
409 #endif
410    return NULL;
411 }
412
413 /*
414  * @brief Sets the current primary output's refresh rate.
415  *
416  * @param root Window which's primary output will be queried.
417  * @param size_index Referencing the size to be set.
418  * @param rate The refresh rate to be set.
419  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
420  */
421 EAPI Eina_Bool 
422 ecore_x_randr_screen_primary_output_refresh_rate_set(Ecore_X_Window root, int size_index, Ecore_X_Randr_Refresh_Rate rate)
423 {
424 #ifdef ECORE_XRANDR
425    if (_randr_version >= RANDR_VERSION_1_1)
426      {
427         XRRScreenConfiguration *cfg = NULL;
428
429         /* try to get the screen config from XRandr */
430         if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
431           {
432              Eina_Bool ret = EINA_FALSE;
433              Rotation rot = 0;
434
435              /* get the current rotation */
436              XRRConfigRotations(cfg, &rot);
437  
438              /* try to set the new screen config
439               * 
440               * NB: Returns Success (0) if it works */
441              if (!XRRSetScreenConfigAndRate(_ecore_x_disp, cfg, root, 
442                                             size_index, rot, rate, CurrentTime))
443                {
444                   ret = EINA_TRUE;
445                }
446
447              /* free the returned screen config */
448              XRRFreeScreenConfigInfo(cfg);
449
450              return ret;
451           }
452      }
453 #endif
454    return EINA_FALSE;
455 }
456
457 /***************************************
458  * API Functions for RandR version 1.2 *
459  ***************************************/
460
461 /**
462  * @brief Enable event selection. This enables basic interaction with
463  * output/crtc events and requires RandR >= 1.2.
464  *
465  * @param win Select this window's properties for RandR events.
466  * @param on Enable/disable selecting.
467  */
468 EAPI void 
469 ecore_x_randr_events_select(Ecore_X_Window win, Eina_Bool on)
470 {
471 #ifdef ECORE_XRANDR
472    int mask = 0;
473
474    if (on)
475      {
476         mask = RRScreenChangeNotifyMask;
477         if (_randr_version >= RANDR_VERSION_1_2)
478           mask |= (RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | 
479                    RROutputPropertyNotifyMask);
480      }
481
482    /* tell randr what events we want to listen to for this window */
483    XRRSelectInput(_ecore_x_disp, win, mask);
484 #endif
485 }
486
487 /*
488  * @param w width of screen in px
489  * @param h height of screen in px
490  */
491 EAPI void 
492 ecore_x_randr_screen_current_size_get(Ecore_X_Window root, int *w, int *h, int *w_mm, int *h_mm)
493 {
494 #ifdef ECORE_XRANDR
495    if (_randr_version >= RANDR_VERSION_1_2)
496      {
497         int scr = 0;
498
499         /* get the screen number */
500         scr = XRRRootToScreen(_ecore_x_disp, root);
501
502         if (w) *w = DisplayWidth(_ecore_x_disp, scr);
503         if (h) *h = DisplayHeight(_ecore_x_disp, scr);
504         if (w_mm) *w_mm = DisplayWidthMM(_ecore_x_disp, scr);
505         if (h_mm) *h_mm = DisplayHeightMM(_ecore_x_disp, scr);
506      }
507 #endif
508 }
509
510 /*
511  * @param root window which's screen will be queried
512  * @param wmin minimum width the screen can be set to
513  * @param hmin minimum height the screen can be set to
514  * @param wmax maximum width the screen can be set to
515  * @param hmax maximum height the screen can be set to
516  */
517 EAPI void 
518 ecore_x_randr_screen_size_range_get(Ecore_X_Window root, int *wmin, int *hmin, int *wmax, int *hmax)
519 {
520 #ifdef ECORE_XRANDR
521    if (_randr_version >= RANDR_VERSION_1_2)
522      {
523         int swmin = 0, shmin = 0, swmax = 0, shmax = 0;
524
525         /* try to get the screen size range from XRandr
526          * 
527          * NB: returns 1 on success */
528         if ((XRRGetScreenSizeRange(_ecore_x_disp, root, &swmin, &shmin, 
529                                    &swmax, &shmax)))
530           {
531              /* fill in the return variables */
532              if (wmin) *wmin = swmin;
533              if (hmin) *hmin = shmin;
534              if (wmax) *wmax = swmax;
535              if (hmax) *hmax = shmax;
536           }
537      }
538 #endif
539 }
540
541 /**
542  * @brief removes unused screen space. The most upper left CRTC is set to 0x0
543  * and all other CRTCs dx,dy respectively.
544  * @param root the window's screen which will be reset.
545  */
546 EAPI void 
547 ecore_x_randr_screen_reset(Ecore_X_Window root)
548 {
549 #ifdef ECORE_XRANDR
550    XRRScreenResources *res = NULL;
551
552    if (_randr_version < RANDR_VERSION_1_2) return;
553
554    /* try to get the screen resources from Xrandr */
555    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
556      {
557         if (res->ncrtc > 0)
558           {
559              Ecore_X_Randr_Crtc crtcs[res->ncrtc];
560              int i = 0, nenabled = 0;
561              int nw = 0, nh = 0;
562              int dx = 100000, dy = 100000;
563
564              for (i = 0; i < res->ncrtc; i++)
565                {
566                   XRRCrtcInfo *info = NULL;
567
568                   /* try to get the crtc info from Xrandr */
569                   if (!(info = XRRGetCrtcInfo(_ecore_x_disp, res, res->crtcs[i])))
570                     continue;
571
572                   /* safety check */
573                   if ((info->mode <= 0) || (info->noutput == 0))
574                     {
575                        /* free the crtc info */
576                        XRRFreeCrtcInfo(info);
577
578                        continue;
579                     }
580
581                   crtcs[nenabled++] = res->crtcs[i];
582
583                   if ((int)(info->x + info->width) > nw)
584                     nw = (info->x + info->width);
585
586                   if ((int)(info->y + info->height) > nh)
587                     nh = (info->y + info->height);
588
589                   if (info->x < dx) dx = info->x;
590                   if (info->y < dy) dy = info->y;
591
592                   /* free the crtc info */
593                   XRRFreeCrtcInfo(info);
594                }
595
596              /* free the resources */
597              XRRFreeScreenResources(res);
598
599              if ((dx > 0) || (dy > 0))
600                {
601                   if (ecore_x_randr_move_crtcs(root, crtcs, nenabled, -dx, -dy))
602                     {
603                        nw -= dx;
604                        nh -= dy;
605                     }
606                }
607
608              ecore_x_randr_screen_current_size_set(root, nw, nh, -1, -1);
609           }
610      }
611 #endif
612 }
613
614 /*
615  * @param root Window which's screen's size should be set. If invalid (e.g. 
616  * @c NULL) no action is taken.
617  * @param w Width in px the screen should be set to. If out of valid
618  * boundaries, current value is assumed.
619  * @param h Height in px the screen should be set to. If out of valid
620  * boundaries, current value is assumed.
621  * @param w_mm Width in mm the screen should be set to. If @c 0, current
622  * aspect is assumed.
623  * @param h_mm Height in mm the screen should be set to. If @c 0, current
624  * aspect is assumed.
625  * @return @c EINA_TRUE if request was successfully sent or screen is already
626  * in requested size, @c EINA_FALSE if parameters are invalid.
627  */
628 EAPI Eina_Bool 
629 ecore_x_randr_screen_current_size_set(Ecore_X_Window root, int w, int h, int w_mm, int h_mm)
630 {
631 #ifdef ECORE_XRANDR
632    if (_randr_version >= RANDR_VERSION_1_2)
633      {
634         int cw = 0, ch = 0, cwmm = 0, chmm = 0;
635         int wmin = 0, hmin = 0, wmax = 0, hmax = 0;
636
637         /* get the current screen size */
638         ecore_x_randr_screen_current_size_get(root, &cw, &ch, &cwmm, &chmm);
639
640         /* compare to the values passed in. if there are no changes, get out */
641         if ((w == cw) && (h == ch) &&
642             ((w_mm == -1) || (w_mm == cwmm)) &&
643             ((h_mm == -1) || (h_mm == chmm)))
644           return EINA_TRUE;
645
646         /* get the current size range */
647         ecore_x_randr_screen_size_range_get(root, &wmin, &hmin, &wmax, &hmax);
648
649         /* compare to the values passed in. make sure they are within range */
650         if ((w != 0) && ((w < wmin) || (w > wmax))) return EINA_FALSE;
651         if ((h != 0) && ((h < hmin) || (h > hmax))) return EINA_FALSE;
652
653         /* safety check some values */
654         if (w <= 0) w = cw;
655         if (h <= 0) h = ch;
656         if (w_mm <= 0)
657           {
658              if (cw > 0)
659                w_mm = (int)(((double)(cwmm / (double)cw)) * (double)w);
660              else
661                w_mm = (int)(((double)(cwmm)) * (double)w);
662           }
663         if (h_mm <= 0)
664           {
665              if (ch > 0)
666                h_mm = (int)(((double)(chmm / (double)ch)) * (double)h);
667              else
668                h_mm = (int)(((double)(chmm)) * (double)h);
669           }
670
671         /* tell XRandr to set screen size */
672         XRRSetScreenSize(_ecore_x_disp, root, w, h, w_mm, h_mm);
673
674         return EINA_TRUE;
675      }
676 #endif
677    return EINA_FALSE;
678 }
679
680 /*
681  * @brief get detailed information for all modes related to a root window's screen
682  * @param root window which's screen's resources are queried
683  * @param num number of modes returned
684  * @return modes' information
685  */
686 EAPI Ecore_X_Randr_Mode_Info **
687 ecore_x_randr_modes_info_get(Ecore_X_Window root, int *num)
688 {
689    if (num) *num = 0;
690 #ifdef ECORE_XRANDR
691    XRRScreenResources *res = NULL;
692
693    if (_randr_version < RANDR_VERSION_1_2) return NULL;
694
695    /* try to get the screen resources from Xrandr */
696    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
697      {
698         Ecore_X_Randr_Mode_Info **ret = NULL;
699
700         /* set the returned number of modes */
701         if (num) *num = res->nmode;
702
703         /* if we did not get any modes from X, then cleanup and return */
704         if (res->nmode == 0)
705           {
706              /* free the resources */
707              XRRFreeScreenResources(res);
708
709              return NULL;
710           }
711
712         /* try to allocate space for our return variable */
713         if ((ret = (Ecore_X_Randr_Mode_Info **)
714              malloc(res->nmode * sizeof(Ecore_X_Randr_Mode_Info *))))
715           {
716              int i = 0;
717
718              /* loop through all the modes and assign to our return var */
719              for (i = 0; i < res->nmode; i++)
720                {
721                   if ((ret[i] = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
722                     {
723                        ret[i]->xid = res->modes[i].id;
724                        ret[i]->width = res->modes[i].width;
725                        ret[i]->height = res->modes[i].height;
726                        ret[i]->dotClock = res->modes[i].dotClock;
727                        ret[i]->hSyncStart = res->modes[i].hSyncStart;
728                        ret[i]->hSyncEnd = res->modes[i].hSyncEnd;
729                        ret[i]->hTotal = res->modes[i].hTotal;
730                        ret[i]->hSkew = res->modes[i].hSkew;
731                        ret[i]->vSyncStart = res->modes[i].vSyncStart;
732                        ret[i]->vSyncEnd = res->modes[i].vSyncEnd;
733                        ret[i]->vTotal = res->modes[i].vTotal;
734                        if (res->modes[i].nameLength > 0)
735                          {
736                             if ((ret[i]->name = 
737                                  (malloc(res->modes[i].nameLength + 1))))
738                               strncpy(ret[i]->name, res->modes[i].name,
739                                       (res->modes[i].nameLength + 1));
740                             else
741                               ret[i]->name = NULL;
742                          }
743                        else
744                          ret[i]->name = NULL;
745
746                        ret[i]->nameLength = res->modes[i].nameLength;
747                        ret[i]->modeFlags = res->modes[i].modeFlags;
748                     }
749                   else
750                     {
751                        while (i > 0)
752                          free(ret[--i]);
753                        free(ret);
754                        ret = NULL;
755                        break;
756                     }
757                }
758           }
759
760         /* free the resources */
761         XRRFreeScreenResources(res);
762
763         return ret;
764      }
765 #endif
766    return NULL;
767 }
768
769 /*
770  * @brief Add a mode to a display.
771  *
772  * @param root Window to which's screen's ressources are added.
773  * @param mode_info
774  * @return Ecore_X_Randr_Mode of the added mode. Ecore_X_Randr_None if mode
775  * adding failed.
776  * @since 1.2.0
777  */
778 EAPI Ecore_X_Randr_Mode 
779 ecore_x_randr_mode_info_add(Ecore_X_Window root, Ecore_X_Randr_Mode_Info *mode_info)
780 {
781 #ifdef ECORE_XRANDR
782    if (_randr_version >= RANDR_VERSION_1_2)
783      {
784         Ecore_X_Randr_Mode mode = 0;
785
786         /* if we have valid mode_info from the user, then ask XRandr to 
787          * create the new mode using that as base */
788         if (mode_info)
789           mode = XRRCreateMode(_ecore_x_disp, root, (XRRModeInfo *)mode_info);
790
791         return mode;
792      }
793 #endif
794    return 0;
795 }
796
797 /*
798  * @brief Delete a mode from the display.
799  *
800  * @param mode_info
801  * @since 1.2.0
802  */
803 EAPI void 
804 ecore_x_randr_mode_del(Ecore_X_Randr_Mode mode)
805 {
806 #ifdef ECORE_XRANDR
807    if (_randr_version >= RANDR_VERSION_1_2)
808      XRRDestroyMode(_ecore_x_disp, mode);
809 #endif
810 }
811
812 /*
813  * @brief get detailed information for a given mode id
814  * @param root window which's screen's ressources are queried
815  * @param mode the XID which identifies the mode of interest
816  * @return mode's detailed information
817  */
818 EAPI Ecore_X_Randr_Mode_Info *
819 ecore_x_randr_mode_info_get(Ecore_X_Window root, Ecore_X_Randr_Mode mode)
820 {
821 #ifdef ECORE_XRANDR
822    XRRScreenResources *res = NULL;
823
824    if (_randr_version < RANDR_VERSION_1_2) return NULL;
825
826    /* try to get the screen resources from Xrandr */
827    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
828      {
829         Ecore_X_Randr_Mode_Info *ret = NULL;
830         int i = 0;
831
832         if (res->nmode == 0)
833           {
834              /* free the resources */
835              XRRFreeScreenResources(res);
836
837              return NULL;
838           }
839
840         /* loop the mode informations and find the one we want */
841         for (i = 0; i < res->nmode; i++)
842           {
843              /* compare mode ids */
844              if (res->modes[i].id != mode) continue;
845
846              /* try to allocate our return mode information structure */
847              if (!(ret = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
848                break;
849
850              /* copy the mode information into our return structure */
851              ret->xid = res->modes[i].id;
852              ret->width = res->modes[i].width;
853              ret->height = res->modes[i].height;
854              ret->dotClock = res->modes[i].dotClock;
855              ret->hSyncStart = res->modes[i].hSyncStart;
856              ret->hSyncEnd = res->modes[i].hSyncEnd;
857              ret->hTotal = res->modes[i].hTotal;
858              ret->hSkew = res->modes[i].hSkew;
859              ret->vSyncStart = res->modes[i].vSyncStart;
860              ret->vSyncEnd = res->modes[i].vSyncEnd;
861              ret->vTotal = res->modes[i].vTotal;
862              ret->modeFlags = res->modes[i].modeFlags;
863              ret->name = NULL;
864              ret->nameLength = 0;
865              if (res->modes[i].nameLength > 0)
866                {
867                   ret->nameLength = res->modes[i].nameLength;
868                   if ((ret->name = malloc(res->modes[i].nameLength + 1)))
869                     strncpy(ret->name, res->modes[i].name,
870                             (res->modes[i].nameLength + 1));
871                }
872              break;
873           }
874
875         /* free the resources */
876         XRRFreeScreenResources(res);
877
878         return ret;
879      }
880 #endif
881    return NULL;
882 }
883
884 /*
885  * @brief Free detailed mode information. The pointer handed in will be set to
886  * @c NULL after freeing the memory.
887  *
888  * @param mode_info The mode information that should be freed.
889  */
890 EAPI void 
891 ecore_x_randr_mode_info_free(Ecore_X_Randr_Mode_Info *mode_info)
892 {
893 #ifdef ECORE_XRANDR
894    if (_randr_version >= RANDR_VERSION_1_2)
895      {
896         if (mode_info)
897           {
898              if (mode_info->name) free(mode_info->name);
899              free(mode_info);
900           }
901      }
902 #endif
903 }
904
905 /*
906  * @brief Get all known CRTCs related to a root window's screen.
907  *
908  * @param root Window which's screen's ressources are queried.
909  * @param num Number of CRTCs returned.
910  * @return CRTC IDs.
911  */
912 EAPI Ecore_X_Randr_Crtc *
913 ecore_x_randr_crtcs_get(Ecore_X_Window root, int *num)
914 {
915    if (num) *num = 0;
916 #ifdef ECORE_XRANDR
917    XRRScreenResources *res = NULL;
918
919    if (_randr_version < RANDR_VERSION_1_2) return NULL;
920
921    /* try to get the screen resources from Xrandr */
922    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
923      {
924         Ecore_X_Randr_Crtc *ret = NULL;
925
926         if (res->ncrtc == 0)
927           {
928              /* free the resources */
929              XRRFreeScreenResources(res);
930
931              return NULL;
932           }
933
934         /* try to allocate space for our return variable */
935         if ((ret = malloc(res->ncrtc * sizeof(Ecore_X_Randr_Crtc))))
936           {
937              int i = 0;
938
939              if (num) *num = res->ncrtc;
940
941              /* copy the crtc information into our return variable */
942              for (i = 0; i < res->ncrtc; i++)
943                ret[i] = res->crtcs[i];
944           }
945
946         /* free the resources */
947         XRRFreeScreenResources(res);
948
949         return ret;
950      }
951 #endif
952    return NULL;
953 }
954
955 EAPI Ecore_X_Randr_Output *
956 ecore_x_randr_outputs_get(Ecore_X_Window root, int *num)
957 {
958    if (num) *num = 0;
959 #ifdef ECORE_XRANDR
960    XRRScreenResources *res = NULL;
961
962    if (_randr_version < RANDR_VERSION_1_2) return NULL;
963
964    /* try to get the screen resources from Xrandr */
965    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
966      {
967         Ecore_X_Randr_Output *ret = NULL;
968
969         if (res->noutput == 0)
970           {
971              /* free the resources */
972              XRRFreeScreenResources(res);
973
974              return NULL;
975           }
976
977         /* try to allocate space for our return variable */
978         if ((ret = malloc(res->noutput * sizeof(Ecore_X_Randr_Output))))
979           {
980              int i = 0;
981
982              if (num) *num = res->noutput;
983
984              /* copy the output information into our return variable */
985              for (i = 0; i < res->noutput; i++)
986                ret[i] = res->outputs[i];
987           }
988
989         /* free the resources */
990         XRRFreeScreenResources(res);
991
992         return ret;
993      }
994 #endif
995    return NULL;
996 }
997
998 /*
999  * @brief Get the outputs, which display a certain window.
1000  *
1001  * @param window Window the displaying outputs shall be found for
1002  * @param num The number of outputs displaying the window
1003  * @return Array of outputs that display a certain window. @c NULL if no
1004  * outputs was found that displays the specified window.
1005  */
1006 EAPI Ecore_X_Randr_Output *
1007 ecore_x_randr_window_outputs_get(Ecore_X_Window window, int *num)
1008 {
1009    if (num) *num = 0;
1010 #ifdef ECORE_XRANDR
1011    Ecore_X_Window root;
1012    Ecore_X_Randr_Crtc *crtcs = NULL;
1013    int ncrtcs = 0;
1014
1015    if (_randr_version < RANDR_VERSION_1_2) return NULL;
1016
1017    /* grab this windows root window */
1018    root = ecore_x_window_root_get(window);
1019
1020    /* get the crtcs from xrandr */
1021    if ((crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs)))
1022      {
1023         XRRScreenResources *res = NULL;
1024         Ecore_X_Randr_Output *ret = NULL;
1025
1026         /* try to get the screen resources from Xrandr
1027          * 
1028          * NB: We do this ONCE here as we reuse it for every crtc.
1029          * NB: The old code used to loop and fetch the screen resources on 
1030          *     every crtc */
1031         if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1032           {
1033              Ecore_X_Randr_Output *tret = NULL;
1034              int i = 0, nret = 0;
1035
1036              /* for each crtc, get it's outputs */
1037              for (i = 0, nret = 0; i < ncrtcs; i++)
1038                {
1039                   XRRCrtcInfo *crtc = NULL;
1040
1041                   /* try to get the crtc info for this crtc */
1042                   if (!(crtc = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i])))
1043                     continue;
1044                   
1045                   if (crtc->noutput > 0)
1046                     {
1047                        /* try to reallocate our return variable */
1048                        if ((tret = realloc(ret, ((nret + crtc->noutput) * 
1049                                                  sizeof(Ecore_X_Randr_Output)))))
1050                          {
1051                             ret = tret;
1052                             memcpy(&ret[nret], crtc->outputs, 
1053                                    (crtc->noutput * sizeof(Ecore_X_Randr_Output)));
1054                             nret += crtc->noutput;
1055                          }
1056                     }
1057                   /* free the crtc info */
1058                   XRRFreeCrtcInfo(crtc);
1059                }
1060
1061              if (num) *num = nret;
1062
1063              /* free the resources */
1064              XRRFreeScreenResources(res);
1065           }
1066
1067         /* free any allocated crtcs from the get function */
1068         free(crtcs);
1069
1070         return ret;
1071      }
1072 #endif
1073    return NULL;
1074 }
1075
1076 /*
1077  * @deprecated bad naming. Use ecore_x_randr_window_outputs_get instead.
1078  * @brief Get the outputs, which display a certain window.
1079  *
1080  * @param window Window the displaying outputs shall be found for.
1081  * @param num The number of outputs displaying the window.
1082  * @return Array of outputs that display a certain window. @c NULL if no
1083  * outputs was found that displays the specified window.
1084  */
1085 EAPI Ecore_X_Randr_Output *
1086 ecore_x_randr_current_output_get(Ecore_X_Window window, int *num)
1087 {
1088    return ecore_x_randr_window_outputs_get(window, num);
1089 }
1090
1091 /*
1092  * @brief get the CRTCs, which display a certain window
1093  * @param window window the displaying crtcs shall be found for
1094  * @param num the number of crtcs displaying the window
1095  * @return Array of crtcs that display a certain window. @c NULL if no crtcs
1096  * was found that displays the specified window.
1097  * @since 1.2.0
1098  */
1099 EAPI Ecore_X_Randr_Crtc *
1100 ecore_x_randr_window_crtcs_get(Ecore_X_Window window, int *num)
1101 {
1102    if (num) *num = 0;
1103 #ifdef ECORE_XRANDR
1104    Ecore_X_Window root;
1105    Ecore_X_Randr_Crtc *crtcs = NULL;
1106    int ncrtcs = 0;
1107
1108    if (_randr_version < RANDR_VERSION_1_2) return NULL;
1109
1110    /* grab this windows root window */
1111    root = ecore_x_window_root_get(window);
1112
1113    /* get the crtcs from xrandr */
1114    if ((crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs)))
1115      {
1116         XRRScreenResources *res = NULL;
1117         Ecore_X_Randr_Crtc *ret = NULL;
1118
1119         if (ncrtcs < 1)
1120           {
1121              free(crtcs);
1122              return NULL;
1123           }
1124
1125         /* make sure we can allocate our return variable */
1126         if (!(ret = calloc(1, ncrtcs * sizeof(Ecore_X_Randr_Crtc))))
1127           {
1128              free(crtcs);
1129              return NULL;
1130           }
1131
1132         /* try to get the screen resources from Xrandr
1133          * 
1134          * NB: We do this ONCE here as we reuse it for every crtc.
1135          * NB: The old code used to loop and fetch the screen resources on 
1136          *     every crtc */
1137         if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1138           {
1139              Window tw;
1140              Eina_Rectangle wrect, crect;
1141              int i = 0, nret = 0;
1142
1143              /* get the geometry of this window */
1144              ecore_x_window_geometry_get(window, &wrect.x, &wrect.y, 
1145                                          &wrect.w, &wrect.h);
1146
1147              /* translate coordinates relative to root window */
1148              XTranslateCoordinates(_ecore_x_disp, window, root, 
1149                                    0, 0, &wrect.x, &wrect.y, &tw);
1150
1151              for (i = 0; i < ncrtcs; i++)
1152                {
1153                   XRRCrtcInfo *info = NULL;
1154
1155                   /* try to get crtc info */
1156                   if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i])))
1157                     {
1158                        /* check if crtc is enabled */
1159                        if (info->mode != 0)
1160                          {
1161                             /* enabled. get geometry */
1162                             crect.x = info->x;
1163                             crect.y = info->y;
1164                             crect.w = info->width;
1165                             crect.h = info->height;
1166
1167                             /* check intersection with window */
1168                             if (eina_rectangles_intersect(&wrect, &crect))
1169                               {
1170                                  /* add if intersect */
1171                                  ret[nret] = crtcs[i];
1172                                  nret++;
1173                               }
1174                          }
1175
1176                        /* free the crtc info */
1177                        XRRFreeCrtcInfo(info);
1178                     }
1179                }
1180
1181              /* free the resources */
1182              XRRFreeScreenResources(res);
1183
1184              if (num) *num = nret;
1185           }
1186
1187         free(crtcs);
1188
1189         return ret;
1190      }
1191 #endif
1192    return NULL;
1193 }
1194
1195 /*
1196  * @deprecated bad naming. Use ecore_x_randr_window_crtcs_get instead.
1197  * @brief get the CRTCs, which display a certain window
1198  * @param window window the displaying crtcs shall be found for
1199  * @param num the number of crtcs displaying the window
1200  * @return Array of crtcs that display a certain window. @c NULL if no crtcs
1201  * was found that displays the specified window.
1202  */
1203 EAPI Ecore_X_Randr_Crtc *
1204 ecore_x_randr_current_crtc_get(Ecore_X_Window window, int *num)
1205 {
1206    return ecore_x_randr_window_crtcs_get(window, num);
1207 }
1208
1209 /*
1210  * @brief get a CRTC's outputs.
1211  * @param root the root window which's screen will be queried
1212  * @param num number of outputs referenced by given CRTC
1213  */
1214 EAPI Ecore_X_Randr_Output *
1215 ecore_x_randr_crtc_outputs_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *num)
1216 {
1217    if (num) *num = 0;
1218 #ifdef ECORE_XRANDR
1219    XRRScreenResources *res = NULL;
1220
1221    if (_randr_version < RANDR_VERSION_1_2) return NULL;
1222
1223    /* try to get the screen resources from Xrandr */
1224    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1225      {
1226         XRRCrtcInfo *info = NULL;
1227         Ecore_X_Randr_Output *ret = NULL;
1228
1229         /* try to get crtc info */
1230         if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
1231           {
1232              /* if we have no outputs, return NULL */
1233              if (info->noutput == 0)
1234                {
1235                   /* free the crtc info */
1236                   XRRFreeCrtcInfo(info);
1237
1238                   /* free the resources */
1239                   XRRFreeScreenResources(res);
1240
1241                   return NULL;
1242                }
1243
1244              /* try to allocate our return struct */
1245              if ((ret = malloc(info->noutput * sizeof(Ecore_X_Randr_Output))))
1246                {
1247                   int i = 0;
1248
1249                   /* loop the outputs on this crtc */
1250                   for (i = 0; i < info->noutput; i++)
1251                     ret[i] = info->outputs[i];
1252
1253                   if (num) *num = info->noutput;
1254                }
1255
1256              /* free the crtc info */
1257              XRRFreeCrtcInfo(info);
1258           }
1259
1260         /* free the resources */
1261         XRRFreeScreenResources(res);
1262
1263         return ret;
1264      }
1265 #endif
1266    return NULL;
1267 }
1268
1269 /*
1270  * @brief get a CRTC's possible outputs.
1271  * @param root the root window which's screen will be queried
1272  * @param num number of possible outputs referenced by given CRTC
1273  */
1274 EAPI Ecore_X_Randr_Output *
1275 ecore_x_randr_crtc_possible_outputs_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *num)
1276 {
1277    if (num) *num = 0;
1278 #ifdef ECORE_XRANDR
1279    XRRScreenResources *res = NULL;
1280
1281    if (_randr_version < RANDR_VERSION_1_2) return NULL;
1282
1283    /* try to get the screen resources from Xrandr */
1284    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1285      {
1286         XRRCrtcInfo *info = NULL;
1287         Ecore_X_Randr_Output *ret = NULL;
1288
1289         /* try to get crtc info */
1290         if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
1291           {
1292              if (info->npossible == 0)
1293                {
1294                   /* free the crtc info */
1295                   XRRFreeCrtcInfo(info);
1296
1297                   /* free the resources */
1298                   XRRFreeScreenResources(res);
1299
1300                   return NULL;
1301                }
1302
1303              /* try to allocate our return struct */
1304              if ((ret = malloc(info->npossible * sizeof(Ecore_X_Randr_Output))))
1305                {
1306                   int i = 0;
1307
1308                   /* loop the outputs on this crtc */
1309                   for (i = 0; i < info->npossible; i++)
1310                     ret[i] = info->possible[i];
1311
1312                   if (num) *num = info->npossible;
1313                }
1314
1315              /* free the crtc info */
1316              XRRFreeCrtcInfo(info);
1317           }
1318
1319         /* free the resources */
1320         XRRFreeScreenResources(res);
1321
1322         return ret;
1323      }
1324 #endif
1325    return NULL;
1326 }
1327
1328 EAPI void 
1329 ecore_x_randr_crtc_geometry_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h)
1330 {
1331 #ifdef ECORE_XRANDR
1332    XRRScreenResources *res = NULL;
1333
1334    if (_randr_version < RANDR_VERSION_1_2) return;
1335
1336    /* try to get the screen resources from Xrandr */
1337    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1338      {
1339         XRRCrtcInfo *info = NULL;
1340
1341         /* try to get crtc info */
1342         if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
1343           {
1344              if (x) *x = info->x;
1345              if (y) *y = info->y;
1346              if (w) *w = info->width;
1347              if (h) *h = info->height;
1348
1349              /* free the crtc info */
1350              XRRFreeCrtcInfo(info);
1351           }
1352
1353         /* free the resources */
1354         XRRFreeScreenResources(res);
1355      }
1356 #endif
1357 }
1358
1359 EAPI void 
1360 ecore_x_randr_crtc_pos_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y)
1361 {
1362 #ifdef ECORE_XRANDR
1363    if (_randr_version < RANDR_VERSION_1_2) return;
1364
1365    ecore_x_randr_crtc_geometry_get(root, crtc, x, y, NULL, NULL);
1366 #endif
1367 }
1368
1369 /*
1370  * @brief Sets the position of given CRTC within root window's screen.
1371  *
1372  * @param root The window's screen to be queried.
1373  * @param crtc The CRTC which's position within the mentioned screen is to be
1374  * altered.
1375  * @param x Position on the x-axis (0 == left) of the screen. if x < 0 current
1376  * value will be kept.
1377  * @param y Position on the y-ayis (0 == top) of the screen. if y < 0, current
1378  * value will be kept.
1379  * @return @c EINA_TRUE if position could successfully be altered.
1380  */
1381 EAPI Eina_Bool 
1382 ecore_x_randr_crtc_pos_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int x, int y)
1383 {
1384 #ifdef ECORE_XRANDR
1385    int cx = 0, cy = 0, cw = 0, ch = 0;
1386    int sw = 0, sh = 0, nw = 0, nh = 0;
1387
1388    if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;
1389
1390    /* grab the current crtc geometry */
1391    ecore_x_randr_crtc_geometry_get(root, crtc, &cx, &cy, &cw, &ch);
1392
1393    /* grab the current screen geometry */
1394    ecore_x_randr_screen_current_size_get(root, &sw, &sh, NULL, NULL);
1395
1396    /* safety check some values */
1397    if (x < 0) x = cx;
1398    if (y < 0) y = cy;
1399    if ((x + cw) > sw) nw = (x + cw);
1400    if ((y + ch) > sh) nh = (y + ch);
1401
1402    if ((nw > 0) && (nh > 0))
1403      {
1404         /* try to update the current screen geometry */
1405         if (!ecore_x_randr_screen_current_size_set(root, nw, nh, 0, 0))
1406           return EINA_FALSE;
1407      }
1408
1409    /* try to set the new crtc position */
1410    return ecore_x_randr_crtc_settings_set(root, crtc, NULL, -1, x, y, -1, -1);
1411 #endif
1412    return EINA_FALSE;
1413 }
1414
1415 /**
1416  * @brief Get the current set mode of a given CRTC
1417  * @param root the window's screen to be queried
1418  * @param crtc the CRTC which's should be queried
1419  * @return currently set mode or - in case parameters are invalid -
1420  * Ecore_X_Randr_Unset
1421  */
1422 EAPI Ecore_X_Randr_Mode 
1423 ecore_x_randr_crtc_mode_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc)
1424 {
1425 #ifdef ECORE_XRANDR
1426    XRRScreenResources *res = NULL;
1427
1428    if (_randr_version < RANDR_VERSION_1_2) return -1;
1429
1430    /* try to get the screen resources from Xrandr */
1431    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1432      {
1433         XRRCrtcInfo *info = NULL;
1434         Ecore_X_Randr_Mode ret = -1;
1435
1436         /* try to get crtc info */
1437         if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
1438           {
1439              /* get the mode */
1440              ret = info->mode;
1441
1442              /* free the crtc info */
1443              XRRFreeCrtcInfo(info);
1444           }
1445
1446         /* free the resources */
1447         XRRFreeScreenResources(res);
1448
1449         return ret;
1450      }
1451 #endif
1452    return -1;
1453 }
1454
1455 /**
1456  * @brief Sets a mode for a CRTC and the outputs attached to it.
1457  *
1458  * @param root The window's screen to be queried.
1459  * @param crtc The CRTC which shall be set.
1460  * @param outputs Array of outputs which have to be compatible with the mode.
1461  * If @c NULL, CRTC will be disabled.
1462  * @param noutputs Number of outputs in array to be used. Use
1463  * Ecore_X_Randr_Unset (or @c -1) to use currently used outputs.
1464  * @param mode XID of the mode to be set. If set to @c 0 the CRTC will be
1465  * disabled. If set to @c -1 the call will fail.
1466  * @return @c EINA_TRUE if mode setting was successful, @c EINA_FALSE
1467  * otherwise.
1468  */
1469 EAPI Eina_Bool 
1470 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)
1471 {
1472 #ifdef ECORE_XRANDR
1473    if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;
1474
1475    return ecore_x_randr_crtc_settings_set(root, crtc, outputs, noutputs, 
1476                                           -1, -1, mode, -1);
1477 #endif
1478    return EINA_FALSE;
1479 }
1480
1481 EAPI void 
1482 ecore_x_randr_crtc_size_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *w, int *h)
1483 {
1484 #ifdef ECORE_XRANDR
1485    if (_randr_version < RANDR_VERSION_1_2) return;
1486    ecore_x_randr_crtc_geometry_get(root, crtc, NULL, NULL, w, h);
1487 #endif
1488 }
1489
1490 EAPI Ecore_X_Randr_Refresh_Rate 
1491 ecore_x_randr_crtc_refresh_rate_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc EINA_UNUSED, Ecore_X_Randr_Mode mode)
1492 {
1493 #ifdef ECORE_XRANDR
1494    XRRScreenResources *res = NULL;
1495
1496    if (_randr_version < RANDR_VERSION_1_2) return 0.0;
1497
1498    /* try to get the screen resources from Xrandr */
1499    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1500      {
1501         int i = 0;
1502         double ret = 0.0;
1503
1504         for (i = 0; i < res->nmode; i++)
1505           {
1506              if (res->modes[i].id == mode)
1507                {
1508                   if ((res->modes[i].hTotal) && (res->modes[i].vTotal))
1509                     {
1510                        ret = ((double)res->modes[i].dotClock /
1511                               ((double)res->modes[i].hTotal *
1512                                   (double)res->modes[i].vTotal));
1513                     }
1514                   break;
1515                }
1516           }
1517
1518         /* free the resources */
1519         XRRFreeScreenResources(res);
1520
1521         return ret;
1522      }
1523 #endif
1524    return 0.0;
1525 }
1526
1527 EAPI Ecore_X_Randr_Orientation 
1528 ecore_x_randr_crtc_orientations_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc)
1529 {
1530 #ifdef ECORE_XRANDR
1531    XRRScreenResources *res = NULL;
1532
1533    if (_randr_version < RANDR_VERSION_1_2) return 0;
1534
1535    /* try to get the screen resources from Xrandr */
1536    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1537      {
1538         XRRCrtcInfo *info = NULL;
1539         Ecore_X_Randr_Orientation ret = 0;
1540
1541         /* try to get crtc info */
1542         if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
1543           {
1544              /* get the mode */
1545              ret = info->rotations;
1546
1547              /* free the crtc info */
1548              XRRFreeCrtcInfo(info);
1549           }
1550
1551         /* free the resources */
1552         XRRFreeScreenResources(res);
1553
1554         return ret;
1555      }
1556 #endif
1557    return 0;
1558 }
1559
1560 EAPI Ecore_X_Randr_Orientation 
1561 ecore_x_randr_crtc_orientation_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc)
1562 {
1563 #ifdef ECORE_XRANDR
1564    XRRScreenResources *res = NULL;
1565
1566    if (_randr_version < RANDR_VERSION_1_2) return 0;
1567
1568    /* try to get the screen resources from Xrandr */
1569    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1570      {
1571         XRRCrtcInfo *info = NULL;
1572         Ecore_X_Randr_Orientation ret = 0;
1573
1574         /* try to get crtc info */
1575         if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
1576           {
1577              /* get the mode */
1578              ret = info->rotation;
1579
1580              /* free the crtc info */
1581              XRRFreeCrtcInfo(info);
1582           }
1583
1584         /* free the resources */
1585         XRRFreeScreenResources(res);
1586
1587         return ret;
1588      }
1589 #endif
1590    return 0;
1591 }
1592
1593 EAPI Eina_Bool 
1594 ecore_x_randr_crtc_orientation_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, const Ecore_X_Randr_Orientation orientation)
1595 {
1596 #ifdef ECORE_XRANDR
1597    if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;
1598
1599    if (orientation != 0)
1600      return ecore_x_randr_crtc_settings_set(root, crtc, NULL, 
1601                                             -1, -1, -1, -1, orientation);
1602 #endif
1603    return EINA_FALSE;
1604 }
1605
1606 EAPI Eina_Bool 
1607 ecore_x_randr_crtc_clone_set(Ecore_X_Window root, Ecore_X_Randr_Crtc original, Ecore_X_Randr_Crtc cln)
1608 {
1609 #ifdef ECORE_XRANDR
1610    Eina_Bool ret = EINA_FALSE;
1611    XRRScreenResources *res = NULL;
1612
1613    if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;
1614
1615    /* try to get the screen resources from Xrandr */
1616    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1617      {
1618         XRRCrtcInfo *info = NULL;
1619         Ecore_X_Randr_Orientation orig_orient = 0;
1620         Ecore_X_Randr_Mode orig_mode = -1;
1621         int ox = 0, oy = 0;
1622
1623         /* try to get crtc info for original crtc */
1624         if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, original)))
1625           {
1626              ox = info->x;
1627              oy = info->y;
1628              orig_orient = info->rotation;
1629              orig_mode = info->mode;
1630
1631              /* free the crtc info */
1632              XRRFreeCrtcInfo(info);
1633           }
1634
1635         ret = ecore_x_randr_crtc_settings_set(root, cln, NULL, -1, ox, oy, 
1636                                               orig_mode, orig_orient);
1637
1638         /* free the resources */
1639         XRRFreeScreenResources(res);
1640
1641         return ret;
1642      }
1643 #endif
1644    return EINA_FALSE;
1645 }
1646
1647 /**
1648  * @brief Sets the demanded parameters for a given CRTC. Note that the CRTC is
1649  * auto enabled in it's preferred mode, when it was disabled before.
1650  *
1651  * @param root The root window which's default display will be queried.
1652  * @param crtc The CRTC which's configuration should be altered.
1653  * @param outputs An array of outputs, that should display this CRTC's content.
1654  * @param noutputs Number of outputs in the array of outputs. If set to
1655  * Ecore_X_Randr_Unset, current outputs and number of outputs will be used.
1656  * If set to Ecore_X_Randr_None, CRTC will be disabled.
1657  * @param x New x coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current x
1658  * corrdinate will be assumed.
1659  * @param y New y coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current y
1660  * corrdinate will be assumed.
1661  * @param mode The new mode to be set. If Ecore_X_Randr_None is passed, the
1662  * CRTC will be disabled. If Ecore_X_Randr_Unset is passed, the current mode is
1663  * assumed.
1664  * @param orientation The new orientation to be set. If Ecore_X_Randr_Unset is
1665  * used, the current mode is assumed.
1666  * @return @c EINA_TRUE if the configuration alteration was successful,
1667  * @c EINA_FALSE otherwise.
1668  */
1669 EAPI Eina_Bool 
1670 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)
1671 {
1672 #ifdef ECORE_XRANDR
1673    Eina_Bool ret = EINA_FALSE;
1674    XRRScreenResources *res = NULL;
1675
1676    if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;
1677
1678    /* try to get the screen resources from Xrandr */
1679    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1680      {
1681         RRCrtc rcrtc;
1682         RROutput *routputs = NULL;
1683         XRRCrtcInfo *info = NULL;
1684         Eina_Bool need_free = EINA_FALSE;
1685         int i = 0;
1686
1687         rcrtc = (RRCrtc)crtc;
1688
1689         /* try to get crtc info for original crtc */
1690         if (!(info = XRRGetCrtcInfo(_ecore_x_disp, res, rcrtc)))
1691           {
1692              /* free the resources */
1693              XRRFreeScreenResources(res);
1694              return EINA_FALSE;
1695           }
1696
1697         if ((int)mode == -1) mode = info->mode;
1698         if ((int)orientation == -1) orientation = info->rotation;
1699         if (x < 0) x = info->x;
1700         if (y < 0) y = info->y;
1701
1702         if (noutputs < 0)
1703           {
1704              noutputs = info->noutput;
1705              if (noutputs > 0)
1706                {
1707                   routputs = malloc(noutputs * sizeof(RROutput));
1708                   for (i = 0; i < noutputs; i++)
1709                     routputs[i] = info->outputs[i];
1710                   need_free = EINA_TRUE;
1711                }
1712           }
1713         else if (noutputs > 0)
1714           {
1715              routputs = malloc(noutputs * sizeof(RROutput));
1716              for (i = 0; i < noutputs; i++)
1717                routputs[i] = (RROutput)outputs[i];
1718              need_free = EINA_TRUE;
1719           }
1720
1721         /* try to set the crtc config */
1722         if (!XRRSetCrtcConfig(_ecore_x_disp, res, rcrtc, CurrentTime, 
1723                               x, y, mode, orientation, 
1724                               routputs, noutputs))
1725           ret = EINA_TRUE;
1726
1727         if (need_free) free(routputs);
1728
1729         /* free the crtc info */
1730         XRRFreeCrtcInfo(info);
1731
1732         /* free the resources */
1733         XRRFreeScreenResources(res);
1734      }
1735
1736    return ret;
1737 #endif
1738    return EINA_FALSE;
1739 }
1740
1741 /**
1742  * @brief Sets a CRTC relative to another one.
1743  *
1744  * @param root The root window which's default display will be set.
1745  * @param crtc_r1 The CRTC to be positioned.
1746  * @param crtc_r2 The CRTC the position should be relative to.
1747  * @param policy The relation between the crtcs.
1748  * @param alignment In case CRTCs size differ, aligns CRTC1 accordingly at
1749  * CRTC2's borders.
1750  * @return @c EINA_TRUE if crtc could be successfully positioned, @c EINA_FALSE
1751  * if repositioning failed or if position of new crtc would be out of given
1752  * screen's min/max bounds.
1753  */
1754 EAPI Eina_Bool 
1755 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)
1756 {
1757 #ifdef ECORE_XRANDR
1758    Eina_Rectangle r1, r2;
1759    int mw = 0, mh = 0, sw = 0, sh = 0;
1760    int nx = 0, ny = 0;
1761
1762    if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;
1763
1764    /* check each crtc has a valid mode */
1765    if (ecore_x_randr_crtc_mode_get(root, crtc_r1) == 0) return EINA_FALSE;
1766    if (ecore_x_randr_crtc_mode_get(root, crtc_r2) == 0) return EINA_FALSE;
1767
1768    /* get the geometry of each crtc */
1769    ecore_x_randr_crtc_geometry_get(root, crtc_r1, &r1.x, &r1.y, &r1.w, &r1.h);
1770    ecore_x_randr_crtc_geometry_get(root, crtc_r2, &r2.x, &r2.y, &r2.w, &r2.h);
1771
1772    /* get the geometry of the screen */
1773    ecore_x_randr_screen_size_range_get(root, NULL, NULL, &mw, &mh);
1774    ecore_x_randr_screen_current_size_get(root, &sw, &sh, NULL, NULL);
1775
1776    switch (policy)
1777      {
1778       case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT:
1779         nx = (r2.x + r2.w);
1780
1781         switch (alignment)
1782           {
1783            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
1784              ny = -1;
1785              break;
1786            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
1787              ny = ((int)(((double)r2.h / 2.0) + r2.y - ((double)r1.h / 2.0)));
1788              break;
1789            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
1790              ny = ((int)((double)sh / 2.0) - ((double)r1.h / 2.0));
1791              break;
1792           }
1793
1794         break;
1795       case ECORE_X_RANDR_OUTPUT_POLICY_LEFT:
1796         nx = (r2.x - r1.w);
1797
1798         switch (alignment)
1799           {
1800            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
1801              ny = -1;
1802              break;
1803            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
1804              ny = ((int)(((double)r2.h / 2.0) + r2.y - ((double)r1.h / 2.0)));
1805              break;
1806            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
1807              ny = ((int)((double)sh / 2.0) - ((double)r1.h / 2.0));
1808              break;
1809           }
1810
1811         break;
1812       case ECORE_X_RANDR_OUTPUT_POLICY_BELOW:
1813         ny = (r2.y + r2.h);
1814
1815         switch (alignment)
1816           {
1817            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
1818              nx = -1;
1819              break;
1820            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
1821              nx = ((int)((((double)r2.x + (double)r2.w) / 2.0) - 
1822                          ((double)r1.w / 2.0)));
1823              break;
1824            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
1825              nx = ((int)((double)sw / 2.0));
1826              break;
1827           }
1828
1829         break;
1830       case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE:
1831         ny = (r2.y - r1.h);
1832
1833         switch (alignment)
1834           {
1835            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
1836              nx = -1;
1837              break;
1838            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
1839              nx = ((int)((((double)r2.x + (double)r2.w) / 2.0) - 
1840                          ((double)r1.w / 2.0)));
1841              break;
1842            case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
1843              nx = ((int)((double)sw / 2.0));
1844              break;
1845           }
1846
1847         break;
1848       case ECORE_X_RANDR_OUTPUT_POLICY_CLONE:
1849         return ecore_x_randr_crtc_pos_set(root, crtc_r1, r2.x, r2.y);
1850         break;
1851       case ECORE_X_RANDR_OUTPUT_POLICY_NONE:
1852         break;
1853       default:
1854         return EINA_FALSE;
1855      }
1856
1857    if ((nx == r1.x) && (ny == r1.y)) return EINA_TRUE;
1858    if (((ny + r1.h) > mh) || ((nx + r1.w) > mw)) return EINA_FALSE;
1859
1860    return ecore_x_randr_crtc_pos_set(root, crtc_r1, nx, ny);
1861 #else
1862    return EINA_FALSE;
1863 #endif
1864 }
1865
1866 /*
1867  * @since 1.8
1868  */
1869 EAPI Ecore_X_Randr_Crtc_Info *
1870 ecore_x_randr_crtc_info_get(Ecore_X_Window root, const Ecore_X_Randr_Crtc crtc)
1871 {
1872 #ifdef ECORE_XRANDR
1873    XRRScreenResources *res = NULL;
1874
1875    if (_randr_version < RANDR_VERSION_1_2) return NULL;
1876
1877    /* try to get the screen resources from Xrandr */
1878    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
1879      {
1880         XRRCrtcInfo *info = NULL;
1881         Ecore_X_Randr_Crtc_Info *ret = NULL;
1882
1883         /* try to get crtc info */
1884         if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
1885           {
1886              if ((ret = malloc(sizeof(Ecore_X_Randr_Crtc_Info))))
1887                {
1888                   /* copy the mode information into our return structure */
1889                   ret->timestamp = info->timestamp;
1890                   ret->x = info->x;
1891                   ret->y = info->y;
1892                   ret->width = info->width;
1893                   ret->height = info->height;
1894                   ret->mode = info->mode;
1895                   ret->rotation = info->rotation;
1896                   ret->rotations = info->rotations;
1897                   ret->noutput = info->noutput;
1898                   ret->npossible = info->npossible;
1899
1900                   ret->outputs = NULL;
1901                   ret->possible = NULL;
1902
1903                   if (info->noutput > 0)
1904                     {
1905                        if ((ret->outputs = 
1906                             malloc(info->noutput * sizeof(Ecore_X_Randr_Output))))
1907                          {
1908                             int i = 0;
1909
1910                             /* loop the outputs on this crtc */
1911                             for (i = 0; i < info->noutput; i++)
1912                               ret->outputs[i] = info->outputs[i];
1913                          }
1914                     }
1915
1916                   if (info->npossible > 0)
1917                     {
1918                        if ((ret->possible = 
1919                             malloc(info->npossible * sizeof(Ecore_X_Randr_Output))))
1920                          {
1921                             int i = 0;
1922
1923                             /* loop the outputs on this crtc */
1924                             for (i = 0; i < info->npossible; i++)
1925                               ret->possible[i] = info->possible[i];
1926                          }
1927                     }
1928                }
1929
1930              /* free the crtc info */
1931              XRRFreeCrtcInfo(info);
1932           }
1933
1934         /* free the resources */
1935         XRRFreeScreenResources(res);
1936
1937         return ret;
1938      }
1939 #endif
1940    return NULL;
1941 }
1942
1943 /*
1944  * @since 1.8
1945  */
1946 EAPI void 
1947 ecore_x_randr_crtc_info_free(Ecore_X_Randr_Crtc_Info *info)
1948 {
1949 #ifdef ECORE_XRANDR
1950    if (_randr_version >= RANDR_VERSION_1_2)
1951      {
1952         if (info)
1953           {
1954              if (info->outputs) free(info->outputs);
1955              if (info->possible) free(info->possible);
1956              free(info);
1957           }
1958      }
1959 #endif
1960 }
1961
1962 /*
1963  * @brief Add given mode to given output.
1964  *
1965  * @param output The output the mode is added to.
1966  * @param mode The mode added to the output.
1967  * @return @c EINA_FALSE if output or mode equal Ecore_X_Randr_None, else
1968  * @c EINA_TRUE.
1969  * Additionally, if xcb backend is used, the success of the addition is
1970  * reported back directly.
1971  * @since 1.2.0
1972  */
1973 EAPI Eina_Bool 
1974 ecore_x_randr_output_mode_add(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode)
1975 {
1976 #ifdef ECORE_XRANDR
1977    if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;
1978
1979    if ((output) && (mode))
1980      {
1981         /* add this mode to output
1982          * 
1983          * NB: This XRR function returns void so we have to assume it worked */
1984         XRRAddOutputMode(_ecore_x_disp, output, mode);
1985
1986         return EINA_TRUE;
1987      }
1988 #endif
1989    return EINA_FALSE;
1990 }
1991
1992 /*
1993  * @brief delete given mode from given output
1994  * @param output the output the mode is removed from
1995  * @param mode the mode removed from the output
1996  * @since 1.2.0
1997  */
1998 EAPI void 
1999 ecore_x_randr_output_mode_del(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode)
2000 {
2001 #ifdef ECORE_XRANDR
2002    if (_randr_version < RANDR_VERSION_1_2) return;
2003
2004    if ((!output) || (!mode)) return;
2005
2006    XRRDeleteOutputMode(_ecore_x_disp, output, mode);
2007 #endif
2008 }
2009
2010 EAPI Ecore_X_Randr_Mode *
2011 ecore_x_randr_output_modes_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num, int *npreferred)
2012 {
2013 #ifdef ECORE_XRANDR
2014    XRRScreenResources *res = NULL;
2015
2016    if (_randr_version < RANDR_VERSION_1_2) return NULL;
2017
2018    /* try to get the screen resources from Xrandr */
2019    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2020      {
2021         XRROutputInfo *info = NULL;
2022         Ecore_X_Randr_Mode *modes = NULL;
2023
2024         /* try to get output info */
2025         if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
2026           {
2027              if (num) *num = info->nmode;
2028              if (npreferred) *npreferred = info->npreferred;
2029
2030              if (info->nmode > 0)
2031                {
2032                   if ((modes = malloc(info->nmode * sizeof(Ecore_X_Randr_Mode))))
2033                     {
2034                        int i = 0;
2035
2036                        for (i = 0; i < info->nmode; i++)
2037                          modes[i] = info->modes[i];
2038                     }
2039                }
2040
2041              /* free the output info */
2042              XRRFreeOutputInfo(info);
2043           }
2044
2045         /* free the resources */
2046         XRRFreeScreenResources(res);
2047
2048         return modes;
2049      }
2050 #endif
2051    return NULL;
2052 }
2053
2054 /**
2055  * @brief gets the the outputs which might be used simultenously on the same
2056  * CRTC.
2057  * @param root window that this information should be queried for.
2058  * @param output the output which's clones we concern
2059  * @param num number of possible clones
2060  */
2061 EAPI Ecore_X_Randr_Output *
2062 ecore_x_randr_output_clones_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num)
2063 {
2064 #ifdef ECORE_XRANDR
2065    XRRScreenResources *res = NULL;
2066
2067    if (_randr_version < RANDR_VERSION_1_2) return NULL;
2068
2069    /* try to get the screen resources from Xrandr */
2070    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2071      {
2072         XRROutputInfo *info = NULL;
2073         Ecore_X_Randr_Output *outputs = NULL;
2074
2075         /* try to get output info */
2076         if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
2077           {
2078              if (num) *num = info->nclone;
2079
2080              if (info->nclone > 0)
2081                {
2082                   /* try to allocate space for output return */
2083                   if ((outputs = malloc(info->nclone * sizeof(Ecore_X_Randr_Output))))
2084                     {
2085                        int i = 0;
2086
2087                        for (i = 0; i < info->nclone; i++)
2088                          outputs[i] = info->clones[i];
2089                     }
2090                }
2091
2092              /* free the output info */
2093              XRRFreeOutputInfo(info);
2094           }
2095
2096         /* free the resources */
2097         XRRFreeScreenResources(res);
2098
2099         return outputs;
2100      }
2101 #endif
2102    return NULL;
2103 }
2104
2105 EAPI Ecore_X_Randr_Crtc *
2106 ecore_x_randr_output_possible_crtcs_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num)
2107 {
2108 #ifdef ECORE_XRANDR
2109    XRRScreenResources *res = NULL;
2110
2111    if (_randr_version < RANDR_VERSION_1_2) return 0;
2112
2113    /* try to get the screen resources from Xrandr */
2114    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2115      {
2116         XRROutputInfo *info = NULL;
2117         Ecore_X_Randr_Crtc *crtcs = NULL;
2118
2119         /* try to get output info */
2120         if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
2121           {
2122              if (num) *num = info->ncrtc;
2123
2124              if (info->ncrtc > 0)
2125                {
2126                   /* try to allocate space for the return crtcs */
2127                   if ((crtcs = malloc(info->ncrtc * sizeof(Ecore_X_Randr_Crtc))))
2128                     {
2129                        int i = 0;
2130
2131                        for (i = 0; i < info->ncrtc; i++)
2132                          crtcs[i] = info->crtcs[i];
2133                     }
2134                }
2135
2136              /* free the output info */
2137              XRRFreeOutputInfo(info);
2138           }
2139
2140         /* free the resources */
2141         XRRFreeScreenResources(res);
2142
2143         return crtcs;
2144      }
2145 #endif
2146    return NULL;
2147 }
2148
2149 EAPI Ecore_X_Randr_Crtc 
2150 ecore_x_randr_output_crtc_get(Ecore_X_Window root, Ecore_X_Randr_Output output)
2151 {
2152 #ifdef ECORE_XRANDR
2153    XRRScreenResources *res = NULL;
2154
2155    if (_randr_version < RANDR_VERSION_1_2) return 0;
2156
2157    /* try to get the screen resources from Xrandr */
2158    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2159      {
2160         XRROutputInfo *info = NULL;
2161         Ecore_X_Randr_Crtc ret = 0;
2162
2163         /* try to get output info */
2164         if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
2165           {
2166              ret = info->crtc;
2167
2168              /* free the output info */
2169              XRRFreeOutputInfo(info);
2170           }
2171
2172         /* free the resources */
2173         XRRFreeScreenResources(res);
2174
2175         return ret;
2176      }
2177 #endif
2178    return 0;
2179 }
2180
2181 /**
2182  * @brief gets the given output's name as reported by X
2183  * @param root the window which's screen will be queried
2184  * @param output The output for which the name will be reported.
2185  * @param len length of returned c-string.
2186  * @return name of the output as reported by X
2187  */
2188 EAPI char *
2189 ecore_x_randr_output_name_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *len)
2190 {
2191 #ifdef ECORE_XRANDR
2192    XRRScreenResources *res = NULL;
2193
2194    if (_randr_version < RANDR_VERSION_1_2) return 0;
2195
2196    /* try to get the screen resources from Xrandr */
2197    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2198      {
2199         XRROutputInfo *info = NULL;
2200         char *ret = NULL;
2201
2202         /* try to get output info */
2203         if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
2204           {
2205              if (info->name)
2206                {
2207                   size_t s;
2208 #ifdef XRANDR_GOOD
2209                   s = info->nameLen;
2210 #else
2211                   /* pre 1.4.0 does not fill in info->nameLen */
2212                   s = strlen(info->name);
2213 #endif
2214                   ret = malloc(s + 1);
2215                   memcpy(ret, info->name, s);
2216                   ret[s] = 0;
2217                   if (len) *len = s;
2218                }
2219
2220              /* free the output info */
2221              XRRFreeOutputInfo(info);
2222           }
2223
2224         /* free the resources */
2225         XRRFreeScreenResources(res);
2226
2227         return ret;
2228      }
2229 #endif
2230    return NULL;
2231 }
2232
2233 /*
2234  * @deprecated use ecore_x_randr_crtc_gamma_size_get()
2235  */
2236 EINA_DEPRECATED EAPI int 
2237 ecore_x_randr_crtc_gamma_ramp_size_get(Ecore_X_Randr_Crtc crtc EINA_UNUSED)
2238 {
2239    return 0;
2240 }
2241
2242 /*
2243  * @deprecated use ecore_x_randr_crtc_gamma_get()
2244  */
2245 EINA_DEPRECATED EAPI Ecore_X_Randr_Crtc_Gamma **
2246 ecore_x_randr_crtc_gamma_ramps_get(Ecore_X_Randr_Crtc crtc EINA_UNUSED)
2247 {
2248    return NULL;
2249 }
2250
2251 /*
2252  * @deprecated use ecore_x_randr_crtc_gamma_set()
2253  */
2254 EINA_DEPRECATED EAPI Eina_Bool 
2255 ecore_x_randr_crtc_gamma_ramps_set(Ecore_X_Randr_Crtc crtc EINA_UNUSED, const Ecore_X_Randr_Crtc_Gamma *red EINA_UNUSED, const Ecore_X_Randr_Crtc_Gamma *green EINA_UNUSED, const Ecore_X_Randr_Crtc_Gamma *blue EINA_UNUSED)
2256 {
2257    return EINA_FALSE;
2258 }
2259
2260 /*
2261  * @since 1.8
2262  */
2263 EAPI int 
2264 ecore_x_randr_crtc_gamma_size_get(Ecore_X_Randr_Crtc crtc)
2265 {
2266 #ifdef ECORE_XRANDR
2267    if (_randr_version < RANDR_VERSION_1_2) return 0;
2268    return XRRGetCrtcGammaSize(_ecore_x_disp, crtc);
2269 #else
2270    (void)crtc;
2271 #endif
2272    return 0;
2273 }
2274
2275 /*
2276  * @since 1.8
2277  */
2278 EAPI Ecore_X_Randr_Crtc_Gamma_Info *
2279 ecore_x_randr_crtc_gamma_get(Ecore_X_Randr_Crtc crtc)
2280 {
2281 #ifdef ECORE_XRANDR
2282    Ecore_X_Randr_Crtc_Gamma_Info *info = NULL;
2283    XRRCrtcGamma *xgamma = NULL;
2284
2285    if (_randr_version < RANDR_VERSION_1_2) return NULL;
2286
2287    /* try to get the gamma for this crtc from Xrandr */
2288    if (!(xgamma = XRRGetCrtcGamma(_ecore_x_disp, crtc)))
2289      return NULL;
2290
2291    /* try to allocate space for the return struct and copy the results in */
2292    if ((info = malloc(sizeof(Ecore_X_Randr_Crtc_Gamma_Info))))
2293      memcpy(info, xgamma, sizeof(Ecore_X_Randr_Crtc_Gamma_Info));
2294
2295    /* free the returned gamma resource */
2296    XRRFreeGamma(xgamma);
2297
2298    return info;
2299 #else
2300    (void)crtc;
2301 #endif
2302    return NULL;
2303 }
2304
2305 /*
2306  * @since 1.8
2307  */
2308 EAPI Eina_Bool 
2309 ecore_x_randr_crtc_gamma_set(Ecore_X_Randr_Crtc crtc, const Ecore_X_Randr_Crtc_Gamma_Info *gamma)
2310 {
2311 #ifdef ECORE_XRANDR
2312    if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;
2313
2314    /* try to set the gamma
2315     * 
2316     * NB: XRRSetCrtcGamma returns void
2317     */
2318    XRRSetCrtcGamma(_ecore_x_disp, crtc, (XRRCrtcGamma *)gamma);
2319    return EINA_TRUE;
2320 #else
2321    (void)crtc;
2322    (void)gamma;
2323 #endif
2324    return EINA_FALSE;
2325 }
2326
2327 EAPI Eina_Bool 
2328 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)
2329 {
2330 #ifdef ECORE_XRANDR
2331    XRRScreenResources *res = NULL;
2332    Eina_Bool ret = EINA_FALSE;
2333
2334    if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;
2335
2336    if ((nnot_moved <= 0) || (!not_moved)) return EINA_FALSE;
2337
2338    /* try to get the screen resources from Xrandr */
2339    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2340      {
2341         Ecore_X_Randr_Crtc *crtcs = NULL;
2342         int n = 0;
2343
2344         n = (res->ncrtc - nnot_moved);
2345         if (n > 0)
2346           {
2347              /* try to allocate space for a list of crtcs */
2348              if ((crtcs = malloc(n * sizeof(Ecore_X_Randr_Crtc))))
2349                {
2350                   int i = 0, j = 0, k = 0;
2351
2352                   for (i = 0, k = 0; (i < res->ncrtc) && (k < n); i++)
2353                     {
2354                        for (j = 0; j < nnot_moved; j++)
2355                          {
2356                             if (res->crtcs[i] == not_moved[j])
2357                               break;
2358                          }
2359
2360                        if (j == nnot_moved) crtcs[k++] = res->crtcs[i];
2361                     }
2362                }
2363           }
2364
2365         /* free the resources */
2366         XRRFreeScreenResources(res);
2367
2368         /* actually move the crtcs */
2369         if (crtcs)
2370           {
2371              ret = ecore_x_randr_move_crtcs(root, crtcs, n, dx, dy);
2372              free(crtcs);
2373           }
2374
2375         return ret;
2376      }
2377 #endif
2378    return EINA_FALSE;
2379 }
2380
2381 /*
2382  * @brief Move given CRTCs belonging to the given root window's screen dx/dy
2383  * pixels relative to their current position. The screen size will be
2384  * automatically adjusted if necessary and possible.
2385  *
2386  * @param root Window which's screen's resources are used.
2387  * @param crtcs List of CRTCs to be moved.
2388  * @param ncrtc Number of CRTCs in array.
2389  * @param dx Amount of pixels the CRTCs should be moved in x direction.
2390  * @param dy Amount of pixels the CRTCs should be moved in y direction.
2391  * @return @c EINA_TRUE if all crtcs could be moved successfully.
2392  */
2393 EAPI Eina_Bool 
2394 ecore_x_randr_move_crtcs(Ecore_X_Window root, const Ecore_X_Randr_Crtc *crtcs, int ncrtc, int dx, int dy)
2395 {
2396 #ifdef ECORE_XRANDR
2397    XRRScreenResources *res = NULL;
2398    XRRCrtcInfo **info = NULL;
2399    int i = 0;
2400
2401    if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;
2402
2403    if (ncrtc < 1) return EINA_FALSE;
2404
2405    /* try to get the screen resources from Xrandr */
2406    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2407      {
2408         Eina_Bool ret = EINA_TRUE;
2409         int mw = 0, mh = 0, sw = 0, sh = 0;
2410         int nw = 0, nh = 0;
2411
2412         info = alloca(ncrtc * sizeof(XRRCrtcInfo *));
2413         memset(info, 0, ncrtc * sizeof(XRRCrtcInfo *));
2414
2415         ecore_x_randr_screen_size_range_get(root, NULL, NULL, &mw, &mh);
2416         ecore_x_randr_screen_current_size_get(root, &sw, &sh, NULL, NULL);
2417         nw = sw;
2418         nh = sh;
2419
2420         for (i = 0; i < ncrtc; i++)
2421           {
2422              /* try to get crtc info for original crtc */
2423              if ((info[i] = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i])))
2424                {
2425                   if (((info[i]->x + dx) < 0) || ((info[i]->y + dy < 0)) || 
2426                       ((int)(info[i]->x + info[i]->width) > mw) || 
2427                       ((int)(info[i]->y + info[i]->height) > mh))
2428                     {
2429                        goto err;
2430                     }
2431
2432                   nw = MAX(((int)(info[i]->x + info[i]->width) + dx), nw);
2433                   nh = MAX(((int)(info[i]->y + info[i]->height) + dy), nh);
2434                }
2435           }
2436
2437         /* resize the screen if we need to */
2438         if (!(((nw > sw) || (nh > sh)) || 
2439               ecore_x_randr_screen_current_size_set(root, nw, nh, -1, -1)))
2440           goto err;
2441
2442         /* actually move the crtcs */
2443         for (i = 0; ((i < ncrtc) && info[i]); i++)
2444           {
2445              if (!ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, -1, 
2446                                                   (info[i]->x + dx), 
2447                                                   (info[i]->y + dy), 
2448                                                   info[i]->mode, 
2449                                                   info[i]->rotation))
2450                {
2451                   ret = EINA_FALSE;
2452                   break;
2453                }
2454           }
2455
2456         if (i < ncrtc)
2457           {
2458              /* something went wrong somewhere. move everything back */
2459              while ((--i) >= 0)
2460                {
2461                   if (info[i])
2462                     ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, -1, 
2463                                                     (info[i]->x - dx), 
2464                                                     (info[i]->y - dy), 
2465                                                     info[i]->mode, 
2466                                                     info[i]->rotation);
2467                }
2468           }
2469
2470         /* cleanup */
2471         for (i = 0; i < ncrtc; i++)
2472           if (info[i]) XRRFreeCrtcInfo(info[i]);
2473
2474         /* free the resources */
2475         XRRFreeScreenResources(res);
2476
2477         return ret;
2478      }
2479
2480 err:
2481    while (i-- > 0)
2482      {
2483         /* free the crtc info */
2484         if (info[i]) XRRFreeCrtcInfo(info[i]);
2485      }
2486
2487    /* free the resources */
2488    if (res) XRRFreeScreenResources(res);
2489 #endif
2490    return EINA_FALSE;
2491 }
2492
2493 /**
2494  * @brief gets the width and hight of a given mode
2495  * @param mode the mode whose size is to be looked up
2496  * @param w width of given mode in px
2497  * @param h height of given mode in px
2498  */
2499 EAPI void 
2500 ecore_x_randr_mode_size_get(Ecore_X_Window root, Ecore_X_Randr_Mode mode, int *w, int *h)
2501 {
2502 #ifdef ECORE_XRANDR
2503    if (_randr_version < RANDR_VERSION_1_2) return;
2504
2505    if ((mode != 0) && ((w) || (h)))
2506      {
2507         XRRScreenResources *res = NULL;
2508
2509         /* try to get the screen resources from Xrandr */
2510         if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2511           {
2512              int i = 0;
2513
2514              for (i = 0; i < res->nmode; i++)
2515                {
2516                   if (res->modes[i].id == mode)
2517                     {
2518                        if (w) *w = res->modes[i].width;
2519                        if (h) *h = res->modes[i].height;
2520                        break;
2521                     }
2522                }
2523
2524              /* free the resources */
2525              XRRFreeScreenResources(res);
2526           }
2527      }
2528 #endif
2529 }
2530
2531 EAPI Ecore_X_Randr_Connection_Status 
2532 ecore_x_randr_output_connection_status_get(Ecore_X_Window root, Ecore_X_Randr_Output output)
2533 {
2534 #ifdef ECORE_XRANDR
2535    XRRScreenResources *res = NULL;
2536
2537    if (_randr_version < RANDR_VERSION_1_2) 
2538      return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
2539
2540    /* try to get the screen resources from Xrandr */
2541    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2542      {
2543         XRROutputInfo *info = NULL;
2544         Ecore_X_Randr_Connection_Status ret = 
2545           ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
2546
2547         /* try to get output info */
2548         if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
2549           {
2550              ret = info->connection;
2551
2552              /* free the output info */
2553              XRRFreeOutputInfo(info);
2554           }
2555
2556         /* free the resources */
2557         XRRFreeScreenResources(res);
2558
2559         return ret;
2560      }
2561 #endif
2562    return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
2563 }
2564
2565 EAPI void 
2566 ecore_x_randr_output_size_mm_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *w, int *h)
2567 {
2568 #ifdef ECORE_XRANDR
2569    XRRScreenResources *res = NULL;
2570
2571    if (_randr_version < RANDR_VERSION_1_2) return;
2572
2573    /* try to get the screen resources from Xrandr */
2574    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2575      {
2576         XRROutputInfo *info = NULL;
2577
2578         /* try to get output info */
2579         if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
2580           {
2581              if (w) *w = info->mm_width;
2582              if (h) *h = info->mm_height;
2583
2584              /* free the output info */
2585              XRRFreeOutputInfo(info);
2586           }
2587
2588         /* free the resources */
2589         XRRFreeScreenResources(res);
2590      }
2591 #endif
2592 }
2593
2594 EAPI Eina_Bool 
2595 ecore_x_randr_output_crtc_set(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output EINA_UNUSED, const Ecore_X_Randr_Crtc crtc EINA_UNUSED)
2596 {
2597    /* TODO: !! */
2598    return EINA_FALSE;
2599 }
2600
2601 EAPI Eina_Bool 
2602 ecore_x_randr_output_backlight_available(void)
2603 {
2604 #ifdef ECORE_XRANDR
2605    Atom backlight = None;
2606
2607    /* check for new backlight property */
2608    if ((backlight = XInternAtom(_ecore_x_disp, RR_PROPERTY_BACKLIGHT, True)))
2609      return EINA_TRUE;
2610
2611    /* check for legacy backlight property */
2612    if ((backlight = XInternAtom(_ecore_x_disp, "BACKLIGHT", True)))
2613      return EINA_TRUE;
2614 #endif
2615    return EINA_FALSE;
2616 }
2617
2618 /**
2619  * @brief Set up the backlight level to the given level.
2620  *
2621  * @param root The window's screen which will be set.
2622  * @param level Of the backlight between @c 0 and @c 1.
2623  */
2624 EAPI void 
2625 ecore_x_randr_screen_backlight_level_set(Ecore_X_Window root, double level)
2626 {
2627 #ifdef ECORE_XRANDR
2628    XRRScreenResources *res = NULL;
2629    int i = 0;
2630
2631    if (_randr_version < RANDR_VERSION_1_3) return;
2632
2633    /* try to get the screen resources from Xrandr */
2634    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2635      {
2636         /* set the backlight level on each output */
2637         for (i = 0; i < res->noutput; i++)
2638           ecore_x_randr_output_backlight_level_set(root, res->outputs[i], level);
2639
2640         /* free the resources */
2641         XRRFreeScreenResources(res);
2642      }
2643 #endif
2644 }
2645
2646 EAPI double 
2647 ecore_x_randr_output_backlight_level_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output)
2648 {
2649 #ifdef ECORE_XRANDR
2650    XRRPropertyInfo *info = NULL;
2651    Atom backlight = None, type = None;
2652    unsigned long bytes = 0;
2653    unsigned long items = 0;
2654    unsigned char *prop = NULL;
2655    long val = 0;
2656    int format = 0;
2657
2658    /* check if "new" backlight is available */
2659    if (_randr_version >= RANDR_VERSION_1_3)
2660      {
2661         if ((backlight = 
2662              XInternAtom(_ecore_x_disp, RR_PROPERTY_BACKLIGHT, True)))
2663           {
2664              XRRGetOutputProperty(_ecore_x_disp, output, backlight, 0, 4, 
2665                                   False, False, None, &type, &format, 
2666                                   &items, &bytes, &prop);
2667           }
2668      }
2669
2670    if ((!prop) || (items == 0))
2671      {
2672         /* check legacy backlight property
2673          * 
2674          * FIXME: NB: Not sure what randr version we need for the legacy 
2675          * backlight property so skip version check */
2676         if ((backlight = XInternAtom(_ecore_x_disp, "BACKLIGHT", True)))
2677           {
2678              free(prop);
2679              prop = NULL;
2680              XRRGetOutputProperty(_ecore_x_disp, output, backlight, 0, 4, 
2681                                   False, False, None, &type, &format, 
2682                                   &items, &bytes, &prop);
2683           }
2684      }
2685
2686    /* safety check */
2687    if ((!prop) || (type != XA_INTEGER) || (items != 1) || (format != 32))
2688      {
2689         free(prop);
2690         WRN("Backlight property is not supported on this server or driver");
2691         return -1;
2692      }
2693
2694    val = *((long *)prop);
2695    free(prop);
2696
2697    /* try to get the backlight property value from Xrandr */
2698    if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, backlight)))
2699      {
2700         double ret = -1;
2701
2702         if ((info->range) && (info->num_values == 2))
2703           {
2704              /* convert the current value */
2705              ret = ((double)(val - info->values[0])) / 
2706                ((double)(info->values[1] - info->values[0]));
2707           }
2708
2709         /* free the info */
2710         free(info);
2711
2712         return ret;
2713      }
2714 #endif
2715    return -1;
2716 }
2717
2718 EAPI Eina_Bool 
2719 ecore_x_randr_output_backlight_level_set(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, double level)
2720 {
2721 #ifdef ECORE_XRANDR
2722    XRRPropertyInfo *info = NULL;
2723    Atom backlight = None;
2724
2725    /* safety check some input values */
2726    if ((level < 0) || (level > 1))
2727      {
2728         ERR("Backlight level should be between 0 and 1");
2729         return EINA_FALSE;
2730      }
2731
2732    /* check if "new" backlight is available */
2733    if (_randr_version >= RANDR_VERSION_1_3)
2734      backlight = XInternAtom(_ecore_x_disp, RR_PROPERTY_BACKLIGHT, True);
2735
2736    if (!backlight)
2737      backlight = XInternAtom(_ecore_x_disp, "BACKLIGHT", True);
2738
2739    if (!backlight)
2740      {
2741         WRN("Backlight property is not supported on this server or driver");
2742         return EINA_FALSE;
2743      }
2744
2745    /* try to get the output property from Xrandr */
2746    if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, backlight)))
2747      {
2748         Eina_Bool ret = EINA_FALSE;
2749
2750         if ((info->range) && (info->num_values == 2))
2751           {
2752              double min = 0.0, max = 0.0;
2753              long val = 0;
2754
2755              min = info->values[0];
2756              max = info->values[1];
2757              val = (level * (max - min)) + min;
2758              if (val > max) val = max;
2759              if (val < min) val = min;
2760
2761              /* tell xrandr to change the backlight value */
2762              XRRChangeOutputProperty(_ecore_x_disp, output, backlight, 
2763                                      XA_INTEGER, 32, PropModeReplace, 
2764                                      (unsigned char *)&val, 1);
2765
2766              /* send changes to X */
2767              ecore_x_flush();
2768
2769              ret = EINA_TRUE;
2770           }
2771
2772         /* free the info */
2773         free(info);
2774
2775         return ret;
2776      }
2777 #endif
2778    return EINA_FALSE;
2779 }
2780
2781 /**
2782  * @brief gets the EDID information of an attached output if available.
2783  * Note that this information is not to be compared using ordinary string
2784  * comparison functions, since it includes 0-bytes.
2785  * @param root window this information should be queried from
2786  * @param output the XID of the output
2787  * @param length length of the byte-array. If NULL, request will fail.
2788  */
2789 EAPI unsigned char *
2790 ecore_x_randr_output_edid_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, unsigned long *length)
2791 {
2792 #ifdef ECORE_XRANDR
2793    Atom edid = None, type = None;
2794    unsigned char *prop = NULL;
2795    int format = 0;
2796    unsigned long nitems = 0, bytes = 0;
2797
2798    if (_randr_version < RANDR_VERSION_1_2) return NULL;
2799
2800    /* try to get the edid atom */
2801    if (!(edid = XInternAtom(_ecore_x_disp, RR_PROPERTY_RANDR_EDID, False))) 
2802      return NULL;
2803
2804    /* get the output property
2805     * 
2806     * NB: Returns 0 on success */
2807    if (!XRRGetOutputProperty(_ecore_x_disp, output, edid, 0, 128, False, False,
2808                             AnyPropertyType, &type, &format, &nitems, 
2809                             &bytes, &prop))
2810      {
2811         if ((type == XA_INTEGER) && (nitems >= 1) && (format == 8))
2812           {
2813              unsigned char *ret = NULL;
2814
2815              if ((ret = malloc(nitems * sizeof(unsigned char))))
2816                {
2817                   if (length) *length = nitems;
2818                   memcpy(ret, prop, (nitems * sizeof(unsigned char)));
2819                   free(prop);
2820                   return ret;
2821                }
2822           }
2823      }
2824    free(prop);
2825 #endif
2826    return NULL;
2827 }
2828
2829 EAPI Ecore_X_Render_Subpixel_Order 
2830 ecore_x_randr_output_subpixel_order_get(Ecore_X_Window root, Ecore_X_Randr_Output output)
2831 {
2832 #ifdef ECORE_XRANDR
2833    XRRScreenResources *res = NULL;
2834
2835    if (_randr_version < RANDR_VERSION_1_2) 
2836      return ECORE_X_RENDER_SUBPIXEL_ORDER_UNKNOWN;
2837
2838    /* try to get the screen resources from Xrandr */
2839    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
2840      {
2841         XRROutputInfo *info = NULL;
2842         Ecore_X_Render_Subpixel_Order ret = 0;
2843
2844         /* try to get output info */
2845         if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
2846           {
2847              ret = info->subpixel_order;
2848
2849              /* free the output info */
2850              XRRFreeOutputInfo(info);
2851           }
2852
2853         /* free the resources */
2854         XRRFreeScreenResources(res);
2855
2856         return ret;
2857      }
2858 #endif
2859    return ECORE_X_RENDER_SUBPIXEL_ORDER_UNKNOWN;
2860 }
2861
2862 /***************************************
2863  * API Functions for RandR version 1.3 *
2864  ***************************************/
2865
2866 EAPI Ecore_X_Randr_Output *
2867 ecore_x_randr_output_wired_clones_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, int *num)
2868 {
2869 #ifdef ECORE_XRANDR
2870    Atom clones = None, type = None;
2871    unsigned char *prop = NULL;
2872    int format = 0;
2873    unsigned long nitems = 0, bytes = 0;
2874
2875    /* NB: FIXME: 
2876     * 
2877     * I am not sure that this code is correct. This needs checking 
2878     */
2879
2880    if (_randr_version < RANDR_VERSION_1_3) return NULL;
2881
2882    /* try to get the edid atom */
2883    if (!(clones = XInternAtom(_ecore_x_disp, RR_PROPERTY_CLONE_LIST, True)))
2884      return NULL;
2885
2886    /* get the output property
2887     * 
2888     * NB: Returns 0 on success */
2889    if (!XRRGetOutputProperty(_ecore_x_disp, output, clones, 0, 100, False, False, 
2890                             AnyPropertyType, &type, &format, &nitems, 
2891                             &bytes, &prop))
2892      {
2893         if ((type == XA_ATOM) && (nitems >= 1) && (format == 32))
2894           {
2895              Ecore_X_Randr_Output *ret = NULL;
2896
2897              if ((ret = malloc(nitems * sizeof(Ecore_X_Randr_Output))))
2898                {
2899                   if (num) *num = nitems;
2900                   memcpy(ret, prop, (nitems * sizeof(Ecore_X_Randr_Output)));
2901                   free(prop);
2902                   return ret;
2903                }
2904           }
2905      }
2906    free(prop);
2907 #endif
2908    return NULL;
2909 }
2910
2911 EAPI Ecore_X_Randr_Output **
2912 ecore_x_randr_output_compatibility_list_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output EINA_UNUSED, int *num EINA_UNUSED)
2913 {
2914    /* TODO: (1.3) !! */
2915    //RR_PROPERTY_COMPATIBILITY_LIST
2916    return NULL;
2917 }
2918
2919 EAPI Ecore_X_Randr_Signal_Format *
2920 ecore_x_randr_output_signal_formats_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, int *num)
2921 {
2922 #ifdef ECORE_XRANDR
2923    XRRPropertyInfo *info = NULL;
2924    Atom sig, type;
2925    unsigned long bytes = 0;
2926    unsigned long items = 0;
2927    unsigned char *prop = NULL;
2928    int format = 0;
2929
2930    if (_randr_version < RANDR_VERSION_1_3) return NULL;
2931
2932    /* try to get the connector number atom */
2933    if (!(sig = XInternAtom(_ecore_x_disp, RR_PROPERTY_SIGNAL_FORMAT, True)))
2934      return NULL;
2935
2936    /* try to get the output property from Xrandr
2937     * 
2938     * NB: Returns 0 on success */
2939    if (XRRGetOutputProperty(_ecore_x_disp, output, sig, 0, 100, 
2940                             False, False, AnyPropertyType, &type, &format, 
2941                             &items, &bytes, &prop))
2942      {
2943         free(prop);
2944         printf("Signal Format property not supported.\n");
2945         return NULL;
2946      }
2947
2948    free(prop);
2949
2950    /* safety check */
2951    if ((type != XA_ATOM) || (items < 1) || (format != 32))
2952      return NULL;
2953
2954    /* try to get the output property from Xrandr */
2955    if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, sig)))
2956      {
2957         Ecore_X_Randr_Signal_Format *formats = NULL;
2958
2959         if (num) *num = info->num_values;
2960
2961         if (info->num_values > 0)
2962           {
2963              if ((formats = 
2964                   malloc(info->num_values * sizeof(Ecore_X_Randr_Signal_Format))))
2965                {
2966                   memcpy(formats, info->values, 
2967                          (info->num_values * sizeof(Ecore_X_Randr_Signal_Format)));
2968                }
2969           }
2970
2971         /* free the info */
2972         free(info);
2973
2974         return formats;
2975      }
2976 #endif
2977    return NULL;
2978 }
2979
2980 EAPI Eina_Bool 
2981 ecore_x_randr_output_signal_format_set(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output EINA_UNUSED, Ecore_X_Randr_Signal_Format *sig EINA_UNUSED)
2982 {
2983    /* TODO: (1.3) !! */
2984    //RR_PROPERTY_SIGNAL_FORMAT
2985    return EINA_FALSE;
2986 }
2987
2988 EAPI Ecore_X_Randr_Signal_Property *
2989 ecore_x_randr_output_signal_properties_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, int *num)
2990 {
2991 #ifdef ECORE_XRANDR
2992    XRRPropertyInfo *info = NULL;
2993    Atom sig, type;
2994    unsigned long bytes = 0;
2995    unsigned long items = 0;
2996    unsigned char *prop = NULL;
2997    int format = 0;
2998
2999    if (_randr_version < RANDR_VERSION_1_3) return NULL;
3000
3001    /* try to get the connector number atom */
3002    if (!(sig = XInternAtom(_ecore_x_disp, RR_PROPERTY_SIGNAL_PROPERTIES, True)))
3003      return NULL;
3004
3005    /* try to get the output property from Xrandr
3006     * 
3007     * NB: Returns 0 on success */
3008    if (XRRGetOutputProperty(_ecore_x_disp, output, sig, 0, 100, 
3009                             False, False, AnyPropertyType, &type, &format, 
3010                             &items, &bytes, &prop))
3011      {
3012         free(prop);
3013         printf("Signal Properties property not supported.\n");
3014         return NULL;
3015      }
3016
3017    free(prop);
3018
3019    /* safety check */
3020    if ((type != XA_ATOM) || (items < 1) || (format != 32))
3021      return NULL;
3022
3023    /* try to get the output property from Xrandr */
3024    if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, sig)))
3025      {
3026         Ecore_X_Randr_Signal_Property *props = NULL;
3027
3028         if (num) *num = info->num_values;
3029
3030         if (info->num_values > 0)
3031           {
3032              if ((props = 
3033                   malloc(info->num_values * sizeof(Ecore_X_Randr_Signal_Property))))
3034                {
3035                   memcpy(props, info->values, 
3036                          (info->num_values * sizeof(Ecore_X_Randr_Signal_Property)));
3037                }
3038           }
3039
3040         /* free the info */
3041         free(info);
3042
3043         return props;
3044      }
3045 #endif
3046    return NULL;
3047 }
3048
3049 /* TODO NB:
3050  * 
3051  * Document this.
3052  * 
3053  * Returns: 
3054  * 0 == unknown
3055  * 1 == primary
3056  * 2 == secondary
3057  * 3 == (typically) TV Connector but is driver/hardware dependent
3058  * 
3059  */
3060 EAPI int 
3061 ecore_x_randr_output_connector_number_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output)
3062 {
3063 #ifdef ECORE_XRANDR
3064    XRRPropertyInfo *info = NULL;
3065    Atom type;
3066    unsigned long bytes = 0;
3067    unsigned long items = 0;
3068    unsigned char *prop = NULL;
3069    int val = 0, format = 0;
3070
3071    if (_randr_version < RANDR_VERSION_1_3) return -1;
3072
3073    /* try to get the output property from Xrandr
3074     * 
3075     * NB: Returns 0 on success */
3076    if (XRRGetOutputProperty(_ecore_x_disp, output, connector_number, 0, 100, 
3077                             False, False, AnyPropertyType, &type, &format, 
3078                             &items, &bytes, &prop))
3079      {
3080         free(prop);
3081         printf("ConnectionNumber property not supported.\n");
3082         return -1;
3083      }
3084
3085    /* safety check */
3086    if ((type != XA_INTEGER) || (items != 1) || (format != 32))
3087      {
3088         free(prop);
3089         return -1;
3090      }
3091
3092    val = *((int *)prop);
3093    free(prop);
3094
3095    /* try to get the output property from Xrandr */
3096    if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, connector_number)))
3097      {
3098         int ret = 0;
3099
3100         /* convert the current value */
3101         ret = (int)(val - info->values[0]);
3102
3103         /* free the info */
3104         free(info);
3105
3106         return ret;
3107      }
3108 #endif
3109    return -1;
3110 }
3111
3112 EAPI Ecore_X_Randr_Connector_Type 
3113 ecore_x_randr_output_connector_type_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output)
3114 {
3115 #ifdef ECORE_XRANDR
3116    XRRPropertyInfo *info = NULL;
3117    Atom type;
3118    unsigned long bytes = 0;
3119    unsigned long items = 0;
3120    unsigned char *prop = NULL;
3121    int val = 0, format = 0;
3122
3123    if (_randr_version < RANDR_VERSION_1_3) return -1;
3124
3125    /* try to get the connector type atom */
3126    if (XRRGetOutputProperty(_ecore_x_disp, output, connector_type, 0, 100, 
3127                         False, False, AnyPropertyType, &type, &format, 
3128                         &items, &bytes, &prop) != Success)
3129      {
3130         free(prop);
3131         return -1;
3132      }
3133
3134    if ((!prop) || (items == 0))
3135      {
3136         Atom conn;
3137
3138         free(prop);
3139         /* NB: some butthead drivers (*cough* nouveau *cough*) do not 
3140          * implement randr properly. They are not using the connector type 
3141          * property of randr, but rather a "subconnector" property */
3142         if ((conn = XInternAtom(_ecore_x_disp, "subconnector", True)))
3143           XRRGetOutputProperty(_ecore_x_disp, output, conn, 0, 4, 
3144                                False, False, AnyPropertyType, &type, 
3145                                &format, &items, &bytes, &prop);
3146      }
3147
3148    if ((!prop) || (items == 0))
3149      {
3150         free(prop);
3151         WRN("ConnectorType Property not supported.");
3152         return -1;
3153      }
3154
3155    /* safety check */
3156    if ((type != XA_ATOM) || (items != 1) || (format != 32))
3157      return -1;
3158
3159    val = *((int *)prop);
3160    free(prop);
3161
3162    /* try to get the output property from Xrandr */
3163    if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, connector_type)))
3164      {
3165         int ret = 0;
3166
3167         /* convert the current value */
3168         ret = (int)(val - info->values[0]);
3169
3170         /* printf("\tReturn Value: %d\n", ret); */
3171         /* printf("\t\tActual Name: %s\n",  */
3172         /*        XGetAtomName(_ecore_x_disp, ((Atom)info->values[ret]))); */
3173
3174         /* free the info */
3175         free(info);
3176
3177         return ret;
3178      }
3179 #endif
3180    return -1;
3181 }
3182
3183 EAPI Ecore_X_Randr_Output 
3184 ecore_x_randr_primary_output_get(Ecore_X_Window root)
3185 {
3186 #ifdef ECORE_XRANDR
3187    if (_randr_version < RANDR_VERSION_1_3) return 0;
3188    return XRRGetOutputPrimary(_ecore_x_disp, root);
3189 #else
3190    return 0;
3191 #endif
3192 }
3193
3194 EAPI void 
3195 ecore_x_randr_primary_output_set(Ecore_X_Window root, Ecore_X_Randr_Output output)
3196 {
3197 #ifdef ECORE_XRANDR
3198    if (_randr_version < RANDR_VERSION_1_3) return;
3199    XRRSetOutputPrimary(_ecore_x_disp, root, output);
3200 #endif
3201 }
3202
3203 /***************************************
3204  * API Functions for RandR version 1.4 *
3205  ***************************************/
3206
3207 EAPI void 
3208 ecore_x_randr_crtc_panning_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h)
3209 {
3210 #ifdef ECORE_XRANDR
3211    XRRScreenResources *res = NULL;
3212
3213    if (_randr_version < RANDR_VERSION_1_4) return;
3214
3215    /* try to get the screen resources from Xrandr */
3216    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
3217      {
3218         XRRPanning *xpan = NULL;
3219
3220         /* get this crtc's panning */
3221         if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
3222           {
3223              if (x) *x = xpan->left;
3224              if (y) *y = xpan->top;
3225              if (w) *w = xpan->width;
3226              if (h) *h = xpan->height;
3227
3228              /* free the panning resource */
3229              XRRFreePanning(xpan);
3230           }
3231         /* free the resources */
3232         XRRFreeScreenResources(res);
3233      }
3234 #endif
3235 }
3236
3237 EAPI Eina_Bool 
3238 ecore_x_randr_crtc_panning_area_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, const int x, const int y, const int w, const int h)
3239 {
3240 #ifdef ECORE_XRANDR
3241    XRRScreenResources *res = NULL;
3242    Eina_Bool ret = EINA_FALSE;
3243
3244    if (_randr_version < RANDR_VERSION_1_4) return EINA_FALSE;
3245
3246    /* try to get the screen resources from Xrandr */
3247    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
3248      {
3249         XRRPanning *xpan = NULL;
3250
3251         /* get this crtc's panning */
3252         if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
3253           {
3254              xpan->left = x;
3255              xpan->top = y;
3256              xpan->width = w;
3257              xpan->height = h;
3258              xpan->timestamp = CurrentTime;
3259
3260              /* set the panning value */
3261              if (!XRRSetPanning(_ecore_x_disp, res, crtc, xpan))
3262                ret = EINA_TRUE;
3263
3264              /* free the panning resource */
3265              XRRFreePanning(xpan);
3266           }
3267
3268         /* free the resources */
3269         XRRFreeScreenResources(res);
3270      }
3271
3272    return ret;
3273 #else
3274    return EINA_FALSE;
3275 #endif
3276 }
3277
3278 EAPI void 
3279 ecore_x_randr_crtc_tracking_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h)
3280 {
3281 #ifdef ECORE_XRANDR
3282    XRRScreenResources *res = NULL;
3283
3284    if (_randr_version < RANDR_VERSION_1_4) return;
3285
3286    /* try to get the screen resources from Xrandr */
3287    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
3288      {
3289         XRRPanning *xpan = NULL;
3290
3291         /* get this crtc's panning */
3292         if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
3293           {
3294              if (x) *x = xpan->track_left;
3295              if (y) *y = xpan->track_top;
3296              if (w) *w = xpan->track_width;
3297              if (h) *h = xpan->track_height;
3298
3299              /* free the panning resource */
3300              XRRFreePanning(xpan);
3301           }
3302         /* free the resources */
3303         XRRFreeScreenResources(res);
3304      }
3305 #endif
3306 }
3307
3308 EAPI Eina_Bool 
3309 ecore_x_randr_crtc_tracking_area_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, const int x, const int y, const int w, const int h)
3310 {
3311 #ifdef ECORE_XRANDR
3312    XRRScreenResources *res = NULL;
3313    Eina_Bool ret = EINA_FALSE;
3314
3315    if (_randr_version < RANDR_VERSION_1_4) return EINA_FALSE;
3316
3317    /* try to get the screen resources from Xrandr */
3318    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
3319      {
3320         XRRPanning *xpan = NULL;
3321
3322         /* get this crtc's panning */
3323         if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
3324           {
3325              xpan->track_left = x;
3326              xpan->track_top = y;
3327              xpan->track_width = w;
3328              xpan->track_height = h;
3329              xpan->timestamp = CurrentTime;
3330
3331              /* set the panning value */
3332              if (!XRRSetPanning(_ecore_x_disp, res, crtc, xpan))
3333                ret = EINA_TRUE;
3334
3335              /* free the panning resource */
3336              XRRFreePanning(xpan);
3337           }
3338
3339         /* free the resources */
3340         XRRFreeScreenResources(res);
3341      }
3342
3343    return ret;
3344 #else
3345    return EINA_FALSE;
3346 #endif
3347 }
3348
3349 EAPI void 
3350 ecore_x_randr_crtc_border_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h)
3351 {
3352 #ifdef ECORE_XRANDR
3353    XRRScreenResources *res = NULL;
3354
3355    if (_randr_version < RANDR_VERSION_1_4) return;
3356
3357    /* try to get the screen resources from Xrandr */
3358    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
3359      {
3360         XRRPanning *xpan = NULL;
3361
3362         /* get this crtc's panning */
3363         if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
3364           {
3365              if (x) *x = xpan->border_left;
3366              if (y) *y = xpan->border_top;
3367              if (w) *w = xpan->border_right;
3368              if (h) *h = xpan->border_bottom;
3369
3370              /* free the panning resource */
3371              XRRFreePanning(xpan);
3372           }
3373         /* free the resources */
3374         XRRFreeScreenResources(res);
3375      }
3376 #endif
3377 }
3378
3379 EAPI Eina_Bool 
3380 ecore_x_randr_crtc_border_area_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, const int left, const int top, const int right, const int bottom)
3381 {
3382 #ifdef ECORE_XRANDR
3383    XRRScreenResources *res = NULL;
3384    Eina_Bool ret = EINA_FALSE;
3385
3386    if (_randr_version < RANDR_VERSION_1_4) return EINA_FALSE;
3387
3388    /* try to get the screen resources from Xrandr */
3389    if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
3390      {
3391         XRRPanning *xpan = NULL;
3392
3393         /* get this crtc's panning */
3394         if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
3395           {
3396              xpan->border_left = left;
3397              xpan->border_top = top;
3398              xpan->border_right = right;
3399              xpan->border_bottom = bottom;
3400              xpan->timestamp = CurrentTime;
3401
3402              /* set the panning value */
3403              if (!XRRSetPanning(_ecore_x_disp, res, crtc, xpan))
3404                ret = EINA_TRUE;
3405
3406              /* free the panning resource */
3407              XRRFreePanning(xpan);
3408           }
3409
3410         /* free the resources */
3411         XRRFreeScreenResources(res);
3412      }
3413
3414    return ret;
3415 #else
3416    return EINA_FALSE;
3417 #endif
3418 }
3419
3420 /***************************************
3421  * API Functions for RandR Edid
3422  ***************************************/
3423
3424 EAPI Eina_Bool 
3425 ecore_x_randr_edid_has_valid_header(unsigned char *edid, unsigned long edid_length)
3426 {
3427    const unsigned char header[] =
3428      { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
3429
3430    if (!edid) return EINA_FALSE;
3431    if (edid_length < 8) return EINA_FALSE;
3432    if (!memcmp(edid, header, 8)) return EINA_TRUE;
3433    return EINA_FALSE;
3434 }
3435
3436 EAPI Eina_Bool 
3437 ecore_x_randr_edid_info_has_valid_checksum(unsigned char *edid, unsigned long edid_length)
3438 {
3439 #ifdef ECORE_XRANDR
3440    unsigned char *iter = NULL;
3441    char sum = 0;
3442    int i = 0, version = 0;
3443
3444    if (edid_length < 128) return EINA_FALSE;
3445
3446    version = ecore_x_randr_edid_version_get(edid, edid_length);
3447    if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;
3448
3449    for (i = 0; i < 128; i++)
3450      sum += edid[i];
3451
3452    if (sum) return EINA_FALSE;
3453
3454    /* check extension blocks */
3455    for (iter = edid; iter < (edid + edid_length); iter += 128)
3456      {
3457         if (iter[0] == 0x02)
3458           {
3459              for (i = 0, sum = 0; i < 128; i++)
3460                sum += iter[i];
3461           }
3462      }
3463
3464    if (sum) return EINA_FALSE;
3465    return EINA_TRUE;
3466 #else
3467    return EINA_FALSE;
3468 #endif
3469 }
3470
3471 EAPI int 
3472 ecore_x_randr_edid_version_get(unsigned char *edid, unsigned long edid_length)
3473 {
3474 #ifdef ECORE_XRANDR
3475    if ((edid_length > RANDR_EDID_VERSION_MINOR) && 
3476        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
3477      {
3478         return (edid[RANDR_EDID_VERSION_MAJOR] << 8) | 
3479           edid[RANDR_EDID_VERSION_MINOR];
3480      }
3481
3482    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3483 #else
3484    return 0;
3485 #endif
3486 }
3487
3488 EAPI char *
3489 ecore_x_randr_edid_manufacturer_name_get(unsigned char *edid, unsigned long edid_length)
3490 {
3491 #ifdef ECORE_XRANDR
3492    if ((edid_length > RANDR_EDID_MANUFACTURER + 1) && 
3493        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
3494      {
3495         unsigned char *x;
3496         char *name;
3497
3498         if (!(name = malloc(sizeof(char) * 4))) return NULL;
3499
3500         x = (edid + RANDR_EDID_MANUFACTURER);
3501         name[0] = ((x[0] & 0x7c) >> 2) + '@';
3502         name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xe0) >> 5) + '@';
3503         name[2] = (x[1] & 0x1f) + '@';
3504         name[3] = 0;
3505
3506         return name;
3507      }
3508 #endif
3509    return NULL;
3510 }
3511
3512 EAPI char *
3513 ecore_x_randr_edid_display_name_get(unsigned char *edid, unsigned long edid_length)
3514 {
3515 #ifdef ECORE_XRANDR
3516    unsigned char *block = NULL;
3517    int version = 0;
3518
3519    version = ecore_x_randr_edid_version_get(edid, edid_length);
3520    if (version < RANDR_EDID_VERSION_1_3) return NULL;
3521
3522    for (block = (edid + RANDR_EDID_BLOCK); 
3523         block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18)
3524      {
3525         if ((block[0] == 0) && (block[1] == 0))
3526           {
3527              if (block[3] == 0xfc)
3528                {
3529                   char *name, *p;
3530                   const char *edid_name;
3531
3532                   edid_name = (const char *)block + 5;
3533                   if (!(name = malloc(14))) return NULL;
3534                   strncpy(name, edid_name, 13);
3535                   name[13] = 0;
3536
3537                   for (p = name; *p; p++)
3538                     if ((*p < ' ') || (*p > '~')) *p = 0;
3539
3540                   return name;
3541                }
3542           }
3543      }
3544 #endif
3545    return NULL;
3546 }
3547
3548 EAPI char *
3549 ecore_x_randr_edid_display_ascii_get(unsigned char *edid, unsigned long edid_length)
3550 {
3551 #ifdef ECORE_XRANDR
3552    unsigned char *block = NULL;
3553    int version = 0;
3554
3555    version = ecore_x_randr_edid_version_get(edid, edid_length);
3556    if (version < RANDR_EDID_VERSION_1_3) return NULL;
3557
3558    for (block = (edid + RANDR_EDID_BLOCK); 
3559         block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18)
3560      {
3561         if ((block[0] == 0) && (block[1] == 0))
3562           {
3563              if (block[3] == 0xfe)
3564                {
3565                   char *ascii = NULL, *p = NULL;
3566                   const char *edid_ascii;
3567
3568                   edid_ascii = (const char *)block + 5;
3569
3570                   if (!(ascii = malloc(14))) return NULL;
3571                   strncpy(ascii, edid_ascii, 13);
3572                   ascii[13] = 0;
3573                   for (p = ascii; *p; p++)
3574                     if ((*p < ' ') || (*p > '~')) *p = 0;
3575
3576                   return ascii;
3577                }
3578           }
3579      }
3580 #endif
3581    return NULL;
3582 }
3583
3584 EAPI char *
3585 ecore_x_randr_edid_display_serial_get(unsigned char *edid, unsigned long edid_length)
3586 {
3587 #ifdef ECORE_XRANDR
3588    unsigned char *block = NULL;
3589    int version = 0;
3590
3591    version = ecore_x_randr_edid_version_get(edid, edid_length);
3592    if (version < RANDR_EDID_VERSION_1_3) return NULL;
3593
3594    for (block = (edid + RANDR_EDID_BLOCK); 
3595         block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18)
3596      {
3597         if ((block[0] == 0) && (block[1] == 0))
3598           {
3599              if (block[3] == 0xff)
3600                {
3601                   char *serial = NULL, *p = NULL;
3602                   const char *edid_serial;
3603
3604                   edid_serial = (const char *)block + 5;
3605
3606                   if (!(serial = malloc(14))) return NULL;
3607                   strncpy(serial, edid_serial, 13);
3608                   serial[13] = 0;
3609                   for (p = serial; *p; p++)
3610                     if ((*p < ' ') || (*p > '~')) *p = 0;
3611
3612                   return serial;
3613                }
3614           }
3615      }
3616 #endif
3617    return NULL;
3618 }
3619
3620 EAPI int 
3621 ecore_x_randr_edid_model_get(unsigned char *edid, unsigned long edid_length)
3622 {
3623    return ecore_x_randr_edid_manufacturer_model_get(edid, edid_length);
3624 }
3625
3626 EAPI int 
3627 ecore_x_randr_edid_manufacturer_serial_number_get(unsigned char *edid, unsigned long edid_length)
3628 {
3629 #ifdef ECORE_XRANDR
3630    if ((edid_length > RANDR_EDID_MANUFACTURER + 1) && 
3631        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
3632      return (int)(edid[0x0c] + (edid[0x0d] << 8) + 
3633                   (edid[0x0e] << 16) + (edid[0x0f] << 24));
3634
3635    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3636 #else
3637    return 0;
3638 #endif
3639 }
3640
3641 EAPI int 
3642 ecore_x_randr_edid_manufacturer_model_get(unsigned char *edid, unsigned long edid_length)
3643 {
3644 #ifdef ECORE_XRANDR
3645    if ((edid_length > RANDR_EDID_MANUFACTURER + 1) && 
3646        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
3647      return (int)(edid[0x0a] + (edid[0x0b] << 8));
3648 #endif
3649    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3650 }
3651
3652 EAPI Eina_Bool 
3653 ecore_x_randr_edid_dpms_available_get(unsigned char *edid, unsigned long edid_length)
3654 {
3655 #ifdef ECORE_XRANDR
3656    int version = 0;
3657
3658    version = ecore_x_randr_edid_version_get(edid, edid_length);
3659    if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;
3660
3661    return !!(edid[0x18] & 0xE0);
3662 #else
3663    return EINA_FALSE;
3664 #endif
3665 }
3666
3667 EAPI Eina_Bool 
3668 ecore_x_randr_edid_dpms_standby_available_get(unsigned char *edid, unsigned long edid_length)
3669 {
3670 #ifdef ECORE_XRANDR
3671    int version = 0;
3672
3673    version = ecore_x_randr_edid_version_get(edid, edid_length);
3674    if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;
3675
3676    if (edid[0x18] & 0xE0) return !!(edid[0x18] & 0x80);
3677 #endif
3678    return EINA_FALSE;
3679 }
3680
3681 EAPI Eina_Bool 
3682 ecore_x_randr_edid_dpms_suspend_available_get(unsigned char *edid, unsigned long edid_length)
3683 {
3684 #ifdef ECORE_XRANDR
3685    int version = 0;
3686
3687    version = ecore_x_randr_edid_version_get(edid, edid_length);
3688    if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;
3689
3690    if (edid[0x18] & 0xE0) return !!(edid[0x18] & 0x40);
3691 #endif
3692    return EINA_FALSE;
3693 }
3694
3695 EAPI Eina_Bool 
3696 ecore_x_randr_edid_dpms_off_available_get(unsigned char *edid, unsigned long edid_length)
3697 {
3698 #ifdef ECORE_XRANDR
3699    int version = 0;
3700
3701    version = ecore_x_randr_edid_version_get(edid, edid_length);
3702    if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;
3703
3704    if (edid[0x18] & 0xE0) return !!(edid[0x18] & 0x20);
3705 #endif
3706    return EINA_FALSE;
3707 }
3708
3709 EAPI Ecore_X_Randr_Edid_Aspect_Ratio 
3710 ecore_x_randr_edid_display_aspect_ratio_preferred_get(unsigned char *edid, unsigned long edid_length)
3711 {
3712 #ifdef ECORE_XRANDR
3713    unsigned char *block = NULL;
3714    int version = 0;
3715
3716    version = ecore_x_randr_edid_version_get(edid, edid_length);
3717    if (version < RANDR_EDID_VERSION_1_3) 
3718      return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3719
3720    for (block = (edid + RANDR_EDID_BLOCK); 
3721         block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18)
3722      {
3723         if ((block[0] == 0) && (block[1] == 0))
3724           {
3725              if ((block[3] == 0xfd) && (block[10] == 0x04))
3726                {
3727                   Ecore_X_Randr_Edid_Aspect_Ratio_Preferred ratio = 
3728                     (Ecore_X_Randr_Edid_Aspect_Ratio_Preferred)((block[15] & 0xe0) >> 5);
3729
3730                   switch (ratio)
3731                     {
3732                      case RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3:
3733                        return ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3;
3734                      case RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9:
3735                        return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9;
3736                      case RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10:
3737                        return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10;
3738                      case RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4:
3739                        return ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4;
3740                      case RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9:
3741                        return ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9;
3742                      default:
3743                        return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3744                     }
3745                }
3746           }
3747      }
3748
3749    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3750 #else
3751    return 0;
3752 #endif
3753 }
3754
3755 EAPI Ecore_X_Randr_Edid_Aspect_Ratio 
3756 ecore_x_randr_edid_display_aspect_ratios_get(unsigned char *edid, unsigned long edid_length)
3757 {
3758 #ifdef ECORE_XRANDR
3759    Ecore_X_Randr_Edid_Aspect_Ratio ret;
3760    unsigned char *block = NULL;
3761    int version = 0;
3762
3763    ret = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3764
3765    version = ecore_x_randr_edid_version_get(edid, edid_length);
3766    if (version < RANDR_EDID_VERSION_1_3) 
3767      return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3768
3769    for (block = (edid + RANDR_EDID_BLOCK); 
3770         block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18)
3771      {
3772         if ((block[0] == 0) && (block[1] == 0))
3773           {
3774              if ((block[3] == 0xfd) && (block[10] == 0x04))
3775                {
3776                   if (block[14] & 0x80)
3777                     ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3;
3778                   if (block[14] & 0x40)
3779                     ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9;
3780                   if (block[14] & 0x20)
3781                     ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10;
3782                   if (block[14] & 0x10)
3783                     ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4;
3784                   if (block[14] & 0x08)
3785                     ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9;
3786                }
3787           }
3788      }
3789
3790    return ret;
3791 #else
3792    return 0;
3793 #endif
3794 }
3795
3796 EAPI Ecore_X_Randr_Edid_Display_Colorscheme 
3797 ecore_x_randr_edid_display_colorscheme_get(unsigned char *edid, unsigned long edid_length)
3798 {
3799 #ifdef ECORE_XRANDR
3800    Ecore_X_Randr_Edid_Display_Colorscheme ret;
3801    int version = 0;
3802
3803    ret = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3804
3805    version = ecore_x_randr_edid_version_get(edid, edid_length);
3806    if (version < RANDR_EDID_VERSION_1_3) 
3807      return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3808
3809    if (ecore_x_randr_edid_display_type_digital_get(edid, edid_length))
3810      {
3811         ret = ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_4_4_4;
3812         if (edid[0x18] & 0x10)
3813           ret |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_4_4;
3814         if (edid[0x18] & 0x08)
3815           ret |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_2_2;
3816      }
3817    else
3818      ret = (edid[0x18] & 0x18);
3819
3820    return ret;
3821 #else
3822    return 0;
3823 #endif
3824 }
3825
3826 EAPI Eina_Bool 
3827 ecore_x_randr_edid_display_type_digital_get(unsigned char *edid, unsigned long edid_length)
3828 {
3829 #ifdef ECORE_XRANDR
3830    int version = 0;
3831
3832    version = ecore_x_randr_edid_version_get(edid, edid_length);
3833    if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;
3834
3835    return !!(edid[0x14] & 0x80);
3836 #else
3837    return EINA_FALSE;
3838 #endif
3839 }
3840
3841 EAPI Ecore_X_Randr_Edid_Display_Interface_Type 
3842 ecore_x_randr_edid_display_interface_type_get(unsigned char *edid, unsigned long edid_length)
3843 {
3844 #ifdef ECORE_XRANDR
3845    Ecore_X_Randr_Edid_Display_Interface_Type type;
3846    int version = 0;
3847
3848    type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3849
3850    version = ecore_x_randr_edid_version_get(edid, edid_length);
3851    if (version < RANDR_EDID_VERSION_1_3) 
3852      return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3853
3854    type = (edid[0x14] & 0x0f);
3855    if (type > ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT)
3856      type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
3857
3858    return type;
3859 #else
3860    return 0;
3861 #endif
3862 }