forked from enlightenment/enlightenment
RandR: Fix issues discovered here during testing
- Add some more debugging printouts - When we initially plug in a monitor, set to Clone by default - During initial clone, we cannot assume the plugged-in device supports the same Mode so try to find a mode based on size. - On output changes, test that an output has a crtc assigned. - If a detached output Was the primary monitor, reset primary in config to a valid existing monitor. - Improve output_crtc_find code for better detection of where we can place a new output. - Fix "preferred mode" detection error. Signed-off-by: Chris Michael <cp.michael@samsung.com>
This commit is contained in:
parent
1eb26ec077
commit
8b28549aea
|
@ -9,12 +9,13 @@ 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 Ecore_X_Randr_Mode _e_randr_config_output_preferred_mode_get(unsigned int xid);
|
||||
static E_Randr_Output_Config *_e_randr_config_output_new(unsigned int id);
|
||||
static E_Randr_Crtc_Config *_e_randr_config_crtc_find(Ecore_X_Randr_Crtc crtc);
|
||||
static E_Randr_Output_Config *_e_randr_config_output_find(Ecore_X_Randr_Output output);
|
||||
static void _e_randr_config_screen_size_calculate(int *sw, int *sh);
|
||||
static void _e_randr_config_mode_geometry(Ecore_X_Randr_Mode mode, Ecore_X_Randr_Orientation orient, Eina_Rectangle *rect);
|
||||
static void _e_randr_config_primary_update(void);
|
||||
|
||||
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);
|
||||
|
@ -729,7 +730,7 @@ _e_randr_event_cb_output_change(void *data EINA_UNUSED, int type EINA_UNUSED, vo
|
|||
output_found = EINA_TRUE;
|
||||
|
||||
/* is this output still on the same crtc ? */
|
||||
if (output_cfg->crtc != ev->crtc)
|
||||
if ((output_cfg->crtc != ev->crtc) && (ev->crtc != 0))
|
||||
{
|
||||
printf("\t\t\t\tOutput Moved Crtc or Removed\n");
|
||||
|
||||
|
@ -744,35 +745,37 @@ _e_randr_event_cb_output_change(void *data EINA_UNUSED, int type EINA_UNUSED, vo
|
|||
* overwrite any of our saved config
|
||||
*
|
||||
* So for now, just disable it in config by setting exists == FALSE */
|
||||
if (!ev->crtc)
|
||||
if (ev->connection == 1)
|
||||
{
|
||||
/* 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;
|
||||
printf("\t\t\t\t\tOutput Removed\n");
|
||||
output_removed = EINA_TRUE;
|
||||
|
||||
/* if this output was set to be the primary when it was unplugged, then
|
||||
* we need to reset the primary monitor in our config */
|
||||
if (e_randr_cfg->primary == (int)output_cfg->crtc)
|
||||
_e_randr_config_primary_update();
|
||||
}
|
||||
else
|
||||
else if (ev->connection == 0)
|
||||
{
|
||||
/* output moved to new crtc */
|
||||
printf("\t\t\tOutput Moved to New Crtc\n");
|
||||
printf("\t\t\tOutput Moved to New Crtc or Reconnected\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ((ev->crtc != 0) && (output_cfg->crtc == ev->crtc))
|
||||
{
|
||||
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);
|
||||
}
|
||||
else if (ev->crtc == 0)
|
||||
{
|
||||
printf("\t\t\t\tOutput Has No Crtc Assigned\n");
|
||||
}
|
||||
|
||||
if (output_found) break;
|
||||
}
|
||||
|
@ -784,19 +787,186 @@ _e_randr_event_cb_output_change(void *data EINA_UNUSED, int type EINA_UNUSED, vo
|
|||
* 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("\tOutput %d Not Found In Our Config\n", ev->output);
|
||||
printf("\t\tCreate New Output Config\n");
|
||||
|
||||
if ((output_cfg = _e_randr_config_output_new(ev->output)))
|
||||
{
|
||||
E_Randr_Output_Config *ocfg;
|
||||
|
||||
output_new = EINA_TRUE;
|
||||
|
||||
printf("\t\t\tNew Output Config Created: %d\n", output_cfg->xid);
|
||||
|
||||
/* 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 */
|
||||
* 'crtc' and 'exists' properties
|
||||
*
|
||||
* As most users (I think) would expect a newly plugged output to
|
||||
* be a clone of the current desktop, we need to setup this
|
||||
* output to be a clone of the current primary output */
|
||||
|
||||
/* try to find the config for the primary output */
|
||||
if (!(ocfg = _e_randr_config_output_find(e_randr_cfg->primary)))
|
||||
{
|
||||
E_Randr_Crtc_Config *ccfg;
|
||||
Eina_Bool primary_found = EINA_FALSE;
|
||||
|
||||
/* failed to find config for primary output */
|
||||
printf("\t\t\t\tFailed to find Primary Output Config\n");
|
||||
|
||||
/* try to find the first crtc config */
|
||||
EINA_LIST_FOREACH(e_randr_cfg->crtcs, l, ccfg)
|
||||
{
|
||||
Eina_List *ll;
|
||||
|
||||
/* skip if this crtc does not exist */
|
||||
if (!ccfg->exists) continue;
|
||||
|
||||
/* skip if no mode set */
|
||||
if (!ccfg->mode) continue;
|
||||
|
||||
/* loop the outputs in our crtc cfg and
|
||||
* try to find the first one that exists */
|
||||
EINA_LIST_FOREACH(ccfg->outputs, ll, ocfg)
|
||||
{
|
||||
if (!ocfg->exists) continue;
|
||||
if (ocfg->connected)
|
||||
{
|
||||
printf("\t\t\t\t\tFound Primary Output %d\n", ocfg->xid);
|
||||
primary_found = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (primary_found) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ocfg)
|
||||
{
|
||||
Ecore_X_Randr_Mode mode;
|
||||
int x = 0, y = 0, orient = 0;
|
||||
|
||||
printf("\t\t\tHave Primary Output Config %d\n", ocfg->xid);
|
||||
|
||||
/* grab the important settings we need from the primary */
|
||||
if ((crtc_cfg = _e_randr_config_crtc_find(ocfg->crtc)))
|
||||
{
|
||||
x = crtc_cfg->x;
|
||||
y = crtc_cfg->y;
|
||||
mode = crtc_cfg->mode;
|
||||
orient = crtc_cfg->orient;
|
||||
}
|
||||
|
||||
/* find a crtc for this output */
|
||||
if ((crtc_cfg = _e_randr_config_output_crtc_find(output_cfg)))
|
||||
{
|
||||
Ecore_X_Randr_Mode *modes;
|
||||
int ocount, c = 0;
|
||||
int num = 0, pref = 0;
|
||||
Eina_Bool can_clone = EINA_FALSE;
|
||||
|
||||
/* append this output_cfg to the crtc_cfg list of outputs */
|
||||
crtc_cfg->outputs =
|
||||
eina_list_append(crtc_cfg->outputs, output_cfg);
|
||||
|
||||
printf("\t\t\tUsing Crtc Config %d for Cloning\n",
|
||||
crtc_cfg->xid);
|
||||
|
||||
/* we found a valid crtc for this output */
|
||||
output_cfg->crtc = crtc_cfg->xid;
|
||||
output_cfg->exists = (output_cfg->crtc != 0);
|
||||
output_cfg->connected = EINA_TRUE;
|
||||
|
||||
/* We need to verify that the new output can use this
|
||||
* crtc's mode for cloning
|
||||
*
|
||||
* NB: Hmmm, what to do if it Cannot use this mode ?? */
|
||||
modes =
|
||||
ecore_x_randr_output_modes_get(ev->win,
|
||||
output_cfg->xid,
|
||||
&num, &pref);
|
||||
if (modes)
|
||||
{
|
||||
for (c = 0; c < num; c++)
|
||||
{
|
||||
if (modes[c] == mode)
|
||||
{
|
||||
can_clone = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!can_clone)
|
||||
{
|
||||
int mw = 0, mh = 0;
|
||||
|
||||
/* if we can't clone, then we need to find a
|
||||
* mode of the same size */
|
||||
ecore_x_randr_mode_size_get(ev->win, mode,
|
||||
&mw, &mh);
|
||||
|
||||
for (c = 0; c < num; c++)
|
||||
{
|
||||
int cw, ch;
|
||||
|
||||
ecore_x_randr_mode_size_get(ev->win,
|
||||
modes[c],
|
||||
&cw, &ch);
|
||||
if ((cw == mw) && (ch == mh))
|
||||
{
|
||||
mode = modes[c];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modes) free(modes);
|
||||
|
||||
/* tell X about this new output */
|
||||
ocount = eina_list_count(crtc_cfg->outputs);
|
||||
printf("\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(crtc_cfg->outputs, o, out)
|
||||
{
|
||||
couts[c] = out->xid;
|
||||
c++;
|
||||
}
|
||||
|
||||
printf("\tCrtc Settings: %d %d %d %d\n",
|
||||
crtc_cfg->xid, x, y, mode);
|
||||
|
||||
ecore_x_randr_crtc_settings_set(ev->win,
|
||||
crtc_cfg->xid,
|
||||
couts, ocount,
|
||||
x, y, mode, orient);
|
||||
free(couts);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
printf("NO MAIN OUTPUT CONFIG TO CLONE TO !!!\n");
|
||||
}
|
||||
}
|
||||
else if ((output_found) && (ev->crtc == 0))
|
||||
{
|
||||
if (ev->connection == 0)
|
||||
{
|
||||
/* previously configured output as been replugged */
|
||||
|
||||
printf("\t\t\t\tOutput Replugged: %d\n", output_cfg->xid);
|
||||
if ((crtc_cfg = _e_randr_config_output_crtc_find(output_cfg)))
|
||||
{
|
||||
Ecore_X_Randr_Mode mode;
|
||||
|
@ -809,7 +979,7 @@ _e_randr_event_cb_output_change(void *data EINA_UNUSED, int type EINA_UNUSED, vo
|
|||
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)))
|
||||
if ((mode = _e_randr_config_output_preferred_mode_get(output_cfg->xid)))
|
||||
{
|
||||
Evas_Coord mw = 0, mh = 0;
|
||||
|
||||
|
@ -821,10 +991,16 @@ _e_randr_event_cb_output_change(void *data EINA_UNUSED, int type EINA_UNUSED, vo
|
|||
crtc_cfg->width = mw;
|
||||
crtc_cfg->height = mh;
|
||||
}
|
||||
else
|
||||
printf("\t\tNo Mode Found\n");
|
||||
|
||||
/* append this output_cfg to the crtc_cfg list of outputs */
|
||||
crtc_cfg->outputs =
|
||||
eina_list_append(crtc_cfg->outputs, output_cfg);
|
||||
if (eina_list_count(crtc_cfg->outputs) == 0)
|
||||
{
|
||||
crtc_cfg->outputs =
|
||||
eina_list_append(crtc_cfg->outputs, output_cfg);
|
||||
output_changed = EINA_TRUE;
|
||||
}
|
||||
|
||||
/* tell X about this new output */
|
||||
ocount = eina_list_count(crtc_cfg->outputs);
|
||||
|
@ -839,6 +1015,7 @@ _e_randr_event_cb_output_change(void *data EINA_UNUSED, int type EINA_UNUSED, vo
|
|||
couts = malloc(ocount * sizeof(Ecore_X_Randr_Output));
|
||||
EINA_LIST_FOREACH(crtc_cfg->outputs, o, out)
|
||||
{
|
||||
printf("\t\tOutput: %d\n", out->xid);
|
||||
couts[c] = out->xid;
|
||||
c++;
|
||||
}
|
||||
|
@ -855,7 +1032,18 @@ _e_randr_event_cb_output_change(void *data EINA_UNUSED, int type EINA_UNUSED, vo
|
|||
free(couts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* output without a crtc asssigned has been unplugged. Nothing to do in this case */
|
||||
printf("\t\t\t\tOutput Unplugged\n");
|
||||
|
||||
/* just mark it as not existing */
|
||||
output_cfg->exists = EINA_FALSE;
|
||||
|
||||
/* set flag */
|
||||
output_removed = EINA_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* save the config if anything changed or we added a new one */
|
||||
|
@ -974,18 +1162,24 @@ _e_randr_config_output_crtc_find(E_Randr_Output_Config *cfg)
|
|||
{
|
||||
Ecore_X_Window root = 0;
|
||||
E_Randr_Crtc_Config *crtc_cfg = NULL;
|
||||
E_Randr_Output_Config *ocfg = NULL;
|
||||
Ecore_X_Randr_Crtc *possible;
|
||||
int num = 0, i = 0;
|
||||
Eina_List *l;
|
||||
Eina_Bool crtc_found = EINA_FALSE;
|
||||
|
||||
printf("Find Crtc For Output: %d\n", cfg->xid);
|
||||
|
||||
/* grab the root window */
|
||||
root = ecore_x_window_root_first_get();
|
||||
|
||||
/* get a list of possible crtcs for this output */
|
||||
if (!(possible =
|
||||
ecore_x_randr_output_possible_crtcs_get(root, cfg->xid, &num)))
|
||||
return NULL;
|
||||
{
|
||||
printf("\tNo Possible Crtcs Found From X\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (num == 0)
|
||||
{
|
||||
|
@ -993,24 +1187,95 @@ _e_randr_config_output_crtc_find(E_Randr_Output_Config *cfg)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
printf("\tLooping Possible Crtcs\n");
|
||||
|
||||
/* 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;
|
||||
if ((crtc_cfg = _e_randr_config_crtc_find(possible[i])))
|
||||
{
|
||||
printf("\tFound Possible Crtc %d in Config\n", crtc_cfg->xid);
|
||||
|
||||
/* 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;
|
||||
/* try to find this output in this crtc config */
|
||||
EINA_LIST_FOREACH(crtc_cfg->outputs, l, ocfg)
|
||||
{
|
||||
printf("\t\tCrtc Has Output %d\n", ocfg->xid);
|
||||
if (ocfg->xid == cfg->xid)
|
||||
{
|
||||
printf("\t\t\tFound Output %d in Crtc Config\n", cfg->xid);
|
||||
crtc_found = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crtc_found = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
if (crtc_found) break;
|
||||
}
|
||||
|
||||
if (crtc_found) break;
|
||||
if (!crtc_found)
|
||||
{
|
||||
/* no existing crtc config was found which contained this output */
|
||||
|
||||
printf("\tChecking %d for Clone: %d\n", e_randr_cfg->primary, cfg->xid);
|
||||
|
||||
/* loop our config and try to find something we can clone to.
|
||||
* starting with the primary output */
|
||||
if (e_randr_cfg->primary != (int)cfg->xid)
|
||||
{
|
||||
/* E_Randr_Crtc_Config *pcfg = NULL; */
|
||||
|
||||
printf("\t\tTrying to get Primary Crtc Config\n");
|
||||
if ((crtc_cfg = _e_randr_config_crtc_find(e_randr_cfg->primary)))
|
||||
{
|
||||
printf("\t\t\tFound Primary Config\n");
|
||||
/* found the crtc config for the primary monitor */
|
||||
crtc_found = EINA_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!crtc_found)
|
||||
{
|
||||
printf("\tNo Crtc Found Yet\n");
|
||||
|
||||
/* no existing crtc config was found which contained this output */
|
||||
|
||||
/* loop our config and see if we have a crtc which has no outputs existing */
|
||||
|
||||
/* loop the possible crtcs */
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
if ((crtc_cfg = _e_randr_config_crtc_find(possible[i])))
|
||||
{
|
||||
printf("\tFound Possible Crtc %d in Config\n", crtc_cfg->xid);
|
||||
if (eina_list_count(crtc_cfg->outputs) == 0)
|
||||
{
|
||||
printf("\t\tCrtc Config has No Outputs\n");
|
||||
crtc_found = EINA_TRUE;
|
||||
|
||||
if (!crtc_cfg->mode)
|
||||
{
|
||||
Ecore_X_Randr_Mode mode;
|
||||
|
||||
/* get the preferred mode for this output */
|
||||
if ((mode = _e_randr_config_output_preferred_mode_get(cfg->xid)))
|
||||
{
|
||||
Evas_Coord mw = 0, mh = 0;
|
||||
|
||||
ecore_x_randr_mode_size_get(root, mode, &mw, &mh);
|
||||
|
||||
crtc_cfg->mode = mode;
|
||||
crtc_cfg->width = mw;
|
||||
crtc_cfg->height = mh;
|
||||
}
|
||||
else
|
||||
printf("\t\tNo Mode Found\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(possible);
|
||||
|
@ -1021,19 +1286,24 @@ _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)
|
||||
_e_randr_config_output_preferred_mode_get(unsigned int xid)
|
||||
{
|
||||
Ecore_X_Window root = 0;
|
||||
Ecore_X_Randr_Mode *modes;
|
||||
Ecore_X_Randr_Mode mode;
|
||||
int n = 0, p = 0;
|
||||
|
||||
printf("Get Preferred Mode for Output %d\n", xid);
|
||||
|
||||
/* grab the root window */
|
||||
root = ecore_x_window_root_first_get();
|
||||
|
||||
/* get the list of modes for this output */
|
||||
if (!(modes = ecore_x_randr_output_modes_get(root, cfg->xid, &n, &p)))
|
||||
return 0;
|
||||
if (!(modes = ecore_x_randr_output_modes_get(root, xid, &n, &p)))
|
||||
{
|
||||
printf("\tNo Modes returned from X\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
|
@ -1041,7 +1311,15 @@ _e_randr_config_output_preferred_mode_get(E_Randr_Output_Config *cfg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
mode = modes[p - 1];
|
||||
printf("\tNum Modes: %d\n", n);
|
||||
printf("\tP: %d\n", p);
|
||||
if (p > 0)
|
||||
mode = modes[p - 1];
|
||||
else
|
||||
mode = modes[0];
|
||||
|
||||
printf("\tFound Preferred Mode: %d\n", mode);
|
||||
|
||||
free(modes);
|
||||
|
||||
return mode;
|
||||
|
@ -1279,3 +1557,31 @@ _e_randr_config_mode_geometry(Ecore_X_Randr_Mode mode, Ecore_X_Randr_Orientation
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_e_randr_config_primary_update(void)
|
||||
{
|
||||
Eina_List *l, *ll;
|
||||
E_Randr_Crtc_Config *crtc_cfg;
|
||||
E_Randr_Output_Config *output_cfg;
|
||||
|
||||
/* unmark all existing outputs as the primary */
|
||||
EINA_LIST_FOREACH(e_randr_cfg->crtcs, l, crtc_cfg)
|
||||
{
|
||||
EINA_LIST_FOREACH(crtc_cfg->outputs, ll, output_cfg)
|
||||
output_cfg->primary = EINA_FALSE;
|
||||
}
|
||||
|
||||
/* find the first existing output and mark it as primary */
|
||||
EINA_LIST_FOREACH(e_randr_cfg->crtcs, l, crtc_cfg)
|
||||
{
|
||||
if (!crtc_cfg->exists) continue;
|
||||
EINA_LIST_FOREACH(crtc_cfg->outputs, ll, output_cfg)
|
||||
{
|
||||
if (!output_cfg->exists) continue;
|
||||
e_randr_cfg->primary = output_cfg->xid;
|
||||
output_cfg->primary = EINA_TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue