summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2015-01-25 22:43:33 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2015-01-25 22:50:23 +0900
commit33d4531f1d862f5931550dcf9df5508014118b46 (patch)
tree651cb4d1fcba1f2ee6ece801cf24d473853952ae
parentab975cc349d5b0b23bb227e23a4d818071a0ed1e (diff)
e - rewrite randr code entirely. core and dialog. dialog is basic atm
the dialog for now is simple and lets you just raw edit the properties per screen in a dialog. nothing fancy. not user firendly. but it works. the randr core has been totally rewritten and tested against a range of drivers and setups before even getting a commit. it works solidly and configures screens reliably now. drivers tested: nvidia intel radeon some drivers still are unreliable in terms of delivering plug/unplug events for outputs (both intel and radeon are flakey - nvidia is solid and reliable). so to fix this there is now a screen redo action you can bind to a hotkey or something and have e re-evaluate current screen setup and apply ny pending config if needed. also to make reconfiguring prettier the screen is faded to black first, then configured, then faded back in. some drivers work flawlessly with this, others still flicker some garbage. i admit - i haven't tested nouveau, but my general take on this is the randr code is now in far better shape than where it was (minus pretty and easy dialog). the dialog can be done next, but i'd like to get the core in now for more testing. @fix
-rw-r--r--src/bin/Makefile.mk4
-rw-r--r--src/bin/e_actions.c14
-rw-r--r--src/bin/e_comp_object.c2
-rw-r--r--src/bin/e_comp_x.c79
-rw-r--r--src/bin/e_includes.h2
-rw-r--r--src/bin/e_init.c1
-rw-r--r--src/bin/e_randr2.c1581
-rw-r--r--src/bin/e_randr2.h121
-rw-r--r--src/bin/e_xinerama.c1
-rw-r--r--src/modules/Makefile_conf_randr.mk8
-rw-r--r--src/modules/conf_randr/e_int_config_randr2.c744
-rw-r--r--src/modules/conf_randr/e_int_config_randr2.h9
-rw-r--r--src/modules/conf_randr/e_mod_main.c28
-rw-r--r--src/modules/conf_randr/e_mod_main.h2
14 files changed, 2538 insertions, 58 deletions
diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk
index c3a552f..e64dcfb 100644
--- a/src/bin/Makefile.mk
+++ b/src/bin/Makefile.mk
@@ -138,7 +138,7 @@ src/bin/e_place.h \
138src/bin/e_pointer.h \ 138src/bin/e_pointer.h \
139src/bin/e_powersave.h \ 139src/bin/e_powersave.h \
140src/bin/e_prefix.h \ 140src/bin/e_prefix.h \
141src/bin/e_randr.h \ 141src/bin/e_randr2.h \
142src/bin/e_remember.h \ 142src/bin/e_remember.h \
143src/bin/e_resist.h \ 143src/bin/e_resist.h \
144src/bin/e_scale.h \ 144src/bin/e_scale.h \
@@ -364,7 +364,7 @@ $(ENLIGHTENMENTHEADERS)
364if ! HAVE_WAYLAND_ONLY 364if ! HAVE_WAYLAND_ONLY
365enlightenment_src += \ 365enlightenment_src += \
366src/bin/e_comp_x.c \ 366src/bin/e_comp_x.c \
367src/bin/e_randr.c \ 367src/bin/e_randr2.c \
368src/bin/e_xsettings.c 368src/bin/e_xsettings.c
369endif 369endif
370 370
diff --git a/src/bin/e_actions.c b/src/bin/e_actions.c
index d420470..52725c2 100644
--- a/src/bin/e_actions.c
+++ b/src/bin/e_actions.c
@@ -2899,6 +2899,13 @@ ACT_FN_GO(module_toggle, )
2899 else e_module_enable(m); 2899 else e_module_enable(m);
2900} 2900}
2901 2901
2902ACT_FN_GO(screen_redo, __UNUSED__)
2903{
2904 printf("REDOOOOOOOOOOOOOOOOOOOOOOOOOOO\n");
2905 e_randr2_screeninfo_update();
2906 e_randr2_config_apply();
2907}
2908
2902/* local subsystem globals */ 2909/* local subsystem globals */
2903static Eina_Hash *actions = NULL; 2910static Eina_Hash *actions = NULL;
2904static Eina_List *action_list = NULL; 2911static Eina_List *action_list = NULL;
@@ -3240,6 +3247,12 @@ e_actions_init(void)
3240 e_action_predef_name_set(N_("Screen"), N_("Backlight Down"), "backlight_adjust", 3247 e_action_predef_name_set(N_("Screen"), N_("Backlight Down"), "backlight_adjust",
3241 "-10", NULL, 0); 3248 "-10", NULL, 0);
3242 3249
3250 /* screen setup */
3251 ACT_GO(screen_redo);
3252 e_action_predef_name_set(N_("Screen"),
3253 N_("Update and re-apply screen setup"),
3254 "screen_redo", NULL, NULL, 0);
3255
3243 /* window_move_to_center */ 3256 /* window_move_to_center */
3244 ACT_GO(window_move_to_center); 3257 ACT_GO(window_move_to_center);
3245 e_action_predef_name_set(N_("Window : Actions"), N_("Move To Center"), 3258 e_action_predef_name_set(N_("Window : Actions"), N_("Move To Center"),
@@ -3426,6 +3439,7 @@ e_actions_init(void)
3426 e_action_predef_name_set(N_("Keyboard Layouts"), 3439 e_action_predef_name_set(N_("Keyboard Layouts"),
3427 N_("Previous keyboard layout"), "kbd_layout_prev", 3440 N_("Previous keyboard layout"), "kbd_layout_prev",
3428 NULL, NULL, 0); 3441 NULL, NULL, 0);
3442
3429 return 1; 3443 return 1;
3430} 3444}
3431 3445
diff --git a/src/bin/e_comp_object.c b/src/bin/e_comp_object.c
index 5ed9485..6b4df5a 100644
--- a/src/bin/e_comp_object.c
+++ b/src/bin/e_comp_object.c
@@ -657,7 +657,7 @@ static void
657_e_comp_object_setup(E_Comp_Object *cw) 657_e_comp_object_setup(E_Comp_Object *cw)
658{ 658{
659 cw->clip = evas_object_rectangle_add(cw->comp->evas); 659 cw->clip = evas_object_rectangle_add(cw->comp->evas);
660 evas_object_resize(cw->clip, cw->comp->man->w, cw->comp->man->h); 660 evas_object_resize(cw->clip, 999999, 999999);
661 evas_object_smart_member_add(cw->clip, cw->smart_obj); 661 evas_object_smart_member_add(cw->clip, cw->smart_obj);
662 cw->effect_obj = edje_object_add(cw->comp->evas); 662 cw->effect_obj = edje_object_add(cw->comp->evas);
663 evas_object_move(cw->effect_obj, cw->x, cw->y); 663 evas_object_move(cw->effect_obj, cw->x, cw->y);
diff --git a/src/bin/e_comp_x.c b/src/bin/e_comp_x.c
index 6208d20..d8a5813 100644
--- a/src/bin/e_comp_x.c
+++ b/src/bin/e_comp_x.c
@@ -1334,7 +1334,8 @@ _e_comp_x_configure(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_
1334 c = e_comp_find_by_window(ev->win); 1334 c = e_comp_find_by_window(ev->win);
1335 if (c) 1335 if (c)
1336 { 1336 {
1337 e_manager_resize(c->man, ev->w, ev->h); 1337 // do not handle this here - use randr events
1338 //e_manager_resize(c->man, ev->w, ev->h);
1338 return ECORE_CALLBACK_RENEW; 1339 return ECORE_CALLBACK_RENEW;
1339 } 1340 }
1340 ec = _e_comp_x_client_find_by_window(ev->win); 1341 ec = _e_comp_x_client_find_by_window(ev->win);
@@ -4565,14 +4566,32 @@ _e_comp_x_pre_swap(void *data, Evas *e EINA_UNUSED)
4565static Eina_Bool 4566static Eina_Bool
4566_e_comp_x_xinerama_setup(int rw, int rh) 4567_e_comp_x_xinerama_setup(int rw, int rh)
4567{ 4568{
4568 int n, i; 4569 int i;
4569 E_Screen *screen; 4570 E_Screen *screen;
4570 Eina_List *all_screens = NULL; 4571 Eina_List *all_screens = NULL;
4572 Eina_List *l;
4573 E_Randr2_Screen *s;
4571 4574
4572 /* first (and only) root window */ 4575 i = 0;
4573 /* get number of xinerama screens */ 4576 EINA_LIST_FOREACH(e_randr2->screens, l, s)
4574 n = ecore_x_xinerama_screen_count_get(); 4577 {
4575 if (n < 2) 4578 if ((s->config.enabled) &&
4579 (s->config.geom.w > 0) &&
4580 (s->config.geom.h > 0))
4581 {
4582 screen = E_NEW(E_Screen, 1);
4583 screen->escreen = screen->screen = i;
4584 screen->x = s->config.geom.x;
4585 screen->y = s->config.geom.y;
4586 screen->w = s->config.geom.w;
4587 screen->h = s->config.geom.h;
4588 all_screens = eina_list_append(all_screens, screen);
4589 INF("E INIT: XINERAMA SCREEN: [%i][%i], %ix%i+%i+%i",
4590 i, i, screen->w, screen->h, screen->x, screen->y);
4591 i++;
4592 }
4593 }
4594 if (i == 0)
4576 { 4595 {
4577 screen = E_NEW(E_Screen, 1); 4596 screen = E_NEW(E_Screen, 1);
4578 screen->escreen = screen->screen = 0; 4597 screen->escreen = screen->screen = 0;
@@ -4582,30 +4601,33 @@ _e_comp_x_xinerama_setup(int rw, int rh)
4582 screen->h = rh; 4601 screen->h = rh;
4583 all_screens = eina_list_append(all_screens, screen); 4602 all_screens = eina_list_append(all_screens, screen);
4584 } 4603 }
4604 e_xinerama_screens_set(all_screens);
4605 return EINA_TRUE;
4606}
4607
4608static Eina_Bool
4609_e_comp_x_randr_change(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event_info EINA_UNUSED)
4610{
4611 if ((e_comp->man->w != e_randr2->w) ||
4612 (e_comp->man->h != e_randr2->h))
4613 {
4614 e_manager_resize(e_comp->man, e_randr2->w, e_randr2->h);
4615 }
4585 else 4616 else
4586 { 4617 {
4587 for (i = 0; i < n; i++) 4618 E_Client *ec;
4588 {
4589 int x, y, w, h;
4590 4619
4591 /* get each xinerama screen geometry */ 4620 ecore_x_netwm_desk_size_set(e_comp->man->root, e_comp->man->w, e_comp->man->h);
4592 if (ecore_x_xinerama_screen_geometry_get(i, &x, &y, &w, &h)) 4621 _e_comp_x_xinerama_setup(e_comp->man->w, e_comp->man->h);
4593 { 4622
4594 INF("E INIT: XINERAMA SCREEN: [%i][%i], %ix%i+%i+%i", 4623 e_comp_canvas_update();
4595 i, i, w, h, x, y); 4624 E_CLIENT_FOREACH(e_comp, ec)
4596 /* add it to our list */ 4625 {
4597 screen = E_NEW(E_Screen, 1); 4626 if (!e_client_util_ignored_get(ec))
4598 screen->escreen = screen->screen = i; 4627 _e_comp_x_client_zone_geometry_set(ec);
4599 screen->x = x;
4600 screen->y = y;
4601 screen->w = w;
4602 screen->h = h;
4603 all_screens = eina_list_append(all_screens, screen);
4604 }
4605 } 4628 }
4606 } 4629 }
4607 e_xinerama_screens_set(all_screens); 4630 return ECORE_CALLBACK_RENEW;
4608 return EINA_TRUE;
4609} 4631}
4610 4632
4611static void 4633static void
@@ -5251,7 +5273,10 @@ e_comp_x_init(void)
5251 5273
5252 e_desklock_show_hook_add(_e_comp_x_desklock_show); 5274 e_desklock_show_hook_add(_e_comp_x_desklock_show);
5253 e_desklock_hide_hook_add(_e_comp_x_desklock_hide); 5275 e_desklock_hide_hook_add(_e_comp_x_desklock_hide);
5254 if (!e_randr_init()) return 0; 5276
5277 if (!e_randr2_init()) return 0;
5278 E_LIST_HANDLER_APPEND(handlers, E_EVENT_RANDR_CHANGE, _e_comp_x_randr_change, NULL);
5279
5255 if (!e_atoms_init()) return 0; 5280 if (!e_atoms_init()) return 0;
5256 if (!_e_comp_x_screens_setup()) return EINA_FALSE; 5281 if (!_e_comp_x_screens_setup()) return EINA_FALSE;
5257 if (!e_xsettings_init()) 5282 if (!e_xsettings_init())
@@ -5274,7 +5299,7 @@ e_comp_x_shutdown(void)
5274 ecore_x_screensaver_custom_blanking_disable(); 5299 ecore_x_screensaver_custom_blanking_disable();
5275 if (x_fatal) return; 5300 if (x_fatal) return;
5276 e_atoms_shutdown(); 5301 e_atoms_shutdown();
5277 e_randr_shutdown(); 5302 e_randr2_shutdown();
5278 /* ecore_x_ungrab(); */ 5303 /* ecore_x_ungrab(); */
5279 ecore_x_focus_reset(); 5304 ecore_x_focus_reset();
5280 ecore_x_events_allow_all(); 5305 ecore_x_events_allow_all();
diff --git a/src/bin/e_includes.h b/src/bin/e_includes.h
index a39351e..832a7d2 100644
--- a/src/bin/e_includes.h
+++ b/src/bin/e_includes.h
@@ -10,7 +10,7 @@
10#include "e_auth.h" 10#include "e_auth.h"
11#ifdef NEED_X 11#ifdef NEED_X
12# include "e_comp_x.h" 12# include "e_comp_x.h"
13# include "e_randr.h" 13# include "e_randr2.h"
14#endif 14#endif
15#include "e_pixmap.h" 15#include "e_pixmap.h"
16#include "e_comp_object.h" 16#include "e_comp_object.h"
diff --git a/src/bin/e_init.c b/src/bin/e_init.c
index 60c8a61..e61b467 100644
--- a/src/bin/e_init.c
+++ b/src/bin/e_init.c
@@ -64,7 +64,6 @@ e_init_show(void)
64 evas_object_name_set(o, "_e_init_extra_screen"); 64 evas_object_name_set(o, "_e_init_extra_screen");
65 } 65 }
66 evas_object_clip_set(o, zone->bg_clip_object); 66 evas_object_clip_set(o, zone->bg_clip_object);
67 fprintf(stderr, "zone %p: %i %i %ix%i\n", zone, zone->x, zone->y, zone->w, zone->h);
68 evas_object_move(o, zone->x, zone->y); 67 evas_object_move(o, zone->x, zone->y);
69 evas_object_resize(o, zone->w, zone->h); 68 evas_object_resize(o, zone->w, zone->h);
70 evas_object_layer_set(o, E_LAYER_MAX); 69 evas_object_layer_set(o, E_LAYER_MAX);
diff --git a/src/bin/e_randr2.c b/src/bin/e_randr2.c
new file mode 100644
index 0000000..781a55a
--- /dev/null
+++ b/src/bin/e_randr2.c
@@ -0,0 +1,1581 @@
1#include "e.h"
2
3#define E_RANDR_CONFIG_VERSION 1
4
5/////////////////////////////////////////////////////////////////////////
6static void _animated_apply_abort(void);
7static Eina_Bool _cb_delay_timer(void *data);
8static Eina_Bool _cb_fade_animator(void *data);
9static void _animated_apply(void);
10static void _do_apply(void);
11static void _info_free(E_Randr2 *r);
12static E_Config_Randr2 *_config_load(void);
13static void _config_free(E_Config_Randr2 *cfg);
14static Eina_Bool _config_save(E_Randr2 *r, E_Config_Randr2 *cfg);
15static void _config_update(E_Randr2 *r, E_Config_Randr2 *cfg);
16static void _config_apply(E_Randr2 *r, E_Config_Randr2 *cfg);
17static E_Config_Randr2_Screen *_config_screen_find(E_Randr2_Screen *s, E_Config_Randr2 *cfg);
18static int _config_screen_match_count(E_Randr2 *r, E_Config_Randr2 *cfg);
19static char *_screens_fingerprint(E_Randr2 *r);
20static Eina_Bool _screens_differ(E_Randr2 *r1, E_Randr2 *r2);
21static void _cb_acpi_handler_add(void *data);
22static Eina_Bool _cb_screen_change_delay(void *data);
23static void _screen_change_delay(void);
24static Eina_Bool _cb_acpi(void *data, int type, void *event);
25static E_Randr2_Screen *_screen_output_find(const char *out);
26static E_Randr2_Screen *_screen_id_find(const char *id);
27static void _screen_config_takeover(void);
28static void _screen_config_do(E_Randr2_Screen *s);
29static void _screen_config_eval(void);
30static void _screen_config_maxsize(void);
31
32/////////////////////////////////////////////////////////////////////////
33static E_Config_DD *_e_randr2_cfg_edd = NULL;
34static E_Config_DD *_e_randr2_cfg_screen_edd = NULL;
35static Eina_List *_ev_handlers = NULL;
36static Eina_Bool _lid_is_closed = EINA_FALSE;
37static Ecore_Job *_acpi_handler_add_job = NULL;
38static Ecore_Timer *_screen_delay_timer = NULL;
39static Eina_Bool event_screen = EINA_FALSE;
40static Eina_Bool event_ignore = EINA_FALSE;
41
42/////////////////////////////////////////////////////////////////////////
43EAPI E_Config_Randr2 *e_randr2_cfg = NULL;
44EAPI E_Randr2 *e_randr2 = NULL;
45
46EAPI int E_EVENT_RANDR_CHANGE = 0;
47
48/////////////////////////////////////////////////////////////////////////
49// X11 backend
50static Eina_Bool _output_init(void);
51static void _output_shutdown(void);
52static void _output_events_listen(void);
53static void _output_events_unlisten(void);
54static char *_output_screen_get(Ecore_X_Window root, Ecore_X_Randr_Output o);
55static Ecore_X_Randr_Edid_Display_Interface_Type _output_conn_type_get(Ecore_X_Window root, Ecore_X_Randr_Output o);
56static char *_output_name_get(Ecore_X_Window root, Ecore_X_Randr_Output o);
57static Eina_Bool _is_lid_name(const char *name);
58static E_Randr2 *_info_get(void);
59static Eina_Bool _cb_screen_change(void *data, int type, void *event);
60static Eina_Bool _cb_crtc_change(void *data, int type, void *event);
61static Eina_Bool _cb_output_change(void *data, int type, void *event);
62static Eina_Bool _output_name_find(Ecore_X_Window root, const char *name, Ecore_X_Randr_Output *outputs, int outputs_num, Ecore_X_Randr_Output *out_ret);
63static Eina_Bool _output_exists(Ecore_X_Randr_Output out, Ecore_X_Randr_Crtc_Info *info);
64static Eina_Bool _rotation_exists(int rot, Ecore_X_Randr_Crtc_Info *info);
65static Ecore_X_Randr_Mode _mode_screen_find(Ecore_X_Window root, E_Randr2_Screen *s, Ecore_X_Randr_Output out);
66static void _screen_config_apply(void);
67
68/////////////////////////////////////////////////////////////////////////
69EINTERN Eina_Bool
70e_randr2_init(void)
71{
72 if (!_output_init()) return EINA_FALSE;
73 // create data descriptors for config storage
74 _e_randr2_cfg_screen_edd =
75 E_CONFIG_DD_NEW("E_Config_Randr2_Screen", E_Config_Randr2_Screen);
76#undef T
77#undef D
78#define T E_Config_Randr2_Screen
79#define D _e_randr2_cfg_screen_edd
80 E_CONFIG_VAL(D, T, id, STR);
81 E_CONFIG_VAL(D, T, rel_to, STR);
82 E_CONFIG_VAL(D, T, rel_align, DOUBLE);
83 E_CONFIG_VAL(D, T, mode_refresh, DOUBLE);
84 E_CONFIG_VAL(D, T, mode_w, UINT);
85 E_CONFIG_VAL(D, T, mode_h, INT);
86 E_CONFIG_VAL(D, T, rotation, INT);
87 E_CONFIG_VAL(D, T, priority, INT);
88 E_CONFIG_VAL(D, T, rel_mode, UCHAR);
89 E_CONFIG_VAL(D, T, enabled, UCHAR);
90
91 _e_randr2_cfg_edd = E_CONFIG_DD_NEW("E_Config_Randr2", E_Config_Randr2);
92#undef T
93#undef D
94#define T E_Config_Randr2
95#define D _e_randr2_cfg_edd
96 E_CONFIG_VAL(D, T, version, INT);
97 E_CONFIG_LIST(D, T, screens, _e_randr2_cfg_screen_edd);
98 E_CONFIG_VAL(D, T, restore, UCHAR);
99
100 if (!E_EVENT_RANDR_CHANGE) E_EVENT_RANDR_CHANGE = ecore_event_type_new();
101 // delay setting up acpi handler, as acpi is init'ed after randr
102 _acpi_handler_add_job = ecore_job_add(_cb_acpi_handler_add, NULL);
103 // get current lid status of a laptop
104 _lid_is_closed = (e_acpi_lid_status_get() == E_ACPI_LID_CLOSED);
105 // set up events from the driver
106 _output_events_listen();
107 // get current screen info
108 e_randr2 = _info_get();
109 // from screen info calculate screen max dimensions
110 _screen_config_maxsize();
111 // load config and apply it
112 e_randr2_cfg = _config_load();
113 // only apply if restore is set AND at least one configured screen
114 // matches one we have
115 if ((e_randr2_cfg->restore) &&
116 (_config_screen_match_count(e_randr2, e_randr2_cfg) > 0))
117 {
118// _config_update(e_randr2, e_randr2_cfg);
119 _do_apply();
120 }
121 else
122 {
123 _config_update(e_randr2, e_randr2_cfg);
124 e_randr2_config_save();
125 }
126 return EINA_TRUE;
127}
128
129EINTERN int
130e_randr2_shutdown(void)
131{
132 _animated_apply_abort();
133 // nuke any screen config delay handler
134 if (_screen_delay_timer) ecore_timer_del(_screen_delay_timer);
135 _screen_delay_timer = NULL;
136 // stop listening to driver info
137 _output_events_unlisten();
138 // clean up acpi stuff
139 if (_acpi_handler_add_job) ecore_job_del(_acpi_handler_add_job);
140 _acpi_handler_add_job = NULL;
141 // clear up all event handlers
142 E_FREE_LIST(_ev_handlers, ecore_event_handler_del);
143 // free up screen info
144 _info_free(e_randr2);
145 e_randr2 = NULL;
146 _config_free(e_randr2_cfg);
147 e_randr2_cfg = NULL;
148 // free up data descriptors
149 E_CONFIG_DD_FREE(_e_randr2_cfg_edd);
150 E_CONFIG_DD_FREE(_e_randr2_cfg_screen_edd)
151 _output_shutdown();
152 return 1;
153}
154
155EAPI Eina_Bool
156e_randr2_config_save(void)
157{
158 // save our config
159 return _config_save(e_randr2, e_randr2_cfg);
160}
161
162EAPI void
163e_randr2_config_apply(void)
164{
165 _animated_apply();
166}
167
168EAPI void
169e_randr2_screeninfo_update(void)
170{
171 // re-fetch/update current screen info
172 _info_free(e_randr2);
173 e_randr2 = _info_get();
174 _screen_config_maxsize();
175}
176
177/////////////////////////////////////////////////////////////////////////
178static double _start_time = 0.0;
179static Ecore_Animator *_fade_animator = NULL;
180static Ecore_Timer *_apply_delay = NULL;
181Eina_Bool _applying = EINA_FALSE;
182static int _target_from = 0;
183static int _target_to = 0;
184static Evas_Object *_fade_obj = NULL;
185
186static void
187_animated_apply_abort(void)
188{
189 if (_apply_delay) ecore_timer_del(_apply_delay);
190 if (_fade_animator) ecore_animator_del(_fade_animator);
191 _apply_delay = NULL;
192 _fade_animator = NULL;
193 _applying = EINA_FALSE;
194 _fade_obj = NULL;
195}
196
197static Eina_Bool
198_cb_delay_timer(void *data EINA_UNUSED)
199{
200 _apply_delay = NULL;
201 _target_from = 255;
202 _target_to = 0;
203 _start_time = ecore_loop_time_get();
204 _fade_animator = ecore_animator_add(_cb_fade_animator, NULL);
205 return EINA_FALSE;
206}
207
208static Eina_Bool
209_cb_fade_animator(void *data EINA_UNUSED)
210{
211 double t = ecore_loop_time_get() - _start_time;
212 int v;
213
214 t = t / 0.5;
215 if (t < 0.0) t = 0.0;
216 v = _target_from + ((_target_to - _target_from) * t);
217 if (t >= 1.0) v = _target_to;
218 evas_object_color_set(_fade_obj, 0, 0, 0, v);
219 if (v == _target_to)
220 {
221 if (_target_to == 255)
222 {
223 _apply_delay = ecore_timer_add(3.0, _cb_delay_timer, NULL);
224 _do_apply();
225 }
226 else
227 {
228 evas_object_del(_fade_obj);
229 _fade_obj = NULL;
230 _applying = EINA_FALSE;
231 }
232 _fade_animator = NULL;
233 return EINA_FALSE;
234 }
235 return EINA_TRUE;
236}
237
238static void
239_animated_apply(void)
240{
241 Evas *e;
242
243 // fade out, config, wait 3 seconds, fade back in
244 if (_applying) return;
245 _applying = EINA_TRUE;
246 _start_time = ecore_loop_time_get();
247 e = e_comp_get(NULL)->evas;
248 _fade_obj = evas_object_rectangle_add(e);
249 evas_object_pass_events_set(_fade_obj, EINA_TRUE);
250 evas_object_color_set(_fade_obj, 0, 0, 0, 0);
251 evas_object_move(_fade_obj, 0, 0);
252 evas_object_resize(_fade_obj, 999999, 999999);
253 evas_object_layer_set(_fade_obj, EVAS_LAYER_MAX);
254 evas_object_show(_fade_obj);
255 _target_from = 0;
256 _target_to = 255;
257 _fade_animator = ecore_animator_add(_cb_fade_animator, NULL);
258}
259
260static void
261_do_apply(void)
262{
263 // take current screen config and apply it to the driver
264 printf("RRR: re-get info before applying..\n");
265 _info_free(e_randr2);
266 e_randr2 = _info_get();
267 _screen_config_maxsize();
268 printf("RRR: apply config...\n");
269 _config_apply(e_randr2, e_randr2_cfg);
270 printf("RRR: takeover config...\n");
271 _screen_config_takeover();
272 printf("RRR: eval config...\n");
273 _screen_config_eval();
274 printf("RRR: really apply config...\n");
275 _screen_config_apply();
276 printf("RRR: done config...\n");
277}
278
279static void
280_info_free(E_Randr2 *r)
281{
282 E_Randr2_Screen *s;
283 E_Randr2_Mode *m;
284
285 if (!r) return;
286 // free up our randr screen data
287 EINA_LIST_FREE(r->screens, s)
288 {
289 free(s->id);
290 free(s->info.screen);
291 free(s->info.name);
292 free(s->info.edid);
293 EINA_LIST_FREE(s->info.modes, m) free(m);
294 free(s->config.relative.to);
295 free(s);
296 }
297 free(r);
298}
299
300static E_Config_Randr2 *
301_config_load(void)
302{
303 E_Config_Randr2 *cfg;
304
305 // load config and check if version is up to date
306 cfg = e_config_domain_load("e_randr2", _e_randr2_cfg_edd);
307 if (cfg)
308 {
309 if (cfg->version < E_RANDR_CONFIG_VERSION)
310 {
311 _config_free(cfg);
312 cfg = NULL;
313 }
314 else
315 {
316 printf("RRR: loaded existing config\n");
317 return cfg;
318 }
319 }
320
321 // need new config
322 cfg = calloc(1, sizeof(E_Config_Randr2));
323 cfg->version = E_RANDR_CONFIG_VERSION;
324 cfg->screens = NULL;
325 cfg->restore = 1;
326 printf("RRR: fresh config\n");
327 return cfg;
328}
329
330static void
331_config_free(E_Config_Randr2 *cfg)
332{
333 E_Config_Randr2_Screen *cs;
334
335 if (!cfg) return;
336 // free config data
337 EINA_LIST_FREE(cfg->screens, cs) free(cs);
338 free(cfg);
339}
340
341static Eina_Bool
342_config_save(E_Randr2 *r, E_Config_Randr2 *cfg)
343{
344 if ((!r) || (!cfg)) return EINA_FALSE;
345 // save config struct to cfg file
346 return e_config_domain_save("e_randr2", _e_randr2_cfg_edd, cfg);
347}
348
349static void
350_config_update(E_Randr2 *r, E_Config_Randr2 *cfg)
351{
352 Eina_List *l;
353 E_Randr2_Screen *s;
354 E_Config_Randr2_Screen *cs;
355
356 printf("--------------------------------------------------\n");
357 EINA_LIST_FOREACH(r->screens, l, s)
358 {
359 printf("RRR: out id=%s: connected=%i\n", s->id, s->info.connected);
360 if ((!s->id) || (!s->info.connected)) continue;
361 cs = _config_screen_find(s, cfg);
362 if (!cs)
363 {
364 cs = calloc(1, sizeof(E_Config_Randr2_Screen));
365 if (cs)
366 {
367 cs->id = strdup(s->id);
368 cfg->screens = eina_list_prepend(cfg->screens, cs);
369 }
370 }
371 if (cs)
372 {
373 if (s->config.relative.to)
374 cs->rel_to = strdup(s->config.relative.to);
375 cs->rel_align = s->config.relative.align;
376 cs->mode_refresh = s->config.mode.refresh;
377 cs->mode_w = s->config.mode.w;
378 cs->mode_h = s->config.mode.h;
379 cs->rotation = s->config.rotation;
380 cs->priority = s->config.priority;
381 cs->rel_mode = s->config.relative.mode;
382 cs->enabled = s->config.enabled;
383 }
384 }
385 printf("--------------------------------------------------\n");
386}
387
388static void
389_config_apply(E_Randr2 *r, E_Config_Randr2 *cfg)
390{
391 Eina_List *l;
392 E_Randr2_Screen *s;
393 E_Config_Randr2_Screen *cs;
394
395 if ((!r) || (!cfg)) return;
396 EINA_LIST_FOREACH(r->screens, l, s)
397 {
398 printf("RRR: apply '%s'...\n", s->info.name);
399 cs = NULL;
400 if (s->info.connected) cs = _config_screen_find(s, cfg);
401 printf("RRR: connected = %i\n", s->info.connected);
402 if ((cs) && (cs->enabled))
403 {
404 printf("RRR: ... enabled\n");
405 s->config.enabled = EINA_TRUE;
406 s->config.mode.w = cs->mode_w;
407 s->config.mode.h = cs->mode_h;
408 s->config.mode.refresh = cs->mode_refresh;
409 s->config.mode.preferred = EINA_FALSE;
410 s->config.rotation = cs->rotation;
411 s->config.priority = cs->priority;
412 free(s->config.relative.to);
413 if (cs->rel_to) s->config.relative.to = strdup(cs->rel_to);
414 else s->config.relative.to = NULL;
415 s->config.relative.mode = cs->rel_mode;
416 s->config.relative.align = cs->rel_align;
417 }
418 else
419 {
420 printf("RRR: ... disabled\n");
421 s->config.enabled = EINA_FALSE;
422 s->config.geom.x = 0;
423 s->config.geom.y = 0;
424 s->config.geom.w = 0;
425 s->config.geom.h = 0;
426 s->config.mode.w = 0;
427 s->config.mode.h = 0;
428 s->config.mode.refresh = 0.0;
429 s->config.mode.preferred = EINA_FALSE;
430 s->config.rotation = 0;
431 s->config.priority = 0;
432 free(s->config.relative.to);
433 s->config.relative.to = NULL;
434 s->config.relative.mode = E_RANDR2_RELATIVE_NONE;
435 s->config.relative.align = 0.0;
436 }
437 s->config.configured = EINA_TRUE;
438 }
439}
440
441static E_Config_Randr2_Screen *
442_config_screen_find(E_Randr2_Screen *s, E_Config_Randr2 *cfg)
443{
444 Eina_List *l;
445 E_Config_Randr2_Screen *cs;
446
447 if ((!s) || (!cfg)) return NULL;
448 if (!s->id) return NULL;
449 EINA_LIST_FOREACH(cfg->screens, l, cs)
450 {
451 if (!cs->id) continue;
452 if (!strcmp(cs->id, s->id)) return cs;
453 }
454 return NULL;
455}
456
457static int
458_config_screen_match_count(E_Randr2 *r, E_Config_Randr2 *cfg)
459{
460 Eina_List *l, *ll;
461 E_Randr2_Screen *s;
462 E_Config_Randr2_Screen *cs;
463 int count = 0;
464
465 EINA_LIST_FOREACH(cfg->screens, l, cs)
466 {
467 if (!cs->id) continue;
468 EINA_LIST_FOREACH(r->screens, ll, s)
469 {
470 if ((!s->id) || (!s->info.connected)) continue;
471 if (!strcmp(cs->id, s->id)) count++;
472 }
473 }
474 return count;
475}
476
477static void
478_cb_acpi_handler_add(void *data EINA_UNUSED)
479{
480 // add acpi handler in delayed job
481 E_LIST_HANDLER_APPEND(_ev_handlers, E_EVENT_ACPI, _cb_acpi, NULL);
482 _acpi_handler_add_job = NULL;
483}
484
485static char *
486_screens_fingerprint(E_Randr2 *r)
487{
488 Eina_List *l;
489 E_Randr2_Screen *s;
490 Eina_Strbuf *buf;
491 char *str;
492
493 buf = eina_strbuf_new();
494 if (!buf) return NULL;
495 EINA_LIST_FOREACH(r->screens, l, s)
496 {
497 if (!s->id) eina_strbuf_append(buf, ":NULL:");
498 else
499 {
500 eina_strbuf_append(buf, ":");
501 eina_strbuf_append(buf, s->id);
502 eina_strbuf_append(buf, ":");
503 }
504 }
505 str = eina_strbuf_string_steal(buf);
506 eina_strbuf_free(buf);
507 return str;
508}
509
510static Eina_Bool
511_screens_differ(E_Randr2 *r1, E_Randr2 *r2)
512{
513 char *s1, *s2;
514 Eina_Bool changed = EINA_FALSE;
515 Eina_List *l, *ll;
516 E_Randr2_Screen *s, *ss;
517
518 // check monitor outputs and edids, plugged in things
519 s1 = _screens_fingerprint(r1);
520 s2 = _screens_fingerprint(r2);
521 if ((!s1) && (!s2)) return EINA_FALSE;
522 if ((s1) && (s2) && (strcmp(s1, s2))) changed = EINA_TRUE;
523 free(s1);
524 free(s2);
525 // check screen config
526 EINA_LIST_FOREACH(r2->screens, l, s)
527 {
528 if (!s->id) continue;
529 EINA_LIST_FOREACH(r2->screens, ll, ss)
530 {
531 if ((ss->id) && (!strcmp(s->id, ss->id))) break;
532 ss = NULL;
533 }
534 if (!ss) changed = EINA_TRUE;
535 else if ((s->config.geom.x != ss->config.geom.x) ||
536 (s->config.geom.y != ss->config.geom.y) ||
537 (s->config.geom.w != ss->config.geom.w) ||
538 (s->config.geom.h != ss->config.geom.h) ||
539 (s->config.mode.w != ss->config.mode.w) ||
540 (s->config.mode.h != ss->config.mode.h) ||
541 (s->config.enabled != ss->config.enabled) ||
542 (s->config.rotation != ss->config.rotation))
543 changed = EINA_TRUE;
544 }
545 return changed;
546}
547
548static Eina_Bool
549_cb_screen_change_delay(void *data EINA_UNUSED)
550{
551 _screen_delay_timer = NULL;
552 // if we had a screen plug/unplug etc. event and we shouldnt ignore it...
553 if ((event_screen) && (!event_ignore))
554 {
555 E_Randr2 *rtemp;
556 Eina_Bool change = EINA_FALSE;
557
558 printf("RRR: reconfigure screens due to event...\n");
559 rtemp = _info_get();
560 if (rtemp)
561 {
562 if (_screens_differ(e_randr2, rtemp)) change = EINA_TRUE;
563 _info_free(rtemp);
564 }
565 // we plugged or unplugged some monitor - re-apply config so
566 // known screens can be coonfigured
567 if (change) e_randr2_config_apply();
568 }
569 // update screen info after the above apply or due to external changes
570 e_randr2_screeninfo_update();
571 // tell the rest of e some screen reconfigure thing happened
572 ecore_event_add(E_EVENT_RANDR_CHANGE, NULL, NULL, NULL);
573 event_screen = EINA_FALSE;
574 event_ignore = EINA_FALSE;
575 return EINA_FALSE;
576}
577
578static void
579_screen_change_delay(void)
580{
581 // delay handling of screen shances as they can come in in a series over
582 // time and thus we can batch up responding to them by waiting 1.0 sec
583 if (_screen_delay_timer) ecore_timer_del(_screen_delay_timer);
584 _screen_delay_timer = ecore_timer_add(1.0, _cb_screen_change_delay, NULL);
585}
586
587static Eina_Bool
588_cb_acpi(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
589{
590 E_Event_Acpi *ev = event;
591 Eina_Bool lid_closed;
592
593 if (ev->type != E_ACPI_TYPE_LID) return EINA_TRUE;
594 lid_closed = (ev->status == E_ACPI_LID_CLOSED);
595 if (lid_closed == _lid_is_closed) return EINA_TRUE;
596 _lid_is_closed = lid_closed;
597 _screen_change_delay();
598 return EINA_TRUE;
599}
600
601static E_Randr2_Screen *
602_screen_output_find(const char *out)
603{
604 E_Randr2_Screen *s;
605 Eina_List *l;
606 EINA_LIST_FOREACH(e_randr2->screens, l, s)
607 {
608 if (!strcmp(s->info.name, out)) return s;
609 }
610 return NULL;
611}
612
613static E_Randr2_Screen *
614_screen_id_find(const char *id)
615{
616 E_Randr2_Screen *s;
617 Eina_List *l;
618 EINA_LIST_FOREACH(e_randr2->screens, l, s)
619 {
620 if (!strcmp(s->id, id)) return s;
621 }
622 return NULL;
623}
624
625static void
626_screen_config_takeover(void)
627{
628 Eina_List *l;
629 E_Randr2_Screen *s;
630 EINA_LIST_FOREACH(e_randr2->screens, l, s)
631 {
632 s->config.configured = EINA_TRUE;
633 }
634}
635
636static int _config_do_recurse = 0;
637
638static void
639_screen_config_do(E_Randr2_Screen *s)
640{
641 E_Randr2_Screen *s2 = NULL;
642
643 _config_do_recurse++;
644 if (_config_do_recurse > 20)
645 {
646 ERR("screen config loop!");
647 return;
648 }
649 // if screen has a dependency...
650 if ((s->config.relative.mode != E_RANDR2_RELATIVE_UNKNOWN) &&
651 (s->config.relative.mode != E_RANDR2_RELATIVE_NONE) &&
652 (s->config.relative.to))
653 {
654 // if this screen is relative TO something (clone or left/right etc.
655 // then calculate what it is relative to first
656 s2 = _screen_id_find(s->config.relative.to);
657 printf("RRR: '%s' is relative to %p\n", s->info.name, s2);
658 if (!s2)
659 {
660 // strip out everythng in the string from / on as that is edid
661 // and fall back to finding just the output name in the rel
662 // to identifier, rather than the specific screen id
663 char *p, *str = alloca(strlen(s->config.relative.to) + 1);
664 strcpy(str, s->config.relative.to);
665 if ((p = strchr(str, '/'))) *p = 0;
666 s2 = _screen_output_find(str);
667 }
668 printf("RRR: '%s' is relative to %p\n", s->info.name, s2);
669 if (s2) _screen_config_do(s2);
670 }
671 s->config.geom.x = 0;
672 s->config.geom.y = 0;
673 if ((s->config.rotation == 0) || (s->config.rotation == 180))
674 {
675 s->config.geom.w = s->config.mode.w;
676 s->config.geom.h = s->config.mode.h;
677 }
678 else
679 {
680 s->config.geom.w = s->config.mode.h;
681 s->config.geom.h = s->config.mode.w;
682 }
683 if (s2)
684 {
685 if (s->config.relative.mode == E_RANDR2_RELATIVE_CLONE)
686 {
687 printf("RRR: clone relative\n");
688 s->config.geom.x = s2->config.geom.x;
689 s->config.geom.y = s2->config.geom.y;
690 s->config.geom.w = s2->config.geom.w;
691 s->config.geom.h = s2->config.geom.h;
692 s->config.mode.w = s2->config.mode.w;
693 s->config.mode.h = s2->config.mode.h;
694 s->config.rotation = s2->config.rotation;
695 s->config.mode.refresh = s2->config.mode.refresh;
696 }
697 else if (s->config.relative.mode == E_RANDR2_RELATIVE_TO_LEFT)
698 {
699 printf("RRR: to left relative\n");
700 s->config.geom.x = s2->config.geom.x - s->config.geom.w;
701 s->config.geom.y = s2->config.geom.y +
702 ((s2->config.geom.h - s->config.geom.h) *
703 s->config.relative.align);
704 }
705 else if (s->config.relative.mode == E_RANDR2_RELATIVE_TO_RIGHT)
706 {
707 printf("RRR: to right relative\n");
708 s->config.geom.x = s2->config.geom.x + s2->config.geom.w;
709 s->config.geom.y = s2->config.geom.y +
710 ((s2->config.geom.h - s->config.geom.h) *
711 s->config.relative.align);
712 }
713 else if (s->config.relative.mode == E_RANDR2_RELATIVE_TO_ABOVE)
714 {
715 printf("RRR: to above relative\n");
716 s->config.geom.x = s2->config.geom.x +
717 ((s2->config.geom.w - s->config.geom.w) *
718 s->config.relative.align);
719 s->config.geom.y = s2->config.geom.y - s->config.geom.h;
720 }
721 else if (s->config.relative.mode == E_RANDR2_RELATIVE_TO_BELOW)
722 {
723 printf("RRR: to below relative\n");
724 s->config.geom.x = s2->config.geom.x +
725 ((s2->config.geom.w - s->config.geom.w) *
726 s->config.relative.align);
727 s->config.geom.y = s2->config.geom.y + s2->config.geom.h;
728 }
729 }
730}
731
732static void
733_screen_config_eval(void)
734{
735 Eina_List *l;
736 E_Randr2_Screen *s;
737 int minx, miny, maxx, maxy;
738
739 EINA_LIST_FOREACH(e_randr2->screens, l, s)
740 {
741 if (s->config.configured) _screen_config_do(s);
742 }
743 minx = 65535;
744 miny = 65535;
745 maxx = -65536;
746 maxy = -65536;
747 printf("RRR:--------------------------------\n");
748 EINA_LIST_FOREACH(e_randr2->screens, l, s)
749 {
750 if (!s->config.enabled) continue;
751 if (s->config.geom.x < minx) minx = s->config.geom.x;
752 if (s->config.geom.y < miny) miny = s->config.geom.y;
753 if ((s->config.geom.x + s->config.geom.w) > maxx)
754 maxx = s->config.geom.x + s->config.geom.w;
755 if ((s->config.geom.y + s->config.geom.h) > maxy)
756 maxy = s->config.geom.y + s->config.geom.h;
757 printf("RRR: s: '%s' @ %i %i - %ix%i\n",
758 s->info.name,
759 s->config.geom.x, s->config.geom.y,
760 s->config.geom.w, s->config.geom.h);
761 }
762 printf("RRR:--- %i %i -> %i %i\n", minx, miny, maxx, maxy);
763 EINA_LIST_FOREACH(e_randr2->screens, l, s)
764 {
765 s->config.geom.x -= minx;
766 s->config.geom.y -= miny;
767 }
768 e_randr2->w = maxx - minx;
769 e_randr2->h = maxy - miny;
770}
771
772static void
773_screen_config_maxsize(void)
774{
775 Eina_List *l;
776 E_Randr2_Screen *s;
777 int maxx, maxy;
778
779 maxx = -65536;
780 maxy = -65536;
781 printf("RRR:-------------------------------- 2\n");
782 EINA_LIST_FOREACH(e_randr2->screens, l, s)
783 {
784 if (!s->config.enabled) continue;
785 if ((s->config.geom.x + s->config.geom.w) > maxx)
786 maxx = s->config.geom.x + s->config.geom.w;
787 if ((s->config.geom.y + s->config.geom.h) > maxy)
788 maxy = s->config.geom.y + s->config.geom.h;
789 printf("RRR: '%s': %i %i %ix%i\n",
790 s->info.name,
791 s->config.geom.x, s->config.geom.y,
792 s->config.geom.w, s->config.geom.h);
793 }
794 printf("RRR: result max: %ix%i\n", maxx, maxy);
795 e_randr2->w = maxx;
796 e_randr2->h = maxy;
797}
798
799/////////////////////////////////////////////////////////////////////////
800// X11 backend
801static Eina_Bool
802_output_init(void)
803{
804 // is randr extn there?
805 return ecore_x_randr_query();
806}
807
808static void
809_output_shutdown(void)
810{
811}
812
813static void
814_output_events_listen(void)
815{
816 // add handler for randr screen change events
817 E_LIST_HANDLER_APPEND(_ev_handlers, ECORE_X_EVENT_SCREEN_CHANGE,
818 _cb_screen_change, NULL);
819 E_LIST_HANDLER_APPEND(_ev_handlers, ECORE_X_EVENT_RANDR_CRTC_CHANGE,
820 _cb_crtc_change, NULL);
821 E_LIST_HANDLER_APPEND(_ev_handlers, ECORE_X_EVENT_RANDR_OUTPUT_CHANGE,
822 _cb_output_change, NULL);
823 // if it's 1.2 or better then we can select for these events
824 if (ecore_x_randr_version_get() >= E_RANDR_VERSION_1_2)
825 {
826 Ecore_X_Window root = ecore_x_window_root_first_get();
827 ecore_x_randr_events_select(root, EINA_TRUE);
828 }
829}
830
831static void
832_output_events_unlisten(void)
833{
834 // clear up event listening
835 if (ecore_x_randr_version_get() >= E_RANDR_VERSION_1_2)
836 {
837 Ecore_X_Window root = ecore_x_window_root_first_get();
838 ecore_x_randr_events_select(root, EINA_FALSE);
839 }
840}
841
842static char *
843_output_screen_get(Ecore_X_Window root, Ecore_X_Randr_Output o)
844{
845 // get the name of the screen - likely a model name or manufacturer name
846 char *name;
847 unsigned long len = 0;
848 unsigned char *edid = ecore_x_randr_output_edid_get(root, o, &len);
849 if (!edid) return NULL;
850 name = ecore_x_randr_edid_display_name_get(edid, len);
851 free(edid);
852 return name;
853}
854
855static Ecore_X_Randr_Edid_Display_Interface_Type
856_output_conn_type_get(Ecore_X_Window root, Ecore_X_Randr_Output o)
857{
858 // get what kind of connector (hdmi, dvi, displayport etc.) - vga is
859 Ecore_X_Randr_Edid_Display_Interface_Type type;
860 unsigned long len = 0;
861 unsigned char *edid = ecore_x_randr_output_edid_get(root, o, &len);
862 if (!edid) return ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_UNDEFINED;
863 type = ecore_x_randr_edid_display_interface_type_get(edid, len);
864 free(edid);
865 return type;
866}
867
868static char *
869_output_name_get(Ecore_X_Window root, Ecore_X_Randr_Output o)
870{
871 // get the output name - like connector (hdmi-0, dp1, dvi-0-1 etc.)
872 char *name = ecore_x_randr_output_name_get(root, o, NULL);
873 if (name) return name;
874 return _output_screen_get(root, o);
875}
876
877static Eina_Bool
878_is_lid_name(const char *name)
879{
880 // a fixed list of possible built in connector names - likely a laptop
881 // or device internal display
882 if (!name) return EINA_FALSE;
883 if (strstr(name, "LVDS")) return EINA_TRUE;
884 else if (strstr(name, "lvds")) return EINA_TRUE;
885 else if (strstr(name, "Lvds")) return EINA_TRUE;
886 else if (strstr(name, "LCD")) return EINA_TRUE;
887 else if (strstr(name, "eDP")) return EINA_TRUE;
888 else if (strstr(name, "edp")) return EINA_TRUE;
889 else if (strstr(name, "EDP")) return EINA_TRUE;
890 return EINA_FALSE;
891}
892
893static char *
894_edid_string_get(Ecore_X_Window root, Ecore_X_Randr_Output o)
895{
896 // convert the edid binary data into a hex string so we can use it as
897 // part of a name
898 unsigned char *edid = NULL;
899 unsigned long len = 0;
900 char *edid_str = NULL;
901
902 edid = ecore_x_randr_output_edid_get(root, o, &len);
903 if (edid)
904 {
905 unsigned int k, kk;
906
907 edid_str = malloc((len * 2) + 1);
908 if (edid_str)
909 {
910 const char *hexch = "0123456789abcdef";
911
912 for (kk = 0, k = 0; k < len; k++)
913 {
914 edid_str[kk ] = hexch[(edid[k] >> 4) & 0xf];
915 edid_str[kk + 1] = hexch[ edid[k] & 0xf];
916 kk += 2;
917 }
918 edid_str[kk] = 0;
919 }
920 free(edid);
921 }
922 return edid_str;
923}
924
925static E_Randr2_Screen *
926_info_unconf_primary_find(E_Randr2 *r)
927{
928 Eina_List *l;
929 E_Randr2_Screen *s, *s_primary = NULL;
930 int priority = 0;
931
932 EINA_LIST_FOREACH(r->screens, l, s)
933 {
934 if (!((s->config.enabled) &&
935 (s->config.mode.w > 0) && (s->config.mode.h > 0) &&
936 (s->config.geom.w > 0) && (s->config.geom.h > 0)))
937 continue;
938 if (s->config.priority > priority)
939 {
940 s_primary = s;
941 priority = s->config.priority;
942 }
943 }
944 return s_primary;
945}
946
947static E_Randr2_Screen *
948_info_unconf_left_find(E_Randr2 *r)
949{
950 Eina_List *l;
951 E_Randr2_Screen *s, *s_left = NULL;
952 int left_x = 0x7fffffff;
953 int left_size = 0;
954
955 EINA_LIST_FOREACH(r->screens, l, s)
956 {
957 if (!((s->config.enabled) &&
958 (s->config.mode.w > 0) && (s->config.mode.h > 0) &&
959 (s->config.geom.w > 0) && (s->config.geom.h > 0)))
960 continue;
961 if ((s->config.geom.x <= left_x) &&
962 ((s->config.geom.w * s->config.geom.h) > left_size))
963 {
964 left_size = s->config.geom.w * s->config.geom.h;
965 left_x = s->config.geom.x;
966 s_left = s;
967 }
968 }
969 return s_left;
970}
971
972static E_Randr2_Screen *
973_info_unconf_closest_find(E_Randr2 *r, E_Randr2_Screen *s2, Eina_Bool configured)
974{
975 Eina_List *l;
976 E_Randr2_Screen *s, *s_sel = NULL;
977 int dist = 0x7fffffff;
978 int dx, dy;
979
980 EINA_LIST_FOREACH(r->screens, l, s)
981 {
982 if (s == s2) continue;
983 if (!((s->config.enabled) &&
984 (s->config.mode.w > 0) && (s->config.mode.h > 0) &&
985 (s->config.geom.w > 0) && (s->config.geom.h > 0)))
986 continue;
987 if ((!configured) &&
988 (s->config.relative.mode != E_RANDR2_RELATIVE_UNKNOWN))
989 continue;
990 else if ((configured) &&
991 (s->config.relative.mode == E_RANDR2_RELATIVE_UNKNOWN))
992 continue;
993 dx = (s->config.geom.x + (s->config.geom.w / 2)) -
994 (s2->config.geom.x + (s2->config.geom.w / 2));
995 dy = (s->config.geom.y + (s->config.geom.h / 2)) -
996 (s2->config.geom.y + (s2->config.geom.h / 2));
997 dx = sqrt((dx * dx) + (dy * dy));
998 if (dx < dist)
999 {
1000 s_sel = s;
1001 dist = dx;
1002 }
1003 }
1004 return s_sel;
1005}
1006
1007static void
1008_info_relative_fixup(E_Randr2 *r)
1009{
1010 E_Randr2_Screen *s, *s2;
1011 int d, dx, dy;
1012
1013 s = _info_unconf_primary_find(r);
1014 if (s) s->config.relative.mode = E_RANDR2_RELATIVE_NONE;
1015 else
1016 {
1017 s = _info_unconf_left_find(r);
1018 if (!s) return;
1019 s->config.relative.mode = E_RANDR2_RELATIVE_NONE;
1020 }
1021 for (;;)
1022 {
1023 // find the next screen that is closest to the last one we configured
1024 /// that is still not configured yet
1025 s = _info_unconf_closest_find(r, s, EINA_FALSE);
1026 if (!s) break;
1027 s2 = _info_unconf_closest_find(r, s, EINA_TRUE);
1028 // fix up s->config.relative.mode, s->config.relative.to and
1029 // s->config.relative.align to match (as closely as possible)
1030 // the geometry given - config s relative to s2
1031 if (!s2) s->config.relative.mode = E_RANDR2_RELATIVE_NONE;
1032 else
1033 {
1034 s->config.relative.to = strdup(s2->id);
1035 s->config.relative.align = 0.0;
1036 s->config.relative.mode = E_RANDR2_RELATIVE_NONE;
1037 if ((s->config.geom.x + s->config.geom.w) <=
1038 s2->config.geom.x)
1039 {
1040 s->config.relative.mode = E_RANDR2_RELATIVE_TO_LEFT;
1041 d = s->config.geom.h - s2->config.geom.h;
1042 dy = s2->config.geom.y - s->config.geom.y;
1043 if (d != 0)
1044 s->config.relative.align = ((double)dy) / ((double)d);
1045 }
1046 else if (s->config.geom.x >=
1047 (s2->config.geom.x + s2->config.geom.w))
1048 {
1049 s->config.relative.mode = E_RANDR2_RELATIVE_TO_RIGHT;
1050 d = s->config.geom.h - s2->config.geom.h;
1051 dy = s2->config.geom.y - s->config.geom.y;
1052 if (d != 0)
1053 s->config.relative.align = ((double)dy) / ((double)d);
1054 }
1055 else if ((s->config.geom.y + s->config.geom.h) <=
1056 s2->config.geom.y)
1057 {
1058 s->config.relative.mode = E_RANDR2_RELATIVE_TO_ABOVE;
1059 d = s->config.geom.w - s2->config.geom.w;
1060 dx = s2->config.geom.x - s->config.geom.x;
1061 if (d != 0)
1062 s->config.relative.align = ((double)dx) / ((double)d);
1063 }
1064 else if (s->config.geom.y >=
1065 (s2->config.geom.y + s2->config.geom.h))
1066 {
1067 s->config.relative.mode = E_RANDR2_RELATIVE_TO_BELOW;
1068 d = s->config.geom.w - s2->config.geom.w;
1069 dx = s2->config.geom.x - s->config.geom.x;
1070 if (d != 0)
1071 s->config.relative.align = ((double)dx) / ((double)d);
1072 }
1073 else if ((s->config.geom.x == s2->config.geom.x) &&
1074 (s->config.geom.y == s2->config.geom.y) &&
1075 (s->config.geom.w == s2->config.geom.w) &&
1076 (s->config.geom.h == s2->config.geom.h))
1077 {
1078 s->config.relative.mode = E_RANDR2_RELATIVE_CLONE;
1079 }
1080 // XXXL detect clone
1081 if (s->config.relative.align < 0.0)
1082 s->config.relative.align = 0.0;
1083 else if (s->config.relative.align > 1.0)
1084 s->config.relative.align = 1.0;
1085 }
1086 }
1087}
1088
1089static E_Randr2 *
1090_info_get(void)
1091{
1092 Ecore_X_Randr_Crtc *crtcs = NULL;
1093 Ecore_X_Randr_Output *outputs = NULL;
1094 int crtcs_num = 0, outputs_num = 0, i, j, k;
1095 Ecore_X_Window root = ecore_x_window_root_first_get();
1096 E_Randr2 *r = calloc(1, sizeof(E_Randr2));
1097 if (!r) return NULL;
1098
1099 printf("RRR: ................. info get!\n");
1100 // do this to force xrandr to update its content
1101 ecore_x_randr_config_timestamp_get(root);
1102 ecore_x_randr_screen_size_range_get(root, NULL, NULL, NULL, NULL);
1103 ecore_x_sync();
1104
1105 crtcs = ecore_x_randr_crtcs_get(root, &crtcs_num);
1106 outputs = ecore_x_randr_outputs_get(root, &outputs_num);
1107
1108 for (i = 0; i < outputs_num; i++)
1109 {
1110 Ecore_X_Randr_Mode *modes;
1111 Ecore_X_Randr_Edid_Display_Interface_Type conn;
1112 int modes_num = 0, modes_pref = 0;
1113 E_Randr2_Screen *s = calloc(1, sizeof(E_Randr2_Screen));
1114 if (!s) continue;
1115 s->info.name = _output_name_get(root, outputs[i]);
1116 printf("RRR: ...... out %s\n", s->info.name);
1117 if (!s->info.name)
1118 {
1119 free(s);
1120 continue;
1121 }
1122 s->info.screen = _output_screen_get(root, outputs[i]);
1123 s->info.edid = _edid_string_get(root, outputs[i]);
1124 if (s->info.edid)
1125 s->id = malloc(strlen(s->info.name) + 1 + strlen(s->info.edid) + 1);
1126 else
1127 s->id = malloc(strlen(s->info.name) + 1 + 1);
1128 if (!s->id)
1129 {
1130 free(s->info.screen);
1131 free(s->info.edid);
1132 free(s);
1133 continue;
1134 }
1135 strcpy(s->id, s->info.name);
1136 strcat(s->id, "/");
1137 if (s->info.edid) strcat(s->id, s->info.edid);
1138 conn = _output_conn_type_get(root, outputs[i]);
1139 if (conn == ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_UNDEFINED)
1140 s->info.connector = E_RANDR2_CONNECTOR_UNDEFINED;
1141 else if (conn == ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DVI)
1142 s->info.connector = E_RANDR2_CONNECTOR_DVI;
1143 else if (conn == ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_HDMI_A)
1144 s->info.connector = E_RANDR2_CONNECTOR_HDMI_A;
1145 else if (conn == ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_HDMI_B)
1146 s->info.connector = E_RANDR2_CONNECTOR_HDMI_B;
1147 else if (conn == ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_MDDI)
1148 s->info.connector = E_RANDR2_CONNECTOR_MDDI;
1149 else if (conn == ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT)
1150 s->info.connector = E_RANDR2_CONNECTOR_DISPLAY_PORT;
1151 s->info.is_lid = _is_lid_name(s->info.name);
1152 if (ecore_x_randr_output_connection_status_get(root, outputs[i]) ==
1153 ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED)
1154 s->info.connected = EINA_TRUE;
1155 printf("RRR: ...... connected %i\n", s->info.connected);
1156 if (ecore_x_randr_output_backlight_level_get(root, outputs[i]) >= 0.0)
1157 s->info.backlight = EINA_TRUE;
1158 ecore_x_randr_output_size_mm_get(root, outputs[i],
1159 &(s->info.size.w), &(s->info.size.h));
1160 modes = ecore_x_randr_output_modes_get(root, outputs[i],
1161 &modes_num, &modes_pref);
1162 printf("RRR: ...... modes %p\n", modes);
1163 if (modes)
1164 {
1165 for (j = 0; j < modes_num; j++)
1166 {
1167 Ecore_X_Randr_Mode_Info *minfo =
1168 ecore_x_randr_mode_info_get(root, modes[j]);
1169 if (minfo)
1170 {
1171 E_Randr2_Mode *m = calloc(1, sizeof(E_Randr2_Mode));
1172 if (m)
1173 {
1174 m->w = minfo->width;
1175 m->h = minfo->height;
1176 m->refresh =
1177 (double)minfo->dotClock /
1178 (double)(minfo->hTotal * minfo->vTotal);
1179 if (j == (modes_pref - 1))
1180 m->preferred = EINA_TRUE;
1181 s->info.modes = eina_list_append(s->info.modes, m);
1182 }
1183 ecore_x_randr_mode_info_free(minfo);
1184 }
1185 }
1186 free(modes);
1187 }
1188 if (ecore_x_randr_primary_output_get(root) == outputs[i])
1189 s->config.priority = 100;
1190 for (j = 0; j < crtcs_num; j++)
1191 {
1192 Eina_Bool ok, possible;
1193 Ecore_X_Randr_Crtc_Info *info =
1194 ecore_x_randr_crtc_info_get(root, crtcs[j]);
1195 if (info)
1196 {
1197 ok = EINA_FALSE;
1198 possible = EINA_FALSE;
1199 for (k = 0; k < info->noutput; k++)
1200 {
1201 if (info->outputs[k] == outputs[i])
1202 {
1203 ok = EINA_TRUE;
1204 break;
1205 }
1206 }
1207 if (!ok)
1208 {
1209 for (k = 0; k < info->npossible; k++)
1210 {
1211 if (info->possible[k] == outputs[i])
1212 {
1213 ok = EINA_TRUE;
1214 possible = EINA_TRUE;
1215 break;
1216 }
1217 }
1218 }
1219 if (ok)
1220 {
1221 if (!possible)
1222 {
1223 Ecore_X_Randr_Mode_Info *minfo;
1224
1225 s->config.geom.x = info->x;
1226 s->config.geom.y = info->y;
1227 s->config.geom.w = info->width;
1228 s->config.geom.h = info->height;
1229 if (info->rotation & ECORE_X_RANDR_ORIENTATION_ROT_0)
1230 s->config.rotation = 0;
1231 else if (info->rotation & ECORE_X_RANDR_ORIENTATION_ROT_90)
1232 s->config.rotation = 90;
1233 else if (info->rotation & ECORE_X_RANDR_ORIENTATION_ROT_180)
1234 s->config.rotation = 180;
1235 else if (info->rotation & ECORE_X_RANDR_ORIENTATION_ROT_270)
1236 s->config.rotation = 270;
1237 minfo = ecore_x_randr_mode_info_get(root,
1238 info->mode);
1239 if (minfo)
1240 {
1241 s->config.enabled = EINA_TRUE;
1242 s->config.mode.w = minfo->width;
1243 s->config.mode.h = minfo->height;
1244 s->config.mode.refresh =
1245 (double)minfo->dotClock /
1246 (double)(minfo->hTotal * minfo->vTotal);
1247 ecore_x_randr_mode_info_free(minfo);
1248 }
1249 printf("RRR: '%s' %i %i %ix%i\n",
1250 s->info.name,
1251 s->config.geom.x, s->config.geom.y,
1252 s->config.geom.w, s->config.geom.h);
1253 }
1254 if (info->rotations & ECORE_X_RANDR_ORIENTATION_ROT_0)
1255 s->info.can_rot_0 = EINA_TRUE;
1256 if (info->rotations & ECORE_X_RANDR_ORIENTATION_ROT_90)
1257 s->info.can_rot_90 = EINA_TRUE;
1258 if (info->rotations & ECORE_X_RANDR_ORIENTATION_ROT_180)
1259 s->info.can_rot_180 = EINA_TRUE;
1260 if (info->rotations & ECORE_X_RANDR_ORIENTATION_ROT_270)
1261 s->info.can_rot_270 = EINA_TRUE;
1262 }
1263 ecore_x_randr_crtc_info_free(info);
1264 }
1265 }
1266 r->screens = eina_list_append(r->screens, s);
1267 }
1268
1269 free(outputs);
1270 free(crtcs);
1271
1272 _info_relative_fixup(r);
1273 return r;
1274}
1275
1276static Eina_Bool
1277_cb_screen_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1278{
1279 Ecore_X_Event_Screen_Change *ev = event;
1280 printf("RRR: CB screen change...\n");
1281 event_screen = EINA_TRUE;
1282 ecore_x_randr_config_timestamp_get(ev->root);
1283 ecore_x_randr_screen_current_size_get(ev->root, NULL, NULL, NULL, NULL);
1284 ecore_x_sync();
1285 _screen_change_delay();
1286 return EINA_TRUE;
1287}
1288
1289static Eina_Bool
1290_cb_crtc_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1291{
1292 Ecore_X_Event_Randr_Crtc_Change *ev = event;
1293 printf("RRR: CB crtc change...\n");
1294 ecore_x_randr_config_timestamp_get(ev->win);
1295 ecore_x_randr_screen_current_size_get(ev->win, NULL, NULL, NULL, NULL);
1296 ecore_x_sync();
1297 _screen_change_delay();
1298 return EINA_TRUE;
1299}
1300
1301static Eina_Bool
1302_cb_output_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1303{
1304 Ecore_X_Event_Randr_Output_Change *ev = event;
1305 printf("RRR: CB output change...\n");
1306 event_screen = EINA_TRUE;
1307 ecore_x_randr_config_timestamp_get(ev->win);
1308 ecore_x_randr_screen_current_size_get(ev->win, NULL, NULL, NULL, NULL);
1309 ecore_x_sync();
1310 _screen_change_delay();
1311 return EINA_TRUE;
1312}
1313
1314static Eina_Bool
1315_output_name_find(Ecore_X_Window root, const char *name, Ecore_X_Randr_Output *outputs, int outputs_num, Ecore_X_Randr_Output *out_ret)
1316{
1317 int i;
1318 char *n;
1319
1320 for (i = 0; i < outputs_num; i++)
1321 {
1322 n = _output_name_get(root, outputs[i]);
1323 if ((n) && (!strcmp(n, name)))
1324 {
1325 free(n);
1326 *out_ret = outputs[i];
1327 return EINA_TRUE;
1328 }
1329 free(n);
1330 }
1331 return EINA_FALSE;
1332}
1333
1334static Eina_Bool
1335_output_exists(Ecore_X_Randr_Output out, Ecore_X_Randr_Crtc_Info *info)
1336{
1337 int i;
1338
1339 for (i = 0; i < info->npossible; i++)
1340 {
1341 if (out == info->possible[i]) return EINA_TRUE;
1342 }
1343 return EINA_FALSE;
1344}
1345
1346static Eina_Bool
1347_rotation_exists(int rot, Ecore_X_Randr_Crtc_Info *info)
1348{
1349 if ((rot == 0) && (info->rotations & ECORE_X_RANDR_ORIENTATION_ROT_0))
1350 return EINA_TRUE;
1351 if ((rot == 90) && (info->rotations & ECORE_X_RANDR_ORIENTATION_ROT_90))
1352 return EINA_TRUE;
1353 if ((rot == 180) && (info->rotations & ECORE_X_RANDR_ORIENTATION_ROT_180))
1354 return EINA_TRUE;
1355 if ((rot == 270) && (info->rotations & ECORE_X_RANDR_ORIENTATION_ROT_270))
1356 return EINA_TRUE;
1357 return EINA_FALSE;
1358}
1359
1360static Ecore_X_Randr_Mode
1361_mode_screen_find(Ecore_X_Window root, E_Randr2_Screen *s, Ecore_X_Randr_Output out)
1362{
1363 Ecore_X_Randr_Mode_Info *minfo;
1364 Ecore_X_Randr_Mode mode = 0, *modes;
1365 int modes_num = 0, modes_pref = 0, distance = 0x7fffffff;
1366 int diff, i;
1367 double refresh;
1368
1369 modes = ecore_x_randr_output_modes_get(root, out, &modes_num, &modes_pref);
1370 if (!modes)
1371 {
1372 printf("RRR: modes for '%s' FETCH FAILED!!!\n", s->info.name);
1373/*
1374 for (i = 0; i < 500; i++)
1375 {
1376 printf("RRR: try %i\n", i);
1377// if (ecore_x_randr_output_connection_status_get(root, out) !=
1378// ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED) break;
1379 ecore_x_sync();
1380 int n;
1381 Ecore_X_Randr_Crtc *crtcs = ecore_x_randr_output_possible_crtcs_get(root, out, &n);
1382 free(crtcs);
1383 char *name = ecore_x_randr_output_name_get(root, out, &n);
1384 free(name);
1385 printf("RRR: conn: %i\n", ecore_x_randr_output_connection_status_get(root, out));
1386 int mw, mh;
1387 ecore_x_randr_output_size_mm_get(root, out, &mw, &mh);
1388 printf("RRR: bl: %1.2f\n", ecore_x_randr_output_backlight_level_get(root, out));
1389 ecore_x_randr_config_timestamp_get(root);
1390 ecore_x_sync();
1391 ecore_x_randr_screen_current_size_get(root, NULL, NULL, NULL, NULL);
1392 ecore_x_sync();
1393 modes = ecore_x_randr_output_modes_get(root, out, &modes_num, &modes_pref);
1394 if (modes) break;
1395 usleep(1000);
1396 }
1397 */
1398 }
1399 printf("RRR: modes for '%s' are %p [%i]\n", s->info.name, modes, modes_num);
1400 if (modes)
1401 {
1402 for (i = 0; i < modes_num; i++)
1403 {
1404 minfo = ecore_x_randr_mode_info_get(root, modes[i]);
1405 if (!minfo) continue;
1406 refresh = (double)minfo->dotClock /
1407 (double)(minfo->hTotal * minfo->vTotal);
1408 diff =
1409 (100 * abs(s->config.mode.w - minfo->width)) +
1410 (100 * abs(s->config.mode.h - minfo->height)) +
1411 abs((100 * s->config.mode.refresh) - (100 * refresh));
1412 if (diff < distance)
1413 {
1414 mode = modes[i];
1415 distance = diff;
1416 }
1417 ecore_x_randr_mode_info_free(minfo);
1418 }
1419 free(modes);
1420 }
1421 return mode;
1422}
1423
1424static void
1425_screen_config_apply(void)
1426{
1427 Eina_List *l;
1428 E_Randr2_Screen *s;
1429 Ecore_X_Window root = ecore_x_window_root_first_get();
1430 int minw, minh, maxw, maxh, nw, nh, pw, ph, ww, hh;
1431 Ecore_X_Randr_Crtc *crtcs = NULL;
1432 Ecore_X_Randr_Output *outputs = NULL, out, *outconf;
1433 E_Randr2_Screen **screenconf;
1434 int crtcs_num = 0, outputs_num = 0, i;
1435 Ecore_X_Randr_Crtc_Info *info;
1436 int top_priority = 0;
1437
1438 ecore_x_grab();
1439 // set virtual resolution
1440 nw = e_randr2->w;
1441 nh = e_randr2->h;
1442 ecore_x_randr_screen_size_range_get(root, &minw, &minh, &maxw, &maxh);
1443 ecore_x_randr_screen_current_size_get(root, &pw, &ph, NULL, NULL);
1444 {
1445 int ww = 0, hh = 0, ww2 = 0, hh2 = 0;
1446 ecore_x_randr_screen_current_size_get(root, &ww, &hh, &ww2, &hh2);
1447 printf("RRR: cur size: %ix%i\n", ww, hh);
1448 }
1449 printf("RRR: size range: %ix%i -> %ix%i\n", minw, minh, maxw, maxh);
1450 if (nw > maxw) nw = maxw;
1451 if (nh > maxh) nh = maxh;
1452 if (nw < minw) nw = minw;
1453 if (nh < minh) nh = minh;
1454 ww = nw; if (nw < pw) ww = pw;
1455 hh = nh; if (nh < ph) hh = ph;
1456 ecore_x_randr_screen_current_size_set(root, ww, hh, -1, -1);
1457 {
1458 int ww = 0, hh = 0, ww2 = 0, hh2 = 0;
1459 ecore_x_randr_screen_current_size_get(root, &ww, &hh, &ww2, &hh2);
1460 printf("RRR: cur size: %ix%i\n", ww, hh);
1461 }
1462 printf("RRR: set vsize: %ix%i\n", nw, nh);
1463
1464 crtcs = ecore_x_randr_crtcs_get(root, &crtcs_num);
1465 outputs = ecore_x_randr_outputs_get(root, &outputs_num);
1466
1467 if ((crtcs) && (outputs))
1468 {
1469 outconf = alloca(crtcs_num * sizeof(Ecore_X_Randr_Output));
1470 screenconf = alloca(crtcs_num * sizeof(E_Randr2_Screen *));
1471 memset(outconf, 0, crtcs_num * sizeof(Ecore_X_Randr_Output));
1472 memset(screenconf, 0, crtcs_num * sizeof(E_Randr2_Screen *));
1473
1474 // decide which outputs get which crtcs
1475 EINA_LIST_FOREACH(e_randr2->screens, l, s)
1476 {
1477 printf("RRR: find output for '%s'\n", s->info.name);
1478 // XXX: find clones and set them as outputs in an array
1479 if ((s->config.configured) &&
1480 (_output_name_find(root, s->info.name, outputs,
1481 outputs_num, &out)))
1482 {
1483 printf("RRR: enabled: %i\n", s->config.enabled);
1484 if (s->config.enabled)
1485 {
1486 if (s->config.priority > top_priority)
1487 top_priority = s->config.priority;
1488 for (i = 0; i < crtcs_num; i++)
1489 {
1490 if (!outconf[i])
1491 {
1492 printf("RRR: crtc slot empty: %i\n", i);
1493 info = ecore_x_randr_crtc_info_get(root,
1494 crtcs[i]);
1495 if (info)
1496 {
1497 if (_output_exists(out, info) &&
1498 _rotation_exists(s->config.rotation,
1499 info))
1500 {
1501 printf("RRR: assign slot out: %x\n", out);
1502 outconf[i] = out;
1503 screenconf[i] = s;
1504 ecore_x_randr_crtc_info_free(info);
1505 break;
1506 }
1507 }
1508 }
1509 }
1510 }
1511 }
1512 }
1513 // set up a crtc to drive each output (or not)
1514 for (i = 0; i < crtcs_num; i++)
1515 {
1516 // XXX: find clones and set them as outputs in an array
1517 if (outconf[i])
1518 {
1519 Ecore_X_Randr_Orientation orient =
1520 ECORE_X_RANDR_ORIENTATION_ROT_0;
1521 Ecore_X_Randr_Mode mode;
1522
1523 mode = _mode_screen_find(root, screenconf[i], outconf[i]);
1524 if (screenconf[i]->config.rotation == 0)
1525 orient = ECORE_X_RANDR_ORIENTATION_ROT_0;
1526 else if (screenconf[i]->config.rotation == 90)
1527 orient = ECORE_X_RANDR_ORIENTATION_ROT_90;
1528 else if (screenconf[i]->config.rotation == 180)
1529 orient = ECORE_X_RANDR_ORIENTATION_ROT_180;
1530 else if (screenconf[i]->config.rotation == 270)
1531 orient = ECORE_X_RANDR_ORIENTATION_ROT_270;
1532 printf("RRR: crtc on: %i = '%s' @ %i %i - %ix%i orient %i mode %x out %x\n",
1533 i, screenconf[i]->info.name,
1534 screenconf[i]->config.geom.x,
1535 screenconf[i]->config.geom.y,
1536 screenconf[i]->config.geom.w,
1537 screenconf[i]->config.geom.h,
1538 orient, mode, outconf[i]);
1539 if (!ecore_x_randr_crtc_settings_set
1540 (root, crtcs[i], &(outconf[i]), 1,
1541 screenconf[i]->config.geom.x,
1542 screenconf[i]->config.geom.y,
1543 mode, orient))
1544 printf("RRR: failed to set crtc!!!!!!\n");
1545 ecore_x_randr_crtc_panning_area_set
1546 (root, crtcs[i],
1547 screenconf[i]->config.geom.x,
1548 screenconf[i]->config.geom.y,
1549 screenconf[i]->config.geom.w,
1550 screenconf[i]->config.geom.h);
1551 if (screenconf[i]->config.priority == top_priority)
1552 {
1553 ecore_x_randr_primary_output_set(root, outconf[i]);
1554 top_priority = -1;
1555 }
1556 }
1557 else
1558 {
1559 printf("RRR: crtc off: %i\n", i);
1560 ecore_x_randr_crtc_settings_set
1561 (root, crtcs[i], NULL, 0, 0, 0, 0,
1562 ECORE_X_RANDR_ORIENTATION_ROT_0);
1563 }
1564 }
1565 }
1566 free(outputs);
1567 free(crtcs);
1568
1569 ecore_x_randr_screen_current_size_set(root, nw, nh, -1, -1);
1570 {
1571 int ww = 0, hh = 0, ww2 = 0, hh2 = 0;
1572 ecore_x_randr_screen_current_size_get(root, &ww, &hh, &ww2, &hh2);
1573 printf("RRR: cur size: %ix%i\n", ww, hh);
1574 }
1575 ecore_x_randr_screen_size_range_get(root, NULL, NULL, NULL, NULL);
1576 ecore_x_ungrab();
1577 ecore_x_sync();
1578
1579 // ignore the next batch of randr events - we caused them ourselves
1580 event_ignore = EINA_TRUE;
1581}
diff --git a/src/bin/e_randr2.h b/src/bin/e_randr2.h
new file mode 100644
index 0000000..70fd40f
--- /dev/null
+++ b/src/bin/e_randr2.h
@@ -0,0 +1,121 @@
1#ifdef E_TYPEDEFS
2
3typedef struct _E_Randr2 E_Randr2;
4typedef struct _E_Randr2_Screen E_Randr2_Screen;
5typedef struct _E_Randr2_Mode E_Randr2_Mode;
6
7typedef struct _E_Config_Randr2 E_Config_Randr2;
8typedef struct _E_Config_Randr2_Screen E_Config_Randr2_Screen;
9
10#else
11#ifndef E_RANDR2_H
12#define E_RAND2R_H
13
14#define E_RANDR_VERSION_1_1 ((1 << 16) | 1)
15#define E_RANDR_VERSION_1_2 ((1 << 16) | 2)
16#define E_RANDR_VERSION_1_3 ((1 << 16) | 3)
17#define E_RANDR_VERSION_1_4 ((1 << 16) | 4)
18
19typedef enum _E_Randr2_Relative
20{
21 E_RANDR2_RELATIVE_UNKNOWN,
22 E_RANDR2_RELATIVE_NONE,
23 E_RANDR2_RELATIVE_CLONE,
24 E_RANDR2_RELATIVE_TO_LEFT,
25 E_RANDR2_RELATIVE_TO_RIGHT,
26 E_RANDR2_RELATIVE_TO_ABOVE,
27 E_RANDR2_RELATIVE_TO_BELOW
28} E_Randr2_Relative;
29
30typedef enum _E_Randr2_Connector
31{
32 E_RANDR2_CONNECTOR_UNDEFINED,
33 E_RANDR2_CONNECTOR_DVI,
34 E_RANDR2_CONNECTOR_HDMI_A,
35 E_RANDR2_CONNECTOR_HDMI_B,
36 E_RANDR2_CONNECTOR_MDDI,
37 E_RANDR2_CONNECTOR_DISPLAY_PORT
38} E_Randr2_Connector;
39
40struct _E_Randr2
41{
42 Eina_List *screens; // available screens
43 int w, h; // virtual resolution needed for screens (calculated)
44};
45
46struct _E_Randr2_Mode
47{
48 int w, h; // resolution width and height
49 double refresh; // refresh in hz
50 Eina_Bool preferred : 1; // is this the preferred mode for the device?
51};
52
53struct _E_Randr2_Screen
54{
55 char *id; // string id which is "name/edid";
56 struct {
57 char *screen; // name of the screen device attached
58 char *name; // name of the output itself
59 char *edid; // full edid data
60 E_Randr2_Connector connector; // the connector type
61 Eina_Bool is_lid : 1; // is an internal screen
62 Eina_Bool connected : 1; // some screen is plugged in or not
63 Eina_Bool backlight : 1; // does it have backlight controls?
64 Eina_Bool can_rot_0 : 1; // can it do this rotation?
65 Eina_Bool can_rot_90 : 1; // can it do this rotation?
66 Eina_Bool can_rot_180 : 1; // can it do this rotation?
67 Eina_Bool can_rot_270 : 1; // can it do this rotation?
68 Eina_List *modes; // available screen modes here
69 struct {
70 int w, h; // physical width and height in mm
71 } size;
72 } info;
73 struct {
74 struct {
75 E_Randr2_Relative mode; // what relative mode to the screen below
76 char *to; // what screen this one is relative to
77 double align; // alignment along the edge
78 } relative;
79 Eina_Rectangle geom; // the geometry that is set (as a result)
80 E_Randr2_Mode mode; // screen res/refresh to use
81 int rotation; // 0, 90, 180, 270
82 int priority; // larger num == more important
83 Eina_Bool enabled : 1; // should this monitor be enabled?
84 Eina_Bool configured : 1; // has screen been configured by e?
85 } config;
86};
87
88struct _E_Config_Randr2
89{
90 int version;
91 Eina_List *screens;
92 unsigned char restore;
93};
94
95struct _E_Config_Randr2_Screen
96{
97 const char *id;
98 const char *rel_to;
99 double rel_align;
100 double mode_refresh;
101 int mode_w;
102 int mode_h;
103 int rotation;
104 int priority;
105 unsigned char rel_mode;
106 unsigned char enabled;
107};
108
109extern EAPI E_Config_Randr2 *e_randr2_cfg;
110extern EAPI E_Randr2 *e_randr2;
111
112extern EAPI int E_EVENT_RANDR_CHANGE;
113
114EINTERN Eina_Bool e_randr2_init(void);
115EINTERN int e_randr2_shutdown(void);
116EAPI Eina_Bool e_randr2_config_save(void);
117EAPI void e_randr2_config_apply(void);
118EAPI void e_randr2_screeninfo_update(void);
119
120#endif
121#endif
diff --git a/src/bin/e_xinerama.c b/src/bin/e_xinerama.c
index d26a2dd..e75704f 100644
--- a/src/bin/e_xinerama.c
+++ b/src/bin/e_xinerama.c
@@ -132,6 +132,7 @@ _e_xinerama_update(void)
132 INF("======================= screens:"); 132 INF("======================= screens:");
133 EINA_LIST_FOREACH(chosen_screens, l, scr) 133 EINA_LIST_FOREACH(chosen_screens, l, scr)
134 { 134 {
135 scr->screen = n;
135 scr->escreen = n; 136 scr->escreen = n;
136 INF("E INIT: XINERAMA CHOSEN: [%i][%i], %ix%i+%i+%i", 137 INF("E INIT: XINERAMA CHOSEN: [%i][%i], %ix%i+%i+%i",
137 scr->screen, scr->escreen, scr->w, scr->h, scr->x, scr->y); 138 scr->screen, scr->escreen, scr->w, scr->h, scr->x, scr->y);
diff --git a/src/modules/Makefile_conf_randr.mk b/src/modules/Makefile_conf_randr.mk
index 0a727c2..280a402 100644
--- a/src/modules/Makefile_conf_randr.mk
+++ b/src/modules/Makefile_conf_randr.mk
@@ -14,12 +14,8 @@ src_modules_conf_randr_module_la_CPPFLAGS = $(MOD_CPPFLAGS) -DNEED_X=1
14src_modules_conf_randr_module_la_LDFLAGS = $(MOD_LDFLAGS) 14src_modules_conf_randr_module_la_LDFLAGS = $(MOD_LDFLAGS)
15src_modules_conf_randr_module_la_SOURCES = src/modules/conf_randr/e_mod_main.c \ 15src_modules_conf_randr_module_la_SOURCES = src/modules/conf_randr/e_mod_main.c \
16 src/modules/conf_randr/e_mod_main.h \ 16 src/modules/conf_randr/e_mod_main.h \
17 src/modules/conf_randr/e_int_config_randr.c \ 17 src/modules/conf_randr/e_int_config_randr2.c \
18 src/modules/conf_randr/e_int_config_randr.h \ 18 src/modules/conf_randr/e_int_config_randr2.h
19 src/modules/conf_randr/e_smart_randr.c \
20 src/modules/conf_randr/e_smart_randr.h \
21 src/modules/conf_randr/e_smart_monitor.c \
22 src/modules/conf_randr/e_smart_monitor.h
23 19
24PHONIES += conf_randr install-conf_randr 20PHONIES += conf_randr install-conf_randr
25conf_randr: $(conf_randrpkg_LTLIBRARIES) $(conf_randr_DATA) 21conf_randr: $(conf_randrpkg_LTLIBRARIES) $(conf_randr_DATA)
diff --git a/src/modules/conf_randr/e_int_config_randr2.c b/src/modules/conf_randr/e_int_config_randr2.c
new file mode 100644
index 0000000..c51e93d
--- /dev/null
+++ b/src/modules/conf_randr/e_int_config_randr2.c
@@ -0,0 +1,744 @@
1#include "e.h"
2#include "e_mod_main.h"
3#include "e_int_config_randr2.h"
4
5/* local structures */
6struct _E_Config_Dialog_Data
7{
8 E_Config_Dialog *cfd;
9 Eina_List *screen_items;
10 Eina_List *screen_items2;
11 Eina_List *screens;
12 Eina_List *freelist;
13 Evas_Object *name_obj;
14 Evas_Object *screen_obj;
15 Evas_Object *lid_obj;
16 Evas_Object *backlight_obj;
17 Evas_Object *size_obj;
18 Evas_Object *modes_obj;
19 Evas_Object *rotations_obj;
20 Evas_Object *enabled_obj;
21 Evas_Object *priority_obj;
22 Evas_Object *rel_mode_obj;
23 Evas_Object *rel_to_obj;
24 Evas_Object *rel_align_obj;
25 int restore;
26 int screen;
27};
28
29typedef struct
30{
31 E_Config_Dialog_Data *cfdata;
32 E_Randr2_Mode mode;
33} Mode_CBData;
34
35typedef struct
36{
37 E_Config_Dialog_Data *cfdata;
38 int rot;
39} Rot_CBData;
40
41/* local function prototypes */
42static void *_create_data(E_Config_Dialog *cfd);
43static void _free_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata);
44static Evas_Object *_basic_create(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata);
45static int _basic_apply(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata);
46static int _basic_check(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata);
47
48/* public functions */
49E_Config_Dialog *
50e_int_config_randr2(Evas_Object *parent EINA_UNUSED, const char *params EINA_UNUSED)
51{
52 E_Config_Dialog *cfd;
53 E_Config_Dialog_View *v;
54
55 if (e_config_dialog_find("E", "screen/screen_setup")) return NULL;
56 if (!(v = E_NEW(E_Config_Dialog_View, 1))) return NULL;
57
58 /* set dialog view functions & properties */
59 v->create_cfdata = _create_data;
60 v->free_cfdata = _free_data;
61 v->basic.create_widgets = _basic_create;
62 v->basic.apply_cfdata = _basic_apply;
63 v->basic.check_changed = _basic_check;
64 v->override_auto_apply = EINA_TRUE;
65
66 /* create new dialog */
67 cfd = e_config_dialog_new(NULL, _("Screen Setup"),
68 "E", "screen/screen_setup",
69 "preferences-system-screen-resolution",
70 0, v, NULL);
71 return cfd;
72}
73
74/* local functions */
75static void *
76_create_data(E_Config_Dialog *cfd EINA_UNUSED)
77{
78 E_Config_Dialog_Data *cfdata;
79
80 if (!(cfdata = E_NEW(E_Config_Dialog_Data, 1))) return NULL;
81 cfdata->restore = e_randr2_cfg->restore;
82 return cfdata;
83}
84
85static void
86_free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
87{
88 void *dt;
89 E_Config_Randr2_Screen *cs;
90
91 EINA_LIST_FREE(cfdata->screens, cs)
92 {
93 eina_stringshare_del(cs->id);
94 eina_stringshare_del(cs->rel_to);
95 free(cs);
96 }
97 eina_list_free(cfdata->screen_items);
98 eina_list_free(cfdata->screen_items2);
99 EINA_LIST_FREE(cfdata->freelist, dt) free(dt);
100 E_FREE(cfdata);
101}
102
103static void
104_cb_restore_changed(void *data EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
105{
106 E_Config_Dialog_Data *cfdata = data;
107 cfdata->restore = elm_check_state_get(obj);
108 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
109}
110
111static E_Config_Randr2_Screen *
112_config_screen_find(E_Config_Dialog_Data *cfdata)
113{
114 return eina_list_nth(cfdata->screens, cfdata->screen);
115}
116
117static E_Config_Randr2_Screen *
118_config_screen_n_find(E_Config_Dialog_Data *cfdata, int n)
119{
120 return eina_list_nth(cfdata->screens, n);
121}
122
123static E_Randr2_Screen *
124_screen_config_find(E_Config_Randr2_Screen *cs)
125{
126 Eina_List *l;
127 E_Randr2_Screen *s;
128
129 if (!cs->id) return NULL;
130 EINA_LIST_FOREACH(e_randr2->screens, l, s)
131 {
132 if (!s->id) continue;
133 if (!strcmp(cs->id, s->id)) return s;
134 }
135 return NULL;
136}
137
138static E_Randr2_Screen *
139_screen_config_id_find(const char *id)
140{
141 Eina_List *l;
142 E_Randr2_Screen *s;
143
144 if (!id) return NULL;
145 EINA_LIST_FOREACH(e_randr2->screens, l, s)
146 {
147 if (!s->id) continue;
148 if (!strcmp(s->id, id)) return s;
149 }
150 return NULL;
151}
152
153static E_Config_Randr2_Screen *
154_screen_config_randr_id_find(const char *id)
155{
156 Eina_List *l;
157 E_Config_Randr2_Screen *cs;
158
159 if (!id) return NULL;
160 EINA_LIST_FOREACH(e_randr2_cfg->screens, l, cs)
161 {
162 if (!cs->id) continue;
163 if (!strcmp(cs->id, id)) return cs;
164 }
165 return NULL;
166}
167
168static void
169_cb_mode_set(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
170{
171 Mode_CBData *dat = data;
172 E_Config_Dialog_Data *cfdata = dat->cfdata;
173 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
174 if (!cs) return;
175 cs->mode_w = dat->mode.w;
176 cs->mode_h = dat->mode.h;
177 cs->mode_refresh = dat->mode.refresh;
178 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
179}
180
181static void
182_cb_rot_set(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
183{
184 Rot_CBData *dat = data;
185 E_Config_Dialog_Data *cfdata = dat->cfdata;
186 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
187 if (!cs) return;
188 cs->rotation = dat->rot;
189 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
190}
191
192static void
193_basic_screen_info_fill(E_Config_Dialog_Data *cfdata, E_Config_Randr2_Screen *cs, E_Randr2_Screen *s)
194{
195 char buf[100];
196 Eina_List *l;
197 E_Randr2_Mode *m;
198 Elm_Object_Item *it, *it_sel;
199 void *dt;
200
201 if (!s) return;
202 // fill all the screen status info
203 elm_object_text_set(cfdata->name_obj, s->info.name);
204 elm_object_text_set(cfdata->screen_obj, s->info.screen);
205 elm_check_state_set(cfdata->lid_obj, s->info.is_lid);
206 elm_check_state_set(cfdata->backlight_obj, s->info.backlight);
207 snprintf(buf, sizeof(buf), "%imm x %imm", s->info.size.w, s->info.size.h);
208 elm_object_text_set(cfdata->size_obj, buf);
209 // XXX: connector
210
211 EINA_LIST_FREE(cfdata->freelist, dt) free(dt);
212
213 elm_list_clear(cfdata->modes_obj);
214 it_sel = NULL;
215 EINA_LIST_FOREACH(s->info.modes, l, m)
216 {
217 Mode_CBData *mode_cbdata = calloc(1, sizeof(Mode_CBData));
218
219 if (mode_cbdata)
220 {
221 mode_cbdata->cfdata = cfdata;
222 mode_cbdata->mode = *m;
223 snprintf(buf, sizeof(buf), "%ix%i @ %1.2fHz", m->w, m->h, m->refresh);
224 it = elm_list_item_append(cfdata->modes_obj, buf, NULL, NULL, _cb_mode_set, mode_cbdata);
225 cfdata->freelist = eina_list_append(cfdata->freelist, mode_cbdata);
226 printf("mode add %p %p %p\n", mode_cbdata, cfdata->modes_obj, it);
227 if ((cs->mode_w == m->w) && (cs->mode_h == m->h) &&
228 (cs->mode_refresh == m->refresh))
229 it_sel = it;
230 }
231 }
232 if (it_sel) elm_list_item_selected_set(it_sel, EINA_TRUE);
233 elm_list_go(cfdata->modes_obj);
234
235 elm_list_clear(cfdata->rotations_obj);
236 it_sel = NULL;
237 if (s->info.can_rot_0)
238 {
239 Rot_CBData *rot_cbdata = calloc(1, sizeof(Rot_CBData));
240 if (rot_cbdata)
241 {
242 rot_cbdata->cfdata = cfdata;
243 rot_cbdata->rot = 0;
244 it = elm_list_item_append(cfdata->rotations_obj, "0", NULL, NULL, _cb_rot_set, rot_cbdata);
245 cfdata->freelist = eina_list_append(cfdata->freelist, rot_cbdata);
246 if (cs->rotation == 0) it_sel = it;
247 }
248 }
249 if (s->info.can_rot_90)
250 {
251 Rot_CBData *rot_cbdata = calloc(1, sizeof(Rot_CBData));
252 if (rot_cbdata)
253 {
254 rot_cbdata->cfdata = cfdata;
255 rot_cbdata->rot = 90;
256 it = elm_list_item_append(cfdata->rotations_obj, "90", NULL, NULL, _cb_rot_set, rot_cbdata);
257 cfdata->freelist = eina_list_append(cfdata->freelist, rot_cbdata);
258 if (cs->rotation == 90) it_sel = it;
259 }
260 }
261 if (s->info.can_rot_180)
262 {
263 Rot_CBData *rot_cbdata = calloc(1, sizeof(Rot_CBData));
264 if (rot_cbdata)
265 {
266 rot_cbdata->cfdata = cfdata;
267 rot_cbdata->rot = 180;
268 it = elm_list_item_append(cfdata->rotations_obj, "180", NULL, NULL, _cb_rot_set, rot_cbdata);
269 cfdata->freelist = eina_list_append(cfdata->freelist, rot_cbdata);
270 if (cs->rotation == 180) it_sel = it;
271 }
272 }
273 if (s->info.can_rot_270)
274 {
275 Rot_CBData *rot_cbdata = calloc(1, sizeof(Rot_CBData));
276 if (rot_cbdata)
277 {
278 rot_cbdata->cfdata = cfdata;
279 rot_cbdata->rot = 270;
280 it = elm_list_item_append(cfdata->rotations_obj, "270", NULL, NULL, _cb_rot_set, rot_cbdata);
281 cfdata->freelist = eina_list_append(cfdata->freelist, rot_cbdata);
282 if (cs->rotation == 270) it_sel = it;
283 }
284 }
285 if (it_sel) elm_list_item_selected_set(it_sel, EINA_TRUE);
286 elm_list_go(cfdata->rotations_obj);
287
288 elm_check_state_set(cfdata->enabled_obj, cs->enabled);
289
290 elm_slider_value_set(cfdata->priority_obj, cs->priority);
291
292 if (cs->rel_mode == E_RANDR2_RELATIVE_NONE)
293 elm_object_text_set(cfdata->rel_mode_obj, "None");
294 else if (cs->rel_mode == E_RANDR2_RELATIVE_CLONE)
295 elm_object_text_set(cfdata->rel_mode_obj, "Clone");
296 else if (cs->rel_mode == E_RANDR2_RELATIVE_TO_LEFT)
297 elm_object_text_set(cfdata->rel_mode_obj, "Left of");
298 else if (cs->rel_mode == E_RANDR2_RELATIVE_TO_RIGHT)
299 elm_object_text_set(cfdata->rel_mode_obj, "Right of");
300 else if (cs->rel_mode == E_RANDR2_RELATIVE_TO_ABOVE)
301 elm_object_text_set(cfdata->rel_mode_obj, "Above");
302 else if (cs->rel_mode == E_RANDR2_RELATIVE_TO_BELOW)
303 elm_object_text_set(cfdata->rel_mode_obj, "Below");
304 else
305 elm_object_text_set(cfdata->rel_mode_obj, "???");
306
307 elm_slider_value_set(cfdata->rel_align_obj, cs->rel_align);
308
309 if (!cs->rel_to)
310 elm_object_text_set(cfdata->rel_to_obj, "");
311 else
312 {
313 char *str = strdup(cs->rel_to);
314 if (str)
315 {
316 char *p = strchr(str, '/');
317 if (p)
318 {
319 *p = 0;
320 elm_object_text_set(cfdata->rel_to_obj, str);
321 }
322 free(str);
323 }
324 }
325}
326
327static void
328_cb_screen_select(void *data, Evas_Object *obj, void *event)
329{
330 E_Config_Dialog_Data *cfdata = data;
331 Elm_Object_Item *it;
332 Eina_List *l;
333 int i = 0;
334
335 EINA_LIST_FOREACH(cfdata->screen_items, l, it)
336 {
337 if (it == event)
338 {
339 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
340 cfdata->screen = i;
341 if (cs)
342 {
343 E_Randr2_Screen *s = _screen_config_find(cs);
344 if (s)
345 {
346 elm_object_text_set(obj, s->info.name);
347 _basic_screen_info_fill(cfdata, cs, s);
348 }
349 }
350 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
351 return;
352 }
353 i++;
354 }
355}
356
357static void
358_cb_rel_to_set(void *data, Evas_Object *obj, void *event)
359{
360 E_Config_Dialog_Data *cfdata = data;
361 Elm_Object_Item *it;
362 Eina_List *l;
363 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
364 if (!cs) return;
365 int i = 0;
366
367 EINA_LIST_FOREACH(cfdata->screen_items2, l, it)
368 {
369 if (it == event)
370 {
371 E_Config_Randr2_Screen *cs2 = _config_screen_n_find(cfdata, i);
372 printf("find cs = %p\n", cs2);
373 printf("cs id = %s\n", cs2->id);
374 if (cs2 == cs) return;
375 if (cs2)
376 {
377 E_Randr2_Screen *s = _screen_config_id_find(cs2->id);
378 if (s)
379 {
380 printf("find s = %p\n", s);
381 printf("s id = %s\n", s->id);
382 elm_object_text_set(obj, s->info.name);
383 eina_stringshare_del(cs->rel_to);
384 cs->rel_to = eina_stringshare_add(s->id);
385 }
386 }
387 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
388 return;
389 }
390 i++;
391 }
392}
393
394static void
395_cb_rel_align_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
396{
397 E_Config_Dialog_Data *cfdata = data;
398 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
399 if (!cs) return;
400 cs->rel_align = elm_slider_value_get(obj);
401 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
402}
403
404static void
405_cb_rel_mode_none(void *data, Evas_Object *obj, void *event EINA_UNUSED)
406{
407 E_Config_Dialog_Data *cfdata = data;
408 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
409 if (!cs) return;
410 cs->rel_mode = E_RANDR2_RELATIVE_NONE;
411 elm_object_text_set(obj, "None");
412 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
413}
414
415static void
416_cb_rel_mode_clone(void *data, Evas_Object *obj, void *event EINA_UNUSED)
417{
418 E_Config_Dialog_Data *cfdata = data;
419 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
420 if (!cs) return;
421 cs->rel_mode = E_RANDR2_RELATIVE_CLONE;
422 elm_object_text_set(obj, "Clone");
423 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
424}
425
426static void
427_cb_rel_mode_left_of(void *data, Evas_Object *obj, void *event EINA_UNUSED)
428{
429 E_Config_Dialog_Data *cfdata = data;
430 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
431 if (!cs) return;
432 cs->rel_mode = E_RANDR2_RELATIVE_TO_LEFT;
433 elm_object_text_set(obj, "Left of");
434 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
435}
436
437static void
438_cb_rel_mode_right_of(void *data, Evas_Object *obj, void *event EINA_UNUSED)
439{
440 E_Config_Dialog_Data *cfdata = data;
441 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
442 if (!cs) return;
443 cs->rel_mode = E_RANDR2_RELATIVE_TO_RIGHT;
444 elm_object_text_set(obj, "Right of");
445 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
446}
447
448static void
449_cb_rel_mode_above(void *data, Evas_Object *obj, void *event EINA_UNUSED)
450{
451 E_Config_Dialog_Data *cfdata = data;
452 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
453 if (!cs) return;
454 cs->rel_mode = E_RANDR2_RELATIVE_TO_ABOVE;
455 elm_object_text_set(obj, "Above");
456 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
457}
458
459static void
460_cb_rel_mode_below(void *data, Evas_Object *obj, void *event EINA_UNUSED)
461{
462 E_Config_Dialog_Data *cfdata = data;
463 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
464 if (!cs) return;
465 cs->rel_mode = E_RANDR2_RELATIVE_TO_BELOW;
466 elm_object_text_set(obj, "Below");
467 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
468}
469
470static void
471_cb_priority_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
472{
473 E_Config_Dialog_Data *cfdata = data;
474 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
475 if (!cs) return;
476 cs->priority = elm_slider_value_get(obj);
477 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
478}
479
480static void
481_cb_enabled_changed(void *data, Evas_Object *obj, void *event EINA_UNUSED)
482{
483 E_Config_Dialog_Data *cfdata = data;
484 E_Config_Randr2_Screen *cs = _config_screen_find(cfdata);
485 if (!cs) return;
486 cs->enabled = elm_check_state_get(obj);
487 e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
488}
489
490static Evas_Object *
491_basic_create(E_Config_Dialog *cfd, Evas *evas EINA_UNUSED, E_Config_Dialog_Data *cfdata)
492{
493 Evas_Object *win = cfd->dia->win;
494 Evas_Object *o, *bx, *tb;
495 Eina_List *l;
496 E_Randr2_Screen *s, *first = NULL;
497 E_Config_Randr2_Screen *first_cfg = NULL;
498 int i;
499
500 e_dialog_resizable_set(cfd->dia, 1);
501
502 o = elm_box_add(win);
503 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
504 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
505 evas_object_show(o);
506 bx = o;
507
508 o = elm_table_add(win);
509 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
510 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
511 elm_box_pack_end(bx, o);
512 evas_object_show(o);
513 tb = o;
514
515 o = elm_hoversel_add(win);
516 evas_object_size_hint_weight_set(o, 0.0, 0.0);
517 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
518 elm_object_text_set(o, "Outputs");
519 cfdata->screens = NULL;
520 cfdata->screen_items = NULL;
521 i = 0;
522 EINA_LIST_FOREACH(e_randr2->screens, l, s)
523 {
524 Elm_Object_Item *it = NULL;
525
526 if (s->info.connected)
527 {
528 E_Config_Randr2_Screen *cs;
529
530 cs = calloc(1, sizeof(E_Config_Randr2_Screen));
531 if (cs)
532 {
533 if (s->id)
534 cs->id = eina_stringshare_add(s->id);
535 if (s->config.relative.to)
536 cs->rel_to = eina_stringshare_add(s->config.relative.to);
537 cs->rel_align = s->config.relative.align;
538 cs->mode_refresh = s->config.mode.refresh;
539 cs->mode_w = s->config.mode.w;
540 cs->mode_h = s->config.mode.h;
541 cs->rotation = s->config.rotation;
542 cs->priority = s->config.priority;
543 cs->rel_mode = s->config.relative.mode;
544 cs->enabled = s->config.enabled;
545 cfdata->screens = eina_list_append(cfdata->screens, cs);
546 it = elm_hoversel_item_add(o, s->info.name,
547 NULL, ELM_ICON_NONE,
548 _cb_screen_select, cfdata);
549 if (!first)
550 {
551 first = s;
552 first_cfg = cs;
553 cfdata->screen = i;
554 elm_object_text_set(o, s->info.name);
555 }
556 cfdata->screen_items = eina_list_append(cfdata->screen_items, it);
557 i++;
558 }
559 }
560 }
561 elm_table_pack(tb, o, 0, 0, 1, 1);
562 evas_object_show(o);
563
564 o = elm_entry_add(win);
565 elm_entry_scrollable_set(o, EINA_TRUE);
566 elm_entry_single_line_set(o, EINA_TRUE);
567 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
568 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
569 elm_table_pack(tb, o, 0, 1, 1, 1);
570 evas_object_show(o);
571 cfdata->name_obj = o;
572
573 o = elm_entry_add(win);
574 elm_entry_scrollable_set(o, EINA_TRUE);
575 elm_entry_single_line_set(o, EINA_TRUE);
576 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
577 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
578 elm_table_pack(tb, o, 0, 2, 1, 1);
579 evas_object_show(o);
580 cfdata->screen_obj = o;
581
582 o = elm_check_add(win);
583 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
584 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
585 elm_object_text_set(o, "Laptop lid");
586 elm_table_pack(tb, o, 0, 3, 1, 1);
587 evas_object_show(o);
588 cfdata->lid_obj = o;
589
590 o = elm_check_add(win);
591 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
592 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
593 elm_object_text_set(o, "Backlight");
594 elm_table_pack(tb, o, 0, 4, 1, 1);
595 evas_object_show(o);
596 cfdata->backlight_obj = o;
597
598 o = elm_label_add(win);
599 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
600 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
601 elm_table_pack(tb, o, 0, 5, 1, 1);
602 evas_object_show(o);
603 cfdata->size_obj = o;
604
605 o = elm_list_add(win);
606 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
607 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
608 elm_table_pack(tb, o, 1, 0, 1, 10);
609 evas_object_show(o);
610 cfdata->modes_obj = o;
611
612 o = elm_list_add(win);
613 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
614 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
615 elm_table_pack(tb, o, 2, 0, 1, 4);
616 evas_object_show(o);
617 cfdata->rotations_obj = o;
618
619 o = elm_check_add(win);
620 evas_object_size_hint_weight_set(o, 0.0, 0.0);
621 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
622 elm_object_text_set(o, "On");
623 elm_table_pack(tb, o, 2, 4, 1, 1);
624 evas_object_show(o);
625 evas_object_smart_callback_add(o, "changed", _cb_enabled_changed, cfdata);
626 cfdata->enabled_obj = o;
627
628 o = elm_slider_add(win);
629 evas_object_size_hint_weight_set(o, 0.0, 0.0);
630 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
631 elm_object_text_set(o, "Priority");
632 elm_slider_unit_format_set(o, "%3.0f");
633 elm_slider_span_size_set(o, 100);
634 elm_slider_min_max_set(o, 0, 100);
635 elm_table_pack(tb, o, 2, 5, 1, 1);
636 evas_object_show(o);
637 evas_object_smart_callback_add(o, "changed", _cb_priority_changed, cfdata);
638 cfdata->priority_obj = o;
639
640 o = elm_hoversel_add(win);
641 evas_object_size_hint_weight_set(o, 0.0, 0.0);
642 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
643 elm_object_text_set(o, "Relative");
644 elm_hoversel_item_add(o, "None", NULL, ELM_ICON_NONE, _cb_rel_mode_none, cfdata);
645 elm_hoversel_item_add(o, "Clone", NULL, ELM_ICON_NONE, _cb_rel_mode_clone, cfdata);
646 elm_hoversel_item_add(o, "Left of", NULL, ELM_ICON_NONE, _cb_rel_mode_left_of, cfdata);
647 elm_hoversel_item_add(o, "Right of", NULL, ELM_ICON_NONE, _cb_rel_mode_right_of, cfdata);
648 elm_hoversel_item_add(o, "Above", NULL, ELM_ICON_NONE, _cb_rel_mode_above, cfdata);
649 elm_hoversel_item_add(o, "Below", NULL, ELM_ICON_NONE, _cb_rel_mode_below, cfdata);
650 elm_table_pack(tb, o, 2, 6, 1, 1);
651 evas_object_show(o);
652 cfdata->rel_mode_obj = o;
653
654 o = elm_hoversel_add(win);
655 evas_object_size_hint_weight_set(o, 0.0, 0.0);
656 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
657 elm_object_text_set(o, "To");
658 EINA_LIST_FOREACH(e_randr2->screens, l, s)
659 {
660 Elm_Object_Item *it = NULL;
661
662 if (s->info.connected)
663 {
664 it = elm_hoversel_item_add(o, s->info.name,
665 NULL, ELM_ICON_NONE,
666 _cb_rel_to_set, cfdata);
667 cfdata->screen_items2 = eina_list_append(cfdata->screen_items2, it);
668 }
669 }
670 elm_table_pack(tb, o, 2, 7, 1, 1);
671 evas_object_show(o);
672 cfdata->rel_to_obj = o;
673
674 o = elm_slider_add(win);
675 evas_object_size_hint_weight_set(o, 0.0, 0.0);
676 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
677 elm_object_text_set(o, "Align");
678 elm_slider_unit_format_set(o, "%1.1f");
679 elm_slider_span_size_set(o, 100);
680 elm_slider_min_max_set(o, 0.0, 1.0);
681 elm_table_pack(tb, o, 2, 8, 1, 1);
682 evas_object_show(o);
683 evas_object_smart_callback_add(o, "changed", _cb_rel_align_changed, cfdata);
684 cfdata->rel_align_obj = o;
685
686 _basic_screen_info_fill(cfdata, first_cfg, first);
687
688 o = elm_check_add(win);
689 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
690 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
691 elm_object_text_set(o, "Restore setup on start");
692 elm_check_state_set(o, e_randr2_cfg->restore);
693 elm_box_pack_end(bx, o);
694 evas_object_show(o);
695 evas_object_smart_callback_add(o, "changed", _cb_restore_changed, cfdata);
696
697 evas_smart_objects_calculate(evas_object_evas_get(win));
698
699 e_util_win_auto_resize_fill(win);
700 elm_win_center(win, 1, 1);
701 cfdata->cfd = cfd;
702 return bx;
703}
704
705static int
706_basic_apply(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
707{
708 Eina_List *l;
709 E_Config_Randr2_Screen *cs, *cs2;
710
711 e_randr2_cfg->restore = cfdata->restore;
712 EINA_LIST_FOREACH(cfdata->screens, l, cs2)
713 {
714 if (!cs2->id) continue;
715 cs = _screen_config_randr_id_find(cs2->id);
716 if (!cs)
717 {
718 cs = calloc(1, sizeof(E_Config_Randr2_Screen));
719 cs->id = eina_stringshare_add(cs2->id);
720 e_randr2_cfg->screens = eina_list_append(e_randr2_cfg->screens, cs);
721 }
722 if (cs->rel_to) eina_stringshare_del(cs->rel_to);
723 cs->rel_to = NULL;
724 if (cs2->rel_to) cs->rel_to = eina_stringshare_add(cs2->rel_to);
725 cs->rel_align = cs2->rel_align;
726 cs->mode_refresh = cs2->mode_refresh;
727 cs->mode_w = cs2->mode_w;
728 cs->mode_h = cs2->mode_h;
729 cs->mode_refresh = cs2->mode_refresh;
730 cs->rotation = cs2->rotation;
731 cs->priority = cs2->priority;
732 cs->rel_mode = cs2->rel_mode;
733 cs->enabled = cs2->enabled;
734 }
735 e_randr2_config_save();
736 e_randr2_config_apply();
737 return 1;
738}
739
740static int
741_basic_check(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata EINA_UNUSED)
742{
743 return 1;
744}
diff --git a/src/modules/conf_randr/e_int_config_randr2.h b/src/modules/conf_randr/e_int_config_randr2.h
new file mode 100644
index 0000000..60f2aa2
--- /dev/null
+++ b/src/modules/conf_randr/e_int_config_randr2.h
@@ -0,0 +1,9 @@
1#ifdef E_TYPEDEFS
2#else
3# ifndef E_INT_CONFIG_RANDR2_H
4# define E_INT_CONFIG_RANDR2_H
5
6E_Config_Dialog *e_int_config_randr2(Evas_Object *parent, const char *params);
7
8# endif
9#endif
diff --git a/src/modules/conf_randr/e_mod_main.c b/src/modules/conf_randr/e_mod_main.c
index 9f0c32c..d8cb733 100644
--- a/src/modules/conf_randr/e_mod_main.c
+++ b/src/modules/conf_randr/e_mod_main.c
@@ -1,8 +1,8 @@
1#include "e.h" 1#include "e.h"
2#include "e_mod_main.h" 2#include "e_mod_main.h"
3#include "e_int_config_randr.h" 3#include "e_int_config_randr2.h"
4 4
5EAPI E_Module_Api e_modapi = 5EAPI E_Module_Api e_modapi =
6{ 6{
7 E_MODULE_API_VERSION, "Settings - Screen Setup" 7 E_MODULE_API_VERSION, "Settings - Screen Setup"
8}; 8};
@@ -13,43 +13,31 @@ e_modapi_init(E_Module *m)
13 /* create Screen configuration category 13 /* create Screen configuration category
14 * 14 *
15 * NB: If the category already exists, this function just returns */ 15 * NB: If the category already exists, this function just returns */
16 e_configure_registry_category_add("screen", 30, _("Screen"), 16 e_configure_registry_category_add("screen", 30, _("Screen"),
17 NULL, "preferences-desktop-display"); 17 NULL, "preferences-desktop-display");
18 18
19 /* add the randr dialog to the screen category and provide 19 /* add the randr dialog to the screen category and provide
20 * the configure category with the function to call */ 20 * the configure category with the function to call */
21 e_configure_registry_item_add("screen/screen_setup", 20, _("Screen Setup"), 21 e_configure_registry_item_add("screen/screen_setup", 20, _("Screen Setup"),
22 NULL, 22 NULL, "preferences-system-screen-resolution",
23 "preferences-system-screen-resolution", 23 e_int_config_randr2);
24 e_int_config_randr);
25
26
27 /* return the module */
28 return m; 24 return m;
29} 25}
30 26
31EAPI int 27EAPI int
32e_modapi_shutdown(E_Module *m __UNUSED__) 28e_modapi_shutdown(E_Module *m __UNUSED__)
33{ 29{
34 E_Config_Dialog *cfd; 30 E_Config_Dialog *cfd;
35 31
36 /* destroy existing dialogs */
37 while ((cfd = e_config_dialog_get("E", "screen/screen_setup"))) 32 while ((cfd = e_config_dialog_get("E", "screen/screen_setup")))
38 e_object_del(E_OBJECT(cfd)); 33 e_object_del(E_OBJECT(cfd));
39 34
40 /* remove randr dialog from the configuration category */
41 e_configure_registry_item_del("screen/screen_setup"); 35 e_configure_registry_item_del("screen/screen_setup");
42
43 /* remove the screen configuration category
44 *
45 * NB: If there are other items in 'screen' then this function is a no-op */
46 e_configure_registry_category_del("screen"); 36 e_configure_registry_category_del("screen");
47
48 /* return 1 for shutdown success */
49 return 1; 37 return 1;
50} 38}
51 39
52EAPI int 40EAPI int
53e_modapi_save(E_Module *m __UNUSED__) 41e_modapi_save(E_Module *m __UNUSED__)
54{ 42{
55 return 1; 43 return 1;
diff --git a/src/modules/conf_randr/e_mod_main.h b/src/modules/conf_randr/e_mod_main.h
index 45c7afa..9ff8663 100644
--- a/src/modules/conf_randr/e_mod_main.h
+++ b/src/modules/conf_randr/e_mod_main.h
@@ -1,6 +1,7 @@
1#ifndef E_MOD_MAIN_H 1#ifndef E_MOD_MAIN_H
2# define E_MOD_MAIN_H 2# define E_MOD_MAIN_H
3 3
4#if 0
4//# define LOGFNS 1 5//# define LOGFNS 1
5 6
6# ifdef LOGFNS 7# ifdef LOGFNS
@@ -29,3 +30,4 @@ EAPI int e_modapi_save(E_Module *m);
29 */ 30 */
30 31
31#endif 32#endif
33#endif