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 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 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);
{
Ecore_X_Window root = 0;
Ecore_X_Randr_Crtc *crtcs;
+ /* Ecore_X_Randr_Output primary = 0; */
int ncrtcs = 0;
- int sw = 0, sh = 0;
+ int sw = 0, sh = 0, cw = 0, ch = 0;
- printf("E_RANDR Restore\n");
+ printf("E_RANDR CONFIG RESTORE\n");
- /* grab the root window */
- root = ecore_x_window_root_first_get();
+ /* grab the X server so that we can apply settings without triggering
+ * any randr event updates until we are done */
+ ecore_x_grab();
- /* get the current screen size */
- ecore_x_randr_screen_current_size_get(root, &sw, &sh, NULL, NULL);
- printf("\tCurrent Screen Size: %d %d\n", sw, sh);
+ /* get existing primary output */
+ /* primary = ecore_x_randr_primary_output_get(root); */
- /* 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); */
+ /* get existing screen size */
+ ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL);
- /* try to get the list of existing crtcs from X */
+ /* calculate new screen size */
+ _e_randr_config_screen_size_calculate(&sw, &sh);
+ printf("\tCalculated Screen Size: %d %d\n", sw, sh);
+
+ /* get the root window */
+ root = ecore_x_window_root_first_get();
+
+ /* get a list of 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;
- Eina_Bool primary_set = EINA_FALSE;
-
- printf("\tHave Crtcs\n");
+ Ecore_X_Randr_Output *outputs;
+ int c = 0, noutputs = 0;
- /* for each crtc that X has, check our config and see if we have it */
- for (i = 0; i < ncrtcs; i++)
+ /* loop the X crtcs */
+ for (c = 0; c < ncrtcs; c++)
{
- Eina_Bool crtc_found = EINA_FALSE;
-
- 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)
+ E_Randr_Crtc_Config *cfg;
+ Evas_Coord x, y, w, h;
+ Ecore_X_Randr_Mode mode = 0;
+ Ecore_X_Randr_Orientation orient =
+ ECORE_X_RANDR_ORIENTATION_ROT_0;
+ Eina_Rectangle rect;
+
+ /* Firstly, disable any crtcs which are disabled in our config OR
+ * which are larger than the target size */
+
+ /* try to find this crtc in our config */
+ if ((cfg = _e_randr_config_crtc_find(crtcs[c])))
{
- /* try to find this crtc */
- if (crtc_cfg->xid != crtcs[i]) continue;
-
- crtc_found = EINA_TRUE;
- printf("\t\t\tFound Crtc in Config\n");
- valid_crtcs = eina_list_append(valid_crtcs, crtc_cfg);
+ x = cfg->x;
+ y = cfg->y;
+ w = cfg->width;
+ h = cfg->height;
+ mode = cfg->mode;
+ orient = cfg->orient;
}
-
- if (!crtc_found)
+ else
{
- 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)))
+ /* this crtc is not in our config. get values from X */
+#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, crtcs[c])))
{
- /* assign id */
- crtc_cfg->xid = crtcs[i];
- crtc_cfg->exists = EINA_TRUE;
+ x = cinfo->x;
+ y = cinfo->y;
+ w = cinfo->width;
+ h = cinfo->height;
+ mode = cinfo->mode;
+ orient = cinfo->rotation;
+
+ ecore_x_randr_crtc_info_free(cinfo);
+ }
+#else
+ /* get geometry of this crtc */
+ ecore_x_randr_crtc_geometry_get(root, crtcs[c],
+ &x, &y, &w, &h);
+
+ /* get mode */
+ mode = ecore_x_randr_crtc_mode_get(root, crtcs[c]);
- /* fill in crtc_cfg values from X */
- _e_randr_config_crtc_update(crtc_cfg);
+ /* get orientation */
+ orient = ecore_x_randr_crtc_orientation_get(root, crtcs[c]);
+#endif
+ }
- 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);
+ /* at this point, we should have geometry, mode and orientation.
+ * We can now proceed to calculate crtc size */
+ _e_randr_config_mode_geometry(mode, orient, &rect);
- /* append to randr cfg */
- e_randr_cfg->crtcs =
- eina_list_append(e_randr_cfg->crtcs, crtc_cfg);
+ x += rect.x;
+ y += rect.y;
+ w = rect.w;
+ h = rect.h;
- e_randr_config_save();
+ /* if it fits within the screen and is "enabled", skip it */
+ if (((x + w) <= sw) && ((y + h) <= sh) && (mode != 0))
+ continue;
- /* append to our short list */
- valid_crtcs = eina_list_append(valid_crtcs, crtc_cfg);
- }
- }
+ /* it does not fit or disabled in our config. disable it in X */
+ ecore_x_randr_crtc_settings_set(root, crtcs[c], NULL, 0, 0, 0, 0,
+ ECORE_X_RANDR_ORIENTATION_ROT_0);
}
- free(crtcs);
-
- printf("\t\tLooping Valid Crtcs\n");
+ /* apply the new screen size */
+ if ((sw != cw) || (sh != ch))
+ ecore_x_randr_screen_current_size_set(root, sw, sh, -1, -1);
- /* for each X crtc that we have config for, check outputs */
- EINA_LIST_FOREACH(valid_crtcs, l, crtc_cfg)
+ /* apply any stored crtc settings */
+ for (c = 0; c < ncrtcs; c++)
{
- Ecore_X_Randr_Output *outputs;
- int noutputs;
- Eina_List *valid_outputs = NULL;
+ E_Randr_Crtc_Config *cfg;
- /* 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)))
+ /* try to find this crtc in our config */
+ if ((cfg = _e_randr_config_crtc_find(crtcs[c])))
{
- int j = 0;
+ Eina_List *l, *valid = NULL;
+ E_Randr_Output_Config *output_cfg;
+ Ecore_X_Randr_Output *coutputs;
+ int count = 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++)
+ /* loop any outputs in this crtc cfg */
+ EINA_LIST_FOREACH(cfg->outputs, l, output_cfg)
{
- Eina_List *ll;
- E_Randr_Output_Config *output_cfg;
Ecore_X_Randr_Connection_Status status =
ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
+ /* get connection status */
status =
ecore_x_randr_output_connection_status_get(root,
- outputs[j]);
+ output_cfg->xid);
+
+ /* skip this output if it is not connected */
if (status != ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED)
continue;
- 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 */
- 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;
- }
+ /* append to the list of valid outputs */
+ valid = eina_list_append(valid, 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);
+ count = eina_list_count(valid);
- if (ocount > 0)
+ /* try to allocate space for x randr outputs */
+ if ((coutputs = calloc(count, sizeof(Ecore_X_Randr_Output))))
{
- Ecore_X_Randr_Output *couts;
- Eina_List *o;
- E_Randr_Output_Config *out;
- Eina_Bool need_size_set = EINA_FALSE;
+ int o = 0;
- couts = malloc(ocount * sizeof(Ecore_X_Randr_Output));
- EINA_LIST_FOREACH(valid_outputs, o, out)
+ /* for each entry in valid outputs, place in X list */
+ EINA_LIST_FOREACH(valid, l, output_cfg)
{
- couts[c] = out->xid;
- c++;
+ coutputs[o] = output_cfg->xid;
+ o++;
}
- switch (crtc_cfg->orient)
- {
- case ECORE_X_RANDR_ORIENTATION_ROT_0:
- case ECORE_X_RANDR_ORIENTATION_ROT_180:
- if (sw < (crtc_cfg->x + crtc_cfg->width))
- {
- sw += crtc_cfg->width;
- need_size_set = EINA_TRUE;
- }
- if (sh < (crtc_cfg->y + crtc_cfg->height))
- {
- sh = (crtc_cfg->y + crtc_cfg->height);
- need_size_set = EINA_TRUE;
- }
- break;
- case ECORE_X_RANDR_ORIENTATION_ROT_90:
- case ECORE_X_RANDR_ORIENTATION_ROT_270:
- if (sw < (crtc_cfg->x + crtc_cfg->width))
- {
- sw = (crtc_cfg->x + crtc_cfg->width);
- need_size_set = EINA_TRUE;
- }
- if (sh < (crtc_cfg->y + crtc_cfg->height))
- {
- sh += crtc_cfg->height;
- need_size_set = EINA_TRUE;
- }
- break;
- default:
- break;
- }
+ }
- if (need_size_set)
- {
+ /* apply our stored crtc settings */
+ ecore_x_randr_crtc_settings_set(root, crtcs[c], coutputs,
+ count, cfg->x, cfg->y,
+ cfg->mode, cfg->orient);
- printf("\t\t\t\t\tNew Screen Size: %d %d\n",
- sw, sh);
- ecore_x_randr_screen_current_size_set(root,
- sw, sh,
- -1, -1);
- need_size_set = EINA_FALSE;
- }
+ /* cleanup */
+ eina_list_free(valid);
+ free(coutputs);
+ }
+ }
- printf("\t\t\t\t\tCrtc Settings: %d %d %d %d %d %d\n",
- crtc_cfg->xid, crtc_cfg->x, crtc_cfg->y,
- crtc_cfg->width, crtc_cfg->height,
- crtc_cfg->mode);
+ /* free list of crtcs */
+ free(crtcs);
- ecore_x_randr_crtc_settings_set(root, crtc_cfg->xid,
- couts, ocount,
- crtc_cfg->x,
- crtc_cfg->y,
- crtc_cfg->mode,
- crtc_cfg->orient);
+ /* apply primary if we have one set */
+ if (e_randr_cfg->primary)
+ {
+ Eina_Bool primary_set = EINA_FALSE;
- if (!primary_set)
- {
- EINA_LIST_FOREACH(valid_outputs, o, out)
- {
- if ((out->primary) &&
- ((int)out->xid == e_randr_cfg->primary))
- {
- ecore_x_randr_primary_output_set(root, out->xid);
- primary_set = EINA_TRUE;
- break;
- }
- }
- }
+ /* get list of valid outputs */
+ if ((outputs = ecore_x_randr_outputs_get(root, &noutputs)))
+ {
+ /* loop valid outputs and check that our primary exists */
+ for (c = 0; c < noutputs; c++)
+ {
+ Ecore_X_Randr_Connection_Status status =
+ ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
+
+ /* skip if this output is not one we are looking for */
+ if ((int)outputs[c] != e_randr_cfg->primary)
+ continue;
+
+ /* check that this output is actually connected */
+ status =
+ ecore_x_randr_output_connection_status_get(root,
+ outputs[c]);
- if (!primary_set)
+ /* if it is actually connected, set primary */
+ if (status == ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED)
{
- /* if no primary was set, set it to the first output */
- out = eina_list_nth(valid_outputs, 0);
- ecore_x_randr_primary_output_set(root, out->xid);
- e_randr_cfg->primary = (int)out->xid;
- e_randr_config_save();
+ ecore_x_randr_primary_output_set(root, outputs[c]);
primary_set = EINA_TRUE;
+ break;
}
-
- free(couts);
}
+
+ /* free list of outputs */
+ free(outputs);
}
- eina_list_free(valid_outputs);
+
+ /* fallback to no primary */
+ if (!primary_set)
+ ecore_x_randr_primary_output_set(root, 0);
}
- eina_list_free(valid_crtcs);
+ else
+ ecore_x_randr_primary_output_set(root, 0);
}
-// if (need_reset) ecore_x_randr_screen_reset(root);
+ /* release the server grab */
+ ecore_x_ungrab();
+
+ ecore_x_randr_screen_reset(root);
}
static Eina_Bool
return cfg;
}
+
+static E_Randr_Crtc_Config *
+_e_randr_config_crtc_find(Ecore_X_Randr_Crtc crtc)
+{
+ Eina_List *l;
+ E_Randr_Crtc_Config *crtc_cfg;
+
+ EINA_LIST_FOREACH(e_randr_cfg->crtcs, l, crtc_cfg)
+ {
+ if (crtc_cfg->xid == crtc)
+ return crtc_cfg;
+ }
+
+ return NULL;
+}
+
+static E_Randr_Output_Config *
+_e_randr_config_output_find(Ecore_X_Randr_Output output)
+{
+ Eina_List *l;
+ E_Randr_Crtc_Config *crtc_cfg;
+ E_Randr_Output_Config *output_cfg;
+
+ EINA_LIST_FOREACH(e_randr_cfg->crtcs, l, crtc_cfg)
+ {
+ Eina_List *ll;
+
+ EINA_LIST_FOREACH(crtc_cfg->outputs, ll, output_cfg)
+ {
+ if (output_cfg->xid == output)
+ return output_cfg;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+_e_randr_config_screen_size_calculate(int *sw, int *sh)
+{
+ Ecore_X_Window root = 0;
+ Ecore_X_Randr_Output *outputs;
+ int noutputs = 0;
+ int minw = 0, minh = 0;
+ int maxw = 0, maxh = 0;
+
+ /* get the root window */
+ root = ecore_x_window_root_first_get();
+
+ /* get the min and max screen size */
+ ecore_x_randr_screen_size_range_get(root, &minw, &minh, &maxw, &maxh);
+
+ /* get outputs from X */
+ if ((outputs = ecore_x_randr_outputs_get(root, &noutputs)))
+ {
+ int i = 0;
+
+ /* loop X outputs */
+ for (i = 0; i < noutputs; i++)
+ {
+ E_Randr_Output_Config *output_cfg;
+ Ecore_X_Randr_Connection_Status status =
+ ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
+ Ecore_X_Randr_Orientation orient =
+ ECORE_X_RANDR_ORIENTATION_ROT_0;
+ Ecore_X_Randr_Mode mode = 0;
+ int x = 0, y = 0, w = 0, h = 0;
+ Eina_Rectangle rect;
+
+ /* get connection status */
+ status =
+ ecore_x_randr_output_connection_status_get(root, outputs[i]);
+
+ /* skip this output if it is not connected */
+ if (status != ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED)
+ continue;
+
+ /* see if we have this output in our config */
+ if ((output_cfg = _e_randr_config_output_find(outputs[i])))
+ {
+ E_Randr_Crtc_Config *crtc_cfg;
+
+ /* try to find the crtc config for this output */
+ if ((crtc_cfg = _e_randr_config_crtc_find(output_cfg->crtc)))
+ {
+ /* if this crtc is disabled in our config, skip it
+ *
+ * NB: Since we will end up disabling this crtc, then
+ * we should not use it to calculate screen size */
+ if (!crtc_cfg->mode) continue;
+
+ /* get geometry and mode */
+ x = crtc_cfg->x;
+ y = crtc_cfg->y;
+ w = crtc_cfg->width;
+ h = crtc_cfg->height;
+ mode = crtc_cfg->mode;
+ orient = crtc_cfg->orient;
+ }
+ }
+
+ /* if we have no config for this output. get values from X */
+ if ((!w) || (!h))
+ {
+ Ecore_X_Randr_Crtc crtc = 0;
+
+#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, crtc)))
+ {
+ x = cinfo->x;
+ y = cinfo->y;
+ w = cinfo->width;
+ h = cinfo->height;
+ mode = cinfo->mode;
+ orient = cinfo->rotation;
+
+ ecore_x_randr_crtc_info_free(cinfo);
+ }
+#else
+ /* get geometry of this crtc */
+ ecore_x_randr_crtc_geometry_get(root, crtc, &x, &y, &w, &h);
+
+ /* get mode */
+ mode = ecore_x_randr_crtc_mode_get(root, crtc);
+
+ /* get orientation */
+ orient = ecore_x_randr_crtc_orientation_get(root, crtc);
+#endif
+ }
+
+ /* at this point, we should have geometry, mode and orientation.
+ * We can now proceed to calculate screen size */
+
+ _e_randr_config_mode_geometry(mode, orient, &rect);
+
+ x += rect.x;
+ y += rect.y;
+ w = rect.w;
+ h = rect.h;
+
+ if ((x + w) > *sw)
+ *sw = (x + w);
+ if ((y + h) > *sh)
+ *sh = (y + h);
+ }
+
+ /* free any space allocated */
+ free(outputs);
+ }
+
+ if ((*sw > maxw) || (*sh > maxh))
+ {
+ printf("Calculated Screen Size %dx%d is Larger Than Max %dx%d!!!\n",
+ *sw, *sh, maxw, maxh);
+ }
+ else
+ {
+ if (*sw < minw) *sw = minw;
+ if (*sh < minh) *sh = minh;
+ }
+}
+
+static void
+_e_randr_config_mode_geometry(Ecore_X_Randr_Mode mode, Ecore_X_Randr_Orientation orient, Eina_Rectangle *rect)
+{
+ Ecore_X_Window root = 0;
+ Evas_Point p[4];
+ int mw = 0, mh = 0;
+ int mode_width = 0, mode_height = 0;
+ int i = 0;
+ Eina_Rectangle tmp;
+
+ /* get the root window */
+ root = ecore_x_window_root_first_get();
+
+ /* get the size of this mode */
+ ecore_x_randr_mode_size_get(root, mode, &mode_width, &mode_height);
+
+ /* based on orientation, calculate mode sizes */
+ switch (orient)
+ {
+ case ECORE_X_RANDR_ORIENTATION_ROT_0:
+ case ECORE_X_RANDR_ORIENTATION_ROT_180:
+ mw = mode_width;
+ mh = mode_height;
+ break;
+ case ECORE_X_RANDR_ORIENTATION_ROT_90:
+ case ECORE_X_RANDR_ORIENTATION_ROT_270:
+ mw = mode_height;
+ mh = mode_width;
+ break;
+ default:
+ break;
+ }
+
+ p[0].x = 0;
+ p[0].y = 0;
+ p[1].x = mw;
+ p[1].y = 0;
+ p[2].x = mw;
+ p[2].y = mh;
+ p[3].x = 0;
+ p[3].y = mh;
+
+ for (i = 0; i < 4; i++)
+ {
+ double x = 0.0, y = 0.0;
+
+ x = p[i].x;
+ y = p[i].y;
+
+ eina_rectangle_coords_from(&tmp, floor(x), floor(y), ceil(x), ceil(y));
+ if (i == 0)
+ *rect = tmp;
+ else
+ {
+ if (tmp.x < rect->x) rect->x = tmp.x;
+ if (tmp.y < rect->y) rect->y = tmp.y;
+ if (tmp.w > rect->w) rect->w = tmp.w;
+ if (tmp.h > rect->h) rect->h = tmp.h;
+ }
+ }
+}