princeamd pushed a commit to branch enlightenment-0.17.

commit 7fa2c66d742f6bb0ce001b36d4387ec07560a05c
Author: Chris Michael <[email protected]>
Date:   Sat May 18 16:25:54 2013 +0100

    Backport: 9e605eb :: Fix randr plug-n-play for cedric because he asked 
nicely ;)
    
    - Add config timestamping to our randr config.
    - remove property_notify handler as we never use it.
    - Unify some code to remove duplication
    - Add a lot of debugging output.
        Yes, e_randr is going to be noisy for a little while until I can
        verify that it works for others also.
    - Too many other changes to list.
        Suffice to say, this makes e_randr plug-n-play work (here anyway).
    
    NB: Right now, this just clones. It Could be changed to extend new
    monitors tho
    
    NB: This works here, on my laptop at home. If you find it does not
    work for you, please supply the output of E's startup/restart when you
    plug AND unplug monitors.
    
    Signed-off-by: Chris Michael <[email protected]>
    Signed-off-by: Deon Thomas <[email protected]>
---
 src/bin/e_randr.c | 773 +++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 614 insertions(+), 159 deletions(-)

diff --git a/src/bin/e_randr.c b/src/bin/e_randr.c
index 154275d..9096e4b 100644
--- a/src/bin/e_randr.c
+++ b/src/bin/e_randr.c
@@ -6,11 +6,15 @@ static void _e_randr_config_new(void);
 static void _e_randr_config_free(void);
 static Eina_Bool _e_randr_config_cb_timer(void *data);
 static void _e_randr_config_restore(void);
+static Eina_Bool _e_randr_config_crtc_update(E_Randr_Crtc_Config *cfg);
+static Eina_Bool _e_randr_config_output_update(E_Randr_Output_Config *cfg);
+static E_Randr_Crtc_Config 
*_e_randr_config_output_crtc_find(E_Randr_Output_Config *cfg);
+static Ecore_X_Randr_Mode 
_e_randr_config_output_preferred_mode_get(E_Randr_Output_Config *cfg);
+static E_Randr_Output_Config *_e_randr_config_output_new(unsigned int id);
 
 static Eina_Bool _e_randr_event_cb_screen_change(void *data EINA_UNUSED, int 
type EINA_UNUSED, void *event);
 static Eina_Bool _e_randr_event_cb_crtc_change(void *data EINA_UNUSED, int 
type EINA_UNUSED, void *event);
 static Eina_Bool _e_randr_event_cb_output_change(void *data EINA_UNUSED, int 
type EINA_UNUSED, void *event);
-static Eina_Bool _e_randr_event_cb_property_change(void *data EINA_UNUSED, int 
type EINA_UNUSED, void *event EINA_UNUSED);
 
 /* local variables */
 static Eina_List *_randr_event_handlers = NULL;
@@ -55,9 +59,6 @@ e_randr_init(void)
         E_LIST_HANDLER_APPEND(_randr_event_handlers, 
                               ECORE_X_EVENT_RANDR_OUTPUT_CHANGE, 
                               _e_randr_event_cb_output_change, NULL);
-        E_LIST_HANDLER_APPEND(_randr_event_handlers, 
-                              ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY, 
-                              _e_randr_event_cb_property_change, NULL);
      }
 
    return EINA_TRUE;
@@ -154,6 +155,7 @@ _e_randr_config_load(void)
    E_CONFIG_LIST(D, T, crtcs, _e_randr_crtc_edd);
    E_CONFIG_VAL(D, T, restore, UCHAR);
    E_CONFIG_VAL(D, T, poll_interval, INT);
+   E_CONFIG_VAL(D, T, config_timestamp, ULL);
 
    /* try to load the randr config */
    if ((e_randr_cfg = e_config_domain_load("e_randr", _e_randr_edd)))
@@ -199,12 +201,6 @@ _e_randr_config_load(void)
    /* e_randr_config_new could return without actually creating a new config */
    if (!e_randr_cfg) return EINA_FALSE;
 
-   /* handle upgrading any old config */
-   /* if (e_randr_cfg->version < E_RANDR_CONFIG_FILE_VERSION) */
-   /*   { */
-
-   /*   } */
-
    if ((do_restore) && (e_randr_cfg->restore))
      _e_randr_config_restore();
 
@@ -216,7 +212,6 @@ _e_randr_config_new(void)
 {
    Ecore_X_Window root = 0;
    Ecore_X_Randr_Crtc *crtcs = NULL;
-   Ecore_X_Randr_Output primary = 0;
    int ncrtcs = 0, i = 0;
 
    /* create new randr cfg */
@@ -235,9 +230,6 @@ _e_randr_config_new(void)
    /* grab the root window once */
    root = ecore_x_window_root_first_get();
 
-   /* get which output is primary */
-   primary = ecore_x_randr_primary_output_get(root);
-
    /* record the current screen size in our config */
    ecore_x_randr_screen_current_size_get(root, &e_randr_cfg->screen.width, 
                                          &e_randr_cfg->screen.height, 
@@ -261,18 +253,8 @@ _e_randr_config_new(void)
              crtc_cfg->xid = crtcs[i];
              crtc_cfg->exists = EINA_TRUE;
 
-             /* record the geometry of this crtc in our config */
-             ecore_x_randr_crtc_geometry_get(root, crtcs[i], 
-                                             &crtc_cfg->x, &crtc_cfg->y, 
-                                             &crtc_cfg->width, 
-                                             &crtc_cfg->height);
-
-             /* record the orientation of this crtc in our config */
-             crtc_cfg->orient = 
-               ecore_x_randr_crtc_orientation_get(root, crtcs[i]);
-
-             /* record the mode id of this crtc in our config */
-             crtc_cfg->mode = ecore_x_randr_crtc_mode_get(root, crtcs[i]);
+             /* fill in crtc_cfg values from X */
+             _e_randr_config_crtc_update(crtc_cfg);
 
              /* try to get any outputs on this crtc */
              if ((outputs = 
@@ -283,46 +265,13 @@ _e_randr_config_new(void)
                   for (j = 0; j < noutputs; j++)
                     {
                        E_Randr_Output_Config *output_cfg = NULL;
-                       Ecore_X_Randr_Connection_Status status = 1;
-                       int clone_count = 0;
 
                        /* try to create new output config */
-                       if (!(output_cfg = E_NEW(E_Randr_Output_Config, 1)))
+                       if (!(output_cfg = 
_e_randr_config_output_new(outputs[j])))
                          continue;
 
-                       /* assign output xid */
-                       output_cfg->xid = outputs[j];
-
                        /* assign crtc for this output */
                        output_cfg->crtc = crtcs[i];
-
-                       /* set this output policy */
-                       output_cfg->policy = ECORE_X_RANDR_OUTPUT_POLICY_NONE;
-
-                       /* get if this output is the primary */
-                       output_cfg->primary = EINA_FALSE;
-                       if (outputs[j] == primary) 
-                         output_cfg->primary = EINA_TRUE;
-
-                       /* record the edid for this output */
-                       output_cfg->edid = 
-                         ecore_x_randr_output_edid_get(root, outputs[j], 
-                                                       
&output_cfg->edid_count);
-
-                       /* get the clones for this output */
-                       output_cfg->clones = 
-                         ecore_x_randr_output_clones_get(root, outputs[j], 
-                                                         &clone_count);
-                       
-                       output_cfg->clone_count = (long)clone_count;
-
-                       status = 
-                         ecore_x_randr_output_connection_status_get(root, 
outputs[j]);
-
-                       output_cfg->connected = EINA_FALSE;
-                       if (status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED)
-                         output_cfg->connected = EINA_TRUE;
-
                        output_cfg->exists = EINA_TRUE;
 
                        /* add this output to the list for this crtc */
@@ -341,6 +290,9 @@ _e_randr_config_new(void)
         free(crtcs);
      }
 
+   /* update recorded config timestamp */
+   e_randr_cfg->config_timestamp = ecore_x_randr_config_timestamp_get(root);
+
    /* set limits */
    E_CONFIG_LIMIT(e_randr_cfg->poll_interval, 1, 1024);
 
@@ -390,37 +342,34 @@ _e_randr_config_restore(void)
    Ecore_X_Window root = 0;
    Ecore_X_Randr_Crtc *crtcs;
    int ncrtcs = 0;
-   Eina_Bool need_reset = EINA_FALSE;
 
-   /* try to restore settings
-    * 
-    * NB: When we restore, check the resolutions (current vs saved)
-    * and if there is no change then we do not need to call 
-    * screen_reset as this triggers a full comp refresh. We can 
-    * accomplish this simply by checking the mode */
+   printf("E_RANDR Restore\n");
 
    /* grab the root window */
    root = ecore_x_window_root_first_get();
 
-   /* try to get the list of crtcs */
+   /* set the screen size */
+   /* NB: Disabled for now as our saved screen size may not be valid 
+    * if any of our saved outputs are missing in X */
+   /* ecore_x_randr_screen_current_size_set(root, e_randr_cfg->screen.width,  
*/
+   /*                                       e_randr_cfg->screen.height, -1, 
-1); */
+
+   /* try to get the list of existing crtcs from X */
    if ((crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs)))
      {
         int i = 0;
+        Eina_List *valid_crtcs = NULL;
+        Eina_List *l;
+        E_Randr_Crtc_Config *crtc_cfg;
+
+        printf("\tHave Crtcs\n");
 
+        /* for each crtc that X has, check our config and see if we have it */
         for (i = 0; i < ncrtcs; i++)
           {
-             Eina_List *l;
-             E_Randr_Crtc_Config *crtc_cfg;
-             Ecore_X_Randr_Mode mode;
-             Ecore_X_Randr_Output *outputs;
-             int noutputs = 0;
-
-             /* get the mode */
-             mode = ecore_x_randr_crtc_mode_get(root, crtcs[i]);
+             Eina_Bool crtc_found = EINA_FALSE;
 
-             /* get the outputs */
-             outputs = 
-               ecore_x_randr_crtc_outputs_get(root, crtcs[i], &noutputs);
+             printf("\t\tChecking For Crtc: %d in Our Config\n", crtcs[i]);
 
              /* loop our config and find this crtc */
              EINA_LIST_FOREACH(e_randr_cfg->crtcs, l, crtc_cfg)
@@ -428,33 +377,167 @@ _e_randr_config_restore(void)
                   /* try to find this crtc */
                   if (crtc_cfg->xid != crtcs[i]) continue;
 
-                  /* apply the stored settings */
-                  if (!crtc_cfg->mode)
-                    ecore_x_randr_crtc_settings_set(root, crtc_cfg->xid, 
-                                                    NULL, 0, 0, 0, 0, 
-                                                    
ECORE_X_RANDR_ORIENTATION_ROT_0);
-                  else
-                    ecore_x_randr_crtc_settings_set(root, crtc_cfg->xid, 
-                                                    outputs, noutputs, 
-                                                    crtc_cfg->x, crtc_cfg->y, 
-                                                    crtc_cfg->mode, 
-                                                    crtc_cfg->orient);
+                  crtc_found = EINA_TRUE;
+                  printf("\t\t\tFound Crtc in Config\n");
+                  valid_crtcs = eina_list_append(valid_crtcs, crtc_cfg);
+               }
+
+             if (!crtc_found)
+               {
+                  printf("\t\t\tCrtc Not Found in Config\n");
+                  printf("\t\t\t\tCreating New\n");
+                  /* create new crtc config */
+                  if ((crtc_cfg = E_NEW(E_Randr_Crtc_Config, 1)))
+                    {
+                       /* assign id */
+                       crtc_cfg->xid = crtcs[i];
+                       crtc_cfg->exists = EINA_TRUE;
 
-                  if (crtc_cfg->mode != mode)
-                    need_reset = EINA_TRUE;
+                       /* fill in crtc_cfg values from X */
+                       _e_randr_config_crtc_update(crtc_cfg);
 
-                  break;
-               }
+                       printf("\t\t\t\tNew Crtc Geom: %d %d %d %d\n",
+                              crtc_cfg->x, crtc_cfg->y, crtc_cfg->width, 
+                              crtc_cfg->height);
+                       printf("\t\t\t\tNew Crtc Mode: %d\n", crtc_cfg->mode);
+
+                       /* append to randr cfg */
+                       e_randr_cfg->crtcs = 
+                         eina_list_append(e_randr_cfg->crtcs, crtc_cfg);
 
-             /* free any allocated memory from ecore_x_randr */
-             free(outputs);
+                       e_randr_config_save();
+
+                       /* append to our short list */
+                       valid_crtcs = eina_list_append(valid_crtcs, crtc_cfg);
+                    }
+               }
           }
 
-        /* free any allocated memory from ecore_x_randr */
         free(crtcs);
+
+        printf("\t\tLooping Valid Crtcs\n");
+
+        /* for each X crtc that we have config for, check outputs */
+        EINA_LIST_FOREACH(valid_crtcs, l, crtc_cfg)
+          {
+             Ecore_X_Randr_Output *outputs;
+             int noutputs;
+             Eina_List *valid_outputs = NULL;
+
+             /* we have this crtc. try to get list of outputs from X */
+             if ((outputs = 
+                  ecore_x_randr_crtc_outputs_get(root, crtc_cfg->xid, 
&noutputs)))
+               {
+                  int j = 0;
+
+                  printf("\t\t\tHave X Outputs For Crtc: %d\n", crtc_cfg->xid);
+
+                  /* loop the X outputs and find a matching config */
+                  for (j = 0; j < noutputs; j++)
+                    {
+                       Eina_List *ll;
+                       E_Randr_Output_Config *output_cfg;
+                       /* Eina_Bool output_found = EINA_FALSE; */
+
+                       printf("\t\t\t\tChecking for Output: %d in Our 
Config\n", outputs[j]);
+
+                       /* loop our outputs for this crtc */
+                       EINA_LIST_FOREACH(crtc_cfg->outputs, ll, output_cfg)
+                         {
+                            /* try to find this output */
+                            if (output_cfg->xid != outputs[j]) continue;
+
+                            /* we have this output */
+                            /* output_found = EINA_TRUE; */
+
+                            printf("\t\t\t\tFound Output In Config: %d\n", 
outputs[j]);
+
+                            /* add this output config to the list of 
+                             * ones that we are going to restore for 
+                             * this crtc */
+                            valid_outputs = 
+                              eina_list_append(valid_outputs, output_cfg);
+
+                            break;
+                         }
+
+                       /* if (!output_found) */
+                       /*   { */
+                       /*      printf("\t\t\tOutput Not Found, Creating 
New\n"); */
+
+                       /*      if ((output_cfg =  */
+                       /*           _e_randr_output_config_new(outputs[j]))) */
+                       /*        { */
+                       /*           valid_outputs =  */
+                       /*             eina_list_append(valid_outputs, 
output_cfg); */
+                       /*        } */
+                       /*   } */
+                    }
+
+                  free(outputs);
+               }
+             else
+               {
+                  printf("\t\t\tNo Outputs For Crtc: %d\n", crtc_cfg->xid);
+                  /* crtc has no outputs assigned */
+                  /* Need to check possibles */
+               }
+
+             /* apply settings for this crtc */
+             printf("\t\t\t\tApplying Crtc Settings: %d\n", crtc_cfg->xid);
+
+             if (!crtc_cfg->mode)
+               {
+                  printf("\t\t\t\t\tCRTC HAS NO MODE !!!\n");
+                  ecore_x_randr_crtc_settings_set(root, crtc_cfg->xid, 
+                                                  NULL, 0, 0, 0, 0, 
+                                                  
ECORE_X_RANDR_ORIENTATION_ROT_0);
+               }
+             else 
+               {
+                  int ocount, c = 0;
+
+                  ocount = eina_list_count(valid_outputs);
+                  printf("\t\t\t\t\tNum Outputs: %d\n", ocount);
+
+                  if (ocount > 0)
+                    {
+                       Ecore_X_Randr_Output *couts;
+                       Eina_List *o;
+                       E_Randr_Output_Config *out;
+
+                       couts = malloc(ocount * sizeof(Ecore_X_Randr_Output));
+                       EINA_LIST_FOREACH(valid_outputs, o, out)
+                         {
+                            couts[c] = out->xid;
+                            c++;
+                         }
+
+                       printf("\t\t\t\t\tCrtc Settings: %d %d %d %d\n", 
crtc_cfg->xid, 
+                              crtc_cfg->x, crtc_cfg->y, crtc_cfg->mode);
+
+                       /* Evas_Coord mw, mh; */
+                       /* get the size of the mode */
+                       /* ecore_x_randr_mode_size_get(root, crtc_cfg->mode, 
&mw, &mh); */
+                       /* printf("\t\t\t\t\t\tMode Size: %d %d\n", mw, mh); */
+
+                       ecore_x_randr_crtc_settings_set(root, crtc_cfg->xid, 
+                                                       couts, ocount, 
+                                                       crtc_cfg->x, 
+                                                       crtc_cfg->y, 
+                                                       crtc_cfg->mode, 
+                                                       crtc_cfg->orient);
+                       free(couts);
+                    }
+               }
+             eina_list_free(valid_outputs);
+          }
+        eina_list_free(valid_crtcs);
      }
 
-   if (need_reset) ecore_x_randr_screen_reset(root);
+//   e_randr_config_save();
+
+//   if (need_reset) ecore_x_randr_screen_reset(root);
 }
 
 static Eina_Bool 
@@ -465,20 +548,34 @@ _e_randr_event_cb_screen_change(void *data EINA_UNUSED, 
int type EINA_UNUSED, vo
 
    ev = event;
 
-   printf("E_RANDR Event: Screen Change\n");
+   printf("E_RANDR Event: Screen Change: %d %d\n", 
+          ev->size.width, ev->size.height);
+
+   /* check if this event's root window is Our root window */
+   if (ev->root != e_manager_current_get()->root) 
+     return ECORE_CALLBACK_RENEW;
 
    if (e_randr_cfg->screen.width != ev->size.width)
      {
+        printf("\tWidth Changed\n");
         e_randr_cfg->screen.width = ev->size.width;
         changed = EINA_TRUE;
      }
 
    if (e_randr_cfg->screen.height != ev->size.height)
      {
+        printf("\tHeight Changed\n");
         e_randr_cfg->screen.height = ev->size.height;
         changed = EINA_TRUE;
      }
 
+   if (e_randr_cfg->config_timestamp != ev->config_time)
+     {
+        printf("\tConfig Timestamp Changed\n");
+        e_randr_cfg->config_timestamp = ev->config_time;
+        changed = EINA_TRUE;
+     }
+
    if (changed) e_randr_config_save();
 
    return ECORE_CALLBACK_RENEW;
@@ -490,39 +587,50 @@ _e_randr_event_cb_crtc_change(void *data EINA_UNUSED, int 
type EINA_UNUSED, void
    Ecore_X_Event_Randr_Crtc_Change *ev;
    Eina_List *l = NULL;
    E_Randr_Crtc_Config *crtc_cfg;
-   Eina_Bool changed = EINA_FALSE;
+   Eina_Bool crtc_new = EINA_FALSE;
+   Eina_Bool crtc_found = EINA_FALSE;
+   Eina_Bool crtc_changed = EINA_FALSE;
 
    ev = event;
-   if (ev->crtc == 0) return ECORE_CALLBACK_RENEW;
-
-   printf("E_RANDR Event: Crtc Change: %d\n", ev->crtc);
 
+   /* loop our crtc configs and try to find this one */
    EINA_LIST_FOREACH(e_randr_cfg->crtcs, l, crtc_cfg)
      {
-        if (crtc_cfg->xid == ev->crtc)
+        /* skip if not this crtc */
+        if (crtc_cfg->xid != ev->crtc) continue;
+
+        crtc_found = EINA_TRUE;
+        break;
+     }
+
+   if (!crtc_found)
+     {
+        /* if this crtc is not found in our config, create it */
+        if ((crtc_cfg = E_NEW(E_Randr_Crtc_Config, 1)))
           {
-             if ((crtc_cfg->x != ev->geo.x) || 
-                 (crtc_cfg->y != ev->geo.y) || 
-                 (crtc_cfg->width != ev->geo.w) || 
-                 (crtc_cfg->height != ev->geo.h) || 
-                 (crtc_cfg->orient != ev->orientation) || 
-                 (crtc_cfg->mode != ev->mode))
-               {
-                  crtc_cfg->x = ev->geo.x;
-                  crtc_cfg->y = ev->geo.y;
-                  crtc_cfg->width = ev->geo.w;
-                  crtc_cfg->height = ev->geo.h;
-                  crtc_cfg->orient = ev->orientation;
-                  crtc_cfg->mode = ev->mode;
-
-                  changed = EINA_TRUE;
-               }
+             /* assign id */
+             crtc_cfg->xid = ev->crtc;
+             crtc_cfg->exists = EINA_TRUE;
 
-             break;
+             crtc_new = EINA_TRUE;
+
+             /* append to randr cfg */
+             e_randr_cfg->crtcs = 
+               eina_list_append(e_randr_cfg->crtcs, crtc_cfg);
           }
      }
 
-   if (changed) e_randr_config_save();
+   /* check (and update if needed) our crtc config
+    * NB: This will fill in any new ones also */
+   crtc_changed = _e_randr_config_crtc_update(crtc_cfg);
+
+   /* save the config if anything changed or we added a new one */
+   if ((crtc_changed) || (crtc_new)) 
+     {
+        printf("E_RANDR Event: Crtc Change\n");
+        printf("\tCrtc: %d Changed or New. Saving Config\n", ev->crtc);
+        e_randr_config_save();
+     }
 
    return ECORE_CALLBACK_RENEW;
 }
@@ -533,71 +641,418 @@ _e_randr_event_cb_output_change(void *data EINA_UNUSED, 
int type EINA_UNUSED, vo
    Ecore_X_Event_Randr_Output_Change *ev;
    Eina_List *l = NULL;
    E_Randr_Crtc_Config *crtc_cfg;
-   Eina_Bool changed = EINA_FALSE;
+   E_Randr_Output_Config *output_cfg;
+   Eina_Bool output_new = EINA_FALSE;
+   Eina_Bool output_found = EINA_FALSE;
+   Eina_Bool output_changed = EINA_FALSE;
+   Eina_Bool output_removed = EINA_FALSE;
 
    ev = event;
 
-   /* TODO: NB: Hmmm, this is problematic :( The spec says we should get an 
-    * event here when an output is disconnected (hotplug) if 
-    * the hardware (video card) is capable of detecting this HOWEVER, in my 
-    * tests, my nvidia card does not detect this.
-    * 
-    * To work around this, we have added a poller to check X randr config 
-    * against what we have saved in e_randr_cfg */
-   printf("E_RANDR Event: Output Change: %d\n", ev->output);
+   /* check if this event's root window is Our root window */
+   if (ev->win != e_manager_current_get()->root) 
+     return ECORE_CALLBACK_RENEW;
 
+   printf("E_RANDR Event: Output Change\n");
+   printf("\tOutput: %d\n", ev->output);
+
+   if (ev->crtc)
+     printf("\t\tCrtc: %lu\n", (unsigned long)ev->crtc);
+   else
+     printf("\t\tNo Crtc\n");
+
+   printf("\t\tMode: %d\n", ev->mode);
+
+   if (ev->connection == 0)
+     printf("\t\tOutput Connected\n");
+   else if (ev->connection == 1)
+     printf("\t\tOutput Disconnected\n");
+
+   /* loop our crtcs and try to find this output */
+   printf("\tLooping Our Crtc Configs\n");
    EINA_LIST_FOREACH(e_randr_cfg->crtcs, l, crtc_cfg)
      {
-        Eina_List *o;
-        E_Randr_Output_Config *output_cfg;
-
-        if (ev->crtc != crtc_cfg->xid) continue;
+        Eina_List *ll;
 
-        if ((crtc_cfg->mode != ev->mode) || 
-            (crtc_cfg->orient != ev->orientation))
+        /* loop the outputs in our crtc cfg and try to find this one */
+        printf("\t\tLooping Our Output Configs on this Crtc: %d\n", 
crtc_cfg->xid);
+        EINA_LIST_FOREACH(crtc_cfg->outputs, ll, output_cfg)
           {
-             crtc_cfg->mode = ev->mode;
-             crtc_cfg->orient = ev->orientation;
-             changed = EINA_TRUE;
+             /* try to find this output */
+             if (output_cfg->xid != ev->output) continue;
+
+             /* FIXME: NB: Hmmm, we may need to also compare edids here (not 
just X id) */
+
+             printf("\t\t\tFound Output %d on Crtc: %d\n", output_cfg->xid, 
output_cfg->crtc);
+             output_found = EINA_TRUE;
+
+             /* is this output still on the same crtc ? */
+             if (output_cfg->crtc != ev->crtc)
+               {
+                  printf("\t\t\t\tOutput Moved Crtc or Removed\n");
+
+                  /* if event crtc is 0, then this output is not assigned to 
any crtc, 
+                   * so we need to remove it from any existing crtc_cfg 
Outputs.
+                   * 
+                   * NB: In a typical scenario, we would remove and free this 
output cfg, 
+                   * HOWEVER we will NOT do that here. Reasoning is that if 
someone 
+                   * replugs this output, we can restore any saved config. 
+                   * 
+                   * NB: Do not call _e_randr_config_output_update in this 
case as that will 
+                   * overwrite any of our saved config
+                   * 
+                   * So for now, just disable it in config by setting exists 
== FALSE */
+                  if (!ev->crtc)
+                    {
+                       /* free this output_cfg */
+                       /* if (output_cfg->clones) free(output_cfg->clones); */
+                       /* if (output_cfg->edid) free(output_cfg->edid); */
+                       /* E_FREE(output_cfg); */
+
+                       /* remove from this crtc */
+                       /* crtc_cfg->outputs = 
eina_list_remove_list(crtc_cfg->outputs, ll); */
+
+                       /* just mark it as not existing */
+                       output_cfg->exists = EINA_FALSE;
+
+                       /* set flag */
+                       output_removed = EINA_TRUE;
+                    }
+                  else
+                    {
+                       /* output moved to new crtc */
+                       printf("\t\t\tOutput Moved to New Crtc\n");
+                    }
+               }
+             else
+               {
+                  printf("\t\t\t\tOutput On Same Crtc\n");
+
+                  /* check (and update if needed) our output config */
+                  output_changed = _e_randr_config_output_update(output_cfg);
+               }
+
+             if (output_found) break;
           }
 
-        EINA_LIST_FOREACH(crtc_cfg->outputs, o, output_cfg)
+        if (output_found) break;
+     }
+
+   /* if the output was not found above, and it is plugged in, 
+    * then we need to create a new one */
+   if ((!output_found) && (ev->connection == 0))
+     {
+        printf("\tOutput Not Found In Config: %d\n", ev->output);
+        printf("\t\tCreate New Output Config\n");
+
+        if ((output_cfg = _e_randr_config_output_new(ev->output)))
           {
-             if (output_cfg->xid == ev->output)
+             output_new = EINA_TRUE;
+
+             /* since this is a new output cfg, the above 
+              * output_update function (inside new) will set 'exists' to false 
+              * because no crtc has been assigned yet.
+              * 
+              * We need to find a valid crtc for this output and set the 
+              * 'crtc' and 'exists' properties */
+             if ((crtc_cfg = _e_randr_config_output_crtc_find(output_cfg)))
                {
-                  Eina_Bool connected = EINA_FALSE;
+                  Ecore_X_Randr_Mode mode;
 
-                  connected = ((ev->connection) ? EINA_FALSE : EINA_TRUE);
+                  /* we found a valid crtc for this output */
+                  output_cfg->crtc = crtc_cfg->xid;
+                  output_cfg->exists = (output_cfg->crtc != 0);
 
-                  if ((output_cfg->crtc != ev->crtc) || 
-                      (output_cfg->connected != connected))
+                  printf("\t\t\tOutput Crtc Is: %d\n", output_cfg->crtc);
+
+                  /* get the preferred mode for this output */
+                  if ((mode = 
_e_randr_config_output_preferred_mode_get(output_cfg)))
                     {
-                       printf("Output Changed: %d\n", ev->output);
-                       printf("\tConnected: %d\n", connected);
+                       Evas_Coord mw = 0, mh = 0;
 
-                       output_cfg->crtc = ev->crtc;
-                       output_cfg->connected = connected;
-                       output_cfg->exists = connected;
+                       /* get the size of this mode */
+                       ecore_x_randr_mode_size_get(ev->win, mode, &mw, &mh);
 
-                       changed = EINA_TRUE;
+                       /* update crtc config with this mode info */
+                       crtc_cfg->mode = mode;
+                       crtc_cfg->width = mw;
+                       crtc_cfg->height = mh;
                     }
 
-                  break;
+                  /* append this output_cfg to the crtc_cfg list of outputs */
+                  crtc_cfg->outputs = 
+                    eina_list_append(crtc_cfg->outputs, output_cfg);
+
+                  printf("APPLY NEW OUTPUT: %d\n", output_cfg->xid);
+                  /* tell X about this new output */
+                  int ocount, c = 0;
+
+                  ocount = eina_list_count(crtc_cfg->outputs);
+                  printf("\tNum Outputs: %d\n", ocount);
+
+                  if (ocount > 0)
+                    {
+                       Ecore_X_Randr_Output *couts;
+                       Eina_List *o;
+                       E_Randr_Output_Config *out;
+
+                       couts = malloc(ocount * sizeof(Ecore_X_Randr_Output));
+                       EINA_LIST_FOREACH(crtc_cfg->outputs, o, out)
+                         {
+                            couts[c] = out->xid;
+                            c++;
+                         }
+
+                       printf("\tCrtc Settings: %d %d %d %d\n", crtc_cfg->xid, 
+                              crtc_cfg->x, crtc_cfg->y, crtc_cfg->mode);
+
+                       /* Evas_Coord mw, mh; */
+                       /* get the size of the mode */
+                       /* ecore_x_randr_mode_size_get(root, crtc_cfg->mode, 
&mw, &mh); */
+                       /* printf("\t\t\t\t\t\tMode Size: %d %d\n", mw, mh); */
+
+                       ecore_x_randr_crtc_settings_set(ev->win, crtc_cfg->xid, 
+                                                       couts, ocount, 
+                                                       crtc_cfg->x, 
+                                                       crtc_cfg->y, 
+                                                       crtc_cfg->mode, 
+                                                       crtc_cfg->orient);
+                       free(couts);
+                    }
                }
           }
      }
 
-   if (changed) e_randr_config_save();
+   /* save the config if anything changed or we added a new one */
+   if ((output_changed) || (output_new) || (output_removed))
+     {
+        printf("\t\t\t\tOutput Changed, Added, or Removed. Saving Config\n");
+        e_randr_config_save();
+     }
+
+   /* if we added or removed any outputs, we need to reset */
+   if ((output_new) || (output_removed))
+     {
+        /* we need to inform X about the changes */
+        /* easier just to call the restore function with the updated config */
+        /* _e_randr_config_restore(); */
+
+        ecore_x_randr_screen_reset(ev->win);
+     }
 
    return ECORE_CALLBACK_RENEW;
 }
 
+/* This function compares our crtc config against what X has and updates our
+ * view of this crtc. It returns EINA_TRUE is anything changed 
+ * 
+ * NB: This Does Not Handle Outputs on the Crtc.*/
 static Eina_Bool 
-_e_randr_event_cb_property_change(void *data EINA_UNUSED, int type 
EINA_UNUSED, void *event EINA_UNUSED)
+_e_randr_config_crtc_update(E_Randr_Crtc_Config *cfg)
 {
-   /* Ecore_X_Event_Randr_Output_Property_Notify *ev; */
+   Ecore_X_Window root = 0;
+   Eina_Bool ret = EINA_FALSE;
 
-   /* ev = event; */
-   printf("E_RANDR Event: Property Change\n");
-   return ECORE_CALLBACK_RENEW;
+   /* grab the root window */
+   root = ecore_x_window_root_first_get();
+
+#if ((ECORE_VERSION_MAJOR >= 1) && (ECORE_VERSION_MINOR >= 8))
+   Ecore_X_Randr_Crtc_Info *cinfo;
+
+   /* get crtc info from X */
+   if ((cinfo = ecore_x_randr_crtc_info_get(root, cfg->xid)))
+     {
+        /* check for changes */
+        if ((cfg->x != cinfo->x) || (cfg->y != cinfo->y) || 
+            (cfg->width != (int)cinfo->width) || (cfg->height != 
(int)cinfo->height) || 
+            (cfg->mode != cinfo->mode) || (cfg->orient != cinfo->rotation))
+          {
+             cfg->x = cinfo->x;
+             cfg->y = cinfo->y;
+             cfg->width = cinfo->width;
+             cfg->height = cinfo->height;
+             cfg->mode = cinfo->mode;
+             cfg->orient = cinfo->rotation;
+
+             ret = EINA_TRUE;
+          }
+
+        ecore_x_randr_crtc_info_free(cinfo);
+     }
+#else
+   Evas_Coord x, y, w, h;
+   unsigned int orient, mode;
+
+   /* get geometry of this crtc */
+   ecore_x_randr_crtc_geometry_get(root, ev->crtc, &x, &y, &w, &h);
+   if ((cfg->x != x) || (cfg->y != y) || 
+       (cfg->width != w) || (cfg->height != h))
+     {
+        cfg->x = x;
+        cfg->y = y;
+        cfg->width = w;
+        cfg->height = h;
+
+        ret = EINA_TRUE;
+     }
+
+   /* get orientation */
+   orient = ecore_x_randr_crtc_orientation_get(root, cfg->xid);
+   if (cfg->orient != orient)
+     {
+        cfg->orient = orient;
+        ret = EINA_TRUE;
+     }
+
+   /* get mode */
+   mode = ecore_x_randr_crtc_mode_get(root, cfg->xid);
+   if (cfg->mode != mode)
+     {
+        cfg->mode = mode;
+        ret = EINA_TRUE;
+     }
+#endif
+
+   return ret;
+}
+
+static Eina_Bool 
+_e_randr_config_output_update(E_Randr_Output_Config *cfg)
+{
+   Ecore_X_Window root = 0;
+   Eina_Bool ret = EINA_FALSE;
+   Ecore_X_Randr_Output primary = 0;
+   Ecore_X_Randr_Crtc crtc;
+   Ecore_X_Randr_Connection_Status status;
+   /* int clone_count = 0; */
+
+   /* grab the root window */
+   root = ecore_x_window_root_first_get();
+
+   /* get which output is primary */
+   primary = ecore_x_randr_primary_output_get(root);
+
+   /* set this output policy */
+   cfg->policy = ECORE_X_RANDR_OUTPUT_POLICY_NONE;
+
+   /* get if this output is the primary */
+   if (cfg->primary != ((cfg->xid == primary)))
+     {
+        cfg->primary = ((cfg->xid == primary));
+        ret = EINA_TRUE;
+     }
+
+   /* get the crtc for this output */
+   crtc = ecore_x_randr_output_crtc_get(root, cfg->xid);
+   if (cfg->crtc != crtc)
+     {
+        cfg->crtc = crtc;
+        ret = EINA_TRUE;
+     }
+
+   /* does it exist in X ?? */
+   if (cfg->exists != (crtc != 0))
+     {
+        cfg->exists = (crtc != 0);
+        ret = EINA_TRUE;
+     }
+
+   /* record the edid for this output */
+   /* cfg->edid = ecore_x_randr_output_edid_get(root, cfg->xid, 
&cfg->edid_count); */
+
+   /* get the clones for this output */
+   /* cfg->clones =  */
+   /*   ecore_x_randr_output_clones_get(root, cfg->xid, &clone_count); */
+   /* cfg->clone_count = (unsigned long)clone_count; */
+
+   status = ecore_x_randr_output_connection_status_get(root, cfg->xid);
+   if (cfg->connected != (status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED))
+     {
+        cfg->connected = (status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED);
+        ret = EINA_TRUE;
+     }
+
+   return ret;
+}
+
+static E_Randr_Crtc_Config *
+_e_randr_config_output_crtc_find(E_Randr_Output_Config *cfg)
+{
+   Ecore_X_Window root = 0;
+   E_Randr_Crtc_Config *crtc_cfg = NULL;
+   Ecore_X_Randr_Crtc *possible;
+   int num = 0, i = 0;
+   Eina_List *l;
+   Eina_Bool crtc_found = EINA_FALSE;
+
+   /* grab the root window */
+   root = ecore_x_window_root_first_get();
+
+   /* get a list of possible crtcs for this output */
+   possible = ecore_x_randr_output_possible_crtcs_get(root, cfg->xid, &num);
+   if ((!possible) || (num == 0)) return NULL;
+
+   /* loop the possible crtcs */
+   for (i = 0; i < num; i++)
+     {
+        /* loop our crtc configs and try to find this one */
+        EINA_LIST_FOREACH(e_randr_cfg->crtcs, l, crtc_cfg)
+          {
+             /* skip if not the one we are looking for */
+             if (crtc_cfg->xid != possible[i]) continue;
+
+             /* check if this crtc already has outputs assigned.
+              * skip if it does because we are trying to find a free crtc */
+             if (eina_list_count(crtc_cfg->outputs) > 0) continue;
+
+             crtc_found = EINA_TRUE;
+             break;
+          }
+
+        if (crtc_found) break;
+     }
+
+   free(possible);
+
+   if (crtc_found) return crtc_cfg;
+
+   return NULL;
+}
+
+static Ecore_X_Randr_Mode 
+_e_randr_config_output_preferred_mode_get(E_Randr_Output_Config *cfg)
+{
+   Ecore_X_Window root = 0;
+   Ecore_X_Randr_Mode *modes;
+   Ecore_X_Randr_Mode mode;
+   int n = 0, p = 0;
+
+   /* grab the root window */
+   root = ecore_x_window_root_first_get();
+
+   /* get the list of modes for this output */
+   modes = ecore_x_randr_output_modes_get(root, cfg->xid, &n, &p);
+   if ((!modes) || (n == 0)) return 0;
+
+   mode = modes[p];
+   free(modes);
+
+   return mode;
+}
+
+static E_Randr_Output_Config *
+_e_randr_config_output_new(unsigned int id)
+{
+   E_Randr_Output_Config *cfg = NULL;
+
+   if ((cfg = E_NEW(E_Randr_Output_Config, 1)))
+     {
+        /* assign output xid */
+        cfg->xid = id;
+
+        /* check (and update if needed) our output config */
+        _e_randr_config_output_update(cfg);
+     }
+
+   return cfg;
 }

-- 

------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev

Reply via email to