e - randr - handle missing relative display and use priority for zone
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>
Fri, 13 Feb 2015 10:23:04 +0000 (19:23 +0900)
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>
Fri, 13 Feb 2015 10:24:31 +0000 (19:24 +0900)
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
src/bin/e_randr2.c
src/bin/e_xinerama.c
src/bin/e_zone.c

index 431e9814531c943b2dc6d8ae35ddc12cf175a44f..bb98932d3dd81ab3f2bc6e074c303da94697edc3 100644 (file)
@@ -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
index bc8b21216f5cdde5954865632548b892e1e8b648..808d424720a1ba3d1869de355f8e0e3558be3219 100644 (file)
@@ -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;
index e75704f84e36fcf3346515ea4530caa12d0ec297..10ee4ad713b6abbb07a1c67f6f6896347d1e9326 100644 (file)
@@ -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++;
index 8da9ad17fde1c33e93de45c9b5f9d813291eb7a5..65aa1a341b1c0150d4aadd1479c56349de48575d 100644 (file)
@@ -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;
 }