[E_BORDER] Add missing code to delete timer when the window gets DEICONIFY_APPROVE...
[platform/core/uifw/e17.git] / src / bin / e_randr_12.c
1 #include "e.h"
2 #include "e_randr_private.h"
3
4 #define POLLINTERVAL 128
5
6 // Set functions for the global e_randr_screen_info struct
7 static void                     _screen_primary_output_assign(E_Randr_Output_Info *removed);
8
9 // Init helper functions
10 static void                     _outputs_init(void);
11 static void                     _crtcs_init(void);
12 static Eina_Bool                _structs_init(void);
13
14 // Retrieval helper functions
15 static Ecore_X_Randr_Mode_Info *_mode_geo_identical_find(Eina_List *modes, Ecore_X_Randr_Mode_Info *mode);
16
17 // Event helper functions
18 static Eina_Bool                _x_poll_cb(void *data __UNUSED__);
19 static Eina_Bool                _crtc_change_event_cb(void *data, int type, void *e);
20 static Eina_Bool                _output_change_event_cb(void *data, int type, void *e);
21 static Eina_Bool                _output_property_change_event_cb(void *data, int type, void *e);
22
23 static Ecore_Poller *poller = NULL;
24 static Eina_List *_event_handlers = NULL;
25 static const char *_CONNECTION_STATES_STRINGS[] = {"CONNECTED", "DISCONNECTED", "UNKNOWN"};
26 static const char *_POLICIES_STRINGS[] = {"ABOVE", "RIGHT", "BELOW", "LEFT", "CLONE", "NONE"};
27
28 //"New" helper functions
29 /**
30  * @return array of E_Randr_Screen_Info_12 elements, or in case not all could
31  * be created or parameter 'nrequested'==0, NULL
32  */
33 static E_Randr_Screen_Info_12 *
34 _screen_info_12_new(void)
35 {
36    E_Randr_Screen_Info_12 *randr_info_12 = NULL;
37
38    EINA_SAFETY_ON_TRUE_RETURN_VAL((e_randr_screen_info.randr_version < ECORE_X_RANDR_1_2), NULL);
39
40    randr_info_12 = E_NEW(E_Randr_Screen_Info_12, 1);
41
42    randr_info_12->min_size.width = Ecore_X_Randr_Unset;
43    randr_info_12->min_size.height = Ecore_X_Randr_Unset;
44    randr_info_12->max_size.width = Ecore_X_Randr_Unset;
45    randr_info_12->max_size.height = Ecore_X_Randr_Unset;
46    randr_info_12->current_size.width = Ecore_X_Randr_Unset;
47    randr_info_12->current_size.height = Ecore_X_Randr_Unset;
48    randr_info_12->crtcs = NULL;
49    randr_info_12->outputs = NULL;
50    randr_info_12->modes = NULL;
51    randr_info_12->primary_output = NULL;
52    randr_info_12->alignment = ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE;
53
54    ecore_x_randr_screen_size_range_get(e_randr_screen_info.root,
55                                        &randr_info_12->min_size.width,
56                                        &randr_info_12->min_size.height,
57                                        &randr_info_12->max_size.width,
58                                        &randr_info_12->max_size.height);
59    ecore_x_randr_screen_current_size_get(e_randr_screen_info.root,
60                                          &randr_info_12->current_size.width,
61                                          &randr_info_12->current_size.height,
62                                          NULL, NULL);
63
64    return randr_info_12;
65 }
66
67 static Eina_Bool
68 _structs_init(void)
69 {
70    //Output stuff
71    Ecore_X_Randr_Output *outputs;
72    E_Randr_Output_Info *output_info = NULL;
73    int noutputs = 0;
74    //CRTC stuff
75    Ecore_X_Randr_Crtc *crtcs = NULL;
76    E_Randr_Crtc_Info *crtc_info = NULL;
77    int ncrtcs = 0;
78    //Modes stuff
79    Ecore_X_Randr_Mode_Info **modes = NULL;
80    int nmodes = 0;
81
82    EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, EINA_FALSE);
83
84    outputs = ecore_x_randr_outputs_get(e_randr_screen_info.root, &noutputs);
85    if (noutputs == 0) return EINA_FALSE;
86
87    while (--noutputs >= 0)
88      {
89         output_info = _output_info_new(outputs[noutputs]);
90         if (output_info)
91           e_randr_screen_info.rrvd_info.randr_info_12->outputs = eina_list_append(e_randr_screen_info.rrvd_info.randr_info_12->outputs, output_info);
92      }
93    free(outputs);
94
95    crtcs = ecore_x_randr_crtcs_get(e_randr_screen_info.root, &ncrtcs);
96    if (ncrtcs == 0) return EINA_FALSE;
97
98    while (--ncrtcs >= 0)
99      {
100         crtc_info = _crtc_info_new(crtcs[ncrtcs]);
101         e_randr_screen_info.rrvd_info.randr_info_12->crtcs = eina_list_append(e_randr_screen_info.rrvd_info.randr_info_12->crtcs, crtc_info);
102      }
103    free(crtcs);
104
105    modes = ecore_x_randr_modes_info_get(e_randr_screen_info.root, &nmodes);
106    if (nmodes == 0) return EINA_FALSE;
107
108    while (--nmodes >= 0)
109      {
110         e_randr_screen_info.rrvd_info.randr_info_12->modes = eina_list_append(e_randr_screen_info.rrvd_info.randr_info_12->modes, modes[nmodes]);
111      }
112
113    free(modes);
114    _outputs_init();
115    _crtcs_init();
116
117    return EINA_TRUE;
118 }
119
120 //Set value / retrieval helper functions
121
122 static void
123 _crtcs_init(void)
124 {
125    E_Randr_Crtc_Info *crtc = NULL;
126    Eina_List *iter;
127
128    EINA_SAFETY_ON_TRUE_RETURN(E_RANDR_12_NO);
129
130    EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->crtcs, iter, crtc)
131      _crtc_refs_set(crtc);
132 }
133
134 static void
135 _outputs_init(void)
136 {
137    E_Randr_Output_Info *output = NULL;
138    Eina_List *iter;
139
140    EINA_SAFETY_ON_TRUE_RETURN(E_RANDR_12_NO);
141
142    EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->outputs, iter, output)
143      {
144         _output_refs_set(output);
145         if (output->connection_status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED)
146           {
147              _monitor_info_free(output->monitor);
148              output->monitor = _monitor_info_new(output);
149           }
150      }
151 }
152
153 static void
154 _screen_primary_output_assign(E_Randr_Output_Info *removed)
155 {
156    Eina_List *iter;
157    E_Randr_Output_Info *primary_output = NULL, *output_info;
158
159    EINA_SAFETY_ON_TRUE_RETURN(E_RANDR_12_NO_OUTPUTS);
160
161    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;
162    if (!(primary_output = _12_screen_info_output_info_get(ecore_x_randr_primary_output_get(e_randr_screen_info.root))))
163      {
164         EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->outputs, iter, output_info)
165           {
166              if (!output_info || (output_info->connection_status != ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) || !output_info->crtc || !output_info->crtc->current_mode) continue;
167              primary_output = output_info;
168              break;
169           }
170      }
171    e_randr_screen_info.rrvd_info.randr_info_12->primary_output = primary_output;
172 }
173
174 //"Free" helper functions
175
176 /**
177  * @param screen_info the screen info to be freed.
178  */
179 void
180 _12_screen_info_free(E_Randr_Screen_Info_12 *screen_info)
181 {
182    Ecore_X_Randr_Mode_Info *mode_info;
183    E_Randr_Crtc_Info *crtc_info;
184    E_Randr_Output_Info *output_info;
185
186    EINA_SAFETY_ON_NULL_RETURN(screen_info);
187    EINA_SAFETY_ON_TRUE_RETURN(E_RANDR_12_NO);
188
189    EINA_LIST_FREE(screen_info->crtcs, crtc_info)
190      _crtc_info_free(crtc_info);
191
192    EINA_LIST_FREE(screen_info->outputs, output_info)
193      _output_info_free(output_info);
194
195    EINA_LIST_FREE(screen_info->modes, mode_info)
196      ecore_x_randr_mode_info_free(mode_info);
197
198    free(screen_info);
199 }
200
201 /*
202  *********************************************
203  *
204  * Getter functions for e_randr_screen_info struct
205  *
206  * ********************************************
207  */
208 Ecore_X_Randr_Mode_Info *
209 _12_screen_info_mode_info_get(const Ecore_X_Randr_Mode mode)
210 {
211    Eina_List *iter;
212    Ecore_X_Randr_Mode_Info *mode_info;
213
214    EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO_MODE(mode), NULL);
215
216    EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->modes, iter, mode_info)
217      {
218         if (mode_info && (mode_info->xid == mode)) return mode_info;
219      }
220    return NULL;
221 }
222
223 E_Randr_Output_Info *
224 _12_screen_info_output_info_get(const Ecore_X_Randr_Output output)
225 {
226    Eina_List *iter;
227    E_Randr_Output_Info *output_info;
228
229    EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO_OUTPUTS, NULL);
230
231    EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->outputs, iter, output_info)
232      {
233         if (output_info && (output_info->xid == output)) return output_info;
234      }
235    return NULL;
236 }
237
238 E_Randr_Crtc_Info *
239 _12_screen_info_crtc_info_get(const Ecore_X_Randr_Crtc crtc)
240 {
241    Eina_List *iter;
242    E_Randr_Crtc_Info *crtc_info;
243
244    EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO_CRTCS, NULL);
245
246    EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->crtcs, iter, crtc_info)
247      {
248         if (crtc_info && (crtc_info->xid == crtc)) return crtc_info;
249      }
250    return NULL;
251 }
252
253 Eina_Bool
254 _12_screen_info_edid_is_available(const E_Randr_Edid_Hash *hash)
255 {
256    Eina_List *iter;
257    E_Randr_Output_Info *output_info;
258
259    EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO_OUTPUTS, EINA_FALSE);
260    EINA_SAFETY_ON_NULL_RETURN_VAL(hash, EINA_FALSE);
261
262    EINA_LIST_FOREACH(e_randr_screen_info.rrvd_info.randr_info_12->outputs, iter, output_info)
263      {
264         if (!output_info || !output_info->monitor)
265           continue;
266         if (output_info->monitor->edid_hash.hash == hash->hash)
267           return EINA_TRUE;
268      }
269    return EINA_FALSE;
270 }
271
272 /*
273  * returns a mode within a given list of modes that is gemetrically identical.
274  * If none is found, NULL is returned.
275  */
276 static Ecore_X_Randr_Mode_Info *
277 _mode_geo_identical_find(Eina_List *modes, Ecore_X_Randr_Mode_Info *mode)
278 {
279    Eina_List *iter;
280    Ecore_X_Randr_Mode_Info *mode_info;
281
282    EINA_LIST_FOREACH(modes, iter, mode_info)
283      {
284         if ((mode_info->width == mode->width) && (mode_info->height == mode->height))
285           return mode_info;
286      }
287    return NULL;
288 }
289
290 /*****************************************************************
291  *
292  * Init. and Shutdown code
293  *
294  *****************************************************************
295  */
296 Eina_Bool
297 _12_screen_info_refresh(void)
298 {
299    EINA_SAFETY_ON_TRUE_RETURN_VAL((e_randr_screen_info.randr_version < ECORE_X_RANDR_1_2), EINA_FALSE);
300
301    if (e_randr_screen_info.rrvd_info.randr_info_12)
302      _12_screen_info_free(e_randr_screen_info.rrvd_info.randr_info_12);
303    if (!(e_randr_screen_info.rrvd_info.randr_info_12 = _screen_info_12_new()) ||
304        !_structs_init())
305      return EINA_FALSE;
306
307    _screen_primary_output_assign(NULL);
308
309    return EINA_TRUE;
310 }
311
312 /******************************************************************
313  *
314  * Event code
315  *
316  ******************************************************************
317  */
318
319 static Eina_Bool
320 _x_poll_cb(void *data __UNUSED__)
321 {
322    EINA_SAFETY_ON_NULL_RETURN_VAL(e_randr_screen_info.rrvd_info.randr_info_12, ECORE_CALLBACK_CANCEL);
323
324    ecore_x_randr_screen_primary_output_orientations_get(e_randr_screen_info.root);
325
326    return ECORE_CALLBACK_RENEW;
327 }
328
329 void
330 _12_event_listeners_add(void)
331 {
332    EINA_SAFETY_ON_TRUE_RETURN(E_RANDR_12_NO);
333
334    ecore_x_randr_events_select(e_randr_screen_info.root, EINA_TRUE);
335    _event_handlers = eina_list_append(_event_handlers, ecore_event_handler_add(ECORE_X_EVENT_RANDR_CRTC_CHANGE, _crtc_change_event_cb, NULL));
336    _event_handlers = eina_list_append(_event_handlers, ecore_event_handler_add(ECORE_X_EVENT_RANDR_OUTPUT_CHANGE, _output_change_event_cb, NULL));
337    _event_handlers = eina_list_append(_event_handlers, ecore_event_handler_add(ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY, _output_property_change_event_cb, NULL));
338    // WORKAROUND problem of X not sending events
339    poller = ecore_poller_add(ECORE_POLLER_CORE, POLLINTERVAL, _x_poll_cb, NULL);
340 }
341
342 /* Usually events are triggered in the following order.
343  * (Dis)connect Display Scenario:
344  * 1.) ECORE_X_EVENT_OUTPUT_CHANGE //Triggered, when a display is connected to an
345  * output
346  * 2.) ECORE_X_EVENT_CRTC_CHANGE //Triggered when the CRTC mode is changed (eg.
347  * enabled by e.g. e_randr or xrandr)
348  * 3.) ECORE_X_EVENT_OUTPUT_CHANGE //Triggered for each output changed by the
349  * preceeding enabling.
350  *
351  * When the mode of a CRTC is changed only events 2 and 3 are triggered
352  *
353  */
354 static Eina_Bool
355 _output_change_event_cb(void *data __UNUSED__, int type, void *ev)
356 {
357    Ecore_X_Event_Randr_Output_Change *oce = (Ecore_X_Event_Randr_Output_Change *)ev;
358    E_Randr_Output_Info *output_info = NULL;
359    E_Randr_Crtc_Info *crtc_info = NULL;
360    Eina_Bool policy_success = EINA_FALSE, con_state_changed = EINA_FALSE;
361
362    EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, ECORE_CALLBACK_CANCEL);
363    EINA_SAFETY_ON_TRUE_RETURN_VAL((type != ECORE_X_EVENT_RANDR_OUTPUT_CHANGE), ECORE_CALLBACK_RENEW);
364
365    /* event information:
366       Ecore_X_Window                  win;
367       Ecore_X_Randr_Output            output;
368       Ecore_X_Randr_Crtc              crtc;
369       Ecore_X_Randr_Mode              mode;
370       Ecore_X_Randr_Orientation       orientation;
371       Ecore_X_Randr_Connection_Status connection;
372       Ecore_X_Render_Subpixel_Order   subpixel_order;
373     */
374
375    EINA_SAFETY_ON_FALSE_RETURN_VAL((output_info = _12_screen_info_output_info_get(oce->output)), ECORE_CALLBACK_RENEW);
376
377    DBG("E_RANDR: Output event: \n"
378        "\t\t: relative to win: %d\n"
379        "\t\t: output (xid): %d\n"
380        "\t\t: used by crtc (xid): %d\n"
381        "\t\t: mode: %d\n"
382        "\t\t: orientation: %d\n"
383        "\t\t: connection state: %s\n"
384        "\t\t: subpixel_order: %d",
385        oce->win,
386        oce->output,
387        oce->crtc,
388        oce->mode,
389        oce->orientation,
390        _CONNECTION_STATES_STRINGS[oce->connection],
391        oce->subpixel_order);
392
393    crtc_info = _12_screen_info_crtc_info_get(oce->crtc);
394    //WORKAROUND
395    //Reason: Missing events, when an output is moved from one CRTC to
396    //        another
397    if (output_info->crtc && (crtc_info != output_info->crtc))
398      output_info->crtc->outputs = eina_list_remove(output_info->crtc->outputs, output_info);
399    //END WORKAROUND
400    output_info->crtc = crtc_info;
401
402    //Update mode references in case a mode was added manually
403    if (output_info->monitor)
404      {
405         eina_list_free(output_info->monitor->modes);
406         output_info->monitor->modes = NULL;
407         eina_list_free(output_info->monitor->preferred_modes);
408         output_info->monitor->preferred_modes = NULL;
409         _monitor_modes_refs_set(output_info->monitor, output_info->xid);
410         //Also update common modes of the used CRTC
411         if (crtc_info && crtc_info->current_mode)
412           {
413              eina_list_free(crtc_info->outputs);
414              crtc_info->outputs = NULL;
415              eina_list_free(crtc_info->outputs_common_modes);
416              crtc_info->outputs_common_modes = NULL;
417              _crtc_outputs_refs_set(crtc_info);
418           }
419      }
420
421    con_state_changed = (Eina_Bool)(output_info->connection_status != oce->connection);
422    output_info->connection_status = oce->connection;
423    output_info->subpixel_order = oce->subpixel_order;
424
425    if (con_state_changed)
426      {
427         _monitor_info_free(output_info->monitor);
428         output_info->monitor = NULL;
429
430         if (oce->connection == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED)
431           {
432              //New device connected!
433              output_info->monitor = _monitor_info_new(output_info);
434              INF("E_RANDR: Output %d was newly connected.", output_info->xid);
435
436              //only try to enable the monitor if there is no serialized setup
437              if (!_12_try_restore_configuration())
438                {
439                   policy_success = e_randr_12_try_enable_output(output_info, output_info->policy, EINA_FALSE);    //maybe give a success message?
440                   INF("E_RANDR: Policy \"%s\" was enforced %ssuccesfully.", _POLICIES_STRINGS[output_info->policy - 1], (policy_success ? "" : "un"));
441                }
442           }
443         else
444           {
445              //connection_state is 'unknown' or 'disconnected': treat as disconnected!
446              if (output_info->crtc)
447                {
448                   output_info->crtc->outputs = eina_list_remove(output_info->crtc->outputs, output_info);
449                   //in case this output was the last one connected on a CRTC,
450                   //disable it again
451                   if (eina_list_count(output_info->crtc->outputs) == 0)
452                     {
453                        //in case it was the only output running on this CRTC, disable
454                        //it.
455                        ecore_x_randr_crtc_mode_set(e_randr_screen_info.root, output_info->crtc->xid, NULL, Ecore_X_Randr_None, Ecore_X_Randr_None);
456                     }
457                }
458              //retry to find a suiting serialized setup for the remaining
459              //connected monitors
460              _12_try_restore_configuration();
461           }
462      }
463
464    return ECORE_CALLBACK_RENEW;
465 }
466
467 static Eina_Bool
468 _crtc_change_event_cb(void *data __UNUSED__, int type, void *ev)
469 {
470    Ecore_X_Event_Randr_Crtc_Change *cce = (Ecore_X_Event_Randr_Crtc_Change *)ev;
471    E_Randr_Crtc_Info *crtc_info;
472
473    EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, ECORE_CALLBACK_CANCEL);
474    EINA_SAFETY_ON_TRUE_RETURN_VAL((type != ECORE_X_EVENT_RANDR_CRTC_CHANGE), ECORE_CALLBACK_RENEW);
475
476    /* event information:
477       Ecore_X_Window                win;
478       Ecore_X_Randr_Crtc            crtc;
479       Ecore_X_Randr_Mode            mode;
480       Ecore_X_Randr_Orientation     orientation;
481       int                           x;
482       int                           y;
483       int                           width;
484       int                           height;
485     */
486    DBG("E_RANDR: CRTC event: \n"
487        "\t\t: relative to win: %d\n"
488        "\t\t: crtc (xid): %d\n"
489        "\t\t: mode (xid): %d\n"
490        "\t\t: orientation: %d\n"
491        "\t\t: x: %d\n"
492        "\t\t: y: %d\n"
493        "\t\t: width: %d\n"
494        "\t\t: height: %d",
495        cce->win,
496        cce->crtc,
497        cce->mode,
498        cce->orientation,
499        cce->geo.x,
500        cce->geo.y,
501        cce->geo.w,
502        cce->geo.h);
503
504    crtc_info = _12_screen_info_crtc_info_get(cce->crtc);
505    EINA_SAFETY_ON_NULL_RETURN_VAL(crtc_info, ECORE_CALLBACK_RENEW);
506
507    crtc_info->current_mode = _12_screen_info_mode_info_get(cce->mode);
508    crtc_info->current_orientation = cce->orientation;
509    crtc_info->geometry.x = cce->geo.x;
510    crtc_info->geometry.y = cce->geo.y;
511    crtc_info->geometry.w = cce->geo.w;
512    crtc_info->geometry.h = cce->geo.h;
513
514    //update screensize if necessary
515    e_randr_screen_info.rrvd_info.randr_info_12->current_size.width = MAX((cce->geo.x + cce->geo.w), e_randr_screen_info.rrvd_info.randr_info_12->current_size.width);
516    e_randr_screen_info.rrvd_info.randr_info_12->current_size.height = MAX((cce->geo.y + cce->geo.h), e_randr_screen_info.rrvd_info.randr_info_12->current_size.height);
517
518    //update output data
519    eina_list_free(crtc_info->outputs);
520    crtc_info->outputs = NULL;
521    eina_list_free(crtc_info->outputs_common_modes);
522    crtc_info->outputs_common_modes = NULL;
523
524    //if still enabled, update references to outputs
525    if (crtc_info->current_mode)
526      {
527         eina_list_free(crtc_info->outputs);
528         crtc_info->outputs = NULL;
529         eina_list_free(crtc_info->outputs_common_modes);
530         crtc_info->outputs_common_modes = NULL;
531         _crtc_outputs_refs_set(crtc_info);
532      }
533
534    //crop the screen
535    ecore_x_randr_screen_reset(e_randr_screen_info.root);
536
537    return ECORE_CALLBACK_RENEW;
538 }
539
540 static Eina_Bool
541 _output_property_change_event_cb(void *data __UNUSED__, int type, void *ev)
542 {
543    Ecore_X_Event_Randr_Output_Property_Notify *opce = (Ecore_X_Event_Randr_Output_Property_Notify *)ev;
544
545    EINA_SAFETY_ON_TRUE_RETURN_VAL(E_RANDR_12_NO, ECORE_CALLBACK_CANCEL);
546    EINA_SAFETY_ON_TRUE_RETURN_VAL((type != ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY), ECORE_CALLBACK_RENEW);
547
548    /* event information:
549       Ecore_X_Window                win;
550       Ecore_X_Randr_Output          output;
551       Ecore_X_Atom                  property;
552       Ecore_X_Time                  time;
553       Ecore_X_Randr_Property_Change state;
554     */
555    EINA_SAFETY_ON_FALSE_RETURN_VAL((_12_screen_info_output_info_get(opce->output)), ECORE_CALLBACK_RENEW);
556
557    return ECORE_CALLBACK_RENEW;
558 }
559
560 /*
561  * Try to enable this output on an unoccupied CRTC. 'Force' in this context
562  * means, that if there are only occupied CRTCs, we disable another output to
563  * enable this one. If not forced we will - if we don't find an unoccupied CRTC
564  * - try to share the output of a CRTC with other outputs already using it
565  *   (clone).
566  */
567 EINTERN Eina_Bool
568 e_randr_12_try_enable_output(E_Randr_Output_Info *output_info, Ecore_X_Randr_Output_Policy policy, Eina_Bool force)
569 {
570    Eina_List *iter, *outputs_list = NULL, *common_modes = NULL;
571    E_Randr_Crtc_Info *crtc_info = NULL, *usable_crtc = NULL;
572    const E_Randr_Crtc_Info *crtc_rel = NULL;
573    E_Randr_Output_Info *primary_output;
574    Ecore_X_Randr_Output *outputs;
575    Ecore_X_Randr_Mode_Info *mode_info;
576    int dx = Ecore_X_Randr_None, dy = Ecore_X_Randr_None;
577    Eina_Bool ret = EINA_TRUE;
578
579    EINA_SAFETY_ON_NULL_RETURN_VAL(output_info, EINA_FALSE);
580    EINA_SAFETY_ON_TRUE_RETURN_VAL((output_info->crtc && output_info->crtc->current_mode), EINA_FALSE);
581
582    /*
583     * Try to find a usable crtc for this output. Either unused or forced.
584     */
585    EINA_LIST_FOREACH(output_info->possible_crtcs, iter, crtc_info)
586      {
587         if (!crtc_info->current_mode || !crtc_info->outputs || force)
588           {
589              usable_crtc = crtc_info;
590              break;
591           }
592      }
593
594    /*
595     * apparently we don't have a CRTC to make use of the device
596     */
597    if (!usable_crtc)
598      return EINA_FALSE;
599
600    //get the CRTC we will refer to, dependend on policy
601    switch (policy)
602      {
603       case ECORE_X_RANDR_OUTPUT_POLICY_NONE:
604         return EINA_TRUE;
605
606       case ECORE_X_RANDR_OUTPUT_POLICY_ASK:
607         e_randr_12_ask_dialog_new(output_info);
608         return EINA_TRUE;  //This is a bit incorrect (dialog feedback is async), but probably not worth a lock.
609
610       case ECORE_X_RANDR_OUTPUT_POLICY_CLONE:
611         /*
612          * Order of approaches to enable a clone (of the primary output):
613          *
614          * 0.  Get Primary output from Server
615          * 1.  Try to add new Output to primary output's CRTC, using the mode used
616          *     by the primary output
617          * 2.  Try to enable clone in the same
618          * 2a. exact mode or a
619          * 2b. geometrically identical mode
620          * 3.  Find a most high resolution mode in common to enable on primary output's CRTC and the new
621          *     output's CRTC
622          * 4.  fail.
623          */
624         //Assign new output, if necessary
625         _screen_primary_output_assign(output_info);
626         if ((primary_output = e_randr_screen_info.rrvd_info.randr_info_12->primary_output))
627           {
628              if (primary_output->crtc && primary_output->crtc->current_mode && eina_list_data_find(output_info->monitor->modes, primary_output->crtc->current_mode))
629                {
630                   /*
631                    * mode currently used by primary output's CRTC is also supported by the new output
632                    */
633                   if (eina_list_data_find(primary_output->crtc->possible_outputs, output_info) && eina_list_data_find(output_info->monitor->modes, primary_output->crtc->current_mode))
634                     {
635                        /*
636                         * 1.  Try to add new Output to primary output's CRTC, using the mode used
637                         * by the primary output
638                         * TODO: check with compatibility list in RandRR >= 1.3
639                         * if available
640                         *
641                         * The new output is also usable by the primary output's
642                         * CRTC. Try to enable this output together with the already
643                         * enabled outputs on the CRTC in already used mode.
644                         */
645                        outputs_list = primary_output->crtc->outputs;
646                        outputs_list = eina_list_append(outputs_list, output_info);
647                        outputs = _outputs_to_array(outputs_list);
648                        primary_output->crtc->outputs = NULL;
649                        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);
650                        free(outputs);
651                        eina_list_free(outputs_list);
652                        return ret;
653                     }
654                   else
655                     {
656                        /*
657                         * 2.  Try to enable clone in the same
658                         */
659
660                        /*
661                         * 2a. exact mode.
662                         */
663                        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);
664                        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);
665                        return ret;
666                     }
667                }
668              else
669                {
670                   /*
671                    * 2b. geometrically identical mode
672                    */
673                   if (primary_output->crtc && (mode_info = _mode_geo_identical_find(output_info->monitor->modes, primary_output->crtc->current_mode)))
674                     {
675                        ret &= ecore_x_randr_crtc_mode_set(e_randr_screen_info.root, usable_crtc->xid, &output_info->xid, 1, mode_info->xid);
676                        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);
677                        return ret;
678                     }
679                   /*
680                    * 3.  Find the highest resolution mode common to enable on primary output's CRTC and the new one.
681                    */
682                   if (((outputs_list = eina_list_append(outputs_list, primary_output)) && (outputs_list = eina_list_append(outputs_list, output_info))))
683                     {
684                        if (primary_output->crtc)
685                          {
686                             common_modes = _outputs_common_modes_get(outputs_list, primary_output->crtc->current_mode);
687                             if ((mode_info = eina_list_nth(common_modes, 0)))
688                               {
689                                  eina_list_free(common_modes);
690                                  INF("Will try to set mode: %dx%d for primary and clone.", mode_info->width, mode_info->height);
691                                  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);
692                                  ret &= ecore_x_randr_crtc_mode_set(e_randr_screen_info.root, usable_crtc->xid, &output_info->xid, 1, mode_info->xid);
693                                  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);
694                               }
695                          }
696                        eina_list_free(outputs_list);
697                     }
698                }
699           }
700         else
701           ERR("E_RANDR: Failed to clone, because of missing or disabled primary output!");
702         /*
703          * 4. FAIL
704          */
705         break;
706
707       default:
708         //enable and position according to used policies
709         if (!(mode_info = ((Ecore_X_Randr_Mode_Info *)eina_list_data_get(output_info->monitor->preferred_modes))))
710           {
711              ERR("E_RANDR: Could not enable output(%d), as it has no preferred modes (and there for none at all)!", output_info->xid);
712              ret = EINA_FALSE;
713              break;
714           }
715
716         //get the crtc we will place our's relative to. If it's NULL, this is the
717         //only output attached, work done.
718         if (!(crtc_rel = _crtc_according_to_policy_get(usable_crtc, policy)))
719           {
720              INF("E_RANDR: CRTC %d enabled. No other CRTC had to be moved.", usable_crtc->xid);
721              ret &= ecore_x_randr_crtc_mode_set(e_randr_screen_info.root, usable_crtc->xid, &output_info->xid, 1, mode_info->xid);
722              return ret;
723           }
724
725         //Calculate new CRTC's position according to policy
726         switch (policy)
727           {
728            case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE:
729              usable_crtc->geometry.x = crtc_rel->geometry.x;
730              usable_crtc->geometry.y = 0;
731              break;
732
733            case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT:
734              usable_crtc->geometry.x = (crtc_rel->geometry.x + crtc_rel->geometry.w);
735              usable_crtc->geometry.y = crtc_rel->geometry.y;
736              break;
737
738            case ECORE_X_RANDR_OUTPUT_POLICY_BELOW:
739              usable_crtc->geometry.x = crtc_rel->geometry.x;
740              usable_crtc->geometry.y = (crtc_rel->geometry.y + crtc_rel->geometry.h);
741              break;
742
743            case ECORE_X_RANDR_OUTPUT_POLICY_LEFT:
744              usable_crtc->geometry.y = crtc_rel->geometry.y;
745              usable_crtc->geometry.x = 0;
746              break;
747
748            default:
749              usable_crtc->geometry.y = 0;
750              usable_crtc->geometry.x = 0;
751           }
752
753         if ((ret &= ecore_x_randr_crtc_settings_set(e_randr_screen_info.root, usable_crtc->xid, &output_info->xid, 1, usable_crtc->geometry.x, usable_crtc->geometry.y, mode_info->xid, ECORE_X_RANDR_ORIENTATION_ROT_0)))
754           {
755              //WORKAROUND
756              //Reason: the CRTC event, that'd bring the new info about the set
757              //mode is arriving too late here.
758              usable_crtc->current_mode = mode_info;
759              usable_crtc->geometry.w = mode_info->width;
760              usable_crtc->geometry.h = mode_info->height;
761              //WORKAROUND END
762
763              INF("E_RANDR: Moved CRTC %d has geometry (x,y,wxh): %d, %d, %dx%d.", usable_crtc->xid, usable_crtc->geometry.x, usable_crtc->geometry.y, usable_crtc->geometry.w, usable_crtc->geometry.h);
764              //following is policy dependend.
765              switch (policy)
766                {
767                 case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE:
768                   dy = (crtc_rel->geometry.y - usable_crtc->geometry.h);
769                   if (dy < 0)
770                     {
771                        //virtual move (move other CRTCs as nessesary)
772                        dy = -dy;
773                        ret &= ecore_x_randr_move_all_crtcs_but(e_randr_screen_info.root,
774                                                                &usable_crtc->xid,
775                                                                1,
776                                                                dx,
777                                                                dy);
778                        INF("E_RANDR: Moving all CRTCs but %d, by %dx%d delta.", usable_crtc->xid, dx, dy);
779                     }
780                   break;
781
782                 case ECORE_X_RANDR_OUTPUT_POLICY_LEFT:
783                   dx = (crtc_rel->geometry.x - usable_crtc->geometry.w);
784                   if (dx < 0)
785                     {
786                        //virtual move (move other CRTCs as nessesary)
787                        dx = -dx;
788                        ret &= ecore_x_randr_move_all_crtcs_but(e_randr_screen_info.root,
789                                                                &usable_crtc->xid,
790                                                                1,
791                                                                dx,
792                                                                dy);
793                        INF("E_RANDR: Moving all CRTCs but %d, by %dx%d delta.", usable_crtc->xid, dx, dy);
794                     }
795                   break;
796
797                 default:
798                   break;
799                }
800           }
801      }
802
803    if (ret)
804      ecore_x_randr_screen_reset(e_randr_screen_info.root);
805
806    return ret;
807 }
808
809 void
810 _12_event_listeners_remove(void)
811 {
812    Ecore_Event_Handler *_event_handler = NULL;
813
814    EINA_LIST_FREE(_event_handlers, _event_handler)
815      ecore_event_handler_del(_event_handler);
816    ecore_poller_del(poller);
817    poller = NULL;
818 }
819