adf9be8addc84cae08ccae0734ca67b3f5210772
[framework/uifw/e17.git] / src / bin / e_randr.c
1 /*
2  * vim:ts=8:sw=3:sts=8:expandtab:cino=>5n-3f0^-2{2
3  */
4 #include "e.h"
5
6 #define ECORE_X_RANDR_1_1 ((1 << 16) | 1)
7 #define ECORE_X_RANDR_1_2 ((1 << 16) | 2)
8 #define ECORE_X_RANDR_1_3 ((1 << 16) | 3)
9
10 #define Ecore_X_Randr_None   0
11 #define Ecore_X_Randr_Unset -1
12
13 /*
14  * TODO:
15  * -fix output policies above and left
16  */
17
18 //following macro namescheme follows cardinal relation
19 //1 : M
20 #define E_RANDR_NO_SCREEN_RET(ret) if (!e_randr_screen_info) return ret
21 #define E_RANDR_NO_11_RET(ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_1) || !e_randr_screen_info->rrvd_info.randr_info_11) return ret
22 #define E_RANDR_NO_12_RET(ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12) return ret
23 #define E_RANDR_NO_CRTCS_RET(ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs) return ret
24 #define E_RANDR_NO_OUTPUTS_RET(ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->outputs) return ret
25 #define E_RANDR_NO_CRTC_RET(crtc, ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc) return ret
26 #define E_RANDR_NO_OUTPUT_RET(output, ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output) return ret
27 #define E_RANDR_NO_MODE_RET(mode, ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->modes || !mode) return ret
28 #define E_RANDR_NO_CRTC_OUTPUT_RET(crtc, output, ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output) return ret
29 #define E_RANDR_NO_CRTC_OUTPUT_MODE_RET(crtc, output, mode, ret) if (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output || !e_randr_screen_info->rrvd_info.randr_info_12->modes || !mode) return ret
30
31 #define E_RANDR_NO_11 (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_1) || !e_randr_screen_info->rrvd_info.randr_info_11)
32 #define E_RANDR_NO_12 (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12)
33 #define E_RANDR_NO_CRTCS (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs)
34 #define E_RANDR_NO_OUTPUTS (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->outputs)
35 #define E_RANDR_NO_MODES (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->modes)
36 #define E_RANDR_NO_CRTC(crtc) (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc)
37 #define E_RANDR_NO_OUTPUT(output) (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output)
38 #define E_RANDR_NO_CRTC_OUTPUT(crtc, output) (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output)
39 #define E_RANDR_NO_CRTC_OUTPUT_MODE(crtc, output, mode) (!e_randr_screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2) || !e_randr_screen_info->rrvd_info.randr_info_12 || !e_randr_screen_info->rrvd_info.randr_info_12->crtcs || !crtc || !e_randr_screen_info->rrvd_info.randr_info_12->outputs || !output || !e_randr_screen_info->rrvd_info.randr_info_12->modes || !mode)
40
41 static Eina_Bool _e_randr_init(void);
42 static void _e_randr_shutdown(void);
43 static void _e_randr_event_listeners_add(void);
44 static void _e_randr_event_listeners_remove(void);
45 static Eina_Bool _e_randr_event_cb(void *data, int type, void *e);
46 static E_Randr_Screen_Info *_e_randr_screen_info_new(void);
47 static void _e_randr_screen_info_free(E_Randr_Screen_Info *screen_info);
48 static E_Randr_Screen_Info_11 *_e_randr_screen_info_11_new(void);
49 static Eina_Bool _e_randr_screen_info_11_set(void);
50 static void _e_randr_screen_info_11_free(E_Randr_Screen_Info_11 *screen_info_11);
51 static E_Randr_Screen_Info_12 *_e_randr_screen_info_12_new(void);
52 static Eina_Bool _e_randr_screen_info_12_set(E_Randr_Screen_Info_12 *screen_info_12);
53 static void _e_randr_screen_info_12_free(E_Randr_Screen_Info_12 *screen_info_12);
54 static E_Randr_Output_Info *_e_randr_output_info_new(int nrequested);
55 static void _e_randr_output_info_free(E_Randr_Output_Info *output_info);
56 static E_Randr_Crtc_Info *_e_randr_crtc_info_new(int nrequested);
57 static void _e_randr_crtc_info_free(E_Randr_Crtc_Info *crtc_info);
58 static Eina_Bool _e_randr_screen_outputs_init(void);
59 static Eina_Bool _e_randr_screen_crtcs_init(void);
60 static Eina_Bool _e_randr_output_modes_add(E_Randr_Output_Info *output_info);
61 static void _e_randr_notify_crtc_mode_change(E_Randr_Crtc_Info *crtc_info);
62 static void _e_randr_notify_output_change(E_Randr_Output_Info *output_info);
63 static Ecore_X_Randr_Mode_Info *_e_randr_mode_info_get(Ecore_X_Randr_Mode mode);
64 static E_Randr_Crtc_Info *_e_randr_crtc_info_get(Ecore_X_Randr_Crtc crtc);
65 static E_Randr_Output_Info *_e_randr_output_info_get(Ecore_X_Randr_Output output);
66 static void _e_randr_output_info_set(E_Randr_Output_Info *output_info);
67 static void _e_randr_crtc_info_set(E_Randr_Crtc_Info *crtc_info);
68 static const E_Randr_Crtc_Info *_e_randr_policy_crtc_get(E_Randr_Crtc_Info* but, E_Randr_Crtc_Info *hint, Ecore_X_Randr_Output_Policy policy);
69 //static Eina_Bool _e_randr_outputs_connected(Eina_List *outputs_info);
70 static Ecore_X_Randr_Output *_e_randr_outputs_to_array(Eina_List *outputs_info);
71 //static int _e_randr_config_find_suiting_config_11(E_Randr_Screen_Restore_Info_11** restore_info);
72 static E_Randr_Screen_Restore_Info_12 * _e_randr_config_find_suiting_config_12(void);
73 //static Eina_Bool _e_randr_config_enable_11(int size_index, Ecore_X_Randr_Refresh_Rate refresh_rate, Ecore_X_Randr_Orientation orientation);
74 //static Eina_Bool _e_randr_config_enable_12(const E_Randr_Screen_Restore_Info_12 *restore_info);
75 static Eina_Bool _e_randr_try_enable_output(E_Randr_Output_Info *output_info, Eina_Bool force);
76 static void _e_randr_crtcs_possible_output_update(E_Randr_Output_Info *output_info);
77 static void _e_randr_crtc_outputs_refs_update(E_Randr_Crtc_Info *crtc_info);
78 static Eina_Bool _e_randr_crtc_move_policy(E_Randr_Crtc_Info *new_crtc);
79 //static int _crtcs_size_sort_cb(const void *d1, const void *d2);
80 static int _outputs_size_sort_cb(const void *d1, const void *d2);
81 static int _modes_size_sort_cb(const void *d1, const void *d2);
82 static Eina_List *_e_randr_outputs_common_modes_get(Eina_List *outputs, Ecore_X_Randr_Mode_Info *max_size_mode);
83 static Ecore_X_Randr_Mode_Info *_e_randr_outputs_common_mode_max_get(Eina_List *outputs, Ecore_X_Randr_Mode_Info *max_size_mode);
84 static Ecore_X_Randr_Mode_Info *_e_randr_mode_geo_identical_find(Eina_List *modes, Ecore_X_Randr_Mode_Info *mode);
85 static Eina_Bool _e_randr_crtc_mode_intersects_crtcs(E_Randr_Crtc_Info *crtc_info, Ecore_X_Randr_Mode_Info *mode);
86 static Eina_Bool _e_randr_crtc_outputs_mode_max_set(E_Randr_Crtc_Info *crtc_info);
87 static Eina_Bool _e_randr_crtcs_clone_crtc_removed(E_Randr_Crtc_Info *former_clone);
88 static void _e_randr_screen_primary_output_assign(E_Randr_Output_Info *removed);
89 static void _e_randr_output_info_hw_info_set(E_Randr_Output_Info *output_info);
90 static void _e_randr_output_hw_info_free(E_Randr_Output_Info *output_info);
91 static Eina_Bool _e_randr_outputs_are_clones(E_Randr_Output_Info *output_info, Eina_List *outputs);
92
93 E_Randr_Screen_Info *e_randr_screen_info = NULL;
94 static Eina_List *_e_randr_event_handlers = NULL;
95
96 EINTERN Eina_Bool
97 e_randr_init(void)
98 {
99    return _e_randr_init();
100 }
101
102 EINTERN int
103 e_randr_shutdown(void)
104 {
105    _e_randr_shutdown();
106    return 1;
107 }
108
109 static Eina_Bool
110 _e_randr_init(void)
111 {
112    int n;
113    Ecore_X_Window *roots;
114    Ecore_X_Window root;
115
116    if(!(roots = ecore_x_window_root_list(&n))) return EINA_FALSE;
117    /* first (and only) root window */
118    root = roots[0];
119    free(roots);
120
121    if (!ecore_x_randr_query() || !(e_randr_screen_info = _e_randr_screen_info_new())) 
122      goto ecore_x_randr_init_fail_free_screen;
123
124    if ((e_randr_screen_info->randr_version = ecore_x_randr_version_get())) 
125      e_randr_screen_info->root = root;
126    if (e_randr_screen_info->randr_version == ECORE_X_RANDR_1_1)
127      {
128         if (!(e_randr_screen_info->rrvd_info.randr_info_11 = _e_randr_screen_info_11_new())) 
129           goto ecore_x_randr_init_fail_free_screen;
130         _e_randr_screen_info_11_set();
131         //_e_randr_config_find_and_enable();
132         return EINA_TRUE;
133      }
134    else if (e_randr_screen_info->randr_version >= ECORE_X_RANDR_1_2)
135      {
136         if (!(e_randr_screen_info->rrvd_info.randr_info_12 =  _e_randr_screen_info_12_new())) 
137           goto ecore_x_randr_init_fail_free_screen;
138         _e_randr_screen_info_12_set(e_randr_screen_info->rrvd_info.randr_info_12);
139         _e_randr_event_listeners_add();
140         if (!_e_randr_screen_outputs_init()) 
141           goto ecore_x_randr_init_fail_free_screen;
142         if (!_e_randr_screen_crtcs_init()) 
143           goto ecore_x_randr_init_fail_free_screen;
144         _e_randr_screen_primary_output_assign(NULL);
145         return EINA_TRUE;
146      }
147
148    //FILO free stack in case we fail to allocate something/can't get hold of
149    //necessary information
150 ecore_x_randr_init_fail_free_screen:
151    if (e_randr_screen_info) 
152      _e_randr_screen_info_free(e_randr_screen_info);
153
154    return EINA_FALSE;
155 }
156
157 static void
158 _e_randr_shutdown(void)
159 {
160    _e_randr_screen_info_free(e_randr_screen_info);
161 }
162
163 /**
164  * @param nrequeste
165  * @return Instance of E_Randr_Screen_Info or if memory couldn't be
166  * allocated NULL.
167  */
168 static E_Randr_Screen_Info *
169 _e_randr_screen_info_new(void)
170 {
171    E_Randr_Screen_Info *ret = NULL;
172    E_Randr_Screen_Info default_info =
173      {
174         .root = Ecore_X_Randr_Unset,
175         .randr_version = Ecore_X_Randr_None,
176         .rrvd_info.randr_info_11 = NULL
177      };
178
179    if (!(ret = malloc(sizeof(E_Randr_Screen_Info)))) return NULL;
180
181    memcpy(ret, &default_info, sizeof(default_info));
182
183    return ret;
184 }
185
186 /**
187  * @param screen_info the screen info to free.
188  */
189 static void
190 _e_randr_screen_info_free(E_Randr_Screen_Info *screen_info)
191 {
192    if ((!screen_info) || !(screen_info->rrvd_info.randr_info_11)) return;
193    switch (e_randr_screen_info->randr_version)
194      {
195       case ECORE_X_RANDR_1_1:
196         _e_randr_screen_info_11_free(screen_info->rrvd_info.randr_info_11);
197         break;
198       case ECORE_X_RANDR_1_2:
199       case ECORE_X_RANDR_1_3:
200         _e_randr_screen_info_12_free(screen_info->rrvd_info.randr_info_12);
201         break;
202      }
203    free(screen_info);
204    screen_info = NULL;
205 }
206
207 /**
208  * @return array of E_Randr_Screen_Info_11 elements, or in case not all could
209  * be created or parameter 'nrequested'==0, NULL
210  */
211 static E_Randr_Screen_Info_11 *
212 _e_randr_screen_info_11_new(void)
213 {
214    E_Randr_Screen_Info_11 *ret = NULL;
215    static const E_Randr_Screen_Info_11 default_info =
216      {
217         .sizes = NULL,
218         .csize_index = Ecore_X_Randr_Unset,
219         .corientation = Ecore_X_Randr_Unset,
220         .orientations = Ecore_X_Randr_Unset,
221         .rates = NULL,
222         .current_rate = Ecore_X_Randr_Unset
223      };
224
225    if (!(ret = malloc(sizeof(E_Randr_Screen_Info_11)))) return NULL;
226
227    ret = memcpy(ret, &default_info, sizeof(default_info));
228
229    return ret;
230 }
231
232 /**
233  * @param screen_info the screen info to be freed.
234  */
235 static void
236 _e_randr_screen_info_11_free(E_Randr_Screen_Info_11 *screen_info)
237 {
238    if (!screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_1)) 
239      return;
240
241    if (screen_info->sizes)
242      {
243         free(eina_list_nth(screen_info->sizes, 0));
244         eina_list_free(screen_info->sizes);
245      }
246    if (screen_info->rates)
247      {
248        /* this may be leaking, but at least it will be valid */
249        eina_list_free(eina_list_nth(screen_info->rates, 0));
250        eina_list_free(screen_info->rates);
251      }
252    free(screen_info);
253    screen_info = NULL;
254 }
255
256 /**
257  * @return array of E_Randr_Screen_Info_12 elements, or in case not all could
258  * be created or parameter 'nrequested'==0, NULL
259  */
260 static E_Randr_Screen_Info_12 *
261 _e_randr_screen_info_12_new(void)
262 {
263    E_Randr_Screen_Info_12 *ret = NULL;
264    static const E_Randr_Screen_Info_12 default_info =
265      {
266         .min_size = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset},
267         .max_size = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset},
268         .current_size = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset},
269         .crtcs = NULL,
270         .outputs = NULL,
271         .primary_output = NULL,
272         .output_policy = ECORE_X_RANDR_OUTPUT_POLICY_NONE,
273         .alignment = ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE
274      };
275
276    if (!(ret = malloc(sizeof(E_Randr_Screen_Info_12)))) return NULL;
277    ret = memcpy(ret, &default_info, sizeof(default_info));
278
279    return ret;
280 }
281
282 static Eina_Bool
283 _e_randr_screen_info_12_set(E_Randr_Screen_Info_12 *screen_info)
284 {
285    E_RANDR_NO_12_RET(EINA_FALSE);
286
287    ecore_x_randr_screen_size_range_get(e_randr_screen_info->root, 
288                                        &screen_info->min_size.width, 
289                                        &screen_info->min_size.height, 
290                                        &screen_info->max_size.width , 
291                                        &screen_info->max_size.height);
292    ecore_x_randr_screen_current_size_get(e_randr_screen_info->root, 
293                                          &screen_info->current_size.width , 
294                                          &screen_info->current_size.height , 
295                                          NULL, NULL);
296
297    return EINA_TRUE;
298 }
299
300 static Eina_Bool
301 _e_randr_screen_info_11_set(void)
302 {
303    E_RANDR_NO_11_RET(EINA_FALSE);
304    
305    E_Randr_Screen_Info_11 *screen_info_11 = e_randr_screen_info->rrvd_info.randr_info_11;
306    Ecore_X_Randr_Screen_Size_MM *sizes = NULL;
307    Ecore_X_Randr_Refresh_Rate *rates = NULL;
308    Eina_List *rates_list;
309    int i, j, nsizes, nrates;
310
311    if (!(sizes = ecore_x_randr_screen_primary_output_sizes_get(e_randr_screen_info->root, &nsizes))) 
312       return EINA_FALSE;
313    for (i = 0; i < nsizes; i++)
314       if (!(screen_info_11->sizes = eina_list_append(screen_info_11->sizes, &sizes[i])))
315          goto _e_randr_screen_info_11_fill_fail_sizes;
316    ecore_x_randr_screen_primary_output_current_size_get(e_randr_screen_info->root, NULL, NULL, NULL, NULL, &(screen_info_11->csize_index));
317    screen_info_11->corientation = ecore_x_randr_screen_primary_output_orientation_get(e_randr_screen_info->root);
318    screen_info_11->orientations = ecore_x_randr_screen_primary_output_orientations_get(e_randr_screen_info->root);
319    for (i = 0; i < nsizes; i++)
320      {
321         rates_list = NULL;
322         if (!(rates = ecore_x_randr_screen_primary_output_refresh_rates_get(e_randr_screen_info->root, i, &nrates)))
323            return EINA_FALSE;
324         for (j = 0; j < nrates; j++)
325            if (!(rates_list = eina_list_append(rates_list, &rates[j])))
326               goto _e_randr_screen_info_11_fill_fail_rates_list;
327         if (!(screen_info_11->rates = eina_list_append(screen_info_11->rates, rates_list)))
328            goto _e_randr_screen_info_11_fill_fail_rates;
329      }
330    screen_info_11->current_rate = ecore_x_randr_screen_primary_output_current_refresh_rate_get(e_randr_screen_info->root);
331    
332    return EINA_TRUE;
333    
334 _e_randr_screen_info_11_fill_fail_rates_list:
335    eina_list_free(rates_list);
336 _e_randr_screen_info_11_fill_fail_rates:
337    free(rates);
338 _e_randr_screen_info_11_fill_fail_sizes:
339    free(sizes);
340    free(screen_info_11);
341    return EINA_FALSE;
342 }
343
344 /**
345  * @param screen_info the screen info to be freed.
346  */
347 static void
348 _e_randr_screen_info_12_free(E_Randr_Screen_Info_12 *screen_info)
349 {
350    Ecore_X_Randr_Mode_Info *mode_info;
351    E_Randr_Crtc_Info *crtc_info;
352    E_Randr_Output_Info *output_info;
353
354    if (!screen_info || (e_randr_screen_info->randr_version < ECORE_X_RANDR_1_2)) return;
355
356    if (e_randr_screen_info->randr_version >= ECORE_X_RANDR_1_2 && screen_info->crtcs)
357      {
358         EINA_LIST_FREE(screen_info->crtcs, crtc_info)
359           _e_randr_crtc_info_free(crtc_info);
360         free(eina_list_nth(screen_info->crtcs, 0));
361      }
362
363    if (e_randr_screen_info->randr_version >= ECORE_X_RANDR_1_2 && screen_info->outputs)
364      {
365         EINA_LIST_FREE(screen_info->outputs, output_info)
366           _e_randr_output_info_free(output_info);
367         free(eina_list_nth(screen_info->outputs, 0));
368      }
369
370    if (e_randr_screen_info->randr_version >= ECORE_X_RANDR_1_2 && screen_info->modes)
371      {
372         EINA_LIST_FREE(screen_info->modes, mode_info)
373           ecore_x_randr_mode_info_free(mode_info);
374      }
375
376    _e_randr_event_listeners_remove();
377
378    free (screen_info);
379    screen_info = NULL;
380 }
381
382 /**
383  * @brief allocates structs with and fills them with default values. The
384  * returned pointer is allocated as one chunk of data since it won't change.
385  * @param nrequested number of E_Randr_Crtc_Info to be created
386  * @return array of E_Randr_Crtc_Info elements, or in case not all could
387  * be created or parameter 'nrequested'==0, NULL
388  */
389 static E_Randr_Crtc_Info *
390 _e_randr_crtc_info_new(int nrequested)
391 {
392    E_Randr_Crtc_Info *ret = NULL;
393    static E_Randr_Crtc_Info default_info =
394      {
395         .xid = Ecore_X_Randr_Unset,
396         .geometry = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset},
397         .panning = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset},
398         .tracking = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset},
399         .border = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, Ecore_X_Randr_Unset},
400         .current_orientation = ECORE_X_RANDR_ORIENTATION_ROT_0,
401         .orientations = Ecore_X_Randr_Unset,
402         .gamma_ramps = NULL,
403         .gamma_ramp_size = Ecore_X_Randr_Unset,
404         .outputs = NULL,
405         .possible_outputs = NULL
406      };
407
408    if (!(ret = malloc(sizeof(E_Randr_Crtc_Info) * nrequested))) return NULL;
409
410    while (nrequested > 0)
411      {
412         memcpy(&ret[--nrequested], &default_info, sizeof(default_info));
413      }
414
415    return ret;
416 }
417
418 /**
419  * @param crtc_info the crtc info to be freed.
420  */
421 static void
422 _e_randr_crtc_info_free(E_Randr_Crtc_Info *crtc_info)
423 {
424    if (!crtc_info) return;
425
426    if (crtc_info->gamma_ramps) free(crtc_info->gamma_ramps);
427    if (crtc_info->outputs) eina_list_free(crtc_info->outputs);
428    if (crtc_info->possible_outputs) eina_list_free(crtc_info->possible_outputs);
429 }
430
431 /**
432  * @brief allocates structs with and fills them with default values. The
433  * returned pointer is allocated as one chunk of data since it won't change.
434  * @param nrequested number of E_Randr_Output_Info to be created
435  * @return E_Randr_Output_Info element, or it could not be
436  * created, NULL
437  */
438 static E_Randr_Output_Info *
439 _e_randr_output_info_new(int nrequested)
440 {
441    E_Randr_Output_Info *ret = NULL;
442    static E_Randr_Output_Info default_info =
443      {
444         .xid = Ecore_X_Randr_Unset,
445         .name = NULL,
446         .crtc = NULL,
447         .possible_crtcs = NULL,
448         .preferred_modes = NULL,
449         .max_backlight = Ecore_X_Randr_Unset,
450         .backlight_level = 0.0,
451         .edid = NULL,
452         .edid_length = 0,
453         .size_mm = {Ecore_X_Randr_Unset, Ecore_X_Randr_Unset},
454         .wired_clones = NULL,
455         .signalformats = Ecore_X_Randr_Unset,
456         .signalformat = Ecore_X_Randr_Unset,
457         .connector_number = Ecore_X_Randr_Unset,
458         .connector_type = Ecore_X_Randr_Unset,
459         .connection_status = ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED,
460         .subpixel_order= Ecore_X_Randr_Unset,
461         .compatible_outputs = NULL
462      };
463
464    if (!(ret = malloc(sizeof(E_Randr_Output_Info) * nrequested))) return NULL;
465
466    while (nrequested > 0)
467      {
468         memcpy(&ret[--nrequested], &default_info, sizeof(default_info));
469      }
470
471    return ret;
472 }
473
474 /*
475  * removes all traces of an output within the data.
476  * @param output_info the output info to be freed.
477  */
478 static void
479 _e_randr_output_info_free(E_Randr_Output_Info *output_info)
480 {
481    Eina_List *iter;
482    E_Randr_Crtc_Info *crtc_info;
483
484    if (!output_info) return;
485    if (output_info->name)
486      {
487         free(output_info->name);
488         output_info->name = NULL;
489      }
490    _e_randr_output_hw_info_free(output_info);
491
492    EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info)
493      {
494         crtc_info->outputs = eina_list_remove(crtc_info->outputs, output_info);
495      }
496 }
497
498 static void
499 _e_randr_output_info_set(E_Randr_Output_Info *output_info)
500 {
501    if (E_RANDR_NO_12 || !output_info) return;
502
503    output_info->name = ecore_x_randr_output_name_get(e_randr_screen_info->root, output_info->xid, &output_info->name_length);
504    output_info->connection_status = ecore_x_randr_output_connection_status_get(e_randr_screen_info->root, output_info->xid);
505 }
506
507 /*
508  * fills a given crtc_info using its xid with
509  * - geometry data (x,y,w,h)
510  * - used outputs structs
511  * - possible outputs structs
512  * - mode
513  * - connection status
514  * - orientation
515  */
516 static void
517 _e_randr_crtc_info_set(E_Randr_Crtc_Info *crtc_info)
518 {
519    Ecore_X_Randr_Mode mode = 0;
520    fprintf(stderr, "Fillng CRTC %d (%p)\n", crtc_info->xid, crtc_info);
521    if (E_RANDR_NO_12 || !crtc_info) return;
522
523    //get references to used and possible E_Randr_Output_Info structs
524    _e_randr_crtc_outputs_refs_update(crtc_info);
525
526    ecore_x_randr_crtc_geometry_get(e_randr_screen_info->root, crtc_info->xid, &crtc_info->geometry.x, &crtc_info->geometry.y, &crtc_info->geometry.w, &crtc_info->geometry.h);
527    mode = ecore_x_randr_crtc_mode_get(e_randr_screen_info->root, crtc_info->xid);
528    crtc_info->current_mode = _e_randr_mode_info_get(mode);
529    fprintf(stderr, "CRTC %d apparently is in mode %d, trying to find it in the list of modes..\n", crtc_info->xid, mode);
530    if (crtc_info->current_mode)
531      fprintf(stderr, "found CRTC %d in mode %d\n", crtc_info->xid, crtc_info->current_mode->xid);
532    crtc_info->current_orientation = ecore_x_randr_crtc_orientation_get(e_randr_screen_info->root, crtc_info->xid);
533    crtc_info->outputs_common_modes = _e_randr_outputs_common_modes_get(crtc_info->outputs, NULL);
534 }
535
536 /*
537  * looks up modes supported by an output and adds them - if they are not already
538  * known by - to the screen's information struct ant the output_info itself
539  */
540 static Eina_Bool
541 _e_randr_output_modes_add(E_Randr_Output_Info *output_info)
542 {
543    Ecore_X_Randr_Mode *modes;
544    Ecore_X_Randr_Mode_Info *mode_info;
545    int nmodes, npreferred;
546    Eina_List *iter;
547    Eina_Bool added_yet = EINA_FALSE;
548
549    if (E_RANDR_NO_12 || !(modes = ecore_x_randr_output_modes_get(e_randr_screen_info->root, output_info->xid, &nmodes, &npreferred))) return EINA_FALSE;
550
551    //In case the monitor does not have any preferred mode at all
552    if (nmodes > 0 && npreferred == 0) npreferred = 1;
553
554    while (--nmodes >= 0)
555      {
556         added_yet = EINA_FALSE;
557         EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->modes, iter, mode_info)
558           {
559              if (mode_info && mode_info->xid == modes[nmodes])
560                {
561                   added_yet = EINA_TRUE;
562                   break;
563                }
564           }
565         if(!added_yet)
566           {
567              mode_info = ecore_x_randr_mode_info_get(e_randr_screen_info->root, modes[nmodes]);
568              e_randr_screen_info->rrvd_info.randr_info_12->modes = eina_list_prepend(e_randr_screen_info->rrvd_info.randr_info_12->modes, mode_info);
569           }
570         output_info->modes = eina_list_prepend(output_info->modes, mode_info);
571         if (nmodes < npreferred) output_info->preferred_modes = eina_list_prepend(output_info->preferred_modes, mode_info);
572
573      }
574
575    free(modes);
576    return EINA_TRUE;
577 }
578
579 static Eina_Bool
580 _e_randr_screen_crtcs_init(void)
581 {
582    Ecore_X_Randr_Crtc *crtcs = NULL;
583    E_Randr_Crtc_Info *crtcs_info = NULL, *crtc = NULL;
584    int i, ncrtcs;
585
586    if (E_RANDR_NO_12 || !(crtcs = ecore_x_randr_crtcs_get(e_randr_screen_info->root, &ncrtcs))) return EINA_FALSE;
587
588    if (!(crtcs_info = _e_randr_crtc_info_new(ncrtcs))) goto ecore_x_randr_screen_crtcs_init_fail_free_crtcs;
589    for (i = 0; i < ncrtcs; i++)
590      {
591         fprintf (stderr, "E_RANDR: filling %d/%d (%d)\n", (i + 1), ncrtcs, crtcs[i]);
592         crtcs_info[i].xid = crtcs[i];
593         _e_randr_crtc_info_set(&crtcs_info[i]);
594         if(!(e_randr_screen_info->rrvd_info.randr_info_12->crtcs = eina_list_append(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, &crtcs_info[i]))) break;
595      }
596    if (i == ncrtcs)
597      {
598         //successfully initialized crtcs!
599         free (crtcs);
600         return EINA_TRUE;
601      }
602    EINA_LIST_FREE(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, crtc)
603      _e_randr_crtc_info_free(crtc);
604    if (e_randr_screen_info->rrvd_info.randr_info_12->crtcs)
605      {
606         free(eina_list_nth(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, 0));
607      }
608
609 ecore_x_randr_screen_crtcs_init_fail_free_crtcs:
610    free(crtcs);
611    return EINA_FALSE;
612 }
613
614 static Eina_Bool
615 _e_randr_screen_outputs_init(void)
616 {
617    Ecore_X_Randr_Output *outputs;
618    E_Randr_Output_Info *outputs_info = NULL, *output_info = NULL;
619    int noutputs = 0;
620    if (E_RANDR_NO_12 || !(outputs = ecore_x_randr_outputs_get(e_randr_screen_info->root, &noutputs))) return EINA_FALSE;
621
622    if (!(outputs_info = _e_randr_output_info_new(noutputs))) goto _e_randr_screen_outputs_init_fail_free_outputs;
623    while (--noutputs >= 0)
624      {
625         outputs_info[noutputs].xid = outputs[noutputs];
626         _e_randr_output_info_set(&outputs_info[noutputs]);
627         outputs_info[noutputs].connection_status = ecore_x_randr_output_connection_status_get(e_randr_screen_info->root, outputs_info[noutputs].xid);
628         if (outputs_info[noutputs].connection_status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED)
629           _e_randr_output_info_hw_info_set(&outputs_info[noutputs]);
630
631         if (!(e_randr_screen_info->rrvd_info.randr_info_12->outputs = eina_list_append(e_randr_screen_info->rrvd_info.randr_info_12->outputs, &outputs_info[noutputs]))) goto _e_randr_screen_outputs_init_fail_free_outputs_list;
632      }
633
634    free(outputs);
635    return EINA_TRUE;
636
637 _e_randr_screen_outputs_init_fail_free_outputs_list:
638    if (e_randr_screen_info->rrvd_info.randr_info_12->outputs)
639      {
640         EINA_LIST_FREE(e_randr_screen_info->rrvd_info.randr_info_12->outputs, output_info)
641           free(output_info);
642      }
643 _e_randr_screen_outputs_init_fail_free_outputs:
644    free(outputs);
645    return EINA_FALSE;
646 }
647
648 static Ecore_X_Randr_Mode_Info*
649 _e_randr_mode_info_get(Ecore_X_Randr_Mode mode)
650 {
651    Eina_List *iter;
652    Ecore_X_Randr_Mode_Info* mode_info;
653
654    E_RANDR_NO_MODE_RET(mode, NULL);
655    EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->modes, iter, mode_info)
656      {
657         if (mode_info && mode_info->xid == mode) return mode_info;
658      }
659    return NULL;
660 }
661
662 static E_Randr_Output_Info*
663 _e_randr_output_info_get(Ecore_X_Randr_Output output)
664 {
665    Eina_List *iter;
666    E_Randr_Output_Info* output_info;
667
668    E_RANDR_NO_OUTPUTS_RET(NULL);
669    EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->outputs, iter, output_info)
670      {
671         if (output_info && output_info->xid == output) return output_info;
672      }
673    return NULL;
674 }
675
676 static E_Randr_Crtc_Info*
677 _e_randr_crtc_info_get(Ecore_X_Randr_Crtc crtc)
678 {
679    Eina_List *iter;
680    E_Randr_Crtc_Info* crtc_info;
681
682    E_RANDR_NO_CRTCS_RET(NULL);
683    EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info)
684      {
685         if (crtc_info && crtc_info->xid == crtc) return crtc_info;
686      }
687    return NULL;
688 }
689
690 static Eina_Bool
691 _e_randr_event_cb(void *data __UNUSED__, int type, void *ev)
692 {
693    E_Randr_Crtc_Info *crtc_info;
694    Eina_Bool enabled;
695
696    if (!e_randr_screen_info) return ECORE_CALLBACK_RENEW;
697    if (type == ECORE_X_EVENT_RANDR_CRTC_CHANGE)
698      {
699         Ecore_X_Event_Randr_Crtc_Change *event = (Ecore_X_Event_Randr_Crtc_Change*) ev;
700         /* available information:
701            struct _Ecore_X_Event_Randr_Crtc_Change
702            {
703            Ecore_X_Window                win;
704            Ecore_X_Randr_Crtc            crtc;
705            Ecore_X_Randr_Mode            mode;
706            Ecore_X_Randr_Orientation     orientation;
707            int                           x;
708            int                           y;
709            int                           width;
710            int                           height;
711            };
712            */
713         crtc_info = _e_randr_crtc_info_get(event->crtc);
714         if (!crtc_info) goto on_exit;
715
716         if (event->mode != Ecore_X_Randr_None)
717           {
718              //switched (on)
719              if ((crtc_info->current_mode != _e_randr_mode_info_get(event->mode)))
720                {
721                   crtc_info->current_mode = _e_randr_mode_info_get(event->mode);
722                   _e_randr_notify_crtc_mode_change(crtc_info);
723                }
724              else
725                crtc_info->current_mode = _e_randr_mode_info_get(event->mode);
726              crtc_info->current_orientation = event->orientation;
727              crtc_info->geometry.x = event->geo.x;
728              crtc_info->geometry.y = event->geo.y;
729              crtc_info->geometry.w = event->geo.w;
730              crtc_info->geometry.h = event->geo.h;
731              //update screensize if necessary
732              e_randr_screen_info->rrvd_info.randr_info_12->current_size.width = MAX((event->geo.x + event->geo.w), e_randr_screen_info->rrvd_info.randr_info_12->current_size.width);
733              e_randr_screen_info->rrvd_info.randr_info_12->current_size.height = MAX((event->geo.y + event->geo.h), e_randr_screen_info->rrvd_info.randr_info_12->current_size.height);
734           }
735         else
736           {
737              //set the max mode common amongst outputs
738              _e_randr_crtcs_clone_crtc_removed(crtc_info);
739
740              //disabled
741              crtc_info->current_orientation = event->orientation;
742              crtc_info->geometry.x = 0;
743              crtc_info->geometry.y = 0;
744              crtc_info->geometry.w = 0;
745              crtc_info->geometry.h = 0;
746              crtc_info->current_mode = NULL;
747              if (crtc_info->outputs) eina_list_free(crtc_info->outputs);
748              crtc_info->outputs = NULL;
749
750              //update screensize of necessary
751              ecore_x_randr_screen_reset(e_randr_screen_info->root);
752              ecore_x_randr_screen_current_size_get(e_randr_screen_info->root, &e_randr_screen_info->rrvd_info.randr_info_12->current_size.width, &e_randr_screen_info->rrvd_info.randr_info_12->current_size.height, NULL, NULL);
753           }
754      }
755    else if (type == ECORE_X_EVENT_RANDR_OUTPUT_CHANGE)
756      {
757         Ecore_X_Event_Randr_Output_Change *event = ev;
758         const E_Randr_Screen_Restore_Info_12 *restore_info;
759         E_Randr_Output_Info* output_info = NULL;
760         /* available information:
761            struct _Ecore_X_Event_Randr_Output_Change
762            {
763            Ecore_X_Window                  win;
764            Ecore_X_Randr_Output            output;
765            Ecore_X_Randr_Crtc              crtc;
766            Ecore_X_Randr_Mode              mode;
767            Ecore_X_Randr_Orientation       orientation;
768            Ecore_X_Randr_Connection_Status connection;
769            Ecore_X_Render_Subpixel_Order   subpixel_order;
770            };
771            */
772         fprintf(stderr, "E_RANDR: Output connected!: \n \
773               E_RANDR: relative to win: %d\n \
774               E_RANDR: relative to output: %d\n \
775               E_RANDR: relative to crtc: %d\n \
776               E_RANDR: relative to mode: %d\n \
777               E_RANDR: relative to orientation: %d\n \
778               E_RANDR: relative to connction: %d (connected = %d, disconnected = %d, unknown %d)\n \
779               E_RANDR: relative to subpixel_order: %d\n",
780                 event->win, event->output, event->crtc, event->mode, event->orientation, event->connection, ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED, ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED, ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN, event->subpixel_order);
781
782         output_info = _e_randr_output_info_get(event->output);
783         if (!output_info) goto on_exit;
784         
785         if ((output_info->crtc = _e_randr_crtc_info_get(event->crtc)))
786           {
787              if (!eina_list_data_find(output_info->crtc->outputs, output_info))
788                 output_info->crtc->outputs = eina_list_append(output_info->crtc->outputs, output_info);
789           }
790
791         output_info->connection_status = event->connection;
792         output_info->subpixel_order = event->subpixel_order;
793         
794         if (event->connection == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED)
795           {
796              if (event->crtc)
797                 output_info->crtc = _e_randr_crtc_info_get(event->crtc);
798
799              if (output_info && !output_info->crtc && !event->crtc && !event->mode)
800                {
801                   //Monitor was attached!
802                   _e_randr_output_info_hw_info_set(output_info);
803                   //make the crtcs aware of their possibly new output
804                   _e_randr_crtcs_possible_output_update(output_info);
805                   if ((restore_info = _e_randr_config_find_suiting_config_12()))
806                      //maybe we have a suiting configuration
807                      //_e_randr_config_enable_12(restore_info);
808                      ;
809                   else
810                      enabled = _e_randr_try_enable_output(output_info, EINA_FALSE); //maybe give a success message?
811                }
812              _e_randr_notify_output_change(output_info);
813           }
814         else if (event->connection == ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED)
815           {
816              if (output_info->crtc)
817                {
818                   //remove output from CRTC
819                   output_info->crtc->outputs = eina_list_remove(output_info->crtc->outputs, output_info);
820                   if (output_info->crtc->current_mode)
821                     {
822                        //in case this output was enabled on some CRTC
823                        if (eina_list_count(output_info->crtc->outputs) == 0)
824                          {
825                             //in case it was the only output running on this CRTC, disable
826                             //it.
827                             ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, output_info->crtc->xid, NULL, Ecore_X_Randr_None, Ecore_X_Randr_None);
828                             //crop the screen of course.
829                             ecore_x_randr_screen_reset(e_randr_screen_info->root);
830                          }
831                        else
832                           _e_randr_crtc_outputs_mode_max_set(output_info->crtc);
833                     }
834                   
835                   if (e_randr_screen_info->rrvd_info.randr_info_12->primary_output && (output_info == e_randr_screen_info->rrvd_info.randr_info_12->primary_output))
836                      _e_randr_screen_primary_output_assign(output_info);
837                   //let's try to get a proper config for the new setup and crop the
838                   //screen afterwards.
839                   if ((restore_info = _e_randr_config_find_suiting_config_12()))
840                     {
841                        //in case we didn't have, init it anyway...
842                        //_e_randr_config_enable_12(restore_info);
843                     }
844                }
845              _e_randr_notify_output_change(output_info);
846              _e_randr_output_hw_info_free(output_info);
847           }
848      }
849    else if (type == ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY)
850      {
851         //Ecore_X_Event_Randr_Output_Property_Notify *event = (Ecore_X_Event_Randr_Output_Property_Notify*) ev;
852         /* available information:
853            struct _Ecore_X_Event_Randr_Output_Property_Notify
854            {
855            Ecore_X_Window                win;
856            Ecore_X_Randr_Output          output;
857            Ecore_X_Atom                  property;
858            Ecore_X_Time                  time;
859            Ecore_X_Randr_Property_Change state;
860            };
861            */
862      }
863  on_exit:
864    return ECORE_CALLBACK_RENEW;
865 }
866
867 static void
868 _e_randr_event_listeners_add(void)
869 {
870    if (E_RANDR_NO_12) return;
871    ecore_x_randr_events_select(e_randr_screen_info->root, EINA_TRUE);
872    _e_randr_event_handlers= eina_list_append(_e_randr_event_handlers, ecore_event_handler_add(ECORE_X_EVENT_RANDR_CRTC_CHANGE, _e_randr_event_cb, NULL));
873    _e_randr_event_handlers= eina_list_append(_e_randr_event_handlers, ecore_event_handler_add(ECORE_X_EVENT_RANDR_OUTPUT_CHANGE, _e_randr_event_cb, NULL));
874    _e_randr_event_handlers= eina_list_append(_e_randr_event_handlers, ecore_event_handler_add(ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY, _e_randr_event_cb, NULL));
875 }
876
877 static void
878 _e_randr_event_listeners_remove(void)
879 {
880    Ecore_Event_Handler *_event_handler = NULL;
881    EINA_LIST_FREE(_e_randr_event_handlers, _event_handler)
882      ecore_event_handler_del(_event_handler);
883 }
884
885 static void
886 _e_randr_notify_crtc_mode_change(E_Randr_Crtc_Info *crtc_info)
887 {
888    //   E_Notification *n;
889    //   char buff[200];
890    //
891    if (crtc_info->current_mode)
892      {
893         //        snprintf(buff, 200, "New resolution is %dx%d. Click here for further information.", crtc_info->current_mode->width, crtc_info->current_mode->height);
894         //        n = e_notification_full_new("RandRR", crtc_info->xid, NULL, "Resolution changed", buff, -1);
895         //        //n = e_notification_full_new("RandRR", id, icon, function, body, timeout);
896         //        e_notification_send(n, NULL, NULL);
897         //        e_notification_unref(n);
898      }
899 }
900 static void
901 _e_randr_notify_output_change(E_Randr_Output_Info *output_info)
902 {
903    //   E_Notification *n;
904    //   char buff[100];
905    if (output_info->connection_status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED)
906      {
907         //        snprintf(buff, 100, "Output %s connected", output_info->name);
908         //        n = e_notification_full_new("RandRR", output_info->xid, NULL, buff, "Click here for further information.", -1);
909      }
910    else
911      {
912         //        snprintf(buff, 100, "Output %s disconnected", output_info->name);
913         //        n = e_notification_full_new("RandRR", output_info->xid, NULL, buff, "Click here to adjust screen setup.", -1);
914      }
915
916    //   //n = e_notification_full_new("RandRR", id, icon, function, body, timeout);
917    //   e_notification_send(n, NULL, NULL);
918    //   e_notification_unref(n);
919 }
920
921 /*
922  * this retrieves a CRTC depending on a policy.
923  * Note that this is enlightenment specific! Enlightenment doesn't 'allow' zones
924  * to overlap. Thus we always use the output with the most extreme position
925  * instead of trying to fill gaps like tetris. Though this could be done by
926  * simply implementing another policy.
927  */
928 static const E_Randr_Crtc_Info*
929 _e_randr_policy_crtc_get(E_Randr_Crtc_Info *but, E_Randr_Crtc_Info *hint __UNUSED__, Ecore_X_Randr_Output_Policy policy)
930 {
931    Eina_List *iter;
932    E_Randr_Crtc_Info *crtc_info, *ret = NULL;
933
934    E_RANDR_NO_CRTCS_RET(NULL);
935
936    //get any crtc that besides 'but' to start with
937    EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info)
938      {
939         if (crtc_info != but)
940           {
941              ret = crtc_info;
942              break;
943           }
944      }
945    if (!ret && (policy != ECORE_X_RANDR_OUTPUT_POLICY_CLONE)) return NULL;
946
947    switch (policy)
948      {
949       case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE:
950         EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info)
951           {
952              if (crtc_info && (crtc_info != but) && (crtc_info->geometry.y <= ret->geometry.y))
953                {
954                   ret = crtc_info;
955                 }
956            }
957         break;
958       case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT:
959         EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info)
960           {
961              if (crtc_info && (crtc_info != but) && ((crtc_info->geometry.x + crtc_info->geometry.w) >= (ret->geometry.x + ret->geometry.w)))
962                {
963                   ret = crtc_info;
964                 }
965            }
966         break;
967
968       case ECORE_X_RANDR_OUTPUT_POLICY_BELOW:
969         EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info)
970           {
971              if (crtc_info && (crtc_info != but) && ((crtc_info->geometry.y + crtc_info->geometry.h) >= (ret->geometry.y + ret->geometry.h)))
972                {
973                   ret = crtc_info;
974                 }
975            }
976         break;
977
978       case ECORE_X_RANDR_OUTPUT_POLICY_LEFT:
979         EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info)
980           {
981              if (crtc_info && (crtc_info != but) && (crtc_info->geometry.x <= ret->geometry.x))
982                {
983                   ret = crtc_info;
984                 }
985            }
986         break;
987
988       case ECORE_X_RANDR_OUTPUT_POLICY_CLONE:
989         ret = (e_randr_screen_info->rrvd_info.randr_info_12->primary_output) ? e_randr_screen_info->rrvd_info.randr_info_12->primary_output->crtc : NULL;
990         break;
991
992       default:
993         break;
994      }
995    return ret;
996 }
997
998 /*
999 static Eina_Bool
1000 _e_randr_outputs_connected(Eina_List *outputs_info)
1001 {
1002    Eina_List *iter;
1003    E_Randr_Output_Info *output_info;
1004
1005    EINA_LIST_FOREACH(outputs_info, iter, output_info)
1006      if (output_info->connection_status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) return EINA_TRUE;
1007    return EINA_FALSE;
1008 }
1009
1010 static Eina_Bool
1011 _e_randr_config_enable_11(int size_index, Ecore_X_Randr_Refresh_Rate refresh_rate, Ecore_X_Randr_Orientation orientation)
1012 {
1013    E_Randr_Screen_Info_11 *current_info_11;
1014
1015    if (E_RANDR_NO_11 || (size_index < 0) || (refresh_rate < 0) || 
1016        (orientation < 0)) return EINA_FALSE;
1017
1018    if (!ecore_x_randr_screen_primary_output_size_set(e_randr_screen_info->root, size_index)
1019        || !ecore_x_randr_screen_primary_output_orientation_set(e_randr_screen_info->root, orientation)
1020        || !ecore_x_randr_screen_primary_output_refresh_rate_set(e_randr_screen_info->root, size_index, refresh_rate)) return EINA_FALSE;
1021
1022    //TODO: move this to the screen event later.
1023    current_info_11 = e_randr_screen_info->rrvd_info.randr_info_11;
1024
1025    current_info_11->csize_index = size_index;
1026    current_info_11->corientation = orientation;
1027    current_info_11->current_rate = refresh_rate;
1028
1029    return EINA_TRUE;
1030 }
1031
1032 static Eina_Bool
1033 _e_randr_config_enable_12(const E_Randr_Screen_Restore_Info_12 *restore_info __UNUSED__)
1034 {
1035       if (E_RANDR_NO_12 || !restore_info) return EINA_FALSE;
1036       E_Randr_Screen_Info_12 *current_info_12;
1037       E_Randr_Screen_Restore_Info_12 *restore_info_12 = NULL;
1038       E_Randr_Crtc_Restore_Info *crtc_restore_info = NULL;
1039       E_Randr_Crtc_Info *crtc_info;
1040       E_Randr_Output_Info *output_info;
1041       Eina_List *crtc_restore_iter;
1042
1043       current_info_12 = (e_randr_screen_info->rrvd_info).randr_info_12;
1044       EINA_LIST_FOREACH(restore_info_12->crtcs, crtc_restore_iter, crtc_restore_info)
1045       {
1046       ;
1047       }
1048       current_info_12->alignment = restore_info_12->alignment;
1049       current_info_12->output_policy = restore_info_12->output_policy;
1050       return EINA_TRUE;
1051    return EINA_FALSE;
1052 }
1053
1054 static int
1055 _e_randr_config_find_suiting_config_11(E_Randr_Screen_Restore_Info_11 **restore_info)
1056 {
1057    E_RANDR_NO_11_RET(Ecore_X_Randr_None);
1058    Eina_List *cfg_screen_restore_info_iter;
1059    E_Randr_Screen_Restore_Info *screen_restore_info;
1060
1061    E_Randr_Screen_Restore_Info_11 *restore_info_11;
1062    Ecore_X_Randr_Screen_Size_MM *sizes;
1063    Ecore_X_Randr_Refresh_Rate *rates = NULL;
1064    int i = 0, j = 0, nsizes = 0, nrates = 0;
1065
1066    EINA_LIST_FOREACH(e_config->screen_info, cfg_screen_restore_info_iter, screen_restore_info)
1067      {
1068         // 'screen_restore_info' should _never_ be NULL, since this functions shouldn't be called due to randr init failing.
1069         if (!screen_restore_info) continue;
1070         if (screen_restore_info->randr_version != ECORE_X_RANDR_1_1) continue;
1071         restore_info_11 = screen_restore_info->rrvd_restore_info.restore_info_11;
1072         if((sizes = ecore_x_randr_screen_primary_output_sizes_get(e_randr_screen_info->root, &nsizes)))
1073           {
1074              for (i = 0; i < nsizes; i++)
1075                {
1076                   if ((restore_info_11->size.width == sizes[i].width)
1077                       && (restore_info_11->size.height == sizes[i].height))
1078                     {
1079                        if ((rates = ecore_x_randr_screen_primary_output_refresh_rates_get(e_randr_screen_info->root, i, &nrates)))
1080                          {
1081                             for (j = 0; j < nrates; j++)
1082                               if (rates[j] == restore_info_11->refresh_rate)
1083                                 {
1084                                    if (restore_info) *restore_info = restore_info_11;
1085                                    free(rates);
1086                                    free(sizes);
1087                                    return i;
1088                                 }
1089                             free(rates);
1090                          }
1091                     }
1092                }
1093              if (sizes) free(sizes);
1094           }
1095      }
1096    return Ecore_X_Randr_Unset;
1097 }
1098 */
1099
1100 /**
1101  * @Brief find configuration with the most hardware currently available
1102  */
1103 static E_Randr_Screen_Restore_Info_12 *
1104 _e_randr_config_find_suiting_config_12(void)
1105 {
1106    //TODO: write geometry based loading
1107    /*
1108       Eina_List *cfg_screen_restore_info_iter;
1109       E_Randr_Screen_Restore_Info *screen_restore_info;
1110
1111       E_Randr_Screen_Info_12 *current_info_12;
1112       E_Randr_Screen_Restore_Info_12 *restore_info_12, *most_matches = NULL;
1113       E_Randr_Output_Info *output_info;
1114       E_Randr_Crtc_Restore_Info *crtc_restore_info;
1115       Ecore_X_Randr_Output *outputs_xids;
1116       Ecore_X_Randr_Crtc *crtcs_xids;
1117       Eina_List *restore_info_12_iter,  *output_iter, *restore_crtcs_iter;
1118
1119       if (e_randr_screen_info && e_config && e_config->screen_info)
1120       {
1121
1122       EINA_LIST_FOREACH(e_config->screen_info, cfg_screen_restore_info_iter, screen_restore_info)
1123       {
1124       if (screen_restore_info->randr_version < ECORE_X_RANDR_1_2) continue;
1125
1126    //HINT: use eina_list_clone and a sort callback to find proper
1127    //crtcs and outputs
1128
1129    //current_info_12 = e_randr_screen_info->rrvd_info.randr_info_12;
1130    }
1131
1132    }
1133    */
1134    return NULL;
1135 }
1136
1137 static Ecore_X_Randr_Output *
1138 _e_randr_outputs_to_array(Eina_List *outputs_info)
1139 {
1140    Ecore_X_Randr_Output *ret = NULL;
1141    E_Randr_Output_Info *output_info;
1142    Eina_List *output_iter;
1143    int i = 0;
1144
1145    if (!outputs_info || !(ret = malloc(sizeof(Ecore_X_Randr_Output) * eina_list_count(outputs_info)))) return NULL;
1146    EINA_LIST_FOREACH(outputs_info, output_iter, output_info)
1147      /* output_info == NULL should _not_ be possible! */
1148      ret[i++] = output_info ? output_info->xid : Ecore_X_Randr_None;
1149    return ret;
1150 }
1151
1152 /*
1153  * Try to enable this output on an unoccupied CRTC. 'Force' in this context
1154  * means, that if there are only occupied CRTCs, we disable another output to
1155  * enable this one. If not forced we will - if we don't find an unoccupied CRTC
1156  * - try to share the output of a CRTC with other outputs already using it
1157  *   (clone).
1158  */
1159 static Eina_Bool
1160 _e_randr_try_enable_output(E_Randr_Output_Info *output_info, Eina_Bool force)
1161 {
1162    if (!output_info) return EINA_FALSE;
1163    else if (output_info->crtc && output_info->crtc->current_mode) return EINA_TRUE;
1164
1165    Eina_List *iter, *outputs_list = NULL;
1166    E_Randr_Crtc_Info *crtc_info, *usable_crtc = NULL;
1167    E_Randr_Output_Info *primary_output;
1168    Ecore_X_Randr_Output *outputs;
1169    Ecore_X_Randr_Mode_Info *mode_info;
1170    Eina_Bool ret = EINA_FALSE;
1171
1172    /*
1173     * Try to find a usable crtc for this output. Either unused or forced.
1174     */
1175    EINA_LIST_FOREACH(output_info->possible_crtcs, iter, crtc_info)
1176      {
1177         if (crtc_info && (!crtc_info->current_mode || force))
1178           {
1179              usable_crtc = crtc_info;
1180              break;
1181           }
1182      }
1183
1184    /*
1185     * apparently we don't have a CRTC to make use of the device
1186     */
1187    if (!usable_crtc) return EINA_FALSE;
1188
1189    //get the CRTC we will refer to, dependend on policy
1190    switch (e_randr_screen_info->rrvd_info.randr_info_12->output_policy)
1191      {
1192       case ECORE_X_RANDR_OUTPUT_POLICY_NONE:
1193          return EINA_TRUE;
1194       case ECORE_X_RANDR_OUTPUT_POLICY_CLONE:
1195          /*
1196           * Order of approaches to enable a clone (of the primary output):
1197           *
1198           * 0.  Get Primary output from Server
1199           * 1.  Try to add new Output to primary output's CRTC, using the mode used
1200           *     by the primary output
1201           * 2.  Try to enable clone in the same
1202           * 2a. exact mode or a
1203           * 2b. geometrically identical mode
1204           * 3.  Find a most high resolution mode in common to enable on primary output's CRTC and the new
1205           *     output's CRTC
1206           * 4.  fail.
1207           */
1208         if ((primary_output = e_randr_screen_info->rrvd_info.randr_info_12->primary_output))
1209           {
1210              if (primary_output->crtc && primary_output->crtc->current_mode && eina_list_data_find(output_info->modes, primary_output->crtc->current_mode))
1211                {
1212                 /*
1213                  * mode currently used by primary output's CRTC is also supported by the new output
1214                  */
1215                   if (_e_randr_outputs_are_clones(output_info, primary_output->crtc->outputs))
1216                     {
1217                      /*
1218                       * 1.  Try to add new Output to primary output's CRTC, using the mode used
1219                       * by the primary output
1220                       * TODO: check with compatibility list in RandRR >= 1.3
1221                       * if available
1222                       *
1223                       * The new output is also usable by the primary output's
1224                       * CRTC. Try to enable this output together with the already
1225                       * enabled outputs on the CRTC in already used mode.
1226                       */
1227                        outputs_list = eina_list_clone(primary_output->crtc->outputs);
1228                        outputs_list = eina_list_append(outputs_list, output_info);
1229                        outputs = _e_randr_outputs_to_array(outputs_list);
1230                        ret = ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, primary_output->crtc->xid, outputs, eina_list_count(outputs_list), primary_output->crtc->current_mode->xid);
1231                        free(outputs);
1232                        eina_list_free(outputs_list);
1233                        return ret;
1234                   }
1235                   else
1236                     {
1237                      /*
1238                       * 2.  Try to enable clone in the same
1239                       */
1240
1241                      /*
1242                       * 2a. exact mode.
1243                       */
1244                        ret = ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, usable_crtc->xid, &output_info->xid, 1, primary_output->crtc->current_mode->xid);
1245                        return (ret && ecore_x_randr_crtc_pos_relative_set(e_randr_screen_info->root, usable_crtc->xid, primary_output->crtc->xid, ECORE_X_RANDR_OUTPUT_POLICY_CLONE, e_randr_screen_info->rrvd_info.randr_info_12->alignment));
1246
1247                   }
1248              }
1249              else
1250                {
1251                 /*
1252                  * 2b. geometrically identical mode
1253                  */
1254                   if (primary_output->crtc && (mode_info = _e_randr_mode_geo_identical_find(output_info->modes, primary_output->crtc->current_mode)))
1255                     {
1256                        ret = ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, usable_crtc->xid, &output_info->xid, 1, mode_info->xid);
1257                        return (ret && ecore_x_randr_crtc_pos_relative_set(e_randr_screen_info->root, usable_crtc->xid, primary_output->crtc->xid, ECORE_X_RANDR_OUTPUT_POLICY_CLONE, e_randr_screen_info->rrvd_info.randr_info_12->alignment));
1258                   }
1259                   /*
1260                    * 3.  Find the highest resolution mode common to enable on primary output's CRTC and the new one.
1261                    */
1262                   if (((outputs_list = eina_list_append(outputs_list, primary_output)) && (outputs_list = eina_list_append(outputs_list, output_info))))
1263                     {
1264                        if (primary_output->crtc)
1265                          {
1266                             if((mode_info = _e_randr_outputs_common_mode_max_get(outputs_list, primary_output->crtc->current_mode)))
1267                               {
1268                                  fprintf(stderr, "Will try to set mode: %dx%d for primary and clone.\n", mode_info->width, mode_info->height);
1269                                  ret = ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, primary_output->crtc->xid, ((Ecore_X_Randr_Output*)Ecore_X_Randr_Unset), Ecore_X_Randr_Unset, mode_info->xid);
1270                                  ret = (ret && ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, usable_crtc->xid, &output_info->xid, 1, mode_info->xid));
1271                                  ret = (ret && ecore_x_randr_crtc_pos_relative_set(e_randr_screen_info->root, usable_crtc->xid, primary_output->crtc->xid, ECORE_X_RANDR_OUTPUT_POLICY_CLONE, e_randr_screen_info->rrvd_info.randr_info_12->alignment));
1272                               }
1273                          }
1274                        eina_list_free(outputs_list);
1275                   }
1276              }
1277
1278         }
1279         else
1280           fprintf(stderr, "Couldn't get primary output!\n");
1281          /*
1282           * 4. FAIL
1283           */
1284         break;
1285
1286       default:
1287         if ((usable_crtc && (!usable_crtc->current_mode)) || force)
1288           {
1289              //enable and position according to used policies
1290              if(!(mode_info = ((Ecore_X_Randr_Mode_Info*)eina_list_nth(output_info->preferred_modes, 0))))
1291                {
1292                   fprintf(stderr, "E_RANDR: Could not enable output(%d), as it has no preferred (and there for none at all) modes.!\n", output_info->xid);
1293                   ret = EINA_FALSE;
1294                   break;
1295                }
1296              if((ret = ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, usable_crtc->xid, &output_info->xid, 1, mode_info->xid)))
1297                {
1298                   usable_crtc->geometry.w = mode_info->width;
1299                   usable_crtc->geometry.h = mode_info->height;
1300                   usable_crtc->geometry.x = 0;
1301                   usable_crtc->geometry.y = 0;
1302
1303                   ret &= _e_randr_crtc_move_policy(usable_crtc);
1304                 }
1305            }
1306      }
1307    ecore_x_randr_screen_reset(e_randr_screen_info->root);
1308    return ret;
1309 }
1310
1311 /*
1312  * updates all crtcs information regarding a new output
1313  */
1314 static void
1315 _e_randr_crtcs_possible_output_update(E_Randr_Output_Info *output_info)
1316 {
1317    Eina_List *iter;
1318    E_Randr_Crtc_Info *crtc_info;
1319    Ecore_X_Randr_Output *outputs = NULL;
1320    int noutputs = 0;
1321
1322    EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info)
1323      {
1324         if (!eina_list_data_find(crtc_info->possible_outputs, output_info))
1325           {
1326              if ((outputs = ecore_x_randr_crtc_possible_outputs_get(e_randr_screen_info->root, crtc_info->xid, &noutputs)))
1327                {
1328                   while (--noutputs >= 0)
1329                     {
1330                        if (outputs[noutputs] == output_info->xid)
1331                          {
1332                             crtc_info->possible_outputs = eina_list_append(crtc_info->possible_outputs, output_info);
1333                             break;
1334                          }
1335                     }
1336                   free(outputs);
1337                }
1338           }
1339      }
1340 }
1341
1342 /*
1343  * setup a crtc's current (possible) outputs references
1344  */
1345 static void
1346 _e_randr_crtc_outputs_refs_update(E_Randr_Crtc_Info *crtc_info)
1347 {
1348    Ecore_X_Randr_Output         *outputs;
1349    E_Randr_Output_Info          *output_info;
1350    int                          i, noutputs;
1351
1352    //get references to output_info structs which are related to this CRTC
1353    if (e_randr_screen_info->rrvd_info.randr_info_12->outputs && (outputs = ecore_x_randr_crtc_outputs_get(e_randr_screen_info->root, crtc_info->xid, &noutputs)))
1354      {
1355         for(i = 0; i < noutputs; i++)
1356           {
1357              if (!(output_info = _e_randr_output_info_get(outputs[i])) || eina_list_data_find(crtc_info->outputs, output_info) || (ecore_x_randr_output_crtc_get(e_randr_screen_info->root, outputs[i]) != crtc_info->xid)) continue;
1358              if(!(crtc_info->outputs = eina_list_append(crtc_info->outputs, output_info))) fprintf(stderr, "E_RANDR: could not add output(%d) to CRTC's(%d) output list!\n", output_info->xid, crtc_info->xid);
1359              output_info->crtc = crtc_info;
1360           }
1361         free(outputs);
1362      }
1363    //get references to possible output_info structs which are related to this CRTC
1364    if (e_randr_screen_info->rrvd_info.randr_info_12->outputs && (outputs = ecore_x_randr_crtc_possible_outputs_get(e_randr_screen_info->root, crtc_info->xid, &noutputs)))
1365      {
1366         for(i = 0; i < noutputs; i++)
1367           {
1368              if (!(output_info = _e_randr_output_info_get(outputs[i])) || eina_list_data_find(crtc_info->possible_outputs, output_info)) continue;
1369              if(!(crtc_info->possible_outputs = eina_list_append(crtc_info->possible_outputs, output_info))) fprintf(stderr, "E_RANDR: could not add output(%d) to CRTC's(%d) possible output list!\n", output_info->xid, crtc_info->xid);
1370           }
1371         free(outputs);
1372      }
1373 }
1374
1375 /*
1376  * reconfigure screen setup according to policy. This is only required if all
1377  * CRTCs' positions might be affected by the another screens' movement. This includes 'virtual' moves,
1378  * which means that e.g. when a crtc should be placed at a position < 0, all
1379  * other crtcs are accordingly moved instead, so the result is the same.
1380  */
1381 static Eina_Bool
1382 _e_randr_crtc_move_policy(E_Randr_Crtc_Info *new_crtc)
1383 {
1384    const E_Randr_Crtc_Info *crtc_rel;
1385    int dx = Ecore_X_Randr_None, dy = Ecore_X_Randr_None;
1386    Eina_Bool ret = EINA_TRUE;
1387
1388    //get the crtc we will place our's relative to. If it's NULL, this is the
1389    //only output attached, work done.
1390    if(!(crtc_rel = _e_randr_policy_crtc_get(new_crtc, NULL, e_randr_screen_info->rrvd_info.randr_info_12->output_policy))) return EINA_TRUE;
1391
1392    //following is policy dependend.
1393    switch (e_randr_screen_info->rrvd_info.randr_info_12->output_policy)
1394      {
1395       case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE:
1396         dy = (crtc_rel->geometry.y - new_crtc->geometry.h);
1397         if (dy < 0)
1398           {
1399              //virtual move (move other CRTCs as nessesary)
1400              dy = -dy;
1401              ret = ecore_x_randr_move_all_crtcs_but(e_randr_screen_info->root,
1402                                                     &new_crtc->xid,
1403                                                     1,
1404                                                     dx,
1405                                                     dy);
1406            }
1407         break;
1408       case ECORE_X_RANDR_OUTPUT_POLICY_LEFT:
1409         dx = (crtc_rel->geometry.x - new_crtc->geometry.w);
1410         if (dx < 0)
1411           {
1412              //virtual move (move other CRTCs as nessesary)
1413              dx = -dx;
1414              ret = ecore_x_randr_move_all_crtcs_but(e_randr_screen_info->root,
1415                                                     &new_crtc->xid,
1416                                                     1,
1417                                                     dx,
1418                                                     dy);
1419            }
1420         break;
1421       default:
1422         break;
1423      }
1424    ret &= ecore_x_randr_crtc_pos_relative_set(e_randr_screen_info->root, new_crtc->xid, crtc_rel->xid, e_randr_screen_info->rrvd_info.randr_info_12->output_policy, e_randr_screen_info->rrvd_info.randr_info_12->alignment);
1425    return ret;
1426 }
1427
1428 /*
1429  * returns the highest resolution mode common ammongst the given outputs,
1430  * optionally limited by max_size_mode. If none is found, NULL is returned.
1431  */
1432 static Ecore_X_Randr_Mode_Info *
1433 _e_randr_outputs_common_mode_max_get(Eina_List *outputs, Ecore_X_Randr_Mode_Info *max_size_mode)
1434 {
1435    Eina_List *all_modes = NULL, *iter, *output_iter, *right;
1436    E_Randr_Output_Info *output_info;
1437    Ecore_X_Randr_Mode_Info *mode_info;
1438    int outputs_mode_found;
1439
1440    //create a list of all available modes
1441    EINA_LIST_FOREACH(outputs, iter, output_info)
1442      {
1443         right = eina_list_clone(output_info->modes);
1444         all_modes = eina_list_merge(all_modes, right);
1445      }
1446
1447    if (max_size_mode)
1448      {
1449         //remove all modes that are larger than max_size_mode
1450         EINA_LIST_FOREACH(all_modes, iter, mode_info)
1451           {
1452              if (_modes_size_sort_cb((void*)max_size_mode, (void*)mode_info) < 0)
1453                all_modes = eina_list_remove(all_modes, mode_info);
1454           }
1455      }
1456
1457    //sort modes by their sizes
1458    all_modes = eina_list_sort(all_modes, eina_list_count(all_modes), _modes_size_sort_cb);
1459    EINA_LIST_REVERSE_FOREACH(all_modes, iter, mode_info)
1460      {
1461         outputs_mode_found = 0;
1462         EINA_LIST_FOREACH(outputs, output_iter, output_info)
1463           {
1464              if (eina_list_data_find(output_info->modes, mode_info))
1465                outputs_mode_found++;
1466           }
1467         if (outputs_mode_found == (int)eina_list_count(outputs))
1468           break;
1469         mode_info = NULL;
1470      }
1471    return mode_info;
1472 }
1473
1474 /*
1475 static int
1476 _crtcs_size_sort_cb(const void *d1, const void *d2)
1477 {
1478    E_Randr_Crtc_Info *crtc1 = ((E_Randr_Crtc_Info*)d1), *crtc2 = ((E_Randr_Crtc_Info*)d2);
1479
1480    return ((crtc1->geometry.w * crtc1->geometry.h) - (crtc2->geometry.w * crtc2->geometry.h));
1481 }
1482 */
1483
1484 static int
1485 _outputs_size_sort_cb(const void *d1, const void *d2)
1486 {
1487    E_Randr_Output_Info *output1 = ((E_Randr_Output_Info*)d1), *output2 = ((E_Randr_Output_Info*)d2);
1488
1489    return (output1 && output1->crtc && output1->crtc->current_mode && output2 && output2->crtc && output2->crtc->current_mode) ?  ((output1->crtc->current_mode->width * output1->crtc->current_mode->height) - (output2->crtc->current_mode->width * output2->crtc->current_mode->height)) : 0;
1490 }
1491
1492 static int
1493 _modes_size_sort_cb(const void *d1, const void *d2)
1494 {
1495    Ecore_X_Randr_Mode_Info *mode1 = ((Ecore_X_Randr_Mode_Info*)d1), *mode2 = ((Ecore_X_Randr_Mode_Info*)d2);
1496
1497    return ((mode1->width * mode1->height) - (mode2->width * mode2->height));
1498 }
1499
1500 /*
1501  * returns a mode within a given list of modes that is gemetrically identical.
1502  * If none is found, NULL is returned.
1503  */
1504 static Ecore_X_Randr_Mode_Info *
1505 _e_randr_mode_geo_identical_find(Eina_List *modes, Ecore_X_Randr_Mode_Info *mode)
1506 {
1507    Eina_List *iter;
1508    Ecore_X_Randr_Mode_Info *mode_info;
1509
1510    EINA_LIST_FOREACH(modes, iter, mode_info)
1511      {
1512         if ((mode_info->width == mode->width) && (mode_info->height == mode->height))
1513           return mode_info;
1514      }
1515    return NULL;
1516 }
1517
1518 /*
1519  * reconfigures a CRTC enabling the highest resolution amongst its outputs,
1520  * without touching any other CRTC currently activated
1521  */
1522 static Eina_Bool
1523 _e_randr_crtc_outputs_mode_max_set(E_Randr_Crtc_Info *crtc_info)
1524 {
1525    Ecore_X_Randr_Mode_Info *mode_info;
1526    Eina_List *iter;
1527    Eina_Bool ret = EINA_TRUE;
1528    Ecore_X_Randr_Output *outputs;
1529
1530    if (!crtc_info || !crtc_info->outputs || !crtc_info->outputs_common_modes) return EINA_FALSE;
1531
1532    EINA_LIST_REVERSE_FOREACH(crtc_info->outputs_common_modes, iter, mode_info)
1533      {
1534         if (!_e_randr_crtc_mode_intersects_crtcs(crtc_info, mode_info))
1535           break;
1536      }
1537    if (!mode_info)
1538      {
1539         eina_list_free(crtc_info->outputs_common_modes);
1540         return EINA_FALSE;
1541      }
1542    if ((outputs = _e_randr_outputs_to_array(crtc_info->outputs)))
1543      {
1544         ret = ecore_x_randr_crtc_mode_set(e_randr_screen_info->root, crtc_info->xid, outputs, eina_list_count(crtc_info->outputs), mode_info->xid);
1545         free(outputs);
1546      }
1547    eina_list_free(crtc_info->outputs_common_modes);
1548
1549    ecore_x_randr_screen_reset(e_randr_screen_info->root);
1550
1551    return ret;
1552 }
1553
1554 /*
1555  * returns EINA_TRUE if given CRTC would intersect with other CRTCs if set to
1556  * given mode
1557  */
1558 static Eina_Bool
1559 _e_randr_crtc_mode_intersects_crtcs(E_Randr_Crtc_Info *crtc_info, Ecore_X_Randr_Mode_Info *mode)
1560 {
1561    Eina_List *iter;
1562    E_Randr_Crtc_Info *tmp;
1563
1564    EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, tmp)
1565      {
1566         if ((tmp == crtc_info) || 
1567             ((tmp->geometry.w <= 0) || (tmp->geometry.h <= 0))) 
1568           continue;
1569         if (E_INTERSECTS(crtc_info->geometry.x, crtc_info->geometry.y, 
1570                          mode->width, mode->height, tmp->geometry.x, 
1571                          tmp->geometry.y, tmp->geometry.w, tmp->geometry.h)
1572             && ((crtc_info->geometry.x != tmp->geometry.x) && 
1573                 (crtc_info->geometry.y != tmp->geometry.y)))
1574           return EINA_TRUE;
1575      }
1576    return EINA_FALSE;
1577 }
1578
1579 /*
1580  * returns a list of modes common ammongst the given outputs,
1581  * optionally limited by max_size_mode. If none are found, NULL is returned.
1582  */
1583 static Eina_List *
1584 _e_randr_outputs_common_modes_get(Eina_List *outputs, Ecore_X_Randr_Mode_Info *max_size_mode)
1585 {
1586    Eina_List *common_modes = NULL, *iter, *output_iter, *right;
1587    E_Randr_Output_Info *output_info;
1588    Ecore_X_Randr_Mode_Info *mode_info;
1589    int outputs_mode_found;
1590
1591    if (!outputs) return NULL;
1592
1593    //create a list of all available modes
1594    EINA_LIST_FOREACH(outputs, iter, output_info)
1595      {
1596         right = eina_list_clone(output_info->modes);
1597         common_modes = eina_list_merge(common_modes, right);
1598      }
1599
1600    if (max_size_mode)
1601      {
1602         //remove all modes that are larger than max_size_mode
1603         EINA_LIST_FOREACH(common_modes, iter, mode_info)
1604           {
1605              if (_modes_size_sort_cb((void*)max_size_mode, (void*)mode_info) < 0)
1606                common_modes = eina_list_remove(common_modes, mode_info);
1607           }
1608      }
1609
1610    //sort modes desc. by their sizes
1611    EINA_LIST_REVERSE_FOREACH(common_modes, iter, mode_info)
1612      {
1613         outputs_mode_found = 0;
1614         EINA_LIST_FOREACH(outputs, output_iter, output_info)
1615           {
1616              if (eina_list_data_find(output_info->modes, mode_info))
1617                outputs_mode_found++;
1618           }
1619         if (outputs_mode_found != (int)eina_list_count(outputs))
1620           common_modes = eina_list_remove(common_modes, mode_info);
1621      }
1622    return common_modes;
1623 }
1624
1625 /*
1626  * reconfigure all CRTCs that had a given CRTC as a clone
1627  */
1628 static Eina_Bool
1629 _e_randr_crtcs_clone_crtc_removed(E_Randr_Crtc_Info *former_clone)
1630 {
1631    Eina_List *iter;
1632    E_Randr_Crtc_Info *crtc_info;
1633
1634    if (!former_clone) return EINA_FALSE;
1635
1636    EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info)
1637      {
1638         if ((crtc_info == former_clone) || ((crtc_info->geometry.w <= 0) || (crtc_info->geometry.h <= 0))) continue;
1639         if ((former_clone->geometry.x == crtc_info->geometry.x) && (former_clone->geometry.y == crtc_info->geometry.y) && (former_clone->geometry.w == crtc_info->geometry.w) && (former_clone->geometry.h == crtc_info->geometry.h))
1640           {
1641              if (!_e_randr_crtc_outputs_mode_max_set(crtc_info)) return EINA_FALSE;
1642           }
1643      }
1644
1645    return EINA_TRUE;
1646
1647 }
1648
1649 static void
1650 _e_randr_screen_primary_output_assign(E_Randr_Output_Info *removed)
1651 {
1652    Eina_List *iter;
1653    E_Randr_Output_Info *primary_output = NULL, *output_info;
1654
1655    E_RANDR_NO_OUTPUTS_RET();
1656
1657    if (e_randr_screen_info->rrvd_info.randr_info_12->primary_output && (removed != e_randr_screen_info->rrvd_info.randr_info_12->primary_output)) return;
1658    if (!(primary_output = _e_randr_output_info_get(ecore_x_randr_primary_output_get(e_randr_screen_info->root))))
1659      {
1660         primary_output = eina_list_data_get(eina_list_last(e_randr_screen_info->rrvd_info.randr_info_12->outputs));
1661
1662         EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->outputs, iter, output_info)
1663           {
1664              if (output_info->connection_status == ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED || !output_info->crtc || !output_info->crtc->current_mode) continue;
1665              if ((!primary_output->crtc || !primary_output->crtc->current_mode) || _outputs_size_sort_cb(output_info, primary_output) > 0) primary_output = output_info;
1666           }
1667         if (!primary_output->crtc || !primary_output->crtc->current_mode) primary_output = NULL;
1668      }
1669    e_randr_screen_info->rrvd_info.randr_info_12->primary_output = primary_output;
1670 }
1671
1672 static void
1673 _e_randr_output_info_hw_info_set(E_Randr_Output_Info *output_info)
1674 {
1675    Ecore_X_Randr_Output *outputs;
1676    Ecore_X_Randr_Crtc *crtcs;
1677    E_Randr_Output_Info *output;
1678    E_Randr_Crtc_Info *crtc;
1679    int i, num;
1680
1681    _e_randr_output_modes_add(output_info);
1682    output_info->edid = ecore_x_randr_output_edid_get(e_randr_screen_info->root, output_info->xid, &output_info->edid_length);
1683    //get the outputs we can use on the same CRTC alongside this one.
1684    if ((outputs = ecore_x_randr_output_clones_get(e_randr_screen_info->root, output_info->xid, &num)))
1685      {
1686         for (i = 0; i < num; i++)
1687           {
1688              if ((output = _e_randr_output_info_get(outputs[i])))
1689                output_info->clones = eina_list_append(output_info->clones, output);
1690           }
1691         free(outputs);
1692      }
1693
1694    //get the CRTCs which are usable with this output.
1695    if ((crtcs = ecore_x_randr_output_possible_crtcs_get(e_randr_screen_info->root, output_info->xid, &num)))
1696      {
1697         for (i = 0; i < num; i++)
1698           {
1699              fprintf(stderr, "E_RANDR: possible CRTC: %d\n", crtcs[i]);
1700              if ((crtc = _e_randr_crtc_info_get(crtcs[i])))
1701                {
1702                   fprintf(stderr, "E_RANDR: \tfound the suiting struct at %p\n", crtc);
1703                   output_info->possible_crtcs = eina_list_append(output_info->possible_crtcs, crtc);
1704                }
1705           }
1706         free(crtcs);
1707      }
1708 }
1709
1710 /*
1711  * free the hardware specifig parts of the information
1712  * removes all traces of an output within the data.
1713  * @param output_info the output info to be freed.
1714  */
1715 static void
1716 _e_randr_output_hw_info_free(E_Randr_Output_Info *output_info)
1717 {
1718    E_Randr_Crtc_Info *crtc_info;
1719    Eina_List *iter;
1720    if (!output_info) return;
1721
1722    if (output_info->modes)
1723      {
1724         eina_list_free(output_info->modes);
1725         output_info->modes = NULL;
1726      }
1727    if (output_info->preferred_modes)
1728      {
1729         eina_list_free(output_info->preferred_modes);
1730         output_info->preferred_modes = NULL;
1731      }
1732    if (output_info->edid)
1733      {
1734         free(output_info->edid);
1735         output_info->edid = NULL;
1736      }
1737    if (output_info->wired_clones)
1738      {
1739         eina_list_free(output_info->wired_clones);
1740         output_info->wired_clones = NULL;
1741      }
1742    if (output_info->compatible_outputs)
1743      {
1744         eina_list_free(output_info->compatible_outputs);
1745         output_info->compatible_outputs = NULL;
1746      }
1747    if (output_info->possible_crtcs)
1748      {
1749         eina_list_free(output_info->possible_crtcs);
1750         output_info->possible_crtcs = NULL;
1751      }
1752    if (output_info->clones)
1753      {
1754         eina_list_free(output_info->clones);
1755         output_info->clones = NULL;
1756      }
1757
1758    EINA_LIST_FOREACH(e_randr_screen_info->rrvd_info.randr_info_12->crtcs, iter, crtc_info)
1759      {
1760         crtc_info->possible_outputs = eina_list_remove(crtc_info->possible_outputs, output_info);
1761      }
1762 }
1763
1764 /*
1765  * checks whether a given output is a common clone of the given list's outputs
1766  */
1767 static Eina_Bool
1768 _e_randr_outputs_are_clones(E_Randr_Output_Info *output_info, Eina_List *outputs)
1769 {
1770    E_Randr_Output_Info *output;
1771    Eina_List *iter;
1772
1773    if (!outputs || !output_info) return EINA_FALSE;
1774
1775    EINA_LIST_FOREACH(output_info->clones, iter, output)
1776      {
1777         if (!eina_list_data_find(output_info->clones, output))
1778           return EINA_FALSE;
1779      }
1780    return EINA_TRUE;
1781 }