Fix bug about updating window information
[platform/core/appfw/app-core.git] / src / appcore-rotation.c
1 /*
2  *  app-core
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26
27 #include <sensor_internal.h>
28 #include <vconf.h>
29 #include <Ecore.h>
30 #include "appcore-internal.h"
31
32 #ifdef X11
33 #include <Ecore_X.h>
34 #include <X11/Xlib.h>
35
36 /* Fixme: to be added for wayland works */
37 #define _MAKE_ATOM(a, s)                                \
38         do {                                            \
39                 a = ecore_x_atom_get(s);                \
40                 if (!a)                                 \
41                         _ERR("##s creation failed.\n"); \
42         } while (0)
43
44 #define STR_ATOM_ROTATION_LOCK "_E_ROTATION_LOCK"
45
46 static Ecore_X_Atom ATOM_ROTATION_LOCK = 0;
47 static Ecore_X_Window root;
48 #endif
49
50 struct rot_s {
51         int handle;
52         int (*callback) (void *event_info, enum appcore_rm, void *);
53         enum appcore_rm mode;
54         int lock;
55         void *cbdata;
56         int cb_set;
57         int sensord_started;
58
59         struct ui_wm_rotate* wm_rotate;
60 };
61 static struct rot_s rot;
62
63 struct rot_evt {
64         enum auto_rotation_state re;
65         enum appcore_rm rm;
66 };
67
68 static struct rot_evt re_to_rm[] = {
69         {
70                 AUTO_ROTATION_DEGREE_0,
71                 APPCORE_RM_PORTRAIT_NORMAL,
72         },
73         {
74                 AUTO_ROTATION_DEGREE_90,
75                 APPCORE_RM_LANDSCAPE_NORMAL,
76         },
77         {
78                 AUTO_ROTATION_DEGREE_180,
79                 APPCORE_RM_PORTRAIT_REVERSE,
80         },
81         {
82                 AUTO_ROTATION_DEGREE_270,
83                 APPCORE_RM_LANDSCAPE_REVERSE,
84         },
85 };
86
87 static enum appcore_rm __get_mode(sensor_data_t data)
88 {
89         int i;
90         int event;
91         enum appcore_rm m;
92
93         m = APPCORE_RM_UNKNOWN;
94         if (data.value_count > 0) {
95                 event = (int)data.values[0];
96         } else {
97                 _ERR("Failed to get sensor data");
98                 return -1;
99         }
100
101         for (i = 0; i < sizeof(re_to_rm) / sizeof(re_to_rm[0]); i++) {
102                 if (re_to_rm[i].re == event) {
103                         m = re_to_rm[i].rm;
104                         break;
105                 }
106         }
107
108         return m;
109 }
110
111 static void __changed_cb(sensor_t sensor, unsigned int event_type,
112                 sensor_data_t *data, void *user_data)
113 {
114         enum appcore_rm m;
115
116         if (rot.lock)
117                 return;
118
119         if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT) {
120                 errno = EINVAL;
121                 return;
122         }
123
124         m = __get_mode(*data);
125
126         _DBG("[APP %d] Rotation: %d -> %d", getpid(), rot.mode, m);
127
128         if (rot.callback) {
129                 if (rot.cb_set && rot.mode != m) {
130                         _DBG("[APP %d] Rotation: %d -> %d", getpid(), rot.mode, m);
131                         rot.callback((void *)&m, m, user_data);
132                         rot.mode = m;
133                 }
134         }
135 }
136
137 static void __lock_cb(keynode_t *node, void *data)
138 {
139         int r;
140         enum appcore_rm m;
141
142         rot.lock = !vconf_keynode_get_bool(node);
143
144         if (rot.lock) {
145                 m = APPCORE_RM_PORTRAIT_NORMAL;
146                 if (rot.mode != m) {
147                         rot.callback((void *)&m, m, data);
148                         rot.mode = m;
149                 }
150                 _DBG("[APP %d] Rotation locked", getpid());
151                 return;
152         }
153
154         _DBG("[APP %d] Rotation unlocked", getpid());
155         if (rot.callback) {
156                 if (rot.cb_set) {
157                         r = appcore_get_rotation_state(&m);
158                         _DBG("[APP %d] Rotmode prev %d -> curr %d", getpid(),
159                              rot.mode, m);
160                         if (!r && rot.mode != m) {
161                                 rot.callback((void *)&m, m, data);
162                                 rot.mode = m;
163                         }
164                 }
165         }
166 }
167
168 static void __add_rotlock(void *data)
169 {
170         int r;
171         int lock;
172
173         lock = 0;
174         r = vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
175         if (r)
176                 _DBG("[APP %d] Rotation vconf get bool failed", getpid());
177
178         rot.lock = !lock;
179
180         vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, __lock_cb,
181                                  data);
182 }
183
184 static void __del_rotlock(void)
185 {
186         vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, __lock_cb);
187         rot.lock = 0;
188 }
189
190 EXPORT_API int appcore_set_rotation_cb(int (*cb) (void *evnet_info, enum appcore_rm, void *),
191                                        void *data)
192 {
193         if (rot.wm_rotate)
194                 return rot.wm_rotate->set_rotation_cb(cb, data);
195         else {
196                 bool r;
197                 int handle;
198                 sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
199
200                 if (cb == NULL) {
201                         errno = EINVAL;
202                         return -1;
203                 }
204
205                 if (rot.callback != NULL) {
206                         errno = EALREADY;
207                         return -1;
208                 }
209
210                 handle = sensord_connect(sensor);
211                 if (handle < 0) {
212                         _ERR("sensord_connect failed: %d", handle);
213                         return -1;
214                 }
215
216                 r = sensord_register_event(handle, AUTO_ROTATION_CHANGE_STATE_EVENT,
217                                       SENSOR_INTERVAL_NORMAL, 0, __changed_cb, data);
218                 if (!r) {
219                         _ERR("sensord_register_event failed");
220                         sensord_disconnect(handle);
221                         return -1;
222                 }
223
224                 rot.cb_set = 1;
225                 rot.callback = cb;
226                 rot.cbdata = data;
227
228                 r = sensord_start(handle, 0);
229                 if (!r) {
230                         _ERR("sensord_start failed");
231                         r = sensord_unregister_event(handle, AUTO_ROTATION_CHANGE_STATE_EVENT);
232                         if (!r)
233                                 _ERR("sensord_unregister_event failed");
234
235                         rot.callback = NULL;
236                         rot.cbdata = NULL;
237                         rot.cb_set = 0;
238                         rot.sensord_started = 0;
239                         sensord_disconnect(handle);
240                         return -1;
241                 }
242                 rot.sensord_started = 1;
243
244                 rot.handle = handle;
245                 __add_rotlock(data);
246
247 #ifdef X11
248                 _MAKE_ATOM(ATOM_ROTATION_LOCK, STR_ATOM_ROTATION_LOCK);
249                 root =  ecore_x_window_root_first_get();
250                 XSelectInput(ecore_x_display_get(), root, PropertyChangeMask);
251 #endif
252         }
253         return 0;
254 }
255
256 EXPORT_API int appcore_unset_rotation_cb(void)
257 {
258         if (rot.wm_rotate)
259                 return rot.wm_rotate->unset_rotation_cb();
260         else {
261                 bool r;
262
263                 _retv_if(rot.callback == NULL, 0);
264
265                 __del_rotlock();
266
267                 if (rot.cb_set) {
268                         r = sensord_unregister_event(rot.handle,
269                                                 AUTO_ROTATION_CHANGE_STATE_EVENT);
270                         if (!r) {
271                                 _ERR("sensord_unregister_event failed");
272                                 return -1;
273                         }
274                         rot.cb_set = 0;
275                 }
276                 rot.callback = NULL;
277                 rot.cbdata = NULL;
278
279                 if (rot.sensord_started == 1) {
280                         r = sensord_stop(rot.handle);
281                         if (!r) {
282                                 _ERR("sensord_stop failed");
283                                 return -1;
284                         }
285                         rot.sensord_started = 0;
286                 }
287
288                 r = sensord_disconnect(rot.handle);
289                 if (!r) {
290                         _ERR("sensord_disconnect failed");
291                         return -1;
292                 }
293                 rot.handle = -1;
294         }
295         return 0;
296 }
297
298 EXPORT_API int appcore_get_rotation_state(enum appcore_rm *curr)
299 {
300         if (rot.wm_rotate)
301                 return rot.wm_rotate->get_rotation_state(curr);
302         else {
303                 bool r;
304                 sensor_data_t data;
305
306                 if (curr == NULL) {
307                         errno = EINVAL;
308                         return -1;
309                 }
310
311                 r = sensord_get_data(rot.handle, AUTO_ROTATION_SENSOR, &data);
312                 if (!r) {
313                         _ERR("sensord_get_data failed");
314                         *curr = APPCORE_RM_UNKNOWN;
315                         return -1;
316                 }
317
318                 *curr = __get_mode(data);
319         }
320         return 0;
321 }
322
323 EXPORT_API int appcore_pause_rotation_cb(void)
324 {
325         if (rot.wm_rotate)
326                 return rot.wm_rotate->pause_rotation_cb();
327         else {
328                 bool r;
329
330                 _retv_if(rot.callback == NULL, 0);
331                 _DBG("[APP %d] appcore_pause_rotation_cb is called", getpid());
332
333                 __del_rotlock();
334
335                 if (rot.cb_set) {
336                         r = sensord_unregister_event(rot.handle,
337                                                 AUTO_ROTATION_CHANGE_STATE_EVENT);
338                         if (!r) {
339                                 _ERR("sensord_unregister_event failed");
340                                 return -1;
341                         }
342                         rot.cb_set = 0;
343                 }
344
345                 if (rot.sensord_started == 1) {
346                         r = sensord_stop(rot.handle);
347                         if (!r) {
348                                 _ERR("sensord_stop failed");
349                                 return -1;
350                         }
351                         rot.sensord_started = 0;
352                 }
353         }
354
355         return 0;
356 }
357
358 EXPORT_API int appcore_resume_rotation_cb(void)
359 {
360         if (rot.wm_rotate)
361                 return rot.wm_rotate->resume_rotation_cb();
362         else {
363                 bool r;
364                 enum appcore_rm m;
365
366                 _retv_if(rot.callback == NULL, 0);
367                 _DBG("[APP %d] appcore_resume_rotation_cb is called", getpid());
368
369                 if (rot.cb_set == 0) {
370                         r = sensord_register_event(rot.handle,
371                                         AUTO_ROTATION_CHANGE_STATE_EVENT,
372                                         SENSOR_INTERVAL_NORMAL, 0, __changed_cb, rot.cbdata);
373                         if (!r) {
374                                 _ERR("sensord_register_event failed");
375                                 return -1;
376                         }
377                         rot.cb_set = 1;
378                 }
379
380                 if (rot.sensord_started == 0) {
381                         r = sensord_start(rot.handle, 0);
382                         if (!r) {
383                                 _ERR("sensord_start failed");
384                                 r = sensord_unregister_event(rot.handle,
385                                                     AUTO_ROTATION_CHANGE_STATE_EVENT);
386                                 if (!r)
387                                         _ERR("sensord_unregister_event failed");
388                                 rot.cb_set = 0;
389                                 return -1;
390                         }
391                         rot.sensord_started = 1;
392                 }
393
394                 __add_rotlock(rot.cbdata);
395
396                 r = appcore_get_rotation_state(&m);
397                 _DBG("[APP %d] Rotmode prev %d -> curr %d", getpid(), rot.mode, m);
398                 if (!r && rot.mode != m && rot.lock == 0) {
399                         rot.callback((void *)&m, m, rot.cbdata);
400                         rot.mode = m;
401                 }
402         }
403         return 0;
404 }
405
406 EXPORT_API int appcore_set_wm_rotation(struct ui_wm_rotate* wm_rotate)
407 {
408         if (!wm_rotate) return -1;
409
410         if (rot.callback) {
411                 wm_rotate->set_rotation_cb(rot.callback, rot.cbdata);
412                 appcore_unset_rotation_cb();
413         }
414         rot.wm_rotate = wm_rotate;
415         _DBG("[APP %d] Support wm rotate:%p", getpid(), wm_rotate);
416         return 0;
417 }