From 054adb6351f2777a4c2f22dee2c83c7ea4548d5e Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Fri, 13 Feb 2015 19:23:04 +0900 Subject: [PATCH] e - randr - handle missing relative display and use priority for zone this makes highest priority screen the lowest (0) zone. this also handles missing screesn that you are relative "of". missing clones are not working atm. also zone reconfigure moves windows now too --- src/bin/e_comp_x.c | 107 +++++++++++++++++++++++++++++++++++++------ src/bin/e_randr2.c | 71 ++++++++++++++++++++++------ src/bin/e_xinerama.c | 2 - src/bin/e_zone.c | 36 ++++++++++++++- 4 files changed, 184 insertions(+), 32 deletions(-) diff --git a/src/bin/e_comp_x.c b/src/bin/e_comp_x.c index 431e98145..bb98932d3 100644 --- a/src/bin/e_comp_x.c +++ b/src/bin/e_comp_x.c @@ -4560,35 +4560,114 @@ _e_comp_x_pre_swap(void *data, Evas *e EINA_UNUSED) c->grabbed = 0; } +static int +_e_comp_x_cinerama_screen_sort_cb(const void *data1, const void *data2) +{ + const E_Randr2_Screen *s1 = data1, *s2 = data2; + int dif; + + dif = -(s1->config.priority - s2->config.priority); + if (dif == 0) + { + dif = s1->config.geom.x - s2->config.geom.x; + if (dif == 0) + dif = s1->config.geom.y - s2->config.geom.y; + } + return dif; +} + static Eina_Bool _e_comp_x_xinerama_setup(int rw, int rh) { int i; E_Screen *screen; + Eina_List *screens = NULL, *screens_rem; Eina_List *all_screens = NULL; - Eina_List *l; - E_Randr2_Screen *s; + Eina_List *l, *ll; + E_Randr2_Screen *s, *s2, *s_chosen; + Eina_Bool removed; - i = 0; + // put screens in tmp list EINA_LIST_FOREACH(e_randr2->screens, l, s) { if ((s->config.enabled) && (s->config.geom.w > 0) && (s->config.geom.h > 0)) { - screen = E_NEW(E_Screen, 1); - screen->escreen = screen->screen = i; - screen->x = s->config.geom.x; - screen->y = s->config.geom.y; - screen->w = s->config.geom.w; - screen->h = s->config.geom.h; - all_screens = eina_list_append(all_screens, screen); - printf("xinerama screen %i %i %ix%i\n", screen->x, screen->y, screen->w, screen->h); - INF("E INIT: XINERAMA SCREEN: [%i][%i], %ix%i+%i+%i", - i, i, screen->w, screen->h, screen->x, screen->y); - i++; + screens = eina_list_append(screens, s); } } + // remove overlapping screens - if a set of screens overlap, keep the + // smallest/lowest res + do + { + removed = EINA_FALSE; + + EINA_LIST_FOREACH(screens, l, s) + { + screens_rem = NULL; + + EINA_LIST_FOREACH(l->next, ll, s2) + { + if (E_INTERSECTS(s->config.geom.x, s->config.geom.y, + s->config.geom.w, s->config.geom.h, + s2->config.geom.x, s2->config.geom.y, + s2->config.geom.w, s2->config.geom.h)) + { + if (!screens_rem) + screens_rem = eina_list_append(screens_rem, s); + screens_rem = eina_list_append(screens_rem, s2); + } + } + // we have intersecting screens - choose the lowest res one + if (screens_rem) + { + removed = EINA_TRUE; + // find the smallest screen (chosen one) + s_chosen = NULL; + EINA_LIST_FOREACH(screens_rem, ll, s2) + { + if (!s_chosen) s_chosen = s2; + else + { + if ((s_chosen->config.geom.w * + s_chosen->config.geom.h) > + (s2->config.geom.w * + s2->config.geom.h)) + s_chosen = s2; + } + } + // remove all from screens but the chosen one + EINA_LIST_FREE(screens_rem, s2) + { + if (s2 != s_chosen) + screens = eina_list_remove_list(screens, l); + } + // break our list walk and try again + break; + } + } + } + while (removed); + // sort screens by priority etc. + screens = eina_list_sort(screens, eina_list_count(screens), + _e_comp_x_cinerama_screen_sort_cb); + i = 0; + EINA_LIST_FOREACH(screens, l, s) + { + screen = E_NEW(E_Screen, 1); + screen->escreen = screen->screen = i; + screen->x = s->config.geom.x; + screen->y = s->config.geom.y; + screen->w = s->config.geom.w; + screen->h = s->config.geom.h; + all_screens = eina_list_append(all_screens, screen); + printf("xinerama screen %i %i %ix%i\n", screen->x, screen->y, screen->w, screen->h); + INF("E INIT: XINERAMA SCREEN: [%i][%i], %ix%i+%i+%i", + i, i, screen->w, screen->h, screen->x, screen->y); + i++; + } + eina_list_free(screens); // if we have NO screens at all (above - i will be 0) AND we have no // existing screens set up in xinerama - then just say root window size // is the entire screen. this should handle the case where you unplug ALL diff --git a/src/bin/e_randr2.c b/src/bin/e_randr2.c index bc8b21216..808d42472 100644 --- a/src/bin/e_randr2.c +++ b/src/bin/e_randr2.c @@ -423,6 +423,7 @@ _config_apply(E_Randr2 *r, E_Config_Randr2 *cfg) s->config.mode.preferred = EINA_FALSE; s->config.rotation = cs->rotation; s->config.priority = cs->priority; + printf("RRR: ... priority = %i\n", cs->priority); free(s->config.relative.to); if (cs->rel_to) s->config.relative.to = strdup(cs->rel_to); else s->config.relative.to = NULL; @@ -659,6 +660,49 @@ _screen_config_takeover(void) } } +static E_Config_Randr2_Screen *_config_screen_string_find(E_Config_Randr2 *cfg, const char *id); +static E_Randr2_Screen *_screen_fuzzy_fallback_find(E_Config_Randr2 *cfg, const char *id); + +static E_Config_Randr2_Screen * +_config_screen_string_find(E_Config_Randr2 *cfg, const char *id) +{ + Eina_List *l; + E_Config_Randr2_Screen *cs; + + if ((!id) || (!cfg)) return NULL; + EINA_LIST_FOREACH(cfg->screens, l, cs) + { + if (!cs->id) continue; + if (!strcmp(cs->id, id)) return cs; + } + return NULL; +} + +static E_Randr2_Screen * +_screen_fuzzy_fallback_find(E_Config_Randr2 *cfg, const char *id) +{ + E_Randr2_Screen *s = NULL; + char *p, *name; + + // strip out everythng in the string from / on as that is edid + // and fall back to finding just the output name in the rel + // to identifier, rather than the specific screen id + name = alloca(strlen(id) + 1); + strcpy(name, id); + if ((p = strchr(name, '/'))) *p = 0; + + s = _screen_id_find(id); + if (!s) s = _screen_id_find(name); + if (!s) + { + E_Config_Randr2_Screen *cs; + + cs = _config_screen_string_find(cfg, id); + if ((cs) && (cs->id)) return _screen_fuzzy_fallback_find(cfg, cs->id); + } + return s; +} + static int _config_do_recurse = 0; static void @@ -680,18 +724,7 @@ _screen_config_do(E_Randr2_Screen *s) { // if this screen is relative TO something (clone or left/right etc. // then calculate what it is relative to first - s2 = _screen_id_find(s->config.relative.to); - printf("RRR: '%s' is relative to %p\n", s->info.name, s2); - if (!s2) - { - // strip out everythng in the string from / on as that is edid - // and fall back to finding just the output name in the rel - // to identifier, rather than the specific screen id - char *p, *str = alloca(strlen(s->config.relative.to) + 1); - strcpy(str, s->config.relative.to); - if ((p = strchr(str, '/'))) *p = 0; - s2 = _screen_output_find(str); - } + s2 = _screen_fuzzy_fallback_find(e_randr2_cfg, s->config.relative.to); printf("RRR: '%s' is relative to %p\n", s->info.name, s2); if (s2) _screen_config_do(s2); } @@ -1137,9 +1170,11 @@ _info_get(void) { Ecore_X_Randr_Mode *modes; Ecore_X_Randr_Edid_Display_Interface_Type conn; - int modes_num = 0, modes_pref = 0; + int modes_num = 0, modes_pref = 0, priority; + E_Config_Randr2_Screen *cs; E_Randr2_Screen *s = calloc(1, sizeof(E_Randr2_Screen)); if (!s) continue; + s->info.name = _output_name_get(root, outputs[i]); printf("RRR: ...... out %s\n", s->info.name); if (!s->info.name) @@ -1215,8 +1250,14 @@ _info_get(void) } free(modes); } - if (ecore_x_randr_primary_output_get(root) == outputs[i]) - s->config.priority = 100; + cs = NULL; + priority = 0; + if (e_randr2_cfg) cs = _config_screen_find(s, e_randr2_cfg); + if (cs) + priority = cs->priority; + else if (ecore_x_randr_primary_output_get(root) == outputs[i]) + priority = 100; + s->config.priority = priority; for (j = 0; j < crtcs_num; j++) { Eina_Bool ok, possible; diff --git a/src/bin/e_xinerama.c b/src/bin/e_xinerama.c index e75704f84..10ee4ad71 100644 --- a/src/bin/e_xinerama.c +++ b/src/bin/e_xinerama.c @@ -132,8 +132,6 @@ _e_xinerama_update(void) INF("======================= screens:"); EINA_LIST_FOREACH(chosen_screens, l, scr) { - scr->screen = n; - scr->escreen = n; INF("E INIT: XINERAMA CHOSEN: [%i][%i], %ix%i+%i+%i", scr->screen, scr->escreen, scr->w, scr->h, scr->x, scr->y); n++; diff --git a/src/bin/e_zone.c b/src/bin/e_zone.c index 8da9ad17f..65aa1a341 100644 --- a/src/bin/e_zone.c +++ b/src/bin/e_zone.c @@ -270,17 +270,40 @@ e_zone_name_set(E_Zone *zone, zone->name = eina_stringshare_add(name); } +static void +e_zone_reconfigure_clients(E_Zone *zone, int dx, int dy, int dw, int dh) +{ + E_Client *ec; + + E_CLIENT_FOREACH(zone->comp, ec) + { + if (ec->zone != zone) continue; + + if ((dx != 0) || (dy != 0)) + evas_object_move(ec->frame, ec->x + dx, ec->y + dy); + // we shrank the zone - adjust windows more + if ((dw < 0) || (dh < 0)) + { + e_client_res_change_geometry_save(ec); + e_client_res_change_geometry_restore(ec); + } + } +} + EAPI void e_zone_move(E_Zone *zone, int x, int y) { E_Event_Zone_Move_Resize *ev; + int dx, dy; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if ((x == zone->x) && (y == zone->y)) return; + dx = x - zone->x; + dy = y - zone->y; zone->x = x; zone->y = y; evas_object_move(zone->bg_object, x, y); @@ -294,6 +317,7 @@ e_zone_move(E_Zone *zone, _e_zone_edge_move_resize(zone); e_zone_bg_reconfigure(zone); + e_zone_reconfigure_clients(zone, dx, dy, 0, 0); } EAPI void @@ -302,11 +326,15 @@ e_zone_resize(E_Zone *zone, int h) { E_Event_Zone_Move_Resize *ev; + int dw, dh; E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if ((w == zone->w) && (h == zone->h)) return; + + dw = w - zone->w; + dh = h - zone->h; zone->w = w; zone->h = h; evas_object_resize(zone->bg_object, w, h); @@ -321,6 +349,7 @@ e_zone_resize(E_Zone *zone, _e_zone_edge_move_resize(zone); e_zone_bg_reconfigure(zone); + e_zone_reconfigure_clients(zone, 0, 0, dw, dh); } EAPI Eina_Bool @@ -331,6 +360,7 @@ e_zone_move_resize(E_Zone *zone, int h) { E_Event_Zone_Move_Resize *ev; + int dx, dy, dw, dh; E_OBJECT_CHECK_RETURN(zone, EINA_FALSE); E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, EINA_FALSE); @@ -338,6 +368,10 @@ e_zone_move_resize(E_Zone *zone, if ((x == zone->x) && (y == zone->y) && (w == zone->w) && (h == zone->h)) return EINA_FALSE; + dx = x - zone->x; + dy = y - zone->y; + dw = w - zone->w; + dh = h - zone->h; zone->x = x; zone->y = y; zone->w = w; @@ -357,8 +391,8 @@ e_zone_move_resize(E_Zone *zone, _e_zone_event_generic_free, NULL); _e_zone_edge_move_resize(zone); - e_zone_bg_reconfigure(zone); + e_zone_reconfigure_clients(zone, dx, dy, dw, dh); return EINA_TRUE; }