svn update: 48958 (latest:48959)
[framework/uifw/ecore.git] / src / lib / ecore_x / xcb / ecore_xcb_randr.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #include "ecore_xcb_private.h"
6
7
8 /**
9  * @defgroup Ecore_X_RandR_Group X RandR Extension Functions
10  *
11  * Functions related to the X RandR extension.
12  */
13
14
15 #ifdef ECORE_XCB_RANDR
16 static int _randr_available = 0;
17 static xcb_randr_query_version_cookie_t _ecore_xcb_randr_init_cookie;
18 #endif /* ECORE_XCB_RANDR */
19
20
21 /* To avoid round trips, the initialization is separated in 2
22    functions: _ecore_xcb_randr_init and
23    _ecore_xcb_randr_init_finalize. The first one gets the cookies and
24    the second one gets the replies and set the atoms. */
25
26 void
27 _ecore_x_randr_init(const xcb_query_extension_reply_t *reply)
28 {
29 #ifdef ECORE_XCB_RANDR
30    if (reply && (reply->present))
31       _ecore_xcb_randr_init_cookie = xcb_randr_query_version_unchecked(_ecore_xcb_conn, 1, 2);
32 #endif /* ECORE_XCB_RANDR */
33 }
34
35 void
36 _ecore_x_randr_init_finalize(void)
37 {
38 #ifdef ECORE_XCB_RANDR
39    xcb_randr_query_version_reply_t *reply;
40
41    reply = xcb_randr_query_version_reply(_ecore_xcb_conn,
42                                          _ecore_xcb_randr_init_cookie, NULL);
43
44    if (reply)
45      {
46         if ((reply->major_version >= 1) &&
47             (reply->minor_version >= 1))
48           _randr_available = 1;
49         free(reply);
50      }
51 #endif /* ECORE_XCB_RANDR */
52 }
53
54 /**
55  * Return whether the X server supports the RandR Extension.
56  * @return 1 if the X RandR Extension is available, 0 otherwise.
57  *
58  * Return 1 if the X server supports the RandR Extension version 1.1,
59  * 0 otherwise.
60  * @ingroup Ecore_X_RandR_Group
61  */
62 EAPI int
63 ecore_x_randr_query(void)
64 {
65 #ifdef ECORE_XCB_RANDR
66    return _randr_available;
67 #else
68    return 0;
69 #endif /* ECORE_XCB_RANDR */
70 }
71
72
73 static Ecore_X_Window
74 _xcb_randr_root_to_screen(Ecore_X_Window root)
75 {
76    xcb_screen_iterator_t iter;
77
78    iter = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
79    for (; iter.rem; xcb_screen_next(&iter))
80      {
81         if (iter.data->root == root)
82           return iter.data->root;
83      }
84
85    return XCB_NONE;
86 }
87
88 /**
89  * Select if the ScreenChangeNotify events  will be sent.
90  * @param window The window.
91  * @param on     1 to enable, 0 to disable.
92  * @return       1 on success, 0 otherwise.
93  *
94  * If @p on value is @c 1, ScreenChangeNotify events
95  * will be sent when the screen configuration changes, either from
96  * this protocol extension, or due to detected external screen
97  * configuration changes. ScreenChangeNotify may also be sent when
98  * this request executes if the screen configuration has changed since
99  * the client connected, to avoid race conditions.
100  * @ingroup Ecore_X_RandR_Group
101  */
102 EAPI int
103 ecore_x_randr_events_select(Ecore_X_Window window,
104                             int            on)
105 {
106 #ifdef ECORE_XCB_RANDR
107      xcb_randr_select_input(_ecore_xcb_conn, window,
108                             on ? XCB_RANDR_SCREEN_CHANGE_NOTIFY : 0);
109      return 1;
110 #else
111    return 0;
112 #endif /* ECORE_XCB_RANDR */
113 }
114
115 /**
116  * Sends the GetScreenInfo request.
117  * @param window Window whose properties are requested.
118  * @ingroup Ecore_X_RandR_Group
119  */
120 EAPI void
121 ecore_x_randr_get_screen_info_prefetch(Ecore_X_Window window)
122 {
123 #ifdef ECORE_XCB_RANDR
124    xcb_randr_get_screen_info_cookie_t cookie;
125
126    cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn,
127                                                 _xcb_randr_root_to_screen(window));
128    _ecore_xcb_cookie_cache(cookie.sequence);
129 #endif /* ECORE_XCB_RANDR */
130 }
131
132
133 /**
134  * Gets the reply of the GetScreenInfo request sent by ecore_x_randr_get_screen_info_prefetch().
135  * @ingroup Ecore_X_RandR_Group
136  */
137 EAPI void
138 ecore_x_randr_get_screen_info_fetch(void)
139 {
140 #ifdef ECORE_XCB_RANDR
141    xcb_randr_get_screen_info_cookie_t cookie;
142    xcb_randr_get_screen_info_reply_t *reply;
143
144    cookie.sequence = _ecore_xcb_cookie_get();
145    reply =xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
146    _ecore_xcb_reply_cache(reply);
147 #endif /* ECORE_XCB_RANDR */
148 }
149
150 /**
151  * Get the set of rotations and reflections.
152  * @param root The window (Unused).
153  * @return     The set of rotations and reflections.
154  *
155  * Get the set of rotations and reflections supported by the screen
156  * associated to @p window (passed to
157  * ecore_x_randr_get_screen_info_prefetch()).
158  *
159  * To use this function, you must call before, and in order,
160  * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
161  * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
162  * @ingroup Ecore_X_RandR_Group
163  */
164 EAPI Ecore_X_Randr_Rotation
165 ecore_x_randr_screen_rotations_get(Ecore_X_Window root __UNUSED__)
166 {
167 #ifdef ECORE_XCB_RANDR
168    xcb_randr_get_screen_info_reply_t *reply;
169
170    reply = _ecore_xcb_reply_get();
171    if (!reply)
172      return 0;
173
174    return reply->rotations;
175 #else
176    return 0;
177 #endif /* ECORE_XCB_RANDR */
178 }
179
180 /**
181  * Get the rotation.
182  * @param root The window (Unused).
183  * @return     The rotation.
184  *
185  * Get the rotation supported by the screen
186  * associated to @p window (passed to
187  * ecore_x_randr_get_screen_info_prefetch()).
188  *
189  * To use this function, you must call before, and in order,
190  * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
191  * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
192  * @ingroup Ecore_X_RandR_Group
193  */
194 EAPI Ecore_X_Randr_Rotation
195 ecore_x_randr_screen_rotation_get(Ecore_X_Window root __UNUSED__)
196 {
197 #ifdef ECORE_XCB_RANDR
198    xcb_randr_get_screen_info_reply_t *reply;
199
200    reply = _ecore_xcb_reply_get();
201    if (!reply)
202      return 0;
203
204    return reply->rotation;
205 #else
206    return 0;
207 #endif /* ECORE_XCB_RANDR */
208 }
209
210 /**
211  * Get the frame buffer sizes.
212  * @param root The window (Unused).
213  * @param num  The number of sizes.
214  * @return     The sizes.
215  *
216  * Get the list of possible frame buffer sizes (at the normal
217  * orientation supported by the screen associated to @p window (passed
218  * to ecore_x_randr_get_screen_info_prefetch()). Each size indicates
219  * both the linear physical size of the screen and the pixel size.
220  *
221  * To use this function, you must call before, and in order,
222  * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
223  * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
224  * @ingroup Ecore_X_RandR_Group
225  */
226 EAPI Ecore_X_Screen_Size *
227 ecore_x_randr_screen_sizes_get(Ecore_X_Window root __UNUSED__,
228                                int           *num)
229 {
230 #ifdef ECORE_XCB_RANDR
231    xcb_randr_get_screen_info_reply_t *reply;
232    xcb_randr_screen_size_t           *sizes;
233    Ecore_X_Screen_Size               *ret;
234    int                                n;
235    int                                i;
236
237    if (num) *num = 0;
238
239    reply = _ecore_xcb_reply_get();
240    if (!reply)
241      return NULL;
242
243    n = xcb_randr_get_screen_info_sizes_length(reply);
244    ret = calloc(n, sizeof(Ecore_X_Screen_Size));
245    if (!ret) return NULL;
246
247    if (num) *num = n;
248    sizes = xcb_randr_get_screen_info_sizes(reply);
249    for (i = 0; i < n; i++)
250      {
251         ret[i].width = sizes[i].width;
252         ret[i].height = sizes[i].height;
253      }
254
255    return ret;
256 #else
257    if (num) *num = 0;
258    return NULL;
259 #endif /* ECORE_XCB_RANDR */
260 }
261
262 /**
263  * Get the current frame buffer size.
264  * @param root The window (Unused).
265  * @return     The active size.
266  *
267  * Get the active frame buffer size supported by the screen associated
268  * to @p window (passed to
269  * ecore_x_randr_get_screen_info_prefetch()).
270  *
271  * To use this function, you must call before, and in order,
272  * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
273  * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
274  * @ingroup Ecore_X_RandR_Group
275  */
276 EAPI Ecore_X_Screen_Size
277 ecore_x_randr_current_screen_size_get(Ecore_X_Window root __UNUSED__)
278 {
279    Ecore_X_Screen_Size ret = { -1, -1 };
280 #ifdef ECORE_XCB_RANDR
281    xcb_randr_get_screen_info_reply_t *reply;
282    xcb_randr_screen_size_t           *sizes;
283    uint16_t                           size_index;
284
285    reply = _ecore_xcb_reply_get();
286    if (!reply)
287      return ret;
288
289    size_index = reply->sizeID;
290    sizes = xcb_randr_get_screen_info_sizes(reply);
291    if (size_index < reply->nSizes)
292      {
293         ret.width = sizes[size_index].mwidth;
294         ret.height = sizes[size_index].mheight;
295      }
296 #endif /* ECORE_XCB_RANDR */
297
298    return ret;
299 }
300
301 /**
302  * Get the current refresh rate.
303  * @param root The window (Unused).
304  * @return     The current refresh rate.
305  *
306  * Get the current refresh rate supported by the screen associated
307  * to @p window (passed to
308  * ecore_x_randr_get_screen_info_prefetch()).
309  *
310  * To use this function, you must call before, and in order,
311  * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
312  * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
313  * @ingroup Ecore_X_RandR_Group
314  */
315 EAPI Ecore_X_Screen_Refresh_Rate
316 ecore_x_randr_current_screen_refresh_rate_get(Ecore_X_Window root __UNUSED__)
317 {
318    Ecore_X_Screen_Refresh_Rate        ret = { -1 };
319 #ifdef ECORE_XCB_RANDR
320    xcb_randr_get_screen_info_reply_t *reply;
321
322    reply = _ecore_xcb_reply_get();
323    if (!reply)
324      return ret;
325
326    ret.rate = reply->rate;
327 #endif /* ECORE_XCB_RANDR */
328
329    return ret;
330 }
331
332 /**
333  * Get the refresh rates.
334  * @param root The window (Unused).
335  * @param num  The number of refresh rates.
336  * @return     The refresh rates.
337  *
338  * Get the list of refresh rates for each size supported by the screen
339  * associated to @p window (passed to
340  * ecore_x_randr_get_screen_info_prefetch()). Each element
341  * of 'sizes' has a corresponding element in 'refresh'. An empty list
342  * indicates no known rates, or a device for which refresh is not
343  * relevant.
344  *
345  * To use this function, you must call before, and in order,
346  * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
347  * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
348  * @ingroup Ecore_X_RandR_Group
349  */
350 EAPI Ecore_X_Screen_Refresh_Rate *
351 ecore_x_randr_screen_refresh_rates_get(Ecore_X_Window root __UNUSED__,
352                                        int            size_id __UNUSED__,
353                                        int           *num)
354 {
355 #ifdef ECORE_XCB_RANDR
356    xcb_randr_get_screen_info_reply_t *reply;
357    Ecore_X_Screen_Refresh_Rate       *ret;
358    Ecore_X_Screen_Refresh_Rate       *tmp;
359    xcb_randr_refresh_rates_iterator_t iter;
360    uint16_t                           n;
361
362    if (num) *num = 0;
363
364    reply = _ecore_xcb_reply_get();
365    if (!reply)
366      return NULL;
367
368    n = reply->nSizes;
369    ret = calloc(n, sizeof(Ecore_X_Screen_Refresh_Rate));
370    if (!ret)
371      return NULL;
372
373    if (num) *num = n;
374
375    /* FIXME: maybe there's a missing function in xcb randr implementation */
376    iter = xcb_randr_get_screen_info_rates_iterator(reply);
377    tmp = ret;
378    for (; iter.rem; xcb_randr_refresh_rates_next(&iter), tmp++)
379      {
380        tmp->rate = iter.data->nRates;;
381      }
382
383    return ret;
384 #else
385    if (num) *num = 0;
386    return NULL;
387 #endif /* ECORE_XCB_RANDR */
388 }
389
390 /* FIXME: round trip. Should we remove it ? */
391
392 /**
393  * Set the screen rotation.
394  * @param root The root window.
395  * @param rot  The rotation.
396  *
397  * Set the rotation of the screen associated to @p root.
398  *
399  * Note that that function is blocking.
400  * @ingroup Ecore_X_RandR_Group
401  */
402 EAPI void
403 ecore_x_randr_screen_rotation_set(Ecore_X_Window         root,
404                                   Ecore_X_Randr_Rotation rot)
405 {
406 #ifdef ECORE_XCB_RANDR
407    xcb_randr_set_screen_config_cookie_t cookie;
408    xcb_randr_set_screen_config_reply_t *reply_config;
409    xcb_randr_get_screen_info_reply_t   *reply;
410
411    reply = _ecore_xcb_reply_get();
412    if (!reply)
413      return;
414
415    cookie = xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root,
416                                                   XCB_CURRENT_TIME,
417                                                   reply->config_timestamp,
418                                                   reply->sizeID,
419                                                   rot,
420                                                   0);
421    reply_config = xcb_randr_set_screen_config_reply(_ecore_xcb_conn, cookie, NULL);
422    if (reply_config)
423      free(reply_config);
424 #endif /* ECORE_XCB_RANDR */
425 }
426
427 /* FIXME: round trip. Should we remove it ? */
428
429 /**
430  * Set the screen size.
431  * @param root The root window.
432  * @param size The size.
433  *
434  * Set the size of the screen associated to @p root.
435  *
436  * Note that that function is blocking.
437  * @ingroup Ecore_X_RandR_Group
438  */
439 EAPI int
440 ecore_x_randr_screen_size_set(Ecore_X_Window      root,
441                               Ecore_X_Screen_Size size)
442 {
443 #ifdef ECORE_XCB_RANDR
444    xcb_randr_set_screen_config_cookie_t cookie;
445    xcb_randr_set_screen_config_reply_t *reply_config;
446    xcb_randr_get_screen_info_reply_t   *reply;
447    xcb_randr_screen_size_iterator_t     iter;
448    int                                  size_index = -1;
449    int                                  i;
450
451    reply = _ecore_xcb_reply_get();
452    if (!reply)
453      return 0;
454
455    iter = xcb_randr_get_screen_info_sizes_iterator(reply);
456    for (i = 0; iter.rem; xcb_randr_screen_size_next(&iter), i++)
457      {
458         if ((iter.data->width = size.width) &&
459             (iter.data->height = size.height) &&
460             (iter.data->mwidth = size.width) &&
461             (iter.data->mheight = size.height))
462           {
463             size_index = i;
464             break;
465           }
466      }
467    if (size_index == -1) return 0;
468
469    cookie = xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root,
470                                                   XCB_CURRENT_TIME,
471                                                   reply->config_timestamp,
472                                                   size_index,
473                                                   XCB_RANDR_ROTATION_ROTATE_0,
474                                                   0);
475    reply_config = xcb_randr_set_screen_config_reply(_ecore_xcb_conn, cookie, NULL);
476    if (!reply_config)
477      return 0;
478
479    free(reply_config);
480
481    return 1;
482 #else
483    return 0;
484 #endif /* ECORE_XCB_RANDR */
485 }
486
487 /* FIXME: round trip. Should we remove it ? */
488
489 /**
490  * Set the screen refresh rate.
491  * @param root The root window.
492  * @param size The size.
493  * @param rate The refresh rate.
494  *
495  * Set the size and the refresh rate of the screen associated to
496  * @p root.
497  *
498  * Note that that function is blocking.
499  * @ingroup Ecore_X_RandR_Group
500  */
501 EAPI int
502 ecore_x_randr_screen_refresh_rate_set(Ecore_X_Window              root,
503                                       Ecore_X_Screen_Size         size,
504                                       Ecore_X_Screen_Refresh_Rate rate)
505 {
506 #ifdef ECORE_XCB_RANDR
507    xcb_randr_set_screen_config_cookie_t cookie;
508    xcb_randr_set_screen_config_reply_t *reply_config;
509    xcb_randr_get_screen_info_reply_t   *reply;
510    xcb_randr_screen_size_iterator_t     iter;
511    int                                  size_index = -1;
512    int                                  i;
513
514    reply = _ecore_xcb_reply_get();
515    if (!reply)
516      return 0;
517
518    iter = xcb_randr_get_screen_info_sizes_iterator(reply);
519    for (i = 0; iter.rem; xcb_randr_screen_size_next(&iter), i++)
520      {
521         if ((iter.data->width = size.width) &&
522             (iter.data->height = size.height) &&
523             (iter.data->mwidth = size.width) &&
524             (iter.data->mheight = size.height))
525           {
526             size_index = i;
527             break;
528           }
529      }
530    if (size_index == -1) return 0;
531
532    cookie = xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root,
533                                                   XCB_CURRENT_TIME,
534                                                   reply->config_timestamp,
535                                                   size_index,
536                                                   XCB_RANDR_ROTATION_ROTATE_0,
537                                                   rate.rate);
538    reply_config = xcb_randr_set_screen_config_reply(_ecore_xcb_conn, cookie, NULL);
539    if (!reply_config)
540      return 0;
541
542    free(reply_config);
543
544    return 1;
545 #else
546    return 0;
547 #endif /* ECORE_XCB_RANDR */
548 }