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