aboutsummaryrefslogblamecommitdiffstats
path: root/src/lib/ecore_x/ecore_x_randr.c
blob: f2288cc40447768450fc808c8ad2acaa84a19f42 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680

















                                                                             


                                         


































                                                                                      
                    












                                                                             


                                                                          



















                                           



                                                                  
                                                             





























                                                        







































































































































































































































































                                                                                                                                

                                

































































































































































                                                                                                                          
                           
           



                                                  
 
                                             
                
                                           
 








                                                                                  
 

                                
 
                                                    
 

                                                        
 

                                                         
 

                                                 
 


                                          
 



                                         
                




                                                                                
                
 

                                                                         






























                                                                                            


                                               












                                                                              
           
                        



                                                                       
                      
           
                        



                                                                       











                                                                                  
                                                            
















                                                                        











                                                                         





















                                                                          








                                                                         
















                                                                     







































































                                                                                    







                                         



























































                                                                              

























                                                                        







                                         


































                                                                        







                                         


































































                                                                             

                                        
                     








                                                                                   
                     





























































                                                                            
                       




                         










































































































                                                                                      











                                                     















































                                                                                               










                                              

























































































































































































































































































































































































                                                                                                                                                                                                        

                                  
                                 



                                         

                                                    
                                                                
           



                                         
 



                                                                 
 


                                      






                                                                 






                                                            

           










                                                                      

                                    
      

              

































































































































                                                                                                                                                                                                



















                                                                               








                                                                           
                                                   


                                                   


                                       
                                        
                     



                                                                                  
 



                                                                 

                     
                                          
                     



                                                                                    
 



                                                                   

                     














                                     












                                                           





           





                                                                         























































                                                                                                           

                                                            
 




                                                                                 
 


                                                        






































                                                                                           
                                          
 





                                                                                      
 


                                                         































                                                                                                   
                                         
 





                                                                                 
 


                                                        








































































                                                                                         










                                                                














                                       





























                                                                                                                                                                                                                             
         
                                                          
 


                                                    

              
      


            




                                                     
 

















                                                                            

              
      


               


             
               
                                                                                                 
 








                                                               


               
      




















                                                                                                                          
                  
           

                                                                  
                


                                                                      
                     




                                                              
 

                                                                       






                                     




                                                                    




























                                                                                                         

                                    







                                                                        
                                                       












































                                                                            
                               


































                                                                              
                                                     


































































































                                                                                                  
                                                                                                                                                  

















































































                                                                                                      

                         






                                                                          
                                                                         
      
                   







































































































                                                                                                                    
                              




                                                       
                                 
                                                                            




                                 
                                                                               


                                                                      
                                                                   






                                                                      
                             



                             
              









































                                                                                         
                                                                                                             


                                   
                              




























                                                                                  
                             



                             
              




                            
                                                                                                                                           






                                   
                                                                                                               





















                                                                            
                   














                                                                   


                                         
           





                                                                                   











                           
                                                                                                                                                              






                                    
                                                                                                                  





















                                                                                
                   














                                                                   


                                         
           





                                                                                     






















                                                                 
                                                                                                       


                                
             






                                                     


                                                
                                                                             


                                                                           
                   





                                                              



                   




                                                   
                                                                                















                                           
                                                                                                     


                                
             







                                                     


                                                                           



                   


                               

                  
                   










                                                                           
                   











                                                           
                                                                              







































                                                                                  
























































































































































































































                                                                                                                                                  

















                                                                                          
                   

























                                                               


                     




                                                                              
                   







                                                                


            




                                                                                        
                   















                                                                    
      





                                                                                   
                   



























                                                                   
      





                                                                                    
                   



























                                                                   
      





                                                                                     
                   



























                                                                   
      











                                                                                                 
                   





                                                                


            




                                                                                         
                   


                                                                
      





                                                                                     
                   





                                                               


                     




                                                                                             
                   





                                                               
      





                                                                                             
                   





                                                               
      





                                                                                         
                   





                                                               
      





                                                                                                     
                   




































                                                                                         


            




                                                                                            
                   































                                                                   


            




                                                                                          
                   




















                                                                              


            




                                                                                           
                   





                                                               


                     




                                                                                             
                   













                                                                


            
 
 #ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "Ecore.h"
#include "ecore_x_private.h"
#include "Ecore_X.h"

/* NB: FIXME:
 * 
 * A lot of this code uses XRRGetScreenInfo and then calls 
 * XRRFreeScreenConfigInfo. Typically this is not an Unheard of thing to do, 
 * however this process of getting config and freeing config does force a 
 * round-trip to the X server */

/* local variables */
static Eina_Bool _randr_avail = EINA_FALSE;

static Ecore_X_Atom connector_type = 0;
static Ecore_X_Atom connector_number = 0;

#ifdef ECORE_XRANDR

# define RANDR_VERSION_1_1 ((1 << 16) | 1)
# define RANDR_VERSION_1_2 ((1 << 16) | 2)
# define RANDR_VERSION_1_3 ((1 << 16) | 3)
# define RANDR_VERSION_1_4 ((1 << 16) | 4)

# define RANDR_EDID_VERSION_1_3 ((1 << 8) | 3)
# define RANDR_EDID_VERSION_MAJOR 0x12
# define RANDR_EDID_VERSION_MINOR 0x13

# define RANDR_EDID_MANUFACTURER 0x08
# define RANDR_EDID_BLOCK 0x36

typedef enum _Ecore_X_Randr_Edid_Aspect_Ratio_Preferred 
{
   RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3 = 0x00,
     RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9 = 0x01,
     RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10 = 0x02,
     RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4 = 0x03,
     RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9 = 0x04
} Ecore_X_Randr_Edid_Aspect_Ratio_Preferred;

static int _randr_major, _randr_minor, _randr_version;

XRRScreenResources *(*_ecore_x_randr_screen_resources_get)(Display *disp, Window win);

#endif

/* local functions */
void 
_ecore_x_randr_init(void)
{
#ifdef ECORE_XRANDR
   _randr_major = 1;
   _randr_minor = 4;
   _randr_version = 0;

   /* try to query the randr extenstion version */
   if (XRRQueryVersion(_ecore_x_disp, &_randr_major, &_randr_minor))
     {
        _randr_version = (_randr_major << 16) | _randr_minor;

        if (_randr_version >= RANDR_VERSION_1_3)
          _ecore_x_randr_screen_resources_get = XRRGetScreenResourcesCurrent;
        else if (_randr_version == RANDR_VERSION_1_2)
          _ecore_x_randr_screen_resources_get = XRRGetScreenResources;

        _randr_avail = EINA_TRUE;

        connector_type = ecore_x_atom_get(RR_PROPERTY_CONNECTOR_TYPE);
        connector_number = ecore_x_atom_get(RR_PROPERTY_CONNECTOR_NUMBER);
     }
#endif
}

/* public functions */
EAPI int 
ecore_x_randr_version_get(void)
{
#ifdef ECORE_XRANDR
   if (_randr_avail) return _randr_version;
#endif
   return -1;
}

EAPI Eina_Bool 
ecore_x_randr_query(void)
{
   return _randr_avail;
}

/**
 * @brief This function returns the current config timestamp from 
 * XRRScreenConfiguration.
 * 
 * @param root root window to query screen configuration from
 * 
 * @returns The screen configuration timestamp
 * 
 * @since 1.8
 */
EAPI Ecore_X_Time 
ecore_x_randr_config_timestamp_get(Ecore_X_Window root)
{
   Ecore_X_Time timestamp = 0;

#ifdef ECORE_XRANDR
   XRRScreenConfiguration *cfg;

   /* try to get the screen configuration from Xrandr */
   if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
     {
        Time tm;

        XRRConfigTimes(cfg, &tm);

        timestamp = (Ecore_X_Time)tm;

        /* free any returned screen config */
        if (cfg) XRRFreeScreenConfigInfo(cfg);
     }
#endif

   return timestamp;
}

/***************************************
 * API Functions for RandR version 1.1 *
 ***************************************/

/*
 * @param root window which's primary output will be queried
 */
EAPI Ecore_X_Randr_Orientation 
ecore_x_randr_screen_primary_output_orientations_get(Ecore_X_Window root)
{
#ifdef ECORE_XRANDR
   Rotation ret = 0, crot = 0;

   /* get the rotations available from XRandr */
   ret = XRRRotations(_ecore_x_disp, 
                      XRRRootToScreen(_ecore_x_disp, root), &crot);

   return ret;
#else
   return 0;
#endif
}

/*
 * @param root window which's primary output will be queried
 * @return the current orientation of the root window's screen primary output
 */
EAPI Ecore_X_Randr_Orientation 
ecore_x_randr_screen_primary_output_orientation_get(Ecore_X_Window root)
{
#ifdef ECORE_XRANDR
   Rotation ret = 0;

   /* get the current rotation available from XRandr */
   XRRRotations(_ecore_x_disp, 
                XRRRootToScreen(_ecore_x_disp, root), &ret);

   return ret;
#else
   return 0;
#endif
}

/*
 * @brief Sets a given screen's primary output's orientation.
 *
 * @param root Window which's screen's primary output will be queried.
 * @param orientation orientation which should be set for the root window's
 * screen primary output.
 * @return @c EINA_TRUE if the primary output's orientation could be
 * successfully altered.
 */
EAPI Eina_Bool 
ecore_x_randr_screen_primary_output_orientation_set(Ecore_X_Window root, Ecore_X_Randr_Orientation orient)
{
#ifdef ECORE_XRANDR
   Eina_Bool ret = EINA_FALSE;
   Rotation crot = 0;
   XRRScreenConfiguration *cfg = NULL;
   int id = 0;

   /* try to get the screen config from XRandr */
   if (!(cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
     return EINA_FALSE;

   /* get the screen's current size id */
   id = XRRConfigCurrentConfiguration(cfg, &crot);

   /* attempt to set the new orientation */
   if (!XRRSetScreenConfig(_ecore_x_disp, cfg, root, id, orient, CurrentTime))
     ret = EINA_TRUE;

   /* free any returned screen config */
   if (cfg) XRRFreeScreenConfigInfo(cfg);

   return ret;
#else
   return EINA_FALSE;
#endif
}

/*
 * @brief gets a screen's primary output's possible sizes
 * @param root window which's primary output will be queried
 * @param num number of sizes reported as supported by the screen's primary output
 * @return an array of sizes reported as supported by the screen's primary output or - if query failed - NULL
 */
EAPI Ecore_X_Randr_Screen_Size_MM *
ecore_x_randr_screen_primary_output_sizes_get(Ecore_X_Window root, int *num)
{
   if (num) *num = 0;
#ifdef ECORE_XRANDR
   Ecore_X_Randr_Screen_Size_MM *ret = NULL;
   XRRScreenSize *sizes;
   int n = 0, i = 0;

   /* retrieve the number of sizes from X, and the sizes themselves.
    * 
    * NB: don't have to free the returned sizes */
   sizes = XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n);
   if (!sizes) return NULL;
   if (n <= 0) return NULL;

   /* try to allocate our structure for these sizes */
   if (!(ret = calloc(n, sizeof(Ecore_X_Randr_Screen_Size_MM))))
     return NULL;

   if (num) *num = n;

   /* fill in our allocated structure with the screen sizes */
   for (i = 0; i < n; i++)
     {
        ret[i].width = sizes[i].width;
        ret[i].height = sizes[i].height;
        ret[i].width_mm = sizes[i].mwidth;
        ret[i].height_mm = sizes[i].mheight;
     }

   return ret;
#else
   return NULL;
#endif
}

EAPI void 
ecore_x_randr_screen_primary_output_current_size_get(Ecore_X_Window root, int *w, int *h, int *w_mm, int *h_mm, int *size_index)
{
#ifdef ECORE_XRANDR
   XRRScreenConfiguration *cfg = NULL;

   /* try to get the screen config from XRandr */
   if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
     {
        XRRScreenSize *sizes;
        Rotation crot = 0;
        int n = 0;

        /* retrieve the number of sizes from X, and the sizes themselves.
         * 
         * NB: don't have to free the returned sizes */
        sizes = 
          XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n);
        if ((sizes) && (n > 0))
          {
             int idx = 0;

             /* get the index of the current configuration */
             idx = XRRConfigCurrentConfiguration(cfg, &crot);

             /* if the index is valid, then fill in the return variables with 
              * the size information for this index */
             if ((idx < n) && (idx >= 0))
               {
                  if (w) *w = sizes[idx].width;
                  if (h) *h = sizes[idx].height;
                  if (w_mm) *w_mm = sizes[idx].mwidth;
                  if (h_mm) *h_mm = sizes[idx].mheight;
                  if (size_index) *size_index = idx;
               }
          }

        /* free the returned screen config */
        XRRFreeScreenConfigInfo(cfg);
     }
#endif
}

/*
 * @brief Sets a given screen's primary output size, but disables all other
 * outputs at the same time.
 *
 * @param root Window which's primary output will be queried.
 * @param size_index Within the list of sizes reported as supported by the root
 * window's screen primary output.
 * @return @c EINA_TRUE on success, @c EINA_FALSE on failure due to e.g.
 * invalid times.
 */
EAPI Eina_Bool 
ecore_x_randr_screen_primary_output_size_set(Ecore_X_Window root, int size_index)
{
#ifdef ECORE_XRANDR
   Eina_Bool ret = EINA_FALSE;
   int n = 0;

   /* check for valid size index first */
   if (size_index < 0) return EINA_FALSE;

   /* get the number of sizes from XRandr */
   XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n);

   /* make sure the requested index is below the number returned from randr */
   if (size_index < n)
     {
        XRRScreenConfiguration *cfg = NULL;

        /* try to get the screen config from XRandr */
        if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
          {
             /* try to set the new screen config
              * 
              * NB: Returns Success (0) if it works */
             if (!XRRSetScreenConfig(_ecore_x_disp, cfg, root, size_index, 
                                      ECORE_X_RANDR_ORIENTATION_ROT_0, 
                                      CurrentTime))
               {
                  ret = EINA_TRUE;
               }

             /* free the returned screen config */
             XRRFreeScreenConfigInfo(cfg);
          }
     }

   return ret;
#else
   return EINA_FALSE;
#endif
}

/*
 * @param root window which's primary output will be queried
 * @return currently used refresh rate or - if request failed or RandRR is not available - 0.0
 */
EAPI Ecore_X_Randr_Refresh_Rate 
ecore_x_randr_screen_primary_output_current_refresh_rate_get(Ecore_X_Window root)
{
#ifdef ECORE_XRANDR
   XRRScreenConfiguration *cfg = NULL;

   /* try to get the screen config from XRandr */
   if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
     {
        Ecore_X_Randr_Refresh_Rate ret = 0.0;

        /* try to get the current refresh rate */
        ret = XRRConfigCurrentRate(cfg);

        /* free the returned screen config */
        XRRFreeScreenConfigInfo(cfg);

        return ret;
     }
#endif
   return 0.0;
}

/*
 * @param root window which's primary output will be queried
 * @param size_index referencing the size to query valid refresh rates for
 * @return currently used refresh rate or - if request failed or RandRR is not available - NULL
 */
EAPI Ecore_X_Randr_Refresh_Rate *
ecore_x_randr_screen_primary_output_refresh_rates_get(Ecore_X_Window root, int size_index, int *num)
{
#ifdef ECORE_XRANDR
   Ecore_X_Randr_Refresh_Rate *rates = NULL;
   int n = 0;

   /* try to get the refresh rates for this screen */
   if ((rates = XRRRates(_ecore_x_disp, 
                         XRRRootToScreen(_ecore_x_disp, root), size_index, &n)))
     {
        Ecore_X_Randr_Refresh_Rate *ret = NULL;

        if (n == 0) return NULL;

        /* try to allocate space for the return */
        if ((ret = malloc(n * sizeof(Ecore_X_Randr_Refresh_Rate))))
          {
             int i = 0;

             /* fill in our return values */
             for (i = 0; i < n; i++)
               ret[i] = rates[i];

             if (num) *num = n;

             return ret;
          }
     }
#endif
   return NULL;
}

/*
 * @brief Sets the current primary output's refresh rate.
 *
 * @param root Window which's primary output will be queried.
 * @param size_index Referencing the size to be set.
 * @param rate The refresh rate to be set.
 * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
 */
EAPI Eina_Bool 
ecore_x_randr_screen_primary_output_refresh_rate_set(Ecore_X_Window root, int size_index, Ecore_X_Randr_Refresh_Rate rate)
{
#ifdef ECORE_XRANDR
   if (_randr_version >= RANDR_VERSION_1_1)
     {
        XRRScreenConfiguration *cfg = NULL;

        /* try to get the screen config from XRandr */
        if ((cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
          {
             Eina_Bool ret = EINA_FALSE;
             Rotation rot = 0;

             /* get the current rotation */
             XRRConfigRotations(cfg, &rot);
 
             /* try to set the new screen config
              * 
              * NB: Returns Success (0) if it works */
             if (!XRRSetScreenConfigAndRate(_ecore_x_disp, cfg, root, 
                                            size_index, rot, rate, CurrentTime))
               {
                  ret = EINA_TRUE;
               }

             /* free the returned screen config */
             XRRFreeScreenConfigInfo(cfg);

             return ret;
          }
     }
#endif
   return EINA_FALSE;
}

/***************************************
 * API Functions for RandR version 1.2 *
 ***************************************/

/**
 * @brief Enable event selection. This enables basic interaction with
 * output/crtc events and requires RandR >= 1.2.
 *
 * @param win Select this window's properties for RandR events.
 * @param on Enable/disable selecting.
 */
EAPI void 
ecore_x_randr_events_select(Ecore_X_Window win, Eina_Bool on)
{
#ifdef ECORE_XRANDR
   int mask = 0;

   if (on)
     {
        mask = RRScreenChangeNotifyMask;
        if (_randr_version >= RANDR_VERSION_1_2)
          mask |= (RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | 
                   RROutputPropertyNotifyMask);
     }

   /* tell randr what events we want to listen to for this window */
   XRRSelectInput(_ecore_x_disp, win, mask);
#endif
}

/*
 * @param w width of screen in px
 * @param h height of screen in px
 */
EAPI void 
ecore_x_randr_screen_current_size_get(Ecore_X_Window root, int *w, int *h, int *w_mm, int *h_mm)
{
#ifdef ECORE_XRANDR
   if (_randr_version >= RANDR_VERSION_1_2)
     {
        int scr = 0;

        /* get the screen number */
        scr = XRRRootToScreen(_ecore_x_disp, root);

        if (w) *w = DisplayWidth(_ecore_x_disp, scr);
        if (h) *h = DisplayHeight(_ecore_x_disp, scr);
        if (w_mm) *w_mm = DisplayWidthMM(_ecore_x_disp, scr);
        if (h_mm) *h_mm = DisplayHeightMM(_ecore_x_disp, scr);
     }
#endif
}

/*
 * @param root window which's screen will be queried
 * @param wmin minimum width the screen can be set to
 * @param hmin minimum height the screen can be set to
 * @param wmax maximum width the screen can be set to
 * @param hmax maximum height the screen can be set to
 */
EAPI void 
ecore_x_randr_screen_size_range_get(Ecore_X_Window root, int *wmin, int *hmin, int *wmax, int *hmax)
{
#ifdef ECORE_XRANDR
   if (_randr_version >= RANDR_VERSION_1_2)
     {
        int swmin = 0, shmin = 0, swmax = 0, shmax = 0;

        /* try to get the screen size range from XRandr
         * 
         * NB: returns 1 on success */
        if ((XRRGetScreenSizeRange(_ecore_x_disp, root, &swmin, &shmin, 
                                   &swmax, &shmax)))
          {
             /* fill in the return variables */
             if (wmin) *wmin = swmin;
             if (hmin) *hmin = shmin;
             if (wmax) *wmax = swmax;
             if (hmax) *hmax = shmax;
          }
     }
#endif
}

/**
 * @brief removes unused screen space. The most upper left CRTC is set to 0x0
 * and all other CRTCs dx,dy respectively.
 * @param root the window's screen which will be reset.
 */
EAPI void 
ecore_x_randr_screen_reset(Ecore_X_Window root)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        if (res->ncrtc > 0)
          {
             Ecore_X_Randr_Crtc crtcs[res->ncrtc];
             int i = 0, nenabled = 0;
             int nw = 0, nh = 0;
             int dx = 100000, dy = 100000;

             for (i = 0; i < res->ncrtc; i++)
               {
                  XRRCrtcInfo *info = NULL;

                  /* try to get the crtc info from Xrandr */
                  if (!(info = XRRGetCrtcInfo(_ecore_x_disp, res, res->crtcs[i])))
                    continue;

                  /* safety check */
                  if ((info->mode <= 0) || (info->noutput == 0))
                    {
                       /* free the crtc info */
                       XRRFreeCrtcInfo(info);

                       continue;
                    }

                  crtcs[nenabled++] = res->crtcs[i];

                  if ((int)(info->x + info->width) > nw)
                    nw = (info->x + info->width);

                  if ((int)(info->y + info->height) > nh)
                    nh = (info->y + info->height);

                  if (info->x < dx) dx = info->x;
                  if (info->y < dy) dy = info->y;

                  /* free the crtc info */
                  XRRFreeCrtcInfo(info);
               }

             /* free the resources */
             XRRFreeScreenResources(res);

             if ((dx > 0) || (dy > 0))
               {
                  if (ecore_x_randr_move_crtcs(root, crtcs, nenabled, -dx, -dy))
                    {
                       nw -= dx;
                       nh -= dy;
                    }
               }

             ecore_x_randr_screen_current_size_set(root, nw, nh, -1, -1);
          }
     }
#endif
}

/*
 * @param root Window which's screen's size should be set. If invalid (e.g. 
 * @c NULL) no action is taken.
 * @param w Width in px the screen should be set to. If out of valid
 * boundaries, current value is assumed.
 * @param h Height in px the screen should be set to. If out of valid
 * boundaries, current value is assumed.
 * @param w_mm Width in mm the screen should be set to. If @c 0, current
 * aspect is assumed.
 * @param h_mm Height in mm the screen should be set to. If @c 0, current
 * aspect is assumed.
 * @return @c EINA_TRUE if request was successfully sent or screen is already
 * in requested size, @c EINA_FALSE if parameters are invalid.
 */
EAPI Eina_Bool 
ecore_x_randr_screen_current_size_set(Ecore_X_Window root, int w, int h, int w_mm, int h_mm)
{
#ifdef ECORE_XRANDR
   if (_randr_version >= RANDR_VERSION_1_2)
     {
        int cw = 0, ch = 0, cwmm = 0, chmm = 0;
        int wmin = 0, hmin = 0, wmax = 0, hmax = 0;

        /* get the current screen size */
        ecore_x_randr_screen_current_size_get(root, &cw, &ch, &cwmm, &chmm);

        /* compare to the values passed in. if there are no changes, get out */
        if ((w == cw) && (h == ch) &&
            ((w_mm == -1) || (w_mm == cwmm)) &&
            ((h_mm == -1) || (h_mm == chmm)))
          return EINA_TRUE;

        /* get the current size range */
        ecore_x_randr_screen_size_range_get(root, &wmin, &hmin, &wmax, &hmax);

        /* compare to the values passed in. make sure they are within range */
        if ((w != 0) && ((w < wmin) || (w > wmax))) return EINA_FALSE;
        if ((h != 0) && ((h < hmin) || (h > hmax))) return EINA_FALSE;

        /* safety check some values */
        if (w <= 0) w = cw;
        if (h <= 0) h = ch;
        if (w_mm <= 0)
          {
             if (cw > 0)
               w_mm = (int)(((double)(cwmm / (double)cw)) * (double)w);
             else
               w_mm = (int)(((double)(cwmm)) * (double)w);
          }
        if (h_mm <= 0)
          {
             if (ch > 0)
               h_mm = (int)(((double)(chmm / (double)ch)) * (double)h);
             else
               h_mm = (int)(((double)(chmm)) * (double)h);
          }

        /* tell XRandr to set screen size */
        XRRSetScreenSize(_ecore_x_disp, root, w, h, w_mm, h_mm);

        return EINA_TRUE;
     }
#endif
   return EINA_FALSE;
}

/*
 * @brief get detailed information for all modes related to a root window's screen
 * @param root window which's screen's resources are queried
 * @param num number of modes returned
 * @return modes' information
 */
EAPI Ecore_X_Randr_Mode_Info **
ecore_x_randr_modes_info_get(Ecore_X_Window root, int *num)
{
   if (num) *num = 0;
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        Ecore_X_Randr_Mode_Info **ret = NULL;

        /* set the returned number of modes */
        if (num) *num = res->nmode;

        /* if we did not get any modes from X, then cleanup and return */
        if (res->nmode == 0)
          {
             /* free the resources */
             XRRFreeScreenResources(res);

             return NULL;
          }

        /* try to allocate space for our return variable */
        if ((ret = (Ecore_X_Randr_Mode_Info **)
             malloc(res->nmode * sizeof(Ecore_X_Randr_Mode_Info *))))
          {
             int i = 0;

             /* loop through all the modes and assign to our return var */
             for (i = 0; i < res->nmode; i++)
               {
                  if ((ret[i] = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
                    {
                       ret[i]->xid = res->modes[i].id;
                       ret[i]->width = res->modes[i].width;
                       ret[i]->height = res->modes[i].height;
                       ret[i]->dotClock = res->modes[i].dotClock;
                       ret[i]->hSyncStart = res->modes[i].hSyncStart;
                       ret[i]->hSyncEnd = res->modes[i].hSyncEnd;
                       ret[i]->hTotal = res->modes[i].hTotal;
                       ret[i]->hSkew = res->modes[i].hSkew;
                       ret[i]->vSyncStart = res->modes[i].vSyncStart;
                       ret[i]->vSyncEnd = res->modes[i].vSyncEnd;
                       ret[i]->vTotal = res->modes[i].vTotal;
                       if (res->modes[i].nameLength > 0)
                         {
                            if ((ret[i]->name = 
                                 (malloc(res->modes[i].nameLength + 1))))
                              strncpy(ret[i]->name, res->modes[i].name,
                                      (res->modes[i].nameLength + 1));
                            else
                              ret[i]->name = NULL;
                         }
                       else
                         ret[i]->name = NULL;

                       ret[i]->nameLength = res->modes[i].nameLength;
                       ret[i]->modeFlags = res->modes[i].modeFlags;
                    }
                  else
                    {
                       while (i > 0)
                         free(ret[--i]);
                       free(ret);
                       ret = NULL;
                       break;
                    }
               }
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return NULL;
}

/*
 * @brief Add a mode to a display.
 *
 * @param root Window to which's screen's ressources are added.
 * @param mode_info
 * @return Ecore_X_Randr_Mode of the added mode. Ecore_X_Randr_None if mode
 * adding failed.
 * @since 1.2.0
 */
EAPI Ecore_X_Randr_Mode 
ecore_x_randr_mode_info_add(Ecore_X_Window root, Ecore_X_Randr_Mode_Info *mode_info)
{
#ifdef ECORE_XRANDR
   if (_randr_version >= RANDR_VERSION_1_2)
     {
        Ecore_X_Randr_Mode mode = 0;

        /* if we have valid mode_info from the user, then ask XRandr to 
         * create the new mode using that as base */
        if (mode_info)
          mode = XRRCreateMode(_ecore_x_disp, root, (XRRModeInfo *)mode_info);

        return mode;
     }
#endif
   return 0;
}

/*
 * @brief Delete a mode from the display.
 *
 * @param mode_info
 * @since 1.2.0
 */
EAPI void 
ecore_x_randr_mode_del(Ecore_X_Randr_Mode mode)
{
#ifdef ECORE_XRANDR
   if (_randr_version >= RANDR_VERSION_1_2)
     XRRDestroyMode(_ecore_x_disp, mode);
#endif
}

/*
 * @brief get detailed information for a given mode id
 * @param root window which's screen's ressources are queried
 * @param mode the XID which identifies the mode of interest
 * @return mode's detailed information
 */
EAPI Ecore_X_Randr_Mode_Info *
ecore_x_randr_mode_info_get(Ecore_X_Window root, Ecore_X_Randr_Mode mode)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        Ecore_X_Randr_Mode_Info *ret = NULL;
        int i = 0;

        if (res->nmode == 0)
          {
             /* free the resources */
             XRRFreeScreenResources(res);

             return NULL;
          }

        /* loop the mode informations and find the one we want */
        for (i = 0; i < res->nmode; i++)
          {
             /* compare mode ids */
             if (res->modes[i].id != mode) continue;

             /* try to allocate our return mode information structure */
             if (!(ret = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
               break;

             /* copy the mode information into our return structure */
             ret->xid = res->modes[i].id;
             ret->width = res->modes[i].width;
             ret->height = res->modes[i].height;
             ret->dotClock = res->modes[i].dotClock;
             ret->hSyncStart = res->modes[i].hSyncStart;
             ret->hSyncEnd = res->modes[i].hSyncEnd;
             ret->hTotal = res->modes[i].hTotal;
             ret->hSkew = res->modes[i].hSkew;
             ret->vSyncStart = res->modes[i].vSyncStart;
             ret->vSyncEnd = res->modes[i].vSyncEnd;
             ret->vTotal = res->modes[i].vTotal;
             ret->modeFlags = res->modes[i].modeFlags;
             ret->name = NULL;
             ret->nameLength = 0;
             if (res->modes[i].nameLength > 0)
               {
                  ret->nameLength = res->modes[i].nameLength;
                  if ((ret->name = malloc(res->modes[i].nameLength + 1)))
                    strncpy(ret->name, res->modes[i].name,
                            (res->modes[i].nameLength + 1));
               }
             break;
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return NULL;
}

/*
 * @brief Free detailed mode information. The pointer handed in will be set to
 * @c NULL after freeing the memory.
 *
 * @param mode_info The mode information that should be freed.
 */
EAPI void 
ecore_x_randr_mode_info_free(Ecore_X_Randr_Mode_Info *mode_info)
{
#ifdef ECORE_XRANDR
   if (_randr_version >= RANDR_VERSION_1_2)
     {
        if (mode_info)
          {
             if (mode_info->name) free(mode_info->name);
             free(mode_info);
          }
     }
#endif
}

/*
 * @brief Get all known CRTCs related to a root window's screen.
 *
 * @param root Window which's screen's ressources are queried.
 * @param num Number of CRTCs returned.
 * @return CRTC IDs.
 */
EAPI Ecore_X_Randr_Crtc *
ecore_x_randr_crtcs_get(Ecore_X_Window root, int *num)
{
   if (num) *num = 0;
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        Ecore_X_Randr_Crtc *ret = NULL;

        if (res->ncrtc == 0)
          {
             /* free the resources */
             XRRFreeScreenResources(res);

             return NULL;
          }

        /* try to allocate space for our return variable */
        if ((ret = malloc(res->ncrtc * sizeof(Ecore_X_Randr_Crtc))))
          {
             int i = 0;

             if (num) *num = res->ncrtc;

             /* copy the crtc information into our return variable */
             for (i = 0; i < res->ncrtc; i++)
               ret[i] = res->crtcs[i];
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return NULL;
}

EAPI Ecore_X_Randr_Output *
ecore_x_randr_outputs_get(Ecore_X_Window root, int *num)
{
   if (num) *num = 0;
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        Ecore_X_Randr_Output *ret = NULL;

        if (res->noutput == 0)
          {
             /* free the resources */
             XRRFreeScreenResources(res);

             return NULL;
          }

        /* try to allocate space for our return variable */
        if ((ret = malloc(res->noutput * sizeof(Ecore_X_Randr_Output))))
          {
             int i = 0;

             if (num) *num = res->noutput;

             /* copy the output information into our return variable */
             for (i = 0; i < res->noutput; i++)
               ret[i] = res->outputs[i];
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return NULL;
}

/*
 * @brief Get the outputs, which display a certain window.
 *
 * @param window Window the displaying outputs shall be found for
 * @param num The number of outputs displaying the window
 * @return Array of outputs that display a certain window. @c NULL if no
 * outputs was found that displays the specified window.
 */
EAPI Ecore_X_Randr_Output *
ecore_x_randr_window_outputs_get(Ecore_X_Window window, int *num)
{
   if (num) *num = 0;
#ifdef ECORE_XRANDR
   Ecore_X_Window root;
   Ecore_X_Randr_Crtc *crtcs = NULL;
   int ncrtcs = 0;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* grab this windows root window */
   root = ecore_x_window_root_get(window);

   /* get the crtcs from xrandr */
   if ((crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs)))
     {
        XRRScreenResources *res = NULL;
        Ecore_X_Randr_Output *ret = NULL;

        /* try to get the screen resources from Xrandr
         * 
         * NB: We do this ONCE here as we reuse it for every crtc.
         * NB: The old code used to loop and fetch the screen resources on 
         *     every crtc */
        if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
          {
             Ecore_X_Randr_Output *tret = NULL;
             int i = 0, nret = 0;

             /* for each crtc, get it's outputs */
             for (i = 0, nret = 0; i < ncrtcs; i++)
               {
                  XRRCrtcInfo *crtc = NULL;

                  /* try to get the crtc info for this crtc */
                  if (!(crtc = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i])))
                    continue;
                  
                  if (crtc->noutput > 0)
                    {
                       /* try to reallocate our return variable */
                       if ((tret = realloc(ret, ((nret + crtc->noutput) * 
                                                 sizeof(Ecore_X_Randr_Output)))))
                         {
                            ret = tret;
                            memcpy(&ret[nret], crtc->outputs, 
                                   (crtc->noutput * sizeof(Ecore_X_Randr_Output)));
                            nret += crtc->noutput;
                         }
                    }
                  /* free the crtc info */
                  XRRFreeCrtcInfo(crtc);
               }

             if (num) *num = nret;

             /* free the resources */
             XRRFreeScreenResources(res);
          }

        /* free any allocated crtcs from the get function */
        free(crtcs);

        return ret;
     }
#endif
   return NULL;
}

/*
 * @deprecated bad naming. Use ecore_x_randr_window_outputs_get instead.
 * @brief Get the outputs, which display a certain window.
 *
 * @param window Window the displaying outputs shall be found for.
 * @param num The number of outputs displaying the window.
 * @return Array of outputs that display a certain window. @c NULL if no
 * outputs was found that displays the specified window.
 */
EAPI Ecore_X_Randr_Output *
ecore_x_randr_current_output_get(Ecore_X_Window window, int *num)
{
   return ecore_x_randr_window_outputs_get(window, num);
}

/*
 * @brief get the CRTCs, which display a certain window
 * @param window window the displaying crtcs shall be found for
 * @param num the number of crtcs displaying the window
 * @return Array of crtcs that display a certain window. @c NULL if no crtcs
 * was found that displays the specified window.
 * @since 1.2.0
 */
EAPI Ecore_X_Randr_Crtc *
ecore_x_randr_window_crtcs_get(Ecore_X_Window window, int *num)
{
   if (num) *num = 0;
#ifdef ECORE_XRANDR
   Ecore_X_Window root;
   Ecore_X_Randr_Crtc *crtcs = NULL;
   int ncrtcs = 0;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* grab this windows root window */
   root = ecore_x_window_root_get(window);

   /* get the crtcs from xrandr */
   if ((crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs)))
     {
        XRRScreenResources *res = NULL;
        Ecore_X_Randr_Crtc *ret = NULL;

        if (ncrtcs < 1)
          {
             free(crtcs);
             return NULL;
          }

        /* make sure we can allocate our return variable */
        if (!(ret = calloc(1, ncrtcs * sizeof(Ecore_X_Randr_Crtc))))
          {
             free(crtcs);
             return NULL;
          }

        /* try to get the screen resources from Xrandr
         * 
         * NB: We do this ONCE here as we reuse it for every crtc.
         * NB: The old code used to loop and fetch the screen resources on 
         *     every crtc */
        if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
          {
             Window tw;
             Eina_Rectangle wrect, crect;
             int i = 0, nret = 0;

             /* get the geometry of this window */
             ecore_x_window_geometry_get(window, &wrect.x, &wrect.y, 
                                         &wrect.w, &wrect.h);

             /* translate coordinates relative to root window */
             XTranslateCoordinates(_ecore_x_disp, window, root, 
                                   0, 0, &wrect.x, &wrect.y, &tw);

             for (i = 0; i < ncrtcs; i++)
               {
                  XRRCrtcInfo *info = NULL;

                  /* try to get crtc info */
                  if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i])))
                    {
                       /* check if crtc is enabled */
                       if (info->mode != 0)
                         {
                            /* enabled. get geometry */
                            crect.x = info->x;
                            crect.y = info->y;
                            crect.w = info->width;
                            crect.h = info->height;

                            /* check intersection with window */
                            if (eina_rectangles_intersect(&wrect, &crect))
                              {
                                 /* add if intersect */
                                 ret[nret] = crtcs[i];
                                 nret++;
                              }
                         }

                       /* free the crtc info */
                       XRRFreeCrtcInfo(info);
                    }
               }

             /* free the resources */
             XRRFreeScreenResources(res);

             if (num) *num = nret;
          }

        free(crtcs);

        return ret;
     }
#endif
   return NULL;
}

/*
 * @deprecated bad naming. Use ecore_x_randr_window_crtcs_get instead.
 * @brief get the CRTCs, which display a certain window
 * @param window window the displaying crtcs shall be found for
 * @param num the number of crtcs displaying the window
 * @return Array of crtcs that display a certain window. @c NULL if no crtcs
 * was found that displays the specified window.
 */
EAPI Ecore_X_Randr_Crtc *
ecore_x_randr_current_crtc_get(Ecore_X_Window window, int *num)
{
   return ecore_x_randr_window_crtcs_get(window, num);
}

/*
 * @brief get a CRTC's outputs.
 * @param root the root window which's screen will be queried
 * @param num number of outputs referenced by given CRTC
 */
EAPI Ecore_X_Randr_Output *
ecore_x_randr_crtc_outputs_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *num)
{
   if (num) *num = 0;
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRCrtcInfo *info = NULL;
        Ecore_X_Randr_Output *ret = NULL;

        /* try to get crtc info */
        if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
          {
             /* if we have no outputs, return NULL */
             if (info->noutput == 0)
               {
                  /* free the crtc info */
                  XRRFreeCrtcInfo(info);

                  /* free the resources */
                  XRRFreeScreenResources(res);

                  return NULL;
               }

             /* try to allocate our return struct */
             if ((ret = malloc(info->noutput * sizeof(Ecore_X_Randr_Output))))
               {
                  int i = 0;

                  /* loop the outputs on this crtc */
                  for (i = 0; i < info->noutput; i++)
                    ret[i] = info->outputs[i];

                  if (num) *num = info->noutput;
               }

             /* free the crtc info */
             XRRFreeCrtcInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return NULL;
}

/*
 * @brief get a CRTC's possible outputs.
 * @param root the root window which's screen will be queried
 * @param num number of possible outputs referenced by given CRTC
 */
EAPI Ecore_X_Randr_Output *
ecore_x_randr_crtc_possible_outputs_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *num)
{
   if (num) *num = 0;
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRCrtcInfo *info = NULL;
        Ecore_X_Randr_Output *ret = NULL;

        /* try to get crtc info */
        if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
          {
             if (info->npossible == 0)
               {
                  /* free the crtc info */
                  XRRFreeCrtcInfo(info);

                  /* free the resources */
                  XRRFreeScreenResources(res);

                  return NULL;
               }

             /* try to allocate our return struct */
             if ((ret = malloc(info->npossible * sizeof(Ecore_X_Randr_Output))))
               {
                  int i = 0;

                  /* loop the outputs on this crtc */
                  for (i = 0; i < info->npossible; i++)
                    ret[i] = info->possible[i];

                  if (num) *num = info->npossible;
               }

             /* free the crtc info */
             XRRFreeCrtcInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return NULL;
}

EAPI void 
ecore_x_randr_crtc_geometry_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRCrtcInfo *info = NULL;

        /* try to get crtc info */
        if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
          {
             if (x) *x = info->x;
             if (y) *y = info->y;
             if (w) *w = info->width;
             if (h) *h = info->height;

             /* free the crtc info */
             XRRFreeCrtcInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);
     }
#endif
}

EAPI void 
ecore_x_randr_crtc_pos_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_2) return;

   ecore_x_randr_crtc_geometry_get(root, crtc, x, y, NULL, NULL);
#endif
}

/*
 * @brief Sets the position of given CRTC within root window's screen.
 *
 * @param root The window's screen to be queried.
 * @param crtc The CRTC which's position within the mentioned screen is to be
 * altered.
 * @param x Position on the x-axis (0 == left) of the screen. if x < 0 current
 * value will be kept.
 * @param y Position on the y-ayis (0 == top) of the screen. if y < 0, current
 * value will be kept.
 * @return @c EINA_TRUE if position could successfully be altered.
 */
EAPI Eina_Bool 
ecore_x_randr_crtc_pos_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int x, int y)
{
#ifdef ECORE_XRANDR
   int cx = 0, cy = 0, cw = 0, ch = 0;
   int sw = 0, sh = 0, nw = 0, nh = 0;

   if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;

   /* grab the current crtc geometry */
   ecore_x_randr_crtc_geometry_get(root, crtc, &cx, &cy, &cw, &ch);

   /* grab the current screen geometry */
   ecore_x_randr_screen_current_size_get(root, &sw, &sh, NULL, NULL);

   /* safety check some values */
   if (x < 0) x = cx;
   if (y < 0) y = cy;
   if ((x + cw) > sw) nw = (x + cw);
   if ((y + ch) > sh) nh = (y + ch);

   if ((nw > 0) && (nh > 0))
     {
        /* try to update the current screen geometry */
        if (!ecore_x_randr_screen_current_size_set(root, nw, nh, 0, 0))
          return EINA_FALSE;
     }

   /* try to set the new crtc position */
   return ecore_x_randr_crtc_settings_set(root, crtc, NULL, -1, x, y, -1, -1);
#endif
   return EINA_FALSE;
}

/**
 * @brief Get the current set mode of a given CRTC
 * @param root the window's screen to be queried
 * @param crtc the CRTC which's should be queried
 * @return currently set mode or - in case parameters are invalid -
 * Ecore_X_Randr_Unset
 */
EAPI Ecore_X_Randr_Mode 
ecore_x_randr_crtc_mode_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return -1;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRCrtcInfo *info = NULL;
        Ecore_X_Randr_Mode ret = -1;

        /* try to get crtc info */
        if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
          {
             /* get the mode */
             ret = info->mode;

             /* free the crtc info */
             XRRFreeCrtcInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return -1;
}

/**
 * @brief Sets a mode for a CRTC and the outputs attached to it.
 *
 * @param root The window's screen to be queried.
 * @param crtc The CRTC which shall be set.
 * @param outputs Array of outputs which have to be compatible with the mode.
 * If @c NULL, CRTC will be disabled.
 * @param noutputs Number of outputs in array to be used. Use
 * Ecore_X_Randr_Unset (or @c -1) to use currently used outputs.
 * @param mode XID of the mode to be set. If set to @c 0 the CRTC will be
 * disabled. If set to @c -1 the call will fail.
 * @return @c EINA_TRUE if mode setting was successful, @c EINA_FALSE
 * otherwise.
 */
EAPI Eina_Bool 
ecore_x_randr_crtc_mode_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, Ecore_X_Randr_Output *outputs, int noutputs, Ecore_X_Randr_Mode mode)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;

   return ecore_x_randr_crtc_settings_set(root, crtc, outputs, noutputs, 
                                          -1, -1, mode, -1);
#endif
   return EINA_FALSE;
}

EAPI void 
ecore_x_randr_crtc_size_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *w, int *h)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_2) return;
   ecore_x_randr_crtc_geometry_get(root, crtc, NULL, NULL, w, h);
#endif
}

EAPI Ecore_X_Randr_Refresh_Rate 
ecore_x_randr_crtc_refresh_rate_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc EINA_UNUSED, Ecore_X_Randr_Mode mode)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return 0.0;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        int i = 0;
        double ret = 0.0;

        for (i = 0; i < res->nmode; i++)
          {
             if (res->modes[i].id == mode)
               {
                  if ((res->modes[i].hTotal) && (res->modes[i].vTotal))
                    {
                       ret = ((double)res->modes[i].dotClock /
                              ((double)res->modes[i].hTotal *
                                  (double)res->modes[i].vTotal));
                    }
                  break;
               }
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return 0.0;
}

EAPI Ecore_X_Randr_Orientation 
ecore_x_randr_crtc_orientations_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return 0;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRCrtcInfo *info = NULL;
        Ecore_X_Randr_Orientation ret = 0;

        /* try to get crtc info */
        if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
          {
             /* get the mode */
             ret = info->rotations;

             /* free the crtc info */
             XRRFreeCrtcInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return 0;
}

EAPI Ecore_X_Randr_Orientation 
ecore_x_randr_crtc_orientation_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return 0;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRCrtcInfo *info = NULL;
        Ecore_X_Randr_Orientation ret = 0;

        /* try to get crtc info */
        if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
          {
             /* get the mode */
             ret = info->rotation;

             /* free the crtc info */
             XRRFreeCrtcInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return 0;
}

EAPI Eina_Bool 
ecore_x_randr_crtc_orientation_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, const Ecore_X_Randr_Orientation orientation)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;

   if (orientation != 0)
     return ecore_x_randr_crtc_settings_set(root, crtc, NULL, 
                                            -1, -1, -1, -1, orientation);
#endif
   return EINA_FALSE;
}

EAPI Eina_Bool 
ecore_x_randr_crtc_clone_set(Ecore_X_Window root, Ecore_X_Randr_Crtc original, Ecore_X_Randr_Crtc cln)
{
#ifdef ECORE_XRANDR
   Eina_Bool ret = EINA_FALSE;
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRCrtcInfo *info = NULL;
        Ecore_X_Randr_Orientation orig_orient = 0;
        Ecore_X_Randr_Mode orig_mode = -1;
        int ox = 0, oy = 0;

        /* try to get crtc info for original crtc */
        if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, original)))
          {
             ox = info->x;
             oy = info->y;
             orig_orient = info->rotation;
             orig_mode = info->mode;

             /* free the crtc info */
             XRRFreeCrtcInfo(info);
          }

        ret = ecore_x_randr_crtc_settings_set(root, cln, NULL, -1, ox, oy, 
                                              orig_mode, orig_orient);

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return EINA_FALSE;
}

/**
 * @brief Sets the demanded parameters for a given CRTC. Note that the CRTC is
 * auto enabled in it's preferred mode, when it was disabled before.
 *
 * @param root The root window which's default display will be queried.
 * @param crtc The CRTC which's configuration should be altered.
 * @param outputs An array of outputs, that should display this CRTC's content.
 * @param noutputs Number of outputs in the array of outputs. If set to
 * Ecore_X_Randr_Unset, current outputs and number of outputs will be used.
 * If set to Ecore_X_Randr_None, CRTC will be disabled.
 * @param x New x coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current x
 * corrdinate will be assumed.
 * @param y New y coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current y
 * corrdinate will be assumed.
 * @param mode The new mode to be set. If Ecore_X_Randr_None is passed, the
 * CRTC will be disabled. If Ecore_X_Randr_Unset is passed, the current mode is
 * assumed.
 * @param orientation The new orientation to be set. If Ecore_X_Randr_Unset is
 * used, the current mode is assumed.
 * @return @c EINA_TRUE if the configuration alteration was successful,
 * @c EINA_FALSE otherwise.
 */
EAPI Eina_Bool 
ecore_x_randr_crtc_settings_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, Ecore_X_Randr_Output *outputs, int noutputs, int x, int y, Ecore_X_Randr_Mode mode, Ecore_X_Randr_Orientation orientation)
{
#ifdef ECORE_XRANDR
   Eina_Bool ret = EINA_FALSE;
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        RRCrtc rcrtc;
        RROutput *routputs = NULL;
        XRRCrtcInfo *info = NULL;
        Eina_Bool need_free = EINA_FALSE;
        int i = 0;

        rcrtc = (RRCrtc)crtc;

        /* try to get crtc info for original crtc */
        if (!(info = XRRGetCrtcInfo(_ecore_x_disp, res, rcrtc)))
          {
             /* free the resources */
             XRRFreeScreenResources(res);
             return EINA_FALSE;
          }

        if ((int)mode == -1) mode = info->mode;
        if ((int)orientation == -1) orientation = info->rotation;
        if (x < 0) x = info->x;
        if (y < 0) y = info->y;

        if (noutputs < 0)
          {
             noutputs = info->noutput;
             if (noutputs > 0)
               {
                  routputs = malloc(noutputs * sizeof(RROutput));
                  for (i = 0; i < noutputs; i++)
                    routputs[i] = info->outputs[i];
                  need_free = EINA_TRUE;
               }
          }
        else if (noutputs > 0)
          {
             routputs = malloc(noutputs * sizeof(RROutput));
             for (i = 0; i < noutputs; i++)
               routputs[i] = (RROutput)outputs[i];
             need_free = EINA_TRUE;
          }

        /* try to set the crtc config */
        if (!XRRSetCrtcConfig(_ecore_x_disp, res, rcrtc, CurrentTime, 
                              x, y, mode, orientation, 
                              routputs, noutputs))
          ret = EINA_TRUE;

        if (need_free) free(routputs);

        /* free the crtc info */
        XRRFreeCrtcInfo(info);

        /* free the resources */
        XRRFreeScreenResources(res);
     }

   return ret;
#endif
   return EINA_FALSE;
}

/**
 * @brief Sets a CRTC relative to another one.
 *
 * @param root The root window which's default display will be set.
 * @param crtc_r1 The CRTC to be positioned.
 * @param crtc_r2 The CRTC the position should be relative to.
 * @param policy The relation between the crtcs.
 * @param alignment In case CRTCs size differ, aligns CRTC1 accordingly at
 * CRTC2's borders.
 * @return @c EINA_TRUE if crtc could be successfully positioned, @c EINA_FALSE
 * if repositioning failed or if position of new crtc would be out of given
 * screen's min/max bounds.
 */
EAPI Eina_Bool 
ecore_x_randr_crtc_pos_relative_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc_r1, Ecore_X_Randr_Crtc crtc_r2, Ecore_X_Randr_Output_Policy policy, Ecore_X_Randr_Relative_Alignment alignment)
{
#ifdef ECORE_XRANDR
   Eina_Rectangle r1, r2;
   int mw = 0, mh = 0, sw = 0, sh = 0;
   int nx = 0, ny = 0;

   if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;

   /* check each crtc has a valid mode */
   if (ecore_x_randr_crtc_mode_get(root, crtc_r1) == 0) return EINA_FALSE;
   if (ecore_x_randr_crtc_mode_get(root, crtc_r2) == 0) return EINA_FALSE;

   /* get the geometry of each crtc */
   ecore_x_randr_crtc_geometry_get(root, crtc_r1, &r1.x, &r1.y, &r1.w, &r1.h);
   ecore_x_randr_crtc_geometry_get(root, crtc_r2, &r2.x, &r2.y, &r2.w, &r2.h);

   /* get the geometry of the screen */
   ecore_x_randr_screen_size_range_get(root, NULL, NULL, &mw, &mh);
   ecore_x_randr_screen_current_size_get(root, &sw, &sh, NULL, NULL);

   switch (policy)
     {
      case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT:
        nx = (r2.x + r2.w);

        switch (alignment)
          {
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
             ny = -1;
             break;
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
             ny = ((int)(((double)r2.h / 2.0) + r2.y - ((double)r1.h / 2.0)));
             break;
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
             ny = ((int)((double)sh / 2.0) - ((double)r1.h / 2.0));
             break;
          }

        break;
      case ECORE_X_RANDR_OUTPUT_POLICY_LEFT:
        nx = (r2.x - r1.w);

        switch (alignment)
          {
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
             ny = -1;
             break;
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
             ny = ((int)(((double)r2.h / 2.0) + r2.y - ((double)r1.h / 2.0)));
             break;
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
             ny = ((int)((double)sh / 2.0) - ((double)r1.h / 2.0));
             break;
          }

        break;
      case ECORE_X_RANDR_OUTPUT_POLICY_BELOW:
        ny = (r2.y + r2.h);

        switch (alignment)
          {
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
             nx = -1;
             break;
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
             nx = ((int)((((double)r2.x + (double)r2.w) / 2.0) - 
                         ((double)r1.w / 2.0)));
             break;
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
             nx = ((int)((double)sw / 2.0));
             break;
          }

        break;
      case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE:
        ny = (r2.y - r1.h);

        switch (alignment)
          {
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
             nx = -1;
             break;
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
             nx = ((int)((((double)r2.x + (double)r2.w) / 2.0) - 
                         ((double)r1.w / 2.0)));
             break;
           case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
             nx = ((int)((double)sw / 2.0));
             break;
          }

        break;
      case ECORE_X_RANDR_OUTPUT_POLICY_CLONE:
        return ecore_x_randr_crtc_pos_set(root, crtc_r1, r2.x, r2.y);
        break;
      case ECORE_X_RANDR_OUTPUT_POLICY_NONE:
        break;
      default:
        return EINA_FALSE;
     }

   if ((nx == r1.x) && (ny == r1.y)) return EINA_TRUE;
   if (((ny + r1.h) > mh) || ((nx + r1.w) > mw)) return EINA_FALSE;

   return ecore_x_randr_crtc_pos_set(root, crtc_r1, nx, ny);
#else
   return EINA_FALSE;
#endif
}

/*
 * @since 1.8
 */
EAPI Ecore_X_Randr_Crtc_Info *
ecore_x_randr_crtc_info_get(Ecore_X_Window root, const Ecore_X_Randr_Crtc crtc)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRCrtcInfo *info = NULL;
        Ecore_X_Randr_Crtc_Info *ret = NULL;

        /* try to get crtc info */
        if ((info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
          {
             if ((ret = malloc(sizeof(Ecore_X_Randr_Crtc_Info))))
               {
                  /* copy the mode information into our return structure */
                  ret->timestamp = info->timestamp;
                  ret->x = info->x;
                  ret->y = info->y;
                  ret->width = info->width;
                  ret->height = info->height;
                  ret->mode = info->mode;
                  ret->rotation = info->rotation;
                  ret->rotations = info->rotations;
                  ret->noutput = info->noutput;
                  ret->npossible = info->npossible;

                  ret->outputs = NULL;
                  ret->possible = NULL;

                  if (info->noutput > 0)
                    {
                       if ((ret->outputs = 
                            malloc(info->noutput * sizeof(Ecore_X_Randr_Output))))
                         {
                            int i = 0;

                            /* loop the outputs on this crtc */
                            for (i = 0; i < info->noutput; i++)
                              ret->outputs[i] = info->outputs[i];
                         }
                    }

                  if (info->npossible > 0)
                    {
                       if ((ret->possible = 
                            malloc(info->npossible * sizeof(Ecore_X_Randr_Output))))
                         {
                            int i = 0;

                            /* loop the outputs on this crtc */
                            for (i = 0; i < info->npossible; i++)
                              ret->possible[i] = info->possible[i];
                         }
                    }
               }

             /* free the crtc info */
             XRRFreeCrtcInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return NULL;
}

/*
 * @since 1.8
 */
EAPI void 
ecore_x_randr_crtc_info_free(Ecore_X_Randr_Crtc_Info *info)
{
#ifdef ECORE_XRANDR
   if (_randr_version >= RANDR_VERSION_1_2)
     {
        if (info)
          {
             if (info->outputs) free(info->outputs);
             if (info->possible) free(info->possible);
             free(info);
          }
     }
#endif
}

/*
 * @brief Add given mode to given output.
 *
 * @param output The output the mode is added to.
 * @param mode The mode added to the output.
 * @return @c EINA_FALSE if output or mode equal Ecore_X_Randr_None, else
 * @c EINA_TRUE.
 * @since 1.2.0
 */
EAPI Eina_Bool 
ecore_x_randr_output_mode_add(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;

   if ((output) && (mode))
     {
        /* add this mode to output
         * 
         * NB: This XRR function returns void so we have to assume it worked */
        XRRAddOutputMode(_ecore_x_disp, output, mode);

        return EINA_TRUE;
     }
#endif
   return EINA_FALSE;
}

/*
 * @brief delete given mode from given output
 * @param output the output the mode is removed from
 * @param mode the mode removed from the output
 * @since 1.2.0
 */
EAPI void 
ecore_x_randr_output_mode_del(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_2) return;

   if ((!output) || (!mode)) return;

   XRRDeleteOutputMode(_ecore_x_disp, output, mode);
#endif
}

EAPI Ecore_X_Randr_Mode *
ecore_x_randr_output_modes_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num, int *npreferred)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRROutputInfo *info = NULL;
        Ecore_X_Randr_Mode *modes = NULL;

        /* try to get output info */
        if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
          {
             if (num) *num = info->nmode;
             if (npreferred) *npreferred = info->npreferred;

             if (info->nmode > 0)
               {
                  if ((modes = malloc(info->nmode * sizeof(Ecore_X_Randr_Mode))))
                    {
                       int i = 0;

                       for (i = 0; i < info->nmode; i++)
                         modes[i] = info->modes[i];
                    }
               }

             /* free the output info */
             XRRFreeOutputInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return modes;
     }
#endif
   return NULL;
}

/**
 * @brief gets the the outputs which might be used simultenously on the same
 * CRTC.
 * @param root window that this information should be queried for.
 * @param output the output which's clones we concern
 * @param num number of possible clones
 */
EAPI Ecore_X_Randr_Output *
ecore_x_randr_output_clones_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRROutputInfo *info = NULL;
        Ecore_X_Randr_Output *outputs = NULL;

        /* try to get output info */
        if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
          {
             if (num) *num = info->nclone;

             if (info->nclone > 0)
               {
                  /* try to allocate space for output return */
                  if ((outputs = malloc(info->nclone * sizeof(Ecore_X_Randr_Output))))
                    {
                       int i = 0;

                       for (i = 0; i < info->nclone; i++)
                         outputs[i] = info->clones[i];
                    }
               }

             /* free the output info */
             XRRFreeOutputInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return outputs;
     }
#endif
   return NULL;
}

EAPI Ecore_X_Randr_Crtc *
ecore_x_randr_output_possible_crtcs_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return 0;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRROutputInfo *info = NULL;
        Ecore_X_Randr_Crtc *crtcs = NULL;

        /* try to get output info */
        if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
          {
             if (num) *num = info->ncrtc;

             if (info->ncrtc > 0)
               {
                  /* try to allocate space for the return crtcs */
                  if ((crtcs = malloc(info->ncrtc * sizeof(Ecore_X_Randr_Crtc))))
                    {
                       int i = 0;

                       for (i = 0; i < info->ncrtc; i++)
                         crtcs[i] = info->crtcs[i];
                    }
               }

             /* free the output info */
             XRRFreeOutputInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return crtcs;
     }
#endif
   return NULL;
}

EAPI Ecore_X_Randr_Crtc 
ecore_x_randr_output_crtc_get(Ecore_X_Window root, Ecore_X_Randr_Output output)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return 0;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRROutputInfo *info = NULL;
        Ecore_X_Randr_Crtc ret = 0;

        /* try to get output info */
        if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
          {
             ret = info->crtc;

             /* free the output info */
             XRRFreeOutputInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return 0;
}

/**
 * @brief gets the given output's name as reported by X
 * @param root the window which's screen will be queried
 * @param output The output for which the name will be reported.
 * @param len length of returned c-string.
 * @return name of the output as reported by X
 */
EAPI char *
ecore_x_randr_output_name_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *len)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return 0;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRROutputInfo *info = NULL;
        char *ret = NULL;

        /* try to get output info */
        if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
          {
             if (info->name)
               {
                  size_t s;
#ifdef XRANDR_GOOD
                  s = info->nameLen;
#else
                  /* pre 1.4.0 does not fill in info->nameLen */
                  s = strlen(info->name);
#endif
                  ret = malloc(s + 1);
                  memcpy(ret, info->name, s);
                  ret[s] = 0;
                  if (len) *len = s;
               }

             /* free the output info */
             XRRFreeOutputInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return NULL;
}

/*
 * @deprecated use ecore_x_randr_crtc_gamma_size_get()
 */
EINA_DEPRECATED EAPI int 
ecore_x_randr_crtc_gamma_ramp_size_get(Ecore_X_Randr_Crtc crtc EINA_UNUSED)
{
   return 0;
}

/*
 * @deprecated use ecore_x_randr_crtc_gamma_get()
 */
EINA_DEPRECATED EAPI Ecore_X_Randr_Crtc_Gamma **
ecore_x_randr_crtc_gamma_ramps_get(Ecore_X_Randr_Crtc crtc EINA_UNUSED)
{
   return NULL;
}

/*
 * @deprecated use ecore_x_randr_crtc_gamma_set()
 */
EINA_DEPRECATED EAPI Eina_Bool 
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)
{
   return EINA_FALSE;
}

/*
 * @since 1.8
 */
EAPI int 
ecore_x_randr_crtc_gamma_size_get(Ecore_X_Randr_Crtc crtc)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_2) return 0;
   return XRRGetCrtcGammaSize(_ecore_x_disp, crtc);
#else
   (void)crtc;
#endif
   return 0;
}

/*
 * @since 1.8
 */
EAPI Ecore_X_Randr_Crtc_Gamma_Info *
ecore_x_randr_crtc_gamma_get(Ecore_X_Randr_Crtc crtc)
{
#ifdef ECORE_XRANDR
   Ecore_X_Randr_Crtc_Gamma_Info *info = NULL;
   XRRCrtcGamma *xgamma = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the gamma for this crtc from Xrandr */
   if (!(xgamma = XRRGetCrtcGamma(_ecore_x_disp, crtc)))
     return NULL;

   /* try to allocate space for the return struct and copy the results in */
   if ((info = malloc(sizeof(Ecore_X_Randr_Crtc_Gamma_Info))))
     memcpy(info, xgamma, sizeof(Ecore_X_Randr_Crtc_Gamma_Info));

   /* free the returned gamma resource */
   XRRFreeGamma(xgamma);

   return info;
#else
   (void)crtc;
#endif
   return NULL;
}

/*
 * @since 1.8
 */
EAPI Eina_Bool 
ecore_x_randr_crtc_gamma_set(Ecore_X_Randr_Crtc crtc, const Ecore_X_Randr_Crtc_Gamma_Info *gamma)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;

   /* try to set the gamma
    * 
    * NB: XRRSetCrtcGamma returns void
    */
   XRRSetCrtcGamma(_ecore_x_disp, crtc, (XRRCrtcGamma *)gamma);
   return EINA_TRUE;
#else
   (void)crtc;
   (void)gamma;
#endif
   return EINA_FALSE;
}

EAPI Eina_Bool 
ecore_x_randr_move_all_crtcs_but(Ecore_X_Window root, const Ecore_X_Randr_Crtc *not_moved, int nnot_moved, int dx, int dy)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;
   Eina_Bool ret = EINA_FALSE;

   if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;

   if ((nnot_moved <= 0) || (!not_moved)) return EINA_FALSE;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        Ecore_X_Randr_Crtc *crtcs = NULL;
        int n = 0;

        n = (res->ncrtc - nnot_moved);
        if (n > 0)
          {
             /* try to allocate space for a list of crtcs */
             if ((crtcs = malloc(n * sizeof(Ecore_X_Randr_Crtc))))
               {
                  int i = 0, j = 0, k = 0;

                  for (i = 0, k = 0; (i < res->ncrtc) && (k < n); i++)
                    {
                       for (j = 0; j < nnot_moved; j++)
                         {
                            if (res->crtcs[i] == not_moved[j])
                              break;
                         }

                       if (j == nnot_moved) crtcs[k++] = res->crtcs[i];
                    }
               }
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        /* actually move the crtcs */
        if (crtcs)
          {
             ret = ecore_x_randr_move_crtcs(root, crtcs, n, dx, dy);
             free(crtcs);
          }

        return ret;
     }
#endif
   return EINA_FALSE;
}

/*
 * @brief Move given CRTCs belonging to the given root window's screen dx/dy
 * pixels relative to their current position. The screen size will be
 * automatically adjusted if necessary and possible.
 *
 * @param root Window which's screen's resources are used.
 * @param crtcs List of CRTCs to be moved.
 * @param ncrtc Number of CRTCs in array.
 * @param dx Amount of pixels the CRTCs should be moved in x direction.
 * @param dy Amount of pixels the CRTCs should be moved in y direction.
 * @return @c EINA_TRUE if all crtcs could be moved successfully.
 */
EAPI Eina_Bool 
ecore_x_randr_move_crtcs(Ecore_X_Window root, const Ecore_X_Randr_Crtc *crtcs, int ncrtc, int dx, int dy)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;
   XRRCrtcInfo **info = NULL;
   int i = 0;

   if (_randr_version < RANDR_VERSION_1_2) return EINA_FALSE;

   if (ncrtc < 1) return EINA_FALSE;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        Eina_Bool ret = EINA_TRUE;
        int mw = 0, mh = 0, sw = 0, sh = 0;
        int nw = 0, nh = 0;

        info = alloca(ncrtc * sizeof(XRRCrtcInfo *));
        memset(info, 0, ncrtc * sizeof(XRRCrtcInfo *));

        ecore_x_randr_screen_size_range_get(root, NULL, NULL, &mw, &mh);
        ecore_x_randr_screen_current_size_get(root, &sw, &sh, NULL, NULL);
        nw = sw;
        nh = sh;

        for (i = 0; i < ncrtc; i++)
          {
             /* try to get crtc info for original crtc */
             if ((info[i] = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i])))
               {
                  if (((info[i]->x + dx) < 0) || ((info[i]->y + dy < 0)) || 
                      ((int)(info[i]->x + info[i]->width) > mw) || 
                      ((int)(info[i]->y + info[i]->height) > mh))
                    {
                       goto err;
                    }

                  nw = MAX(((int)(info[i]->x + info[i]->width) + dx), nw);
                  nh = MAX(((int)(info[i]->y + info[i]->height) + dy), nh);
               }
          }

        /* resize the screen if we need to */
        if (!(((nw > sw) || (nh > sh)) || 
              ecore_x_randr_screen_current_size_set(root, nw, nh, -1, -1)))
          goto err;

        /* actually move the crtcs */
        for (i = 0; ((i < ncrtc) && info[i]); i++)
          {
             if (!ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, -1, 
                                                  (info[i]->x + dx), 
                                                  (info[i]->y + dy), 
                                                  info[i]->mode, 
                                                  info[i]->rotation))
               {
                  ret = EINA_FALSE;
                  break;
               }
          }

        if (i < ncrtc)
          {
             /* something went wrong somewhere. move everything back */
             while ((--i) >= 0)
               {
                  if (info[i])
                    ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, -1, 
                                                    (info[i]->x - dx), 
                                                    (info[i]->y - dy), 
                                                    info[i]->mode, 
                                                    info[i]->rotation);
               }
          }

        /* cleanup */
        for (i = 0; i < ncrtc; i++)
          if (info[i]) XRRFreeCrtcInfo(info[i]);

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }

err:
   while (i-- > 0)
     {
        /* free the crtc info */
        if (info[i]) XRRFreeCrtcInfo(info[i]);
     }

   /* free the resources */
   if (res) XRRFreeScreenResources(res);
#endif
   return EINA_FALSE;
}

/**
 * @brief gets the width and hight of a given mode
 * @param mode the mode whose size is to be looked up
 * @param w width of given mode in px
 * @param h height of given mode in px
 */
EAPI void 
ecore_x_randr_mode_size_get(Ecore_X_Window root, Ecore_X_Randr_Mode mode, int *w, int *h)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_2) return;

   if ((mode != 0) && ((w) || (h)))
     {
        XRRScreenResources *res = NULL;

        /* try to get the screen resources from Xrandr */
        if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
          {
             int i = 0;

             for (i = 0; i < res->nmode; i++)
               {
                  if (res->modes[i].id == mode)
                    {
                       if (w) *w = res->modes[i].width;
                       if (h) *h = res->modes[i].height;
                       break;
                    }
               }

             /* free the resources */
             XRRFreeScreenResources(res);
          }
     }
#endif
}

EAPI Ecore_X_Randr_Connection_Status 
ecore_x_randr_output_connection_status_get(Ecore_X_Window root, Ecore_X_Randr_Output output)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) 
     return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRROutputInfo *info = NULL;
        Ecore_X_Randr_Connection_Status ret = 
          ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;

        /* try to get output info */
        if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
          {
             ret = info->connection;

             /* free the output info */
             XRRFreeOutputInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
}

EAPI void 
ecore_x_randr_output_size_mm_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *w, int *h)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) return;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRROutputInfo *info = NULL;

        /* try to get output info */
        if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
          {
             if (w) *w = info->mm_width;
             if (h) *h = info->mm_height;

             /* free the output info */
             XRRFreeOutputInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);
     }
#endif
}

EAPI Eina_Bool 
ecore_x_randr_output_crtc_set(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output EINA_UNUSED, const Ecore_X_Randr_Crtc crtc EINA_UNUSED)
{
   /* TODO: !! */
   return EINA_FALSE;
}

EAPI Eina_Bool 
ecore_x_randr_output_backlight_available(void)
{
#ifdef ECORE_XRANDR
   Atom backlight = None;

   /* check for new backlight property */
   if ((backlight = XInternAtom(_ecore_x_disp, RR_PROPERTY_BACKLIGHT, True)))
     return EINA_TRUE;

   /* check for legacy backlight property */
   if ((backlight = XInternAtom(_ecore_x_disp, "BACKLIGHT", True)))
     return EINA_TRUE;
#endif
   return EINA_FALSE;
}

/**
 * @brief Set up the backlight level to the given level.
 *
 * @param root The window's screen which will be set.
 * @param level Of the backlight between @c 0 and @c 1.
 */
EAPI void 
ecore_x_randr_screen_backlight_level_set(Ecore_X_Window root, double level)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;
   int i = 0;

   if (_randr_version < RANDR_VERSION_1_3) return;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        /* set the backlight level on each output */
        for (i = 0; i < res->noutput; i++)
          ecore_x_randr_output_backlight_level_set(root, res->outputs[i], level);

        /* free the resources */
        XRRFreeScreenResources(res);
     }
#endif
}

EAPI double 
ecore_x_randr_output_backlight_level_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output)
{
#ifdef ECORE_XRANDR
   XRRPropertyInfo *info = NULL;
   Atom backlight = None, type = None;
   unsigned long bytes = 0;
   unsigned long items = 0;
   unsigned char *prop = NULL;
   long val = 0;
   int format = 0;

   /* check if "new" backlight is available */
   if (_randr_version >= RANDR_VERSION_1_3)
     {
        if ((backlight = 
             XInternAtom(_ecore_x_disp, RR_PROPERTY_BACKLIGHT, True)))
          {
             XRRGetOutputProperty(_ecore_x_disp, output, backlight, 0, 4, 
                                  False, False, None, &type, &format, 
                                  &items, &bytes, &prop);
          }
     }

   if ((!prop) || (items == 0))
     {
        /* check legacy backlight property
         * 
         * FIXME: NB: Not sure what randr version we need for the legacy 
         * backlight property so skip version check */
        if ((backlight = XInternAtom(_ecore_x_disp, "BACKLIGHT", True)))
          {
             free(prop);
             prop = NULL;
             XRRGetOutputProperty(_ecore_x_disp, output, backlight, 0, 4, 
                                  False, False, None, &type, &format, 
                                  &items, &bytes, &prop);
          }
     }

   /* safety check */
   if ((!prop) || (type != XA_INTEGER) || (items != 1) || (format != 32))
     {
        free(prop);
        WRN("Backlight property is not supported on this server or driver");
        return -1;
     }

   val = *((long *)prop);
   free(prop);

   /* try to get the backlight property value from Xrandr */
   if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, backlight)))
     {
        double ret = -1;

        if ((info->range) && (info->num_values == 2))
          {
             /* convert the current value */
             ret = ((double)(val - info->values[0])) / 
               ((double)(info->values[1] - info->values[0]));
          }

        /* free the info */
        free(info);

        return ret;
     }
#endif
   return -1;
}

EAPI Eina_Bool 
ecore_x_randr_output_backlight_level_set(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, double level)
{
#ifdef ECORE_XRANDR
   XRRPropertyInfo *info = NULL;
   Atom backlight = None;

   /* safety check some input values */
   if ((level < 0) || (level > 1))
     {
        ERR("Backlight level should be between 0 and 1");
        return EINA_FALSE;
     }

   /* check if "new" backlight is available */
   if (_randr_version >= RANDR_VERSION_1_3)
     backlight = XInternAtom(_ecore_x_disp, RR_PROPERTY_BACKLIGHT, True);

   if (!backlight)
     backlight = XInternAtom(_ecore_x_disp, "BACKLIGHT", True);

   if (!backlight)
     {
        WRN("Backlight property is not supported on this server or driver");
        return EINA_FALSE;
     }

   /* try to get the output property from Xrandr */
   if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, backlight)))
     {
        Eina_Bool ret = EINA_FALSE;

        if ((info->range) && (info->num_values == 2))
          {
             double min = 0.0, max = 0.0;
             long val = 0;

             min = info->values[0];
             max = info->values[1];
             val = (level * (max - min)) + min;
             if (val > max) val = max;
             if (val < min) val = min;

             /* tell xrandr to change the backlight value */
             XRRChangeOutputProperty(_ecore_x_disp, output, backlight, 
                                     XA_INTEGER, 32, PropModeReplace, 
                                     (unsigned char *)&val, 1);

             /* send changes to X */
             ecore_x_flush();

             ret = EINA_TRUE;
          }

        /* free the info */
        free(info);

        return ret;
     }
#endif
   return EINA_FALSE;
}

/**
 * @brief gets the EDID information of an attached output if available.
 * Note that this information is not to be compared using ordinary string
 * comparison functions, since it includes 0-bytes.
 * @param root window this information should be queried from
 * @param output the XID of the output
 * @param length length of the byte-array. If NULL, request will fail.
 */
EAPI unsigned char *
ecore_x_randr_output_edid_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, unsigned long *length)
{
#ifdef ECORE_XRANDR
   Atom edid = None, type = None;
   unsigned char *prop = NULL;
   int format = 0;
   unsigned long nitems = 0, bytes = 0;

   if (_randr_version < RANDR_VERSION_1_2) return NULL;

   /* try to get the edid atom */
   if (!(edid = XInternAtom(_ecore_x_disp, RR_PROPERTY_RANDR_EDID, False))) 
     return NULL;

   /* get the output property
    * 
    * NB: Returns 0 on success */
   if (!XRRGetOutputProperty(_ecore_x_disp, output, edid, 0, 128, False, False,
                            AnyPropertyType, &type, &format, &nitems, 
                            &bytes, &prop))
     {
        if ((type == XA_INTEGER) && (nitems >= 1) && (format == 8))
          {
             unsigned char *ret = NULL;

             if ((ret = malloc(nitems * sizeof(unsigned char))))
               {
                  if (length) *length = nitems;
                  memcpy(ret, prop, (nitems * sizeof(unsigned char)));
                  free(prop);
                  return ret;
               }
          }
     }
   free(prop);
#endif
   return NULL;
}

EAPI Ecore_X_Render_Subpixel_Order 
ecore_x_randr_output_subpixel_order_get(Ecore_X_Window root, Ecore_X_Randr_Output output)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_2) 
     return ECORE_X_RENDER_SUBPIXEL_ORDER_UNKNOWN;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRROutputInfo *info = NULL;
        Ecore_X_Render_Subpixel_Order ret = 0;

        /* try to get output info */
        if ((info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
          {
             ret = info->subpixel_order;

             /* free the output info */
             XRRFreeOutputInfo(info);
          }

        /* free the resources */
        XRRFreeScreenResources(res);

        return ret;
     }
#endif
   return ECORE_X_RENDER_SUBPIXEL_ORDER_UNKNOWN;
}

/***************************************
 * API Functions for RandR version 1.3 *
 ***************************************/

EAPI Ecore_X_Randr_Output *
ecore_x_randr_output_wired_clones_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, int *num)
{
#ifdef ECORE_XRANDR
   Atom clones = None, type = None;
   unsigned char *prop = NULL;
   int format = 0;
   unsigned long nitems = 0, bytes = 0;

   /* NB: FIXME: 
    * 
    * I am not sure that this code is correct. This needs checking 
    */

   if (_randr_version < RANDR_VERSION_1_3) return NULL;

   /* try to get the edid atom */
   if (!(clones = XInternAtom(_ecore_x_disp, RR_PROPERTY_CLONE_LIST, True)))
     return NULL;

   /* get the output property
    * 
    * NB: Returns 0 on success */
   if (!XRRGetOutputProperty(_ecore_x_disp, output, clones, 0, 100, False, False, 
                            AnyPropertyType, &type, &format, &nitems, 
                            &bytes, &prop))
     {
        if ((type == XA_ATOM) && (nitems >= 1) && (format == 32))
          {
             Ecore_X_Randr_Output *ret = NULL;

             if ((ret = malloc(nitems * sizeof(Ecore_X_Randr_Output))))
               {
                  if (num) *num = nitems;
                  memcpy(ret, prop, (nitems * sizeof(Ecore_X_Randr_Output)));
                  free(prop);
                  return ret;
               }
          }
     }
   free(prop);
#endif
   return NULL;
}

EAPI Ecore_X_Randr_Output **
ecore_x_randr_output_compatibility_list_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output EINA_UNUSED, int *num EINA_UNUSED)
{
   /* TODO: (1.3) !! */
   //RR_PROPERTY_COMPATIBILITY_LIST
   return NULL;
}

EAPI Ecore_X_Randr_Signal_Format *
ecore_x_randr_output_signal_formats_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, int *num)
{
#ifdef ECORE_XRANDR
   XRRPropertyInfo *info = NULL;
   Atom sig, type;
   unsigned long bytes = 0;
   unsigned long items = 0;
   unsigned char *prop = NULL;
   int format = 0;

   if (_randr_version < RANDR_VERSION_1_3) return NULL;

   /* try to get the connector number atom */
   if (!(sig = XInternAtom(_ecore_x_disp, RR_PROPERTY_SIGNAL_FORMAT, True)))
     return NULL;

   /* try to get the output property from Xrandr
    * 
    * NB: Returns 0 on success */
   if (XRRGetOutputProperty(_ecore_x_disp, output, sig, 0, 100, 
                            False, False, AnyPropertyType, &type, &format, 
                            &items, &bytes, &prop))
     {
        free(prop);
        printf("Signal Format property not supported.\n");
        return NULL;
     }

   free(prop);

   /* safety check */
   if ((type != XA_ATOM) || (items < 1) || (format != 32))
     return NULL;

   /* try to get the output property from Xrandr */
   if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, sig)))
     {
        Ecore_X_Randr_Signal_Format *formats = NULL;

        if (num) *num = info->num_values;

        if (info->num_values > 0)
          {
             if ((formats = 
                  malloc(info->num_values * sizeof(Ecore_X_Randr_Signal_Format))))
               {
                  memcpy(formats, info->values, 
                         (info->num_values * sizeof(Ecore_X_Randr_Signal_Format)));
               }
          }

        /* free the info */
        free(info);

        return formats;
     }
#endif
   return NULL;
}

EAPI Eina_Bool 
ecore_x_randr_output_signal_format_set(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output EINA_UNUSED, Ecore_X_Randr_Signal_Format *sig EINA_UNUSED)
{
   /* TODO: (1.3) !! */
   //RR_PROPERTY_SIGNAL_FORMAT
   return EINA_FALSE;
}

EAPI Ecore_X_Randr_Signal_Property *
ecore_x_randr_output_signal_properties_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output, int *num)
{
#ifdef ECORE_XRANDR
   XRRPropertyInfo *info = NULL;
   Atom sig, type;
   unsigned long bytes = 0;
   unsigned long items = 0;
   unsigned char *prop = NULL;
   int format = 0;

   if (_randr_version < RANDR_VERSION_1_3) return NULL;

   /* try to get the connector number atom */
   if (!(sig = XInternAtom(_ecore_x_disp, RR_PROPERTY_SIGNAL_PROPERTIES, True)))
     return NULL;

   /* try to get the output property from Xrandr
    * 
    * NB: Returns 0 on success */
   if (XRRGetOutputProperty(_ecore_x_disp, output, sig, 0, 100, 
                            False, False, AnyPropertyType, &type, &format, 
                            &items, &bytes, &prop))
     {
        free(prop);
        printf("Signal Properties property not supported.\n");
        return NULL;
     }

   free(prop);

   /* safety check */
   if ((type != XA_ATOM) || (items < 1) || (format != 32))
     return NULL;

   /* try to get the output property from Xrandr */
   if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, sig)))
     {
        Ecore_X_Randr_Signal_Property *props = NULL;

        if (num) *num = info->num_values;

        if (info->num_values > 0)
          {
             if ((props = 
                  malloc(info->num_values * sizeof(Ecore_X_Randr_Signal_Property))))
               {
                  memcpy(props, info->values, 
                         (info->num_values * sizeof(Ecore_X_Randr_Signal_Property)));
               }
          }

        /* free the info */
        free(info);

        return props;
     }
#endif
   return NULL;
}

/* TODO NB:
 * 
 * Document this.
 * 
 * Returns: 
 * 0 == unknown
 * 1 == primary
 * 2 == secondary
 * 3 == (typically) TV Connector but is driver/hardware dependent
 * 
 */
EAPI int 
ecore_x_randr_output_connector_number_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output)
{
#ifdef ECORE_XRANDR
   XRRPropertyInfo *info = NULL;
   Atom type;
   unsigned long bytes = 0;
   unsigned long items = 0;
   unsigned char *prop = NULL;
   int val = 0, format = 0;

   if (_randr_version < RANDR_VERSION_1_3) return -1;

   /* try to get the output property from Xrandr
    * 
    * NB: Returns 0 on success */
   if (XRRGetOutputProperty(_ecore_x_disp, output, connector_number, 0, 100, 
                            False, False, AnyPropertyType, &type, &format, 
                            &items, &bytes, &prop))
     {
        free(prop);
        printf("ConnectionNumber property not supported.\n");
        return -1;
     }

   /* safety check */
   if ((type != XA_INTEGER) || (items != 1) || (format != 32))
     {
        free(prop);
        return -1;
     }

   val = *((int *)prop);
   free(prop);

   /* try to get the output property from Xrandr */
   if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, connector_number)))
     {
        int ret = 0;

        /* convert the current value */
        ret = (int)(val - info->values[0]);

        /* free the info */
        free(info);

        return ret;
     }
#endif
   return -1;
}

EAPI Ecore_X_Randr_Connector_Type 
ecore_x_randr_output_connector_type_get(Ecore_X_Window root EINA_UNUSED, Ecore_X_Randr_Output output)
{
#ifdef ECORE_XRANDR
   XRRPropertyInfo *info = NULL;
   Atom type;
   unsigned long bytes = 0;
   unsigned long items = 0;
   unsigned char *prop = NULL;
   int val = 0, format = 0;

   if (_randr_version < RANDR_VERSION_1_3) return -1;

   /* try to get the connector type atom */
   if (XRRGetOutputProperty(_ecore_x_disp, output, connector_type, 0, 100, 
                        False, False, AnyPropertyType, &type, &format, 
                        &items, &bytes, &prop) != Success)
     {
        free(prop);
        return -1;
     }

   if ((!prop) || (items == 0))
     {
        Atom conn;

        free(prop);
        /* NB: some butthead drivers (*cough* nouveau *cough*) do not 
         * implement randr properly. They are not using the connector type 
         * property of randr, but rather a "subconnector" property */
        if ((conn = XInternAtom(_ecore_x_disp, "subconnector", True)))
          XRRGetOutputProperty(_ecore_x_disp, output, conn, 0, 4, 
                               False, False, AnyPropertyType, &type, 
                               &format, &items, &bytes, &prop);
     }

   if ((!prop) || (items == 0))
     {
        free(prop);
        WRN("ConnectorType Property not supported.");
        return -1;
     }

   /* safety check */
   if ((type != XA_ATOM) || (items != 1) || (format != 32))
     return -1;

   val = *((int *)prop);
   free(prop);

   /* try to get the output property from Xrandr */
   if ((info = XRRQueryOutputProperty(_ecore_x_disp, output, connector_type)))
     {
        int ret = 0;

        /* convert the current value */
        ret = (int)(val - info->values[0]);

        /* printf("\tReturn Value: %d\n", ret); */
        /* printf("\t\tActual Name: %s\n",  */
        /*        XGetAtomName(_ecore_x_disp, ((Atom)info->values[ret]))); */

        /* free the info */
        free(info);

        return ret;
     }
#endif
   return -1;
}

EAPI Ecore_X_Randr_Output 
ecore_x_randr_primary_output_get(Ecore_X_Window root)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_3) return 0;
   return XRRGetOutputPrimary(_ecore_x_disp, root);
#else
   return 0;
#endif
}

EAPI void 
ecore_x_randr_primary_output_set(Ecore_X_Window root, Ecore_X_Randr_Output output)
{
#ifdef ECORE_XRANDR
   if (_randr_version < RANDR_VERSION_1_3) return;
   XRRSetOutputPrimary(_ecore_x_disp, root, output);
#endif
}

/***************************************
 * API Functions for RandR version 1.4 *
 ***************************************/

EAPI void 
ecore_x_randr_crtc_panning_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_4) return;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRPanning *xpan = NULL;

        /* get this crtc's panning */
        if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
          {
             if (x) *x = xpan->left;
             if (y) *y = xpan->top;
             if (w) *w = xpan->width;
             if (h) *h = xpan->height;

             /* free the panning resource */
             XRRFreePanning(xpan);
          }
        /* free the resources */
        XRRFreeScreenResources(res);
     }
#endif
}

EAPI Eina_Bool 
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)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;
   Eina_Bool ret = EINA_FALSE;

   if (_randr_version < RANDR_VERSION_1_4) return EINA_FALSE;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRPanning *xpan = NULL;

        /* get this crtc's panning */
        if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
          {
             xpan->left = x;
             xpan->top = y;
             xpan->width = w;
             xpan->height = h;
             xpan->timestamp = CurrentTime;

             /* set the panning value */
             if (!XRRSetPanning(_ecore_x_disp, res, crtc, xpan))
               ret = EINA_TRUE;

             /* free the panning resource */
             XRRFreePanning(xpan);
          }

        /* free the resources */
        XRRFreeScreenResources(res);
     }

   return ret;
#else
   return EINA_FALSE;
#endif
}

EAPI void 
ecore_x_randr_crtc_tracking_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_4) return;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRPanning *xpan = NULL;

        /* get this crtc's panning */
        if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
          {
             if (x) *x = xpan->track_left;
             if (y) *y = xpan->track_top;
             if (w) *w = xpan->track_width;
             if (h) *h = xpan->track_height;

             /* free the panning resource */
             XRRFreePanning(xpan);
          }
        /* free the resources */
        XRRFreeScreenResources(res);
     }
#endif
}

EAPI Eina_Bool 
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)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;
   Eina_Bool ret = EINA_FALSE;

   if (_randr_version < RANDR_VERSION_1_4) return EINA_FALSE;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRPanning *xpan = NULL;

        /* get this crtc's panning */
        if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
          {
             xpan->track_left = x;
             xpan->track_top = y;
             xpan->track_width = w;
             xpan->track_height = h;
             xpan->timestamp = CurrentTime;

             /* set the panning value */
             if (!XRRSetPanning(_ecore_x_disp, res, crtc, xpan))
               ret = EINA_TRUE;

             /* free the panning resource */
             XRRFreePanning(xpan);
          }

        /* free the resources */
        XRRFreeScreenResources(res);
     }

   return ret;
#else
   return EINA_FALSE;
#endif
}

EAPI void 
ecore_x_randr_crtc_border_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;

   if (_randr_version < RANDR_VERSION_1_4) return;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRPanning *xpan = NULL;

        /* get this crtc's panning */
        if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
          {
             if (x) *x = xpan->border_left;
             if (y) *y = xpan->border_top;
             if (w) *w = xpan->border_right;
             if (h) *h = xpan->border_bottom;

             /* free the panning resource */
             XRRFreePanning(xpan);
          }
        /* free the resources */
        XRRFreeScreenResources(res);
     }
#endif
}

EAPI Eina_Bool 
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)
{
#ifdef ECORE_XRANDR
   XRRScreenResources *res = NULL;
   Eina_Bool ret = EINA_FALSE;

   if (_randr_version < RANDR_VERSION_1_4) return EINA_FALSE;

   /* try to get the screen resources from Xrandr */
   if ((res = _ecore_x_randr_screen_resources_get(_ecore_x_disp, root)))
     {
        XRRPanning *xpan = NULL;

        /* get this crtc's panning */
        if ((xpan = XRRGetPanning(_ecore_x_disp, res, crtc)))
          {
             xpan->border_left = left;
             xpan->border_top = top;
             xpan->border_right = right;
             xpan->border_bottom = bottom;
             xpan->timestamp = CurrentTime;

             /* set the panning value */
             if (!XRRSetPanning(_ecore_x_disp, res, crtc, xpan))
               ret = EINA_TRUE;

             /* free the panning resource */
             XRRFreePanning(xpan);
          }

        /* free the resources */
        XRRFreeScreenResources(res);
     }

   return ret;
#else
   return EINA_FALSE;
#endif
}

/***************************************
 * API Functions for RandR Edid
 ***************************************/

EAPI Eina_Bool 
ecore_x_randr_edid_has_valid_header(unsigned char *edid, unsigned long edid_length)
{
   const unsigned char header[] =
     { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };

   if (!edid) return EINA_FALSE;
   if (edid_length < 8) return EINA_FALSE;
   if (!memcmp(edid, header, 8)) return EINA_TRUE;
   return EINA_FALSE;
}

EAPI Eina_Bool 
ecore_x_randr_edid_info_has_valid_checksum(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   unsigned char *iter = NULL;
   char sum = 0;
   int i = 0, version = 0;

   if (edid_length < 128) return EINA_FALSE;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;

   for (i = 0; i < 128; i++)
     sum += edid[i];

   if (sum) return EINA_FALSE;

   /* check extension blocks */
   for (iter = edid; iter < (edid + edid_length); iter += 128)
     {
        if (iter[0] == 0x02)
          {
             for (i = 0, sum = 0; i < 128; i++)
               sum += iter[i];
          }
     }

   if (sum) return EINA_FALSE;
   return EINA_TRUE;
#else
   return EINA_FALSE;
#endif
}

EAPI int 
ecore_x_randr_edid_version_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   if ((edid_length > RANDR_EDID_VERSION_MINOR) && 
       (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
     {
        return (edid[RANDR_EDID_VERSION_MAJOR] << 8) | 
          edid[RANDR_EDID_VERSION_MINOR];
     }

   return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
#else
   return 0;
#endif
}

EAPI char *
ecore_x_randr_edid_manufacturer_name_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   if ((edid_length > RANDR_EDID_MANUFACTURER + 1) && 
       (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
     {
        unsigned char *x;
        char *name;

        if (!(name = malloc(sizeof(char) * 4))) return NULL;

        x = (edid + RANDR_EDID_MANUFACTURER);
        name[0] = ((x[0] & 0x7c) >> 2) + '@';
        name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xe0) >> 5) + '@';
        name[2] = (x[1] & 0x1f) + '@';
        name[3] = 0;

        return name;
     }
#endif
   return NULL;
}

EAPI char *
ecore_x_randr_edid_display_name_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   unsigned char *block = NULL;
   int version = 0;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) return NULL;

   for (block = (edid + RANDR_EDID_BLOCK); 
        block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18)
     {
        if ((block[0] == 0) && (block[1] == 0))
          {
             if (block[3] == 0xfc)
               {
                  char *name, *p;
                  const char *edid_name;

                  edid_name = (const char *)block + 5;
                  if (!(name = malloc(14))) return NULL;
                  strncpy(name, edid_name, 13);
                  name[13] = 0;

                  for (p = name; *p; p++)
                    if ((*p < ' ') || (*p > '~')) *p = 0;

                  return name;
               }
          }
     }
#endif
   return NULL;
}

EAPI char *
ecore_x_randr_edid_display_ascii_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   unsigned char *block = NULL;
   int version = 0;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) return NULL;

   for (block = (edid + RANDR_EDID_BLOCK); 
        block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18)
     {
        if ((block[0] == 0) && (block[1] == 0))
          {
             if (block[3] == 0xfe)
               {
                  char *ascii = NULL, *p = NULL;
                  const char *edid_ascii;

                  edid_ascii = (const char *)block + 5;

                  if (!(ascii = malloc(14))) return NULL;
                  strncpy(ascii, edid_ascii, 13);
                  ascii[13] = 0;
                  for (p = ascii; *p; p++)
                    if ((*p < ' ') || (*p > '~')) *p = 0;

                  return ascii;
               }
          }
     }
#endif
   return NULL;
}

EAPI char *
ecore_x_randr_edid_display_serial_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   unsigned char *block = NULL;
   int version = 0;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) return NULL;

   for (block = (edid + RANDR_EDID_BLOCK); 
        block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18)
     {
        if ((block[0] == 0) && (block[1] == 0))
          {
             if (block[3] == 0xff)
               {
                  char *serial = NULL, *p = NULL;
                  const char *edid_serial;

                  edid_serial = (const char *)block + 5;

                  if (!(serial = malloc(14))) return NULL;
                  strncpy(serial, edid_serial, 13);
                  serial[13] = 0;
                  for (p = serial; *p; p++)
                    if ((*p < ' ') || (*p > '~')) *p = 0;

                  return serial;
               }
          }
     }
#endif
   return NULL;
}

EAPI int 
ecore_x_randr_edid_model_get(unsigned char *edid, unsigned long edid_length)
{
   return ecore_x_randr_edid_manufacturer_model_get(edid, edid_length);
}

EAPI int 
ecore_x_randr_edid_manufacturer_serial_number_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   if ((edid_length > RANDR_EDID_MANUFACTURER + 1) && 
       (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
     return (int)(edid[0x0c] + (edid[0x0d] << 8) + 
                  (edid[0x0e] << 16) + (edid[0x0f] << 24));

   return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
#else
   return 0;
#endif
}

EAPI int 
ecore_x_randr_edid_manufacturer_model_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   if ((edid_length > RANDR_EDID_MANUFACTURER + 1) && 
       (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
     return (int)(edid[0x0a] + (edid[0x0b] << 8));
#endif
   return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
}

EAPI Eina_Bool 
ecore_x_randr_edid_dpms_available_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   int version = 0;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;

   return !!(edid[0x18] & 0xE0);
#else
   return EINA_FALSE;
#endif
}

EAPI Eina_Bool 
ecore_x_randr_edid_dpms_standby_available_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   int version = 0;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;

   if (edid[0x18] & 0xE0) return !!(edid[0x18] & 0x80);
#endif
   return EINA_FALSE;
}

EAPI Eina_Bool 
ecore_x_randr_edid_dpms_suspend_available_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   int version = 0;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;

   if (edid[0x18] & 0xE0) return !!(edid[0x18] & 0x40);
#endif
   return EINA_FALSE;
}

EAPI Eina_Bool 
ecore_x_randr_edid_dpms_off_available_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   int version = 0;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;

   if (edid[0x18] & 0xE0) return !!(edid[0x18] & 0x20);
#endif
   return EINA_FALSE;
}

EAPI Ecore_X_Randr_Edid_Aspect_Ratio 
ecore_x_randr_edid_display_aspect_ratio_preferred_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   unsigned char *block = NULL;
   int version = 0;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) 
     return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;

   for (block = (edid + RANDR_EDID_BLOCK); 
        block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18)
     {
        if ((block[0] == 0) && (block[1] == 0))
          {
             if ((block[3] == 0xfd) && (block[10] == 0x04))
               {
                  Ecore_X_Randr_Edid_Aspect_Ratio_Preferred ratio = 
                    (Ecore_X_Randr_Edid_Aspect_Ratio_Preferred)((block[15] & 0xe0) >> 5);

                  switch (ratio)
                    {
                     case RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3:
                       return ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3;
                     case RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9:
                       return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9;
                     case RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10:
                       return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10;
                     case RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4:
                       return ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4;
                     case RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9:
                       return ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9;
                     default:
                       return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
                    }
               }
          }
     }

   return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
#else
   return 0;
#endif
}

EAPI Ecore_X_Randr_Edid_Aspect_Ratio 
ecore_x_randr_edid_display_aspect_ratios_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   Ecore_X_Randr_Edid_Aspect_Ratio ret;
   unsigned char *block = NULL;
   int version = 0;

   ret = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) 
     return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;

   for (block = (edid + RANDR_EDID_BLOCK); 
        block <= (edid + RANDR_EDID_BLOCK + (3 * 18)); block += 18)
     {
        if ((block[0] == 0) && (block[1] == 0))
          {
             if ((block[3] == 0xfd) && (block[10] == 0x04))
               {
                  if (block[14] & 0x80)
                    ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3;
                  if (block[14] & 0x40)
                    ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9;
                  if (block[14] & 0x20)
                    ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10;
                  if (block[14] & 0x10)
                    ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4;
                  if (block[14] & 0x08)
                    ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9;
               }
          }
     }

   return ret;
#else
   return 0;
#endif
}

EAPI Ecore_X_Randr_Edid_Display_Colorscheme 
ecore_x_randr_edid_display_colorscheme_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   Ecore_X_Randr_Edid_Display_Colorscheme ret;
   int version = 0;

   ret = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) 
     return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;

   if (ecore_x_randr_edid_display_type_digital_get(edid, edid_length))
     {
        ret = ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_4_4_4;
        if (edid[0x18] & 0x10)
          ret |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_4_4;
        if (edid[0x18] & 0x08)
          ret |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_2_2;
     }
   else
     ret = (edid[0x18] & 0x18);

   return ret;
#else
   return 0;
#endif
}

EAPI Eina_Bool 
ecore_x_randr_edid_display_type_digital_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   int version = 0;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) return EINA_FALSE;

   return !!(edid[0x14] & 0x80);
#else
   return EINA_FALSE;
#endif
}

EAPI Ecore_X_Randr_Edid_Display_Interface_Type 
ecore_x_randr_edid_display_interface_type_get(unsigned char *edid, unsigned long edid_length)
{
#ifdef ECORE_XRANDR
   Ecore_X_Randr_Edid_Display_Interface_Type type;
   int version = 0;

   type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;

   version = ecore_x_randr_edid_version_get(edid, edid_length);
   if (version < RANDR_EDID_VERSION_1_3) 
     return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;

   type = (edid[0x14] & 0x0f);
   if (type > ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT)
     type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;

   return type;
#else
   return 0;
#endif
}