add a configurable default policy (default: extend) for screen hotplugging

make an effort to "just work" instead of the classic enlightenment ux of being
as annoying as possible

ref T5707
This commit is contained in:
Mike Blumenkrantz 2017-07-21 16:20:03 -04:00
parent e65c64ff63
commit 48a7181089
4 changed files with 205 additions and 26 deletions

View File

@ -752,6 +752,7 @@ e_comp_x_randr_create(void)
} }
} }
free(modes); free(modes);
e_randr2_screen_modes_sort(s);
} }
cs = NULL; cs = NULL;
priority = 0; priority = 0;

View File

@ -1,6 +1,6 @@
#include "e.h" #include "e.h"
#define E_RANDR_CONFIG_VERSION 1 #define E_RANDR_CONFIG_VERSION 2
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
static Eina_Bool _screen_closed(E_Randr2_Screen *s); static Eina_Bool _screen_closed(E_Randr2_Screen *s);
@ -13,7 +13,7 @@ static void _info_free(E_Randr2 *r);
static E_Config_Randr2 *_config_load(void); static E_Config_Randr2 *_config_load(void);
static void _config_free(E_Config_Randr2 *cfg); static void _config_free(E_Config_Randr2 *cfg);
static Eina_Bool _config_save(E_Randr2 *r, E_Config_Randr2 *cfg); static Eina_Bool _config_save(E_Randr2 *r, E_Config_Randr2 *cfg);
static void _config_update(E_Randr2 *r, E_Config_Randr2 *cfg); static Eina_Bool _config_update(E_Randr2 *r, E_Config_Randr2 *cfg, Eina_Bool );
static void _config_apply(E_Randr2 *r, E_Config_Randr2 *cfg); static void _config_apply(E_Randr2 *r, E_Config_Randr2 *cfg);
static int _config_screen_match_count(E_Randr2 *r, E_Config_Randr2 *cfg); static int _config_screen_match_count(E_Randr2 *r, E_Config_Randr2 *cfg);
static char *_screens_fingerprint(E_Randr2 *r); static char *_screens_fingerprint(E_Randr2 *r);
@ -44,6 +44,8 @@ E_API int E_EVENT_RANDR_CHANGE = 0;
EINTERN Eina_Bool EINTERN Eina_Bool
e_randr2_init(void) e_randr2_init(void)
{ {
int count;
if (!E_EVENT_RANDR_CHANGE) E_EVENT_RANDR_CHANGE = ecore_event_type_new(); if (!E_EVENT_RANDR_CHANGE) E_EVENT_RANDR_CHANGE = ecore_event_type_new();
if ((!e_comp->screen) || (!e_comp->screen->available) || (!e_comp->screen->available())) return EINA_FALSE; if ((!e_comp->screen) || (!e_comp->screen->available) || (!e_comp->screen->available())) return EINA_FALSE;
// create data descriptors for config storage // create data descriptors for config storage
@ -76,6 +78,7 @@ e_randr2_init(void)
E_CONFIG_VAL(D, T, restore, UCHAR); E_CONFIG_VAL(D, T, restore, UCHAR);
E_CONFIG_VAL(D, T, ignore_hotplug_events, UCHAR); E_CONFIG_VAL(D, T, ignore_hotplug_events, UCHAR);
E_CONFIG_VAL(D, T, ignore_acpi_events, UCHAR); E_CONFIG_VAL(D, T, ignore_acpi_events, UCHAR);
E_CONFIG_VAL(D, T, default_policy, UINT);
// set up events from the driver // set up events from the driver
if (e_comp->screen->init) if (e_comp->screen->init)
@ -88,14 +91,20 @@ e_randr2_init(void)
e_randr2_cfg = _config_load(); e_randr2_cfg = _config_load();
// only apply if restore is set AND at least one configured screen // only apply if restore is set AND at least one configured screen
// matches one we have // matches one we have
if ((e_randr2_cfg->restore) &&
(_config_screen_match_count(e_randr2, e_randr2_cfg) > 0)) count = _config_screen_match_count(e_randr2, e_randr2_cfg);
if (e_randr2_cfg->restore && count)
{ {
if (count != (int)eina_list_count(e_randr2->screens))
{
if (_config_update(e_randr2, e_randr2_cfg, 1))
e_randr2_config_save();
}
_do_apply(); _do_apply();
} }
else else
{ {
_config_update(e_randr2, e_randr2_cfg); _config_update(e_randr2, e_randr2_cfg, 0);
e_randr2_config_save(); e_randr2_config_save();
} }
ecore_event_add(E_EVENT_RANDR_CHANGE, NULL, NULL, NULL); ecore_event_add(E_EVENT_RANDR_CHANGE, NULL, NULL, NULL);
@ -314,6 +323,13 @@ _info_free(E_Randr2 *r)
free(r); free(r);
} }
static void
_config_upgrade(E_Config_Randr2 *cfg)
{
if (cfg->version < 2)
cfg->default_policy = E_RANDR2_POLICY_EXTEND;
}
static E_Config_Randr2 * static E_Config_Randr2 *
_config_load(void) _config_load(void)
{ {
@ -324,15 +340,9 @@ _config_load(void)
if (cfg) if (cfg)
{ {
if (cfg->version < E_RANDR_CONFIG_VERSION) if (cfg->version < E_RANDR_CONFIG_VERSION)
{ _config_upgrade(cfg);
_config_free(cfg); printf("RRR: loaded existing config\n");
cfg = NULL; return cfg;
}
else
{
printf("RRR: loaded existing config\n");
return cfg;
}
} }
// need new config // need new config
@ -342,6 +352,7 @@ _config_load(void)
cfg->restore = 1; cfg->restore = 1;
cfg->ignore_hotplug_events = 0; cfg->ignore_hotplug_events = 0;
cfg->ignore_acpi_events = 0; cfg->ignore_acpi_events = 0;
cfg->default_policy = E_RANDR2_POLICY_EXTEND;
printf("RRR: fresh config\n"); printf("RRR: fresh config\n");
return cfg; return cfg;
} }
@ -371,12 +382,20 @@ _config_save(E_Randr2 *r, E_Config_Randr2 *cfg)
return e_config_domain_save("e_randr2", _e_randr2_cfg_edd, cfg); return e_config_domain_save("e_randr2", _e_randr2_cfg_edd, cfg);
} }
static void static Eina_Bool
_config_update(E_Randr2 *r, E_Config_Randr2 *cfg) _config_ask_dialog()
{
e_configure_registry_call("screen/screen_setup", NULL, NULL);
return EINA_FALSE;
}
static Eina_Bool
_config_update(E_Randr2 *r, E_Config_Randr2 *cfg, Eina_Bool update_only)
{ {
Eina_List *l; Eina_List *l;
E_Randr2_Screen *s; E_Randr2_Screen *s;
E_Config_Randr2_Screen *cs; E_Config_Randr2_Screen *cs;
Eina_Bool ret = EINA_FALSE;
printf("--------------------------------------------------\n"); printf("--------------------------------------------------\n");
EINA_LIST_FOREACH(r->screens, l, s) EINA_LIST_FOREACH(r->screens, l, s)
@ -384,6 +403,7 @@ _config_update(E_Randr2 *r, E_Config_Randr2 *cfg)
printf("RRR: out id=%s: connected=%i\n", s->id, s->info.connected); printf("RRR: out id=%s: connected=%i\n", s->id, s->info.connected);
if ((!s->id) || (!s->info.connected) || (_screen_closed(s))) continue; if ((!s->id) || (!s->info.connected) || (_screen_closed(s))) continue;
cs = e_randr2_config_screen_find(s, cfg); cs = e_randr2_config_screen_find(s, cfg);
if (cs && update_only) continue;
if (!cs) if (!cs)
{ {
cs = calloc(1, sizeof(E_Config_Randr2_Screen)); cs = calloc(1, sizeof(E_Config_Randr2_Screen));
@ -395,16 +415,60 @@ _config_update(E_Randr2 *r, E_Config_Randr2 *cfg)
} }
if (cs) if (cs)
{ {
if (s->config.relative.to) if (update_only)
cs->rel_to = eina_stringshare_add(s->config.relative.to); {
cs->rel_align = s->config.relative.align; switch (cfg->default_policy)
cs->mode_refresh = s->config.mode.refresh; {
cs->mode_w = s->config.mode.w; case E_RANDR2_POLICY_EXTEND:
cs->mode_h = s->config.mode.h; if (s->config.relative.mode < E_RANDR2_RELATIVE_TO_LEFT)
cs->rel_mode = E_RANDR2_RELATIVE_TO_RIGHT;
else
cs->rel_mode = s->config.relative.mode;
break;
case E_RANDR2_POLICY_CLONE:
cs->rel_mode = E_RANDR2_RELATIVE_CLONE;
break;
case E_RANDR2_POLICY_ASK:
ecore_timer_loop_add(2, _config_ask_dialog, NULL);
case E_RANDR2_POLICY_NONE:
cs->rel_mode = E_RANDR2_RELATIVE_NONE;
break;
}
}
else
cs->rel_mode = s->config.relative.mode;
if (update_only &&
((cfg->default_policy == E_RANDR2_POLICY_CLONE) ||
(cfg->default_policy == E_RANDR2_POLICY_EXTEND)))
{
E_Randr2_Mode *m = eina_list_data_get(s->info.modes);
cs->enabled = !!m;
cs->mode_refresh = m->refresh;
cs->mode_w = m->w;
cs->mode_h = m->h;
if (s->config.relative.to)
cs->rel_to = eina_stringshare_add(s->config.relative.to);
else
{
/* find right-most screen */
E_Zone *zone = eina_list_last_data_get(e_comp->zones);
eina_stringshare_replace(&cs->rel_to, zone->randr2_id);
}
cs->rel_align = 0;
}
else
{
cs->enabled = s->config.enabled;
cs->mode_refresh = s->config.mode.refresh;
cs->mode_w = s->config.mode.w;
cs->mode_h = s->config.mode.h;
if (s->config.relative.to)
cs->rel_to = eina_stringshare_add(s->config.relative.to);
cs->rel_align = s->config.relative.align;
}
cs->rotation = s->config.rotation; cs->rotation = s->config.rotation;
cs->priority = s->config.priority; cs->priority = s->config.priority;
cs->rel_mode = s->config.relative.mode;
cs->enabled = s->config.enabled;
if (cs->profile) if (cs->profile)
{ {
printf("RRR: store config profile '%s'\n", cs->profile); printf("RRR: store config profile '%s'\n", cs->profile);
@ -418,9 +482,11 @@ _config_update(E_Randr2 *r, E_Config_Randr2 *cfg)
} }
printf("RRR: store scale mul %1.5f\n", cs->scale_multiplier); printf("RRR: store scale mul %1.5f\n", cs->scale_multiplier);
s->config.scale_multiplier = cs->scale_multiplier; s->config.scale_multiplier = cs->scale_multiplier;
ret = EINA_TRUE;
} }
} }
printf("--------------------------------------------------\n"); printf("--------------------------------------------------\n");
return ret;
} }
static void static void
@ -591,19 +657,28 @@ _screens_differ(E_Randr2 *r1, E_Randr2 *r2)
static Eina_Bool static Eina_Bool
_cb_screen_change_delay(void *data EINA_UNUSED) _cb_screen_change_delay(void *data EINA_UNUSED)
{ {
Eina_Bool change = EINA_FALSE;
_screen_delay_timer = NULL; _screen_delay_timer = NULL;
printf("RRR: ... %i %i\n", event_screen, event_ignore); printf("RRR: ... %i %i\n", event_screen, event_ignore);
// if we had a screen plug/unplug etc. event and we shouldnt ignore it... // if we had a screen plug/unplug etc. event and we shouldnt ignore it...
if ((event_screen) && (!event_ignore)) if ((event_screen) && (!event_ignore))
{ {
E_Randr2 *rtemp; E_Randr2 *rtemp;
Eina_Bool change = EINA_FALSE;
printf("RRR: reconfigure screens due to event...\n"); printf("RRR: reconfigure screens due to event...\n");
rtemp = e_comp->screen->create(); rtemp = e_comp->screen->create();
if (rtemp) if (rtemp)
{ {
if (_screens_differ(e_randr2, rtemp)) change = EINA_TRUE; if (_screens_differ(e_randr2, rtemp)) change = EINA_TRUE;
if (e_randr2_cfg->default_policy != E_RANDR2_POLICY_NONE)
{
if (_config_update(rtemp, e_randr2_cfg, 1))
{
e_randr2_config_save();
if (e_randr2_cfg->default_policy != E_RANDR2_POLICY_ASK)
change = EINA_TRUE;
}
}
_info_free(rtemp); _info_free(rtemp);
} }
printf("RRR: change = %i\n", change); printf("RRR: change = %i\n", change);
@ -1268,3 +1343,22 @@ e_randr2_screen_dpi_get(E_Randr2_Screen *s)
dpi2 = (25.4 * (double)(s->config.mode.h)) / (double)(s->info.size.h); dpi2 = (25.4 * (double)(s->config.mode.h)) / (double)(s->info.size.h);
return (dpi1 + dpi2) / 2.0; return (dpi1 + dpi2) / 2.0;
} }
static int
_modelist_sort(const void *a, const void *b)
{
const E_Randr2_Mode *ma = a, *mb = b;
/* largest resolutions first */
if ((ma->w * ma->h) > (mb->w * mb->h)) return -1;
/* highest refresh first */
if (ma->refresh > mb->refresh) return -1;
return 1;
}
EAPI void
e_randr2_screen_modes_sort(E_Randr2_Screen *s)
{
EINA_SAFETY_ON_NULL_RETURN(s);
s->info.modes = eina_list_sort(s->info.modes, 0, _modelist_sort);
}

View File

@ -11,6 +11,14 @@ typedef struct _E_Config_Randr2_Screen E_Config_Randr2_Screen;
#ifndef E_RANDR2_H #ifndef E_RANDR2_H
#define E_RAND2R_H #define E_RAND2R_H
typedef enum
{
E_RANDR2_POLICY_NONE,
E_RANDR2_POLICY_EXTEND,
E_RANDR2_POLICY_CLONE,
E_RANDR2_POLICY_ASK,
} E_Randr2_Policy;
typedef enum _E_Randr2_Relative typedef enum _E_Randr2_Relative
{ {
E_RANDR2_RELATIVE_UNKNOWN, E_RANDR2_RELATIVE_UNKNOWN,
@ -92,6 +100,7 @@ struct _E_Config_Randr2
unsigned char restore; unsigned char restore;
unsigned char ignore_hotplug_events; unsigned char ignore_hotplug_events;
unsigned char ignore_acpi_events; unsigned char ignore_acpi_events;
E_Randr2_Policy default_policy;
}; };
struct _E_Config_Randr2_Screen struct _E_Config_Randr2_Screen
@ -128,6 +137,6 @@ E_API E_Config_Randr2_Screen *e_randr2_config_screen_find(E_Randr2_Screen *s, E_
E_API void e_randr2_screens_setup(int rw, int rh); E_API void e_randr2_screens_setup(int rw, int rh);
E_API E_Randr2_Screen *e_randr2_screen_id_find(const char *id); E_API E_Randr2_Screen *e_randr2_screen_id_find(const char *id);
E_API double e_randr2_screen_dpi_get(E_Randr2_Screen *s); E_API double e_randr2_screen_dpi_get(E_Randr2_Screen *s);
E_API void e_randr2_screen_modes_sort(E_Randr2_Screen *s);
#endif #endif
#endif #endif

View File

@ -27,10 +27,12 @@ struct _E_Config_Dialog_Data
Evas_Object *profile_list_obj; Evas_Object *profile_list_obj;
Evas_Object *scale_custom_obj; Evas_Object *scale_custom_obj;
Evas_Object *scale_value_obj; Evas_Object *scale_value_obj;
Evas_Object *policy_obj;
int restore; int restore;
int hotplug; int hotplug;
int acpi; int acpi;
int screen; int screen;
E_Randr2_Policy policy;
}; };
typedef struct typedef struct
@ -101,6 +103,7 @@ _create_data(E_Config_Dialog *cfd EINA_UNUSED)
cfdata->restore = e_randr2_cfg->restore; cfdata->restore = e_randr2_cfg->restore;
cfdata->hotplug = !e_randr2_cfg->ignore_hotplug_events; cfdata->hotplug = !e_randr2_cfg->ignore_hotplug_events;
cfdata->acpi = !e_randr2_cfg->ignore_acpi_events; cfdata->acpi = !e_randr2_cfg->ignore_acpi_events;
cfdata->policy = e_randr2_cfg->default_policy;
return cfdata; return cfdata;
} }
@ -742,6 +745,66 @@ _cb_enabled_changed(void *data, Evas_Object *obj, void *event EINA_UNUSED)
e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE); e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
} }
static void
_policy_text_update(E_Config_Dialog_Data *cfdata)
{
char pbuf[128];
const char *policy[] =
{
_("Ignore"),
_("Extend"),
_("Clone"),
_("Ask")
};
snprintf(pbuf, sizeof(pbuf), _("Hotplug Policy (%s)"), policy[cfdata->policy]);
elm_object_text_set(cfdata->policy_obj, pbuf);
}
static void
_cb_policy_ignore(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Config_Dialog_Data *cfdata = data;
if (cfdata->policy == E_RANDR2_POLICY_NONE) return;
cfdata->policy = E_RANDR2_POLICY_NONE;
_policy_text_update(cfdata);
e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
}
static void
_cb_policy_ask(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Config_Dialog_Data *cfdata = data;
if (cfdata->policy == E_RANDR2_POLICY_ASK) return;
cfdata->policy = E_RANDR2_POLICY_ASK;
_policy_text_update(cfdata);
e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
}
static void
_cb_policy_extend(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Config_Dialog_Data *cfdata = data;
if (cfdata->policy == E_RANDR2_POLICY_EXTEND) return;
cfdata->policy = E_RANDR2_POLICY_EXTEND;
_policy_text_update(cfdata);
e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
}
static void
_cb_policy_clone(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Config_Dialog_Data *cfdata = data;
if (cfdata->policy == E_RANDR2_POLICY_CLONE) return;
cfdata->policy = E_RANDR2_POLICY_CLONE;
_policy_text_update(cfdata);
e_config_dialog_changed_set(cfdata->cfd, EINA_TRUE);
}
static Evas_Object * static Evas_Object *
_basic_create(E_Config_Dialog *cfd, Evas *evas EINA_UNUSED, E_Config_Dialog_Data *cfdata) _basic_create(E_Config_Dialog *cfd, Evas *evas EINA_UNUSED, E_Config_Dialog_Data *cfdata)
{ {
@ -1045,6 +1108,17 @@ _basic_create(E_Config_Dialog *cfd, Evas *evas EINA_UNUSED, E_Config_Dialog_Data
evas_object_show(o); evas_object_show(o);
evas_object_smart_callback_add(o, "changed", _cb_acpi_changed, cfdata); evas_object_smart_callback_add(o, "changed", _cb_acpi_changed, cfdata);
cfdata->policy_obj = o = elm_hoversel_add(win);
evas_object_size_hint_weight_set(o, 0.0, 0.0);
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
_policy_text_update(cfdata);
elm_hoversel_item_add(o, _("Clone"), NULL, ELM_ICON_NONE, _cb_policy_clone, cfdata);
elm_hoversel_item_add(o, _("Extend"), NULL, ELM_ICON_NONE, _cb_policy_extend, cfdata);
elm_hoversel_item_add(o, _("Ask"), NULL, ELM_ICON_NONE, _cb_policy_ask, cfdata);
elm_hoversel_item_add(o, _("Ignore"), NULL, ELM_ICON_NONE, _cb_policy_ignore, cfdata);
elm_box_pack_end(bx2, o);
evas_object_show(o);
evas_smart_objects_calculate(evas_object_evas_get(win)); evas_smart_objects_calculate(evas_object_evas_get(win));
e_util_win_auto_resize_fill(win); e_util_win_auto_resize_fill(win);
@ -1062,6 +1136,7 @@ _basic_apply(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
e_randr2_cfg->restore = cfdata->restore; e_randr2_cfg->restore = cfdata->restore;
e_randr2_cfg->ignore_hotplug_events = !cfdata->hotplug; e_randr2_cfg->ignore_hotplug_events = !cfdata->hotplug;
e_randr2_cfg->ignore_acpi_events = !cfdata->acpi; e_randr2_cfg->ignore_acpi_events = !cfdata->acpi;
e_randr2_cfg->default_policy = cfdata->policy;
printf("APPLY....................\n"); printf("APPLY....................\n");
EINA_LIST_FOREACH(cfdata->screens, l, cs2) EINA_LIST_FOREACH(cfdata->screens, l, cs2)