Tizen 2.1 base
[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.h>
28 #include <vconf.h>
29 #include <Ecore_X.h>
30 #include <Ecore.h>
31 #include <X11/Xlib.h>
32
33 #include "appcore-internal.h"
34
35 #define _MAKE_ATOM(a, s)                              \
36    do {                                               \
37         a = ecore_x_atom_get(s);                      \
38         if (!a)                                       \
39           _ERR("##s creation failed.\n");             \
40    } while(0)
41
42 #define STR_ATOM_ROTATION_LOCK                "_E_ROTATION_LOCK"
43
44 static Ecore_X_Atom ATOM_ROTATION_LOCK = 0;
45 static Ecore_X_Window root;
46
47 struct rot_s {
48         int handle;
49         int (*callback) (enum appcore_rm, void *);
50         enum appcore_rm mode;
51         int lock;
52         void *cbdata;
53         int cb_set;
54         int sf_started;
55 };
56 static struct rot_s rot;
57
58 struct rot_evt {
59         enum accelerometer_rotate_state re;
60         enum appcore_rm rm;
61 };
62
63 static struct rot_evt re_to_rm[] = {
64         {
65          ROTATION_EVENT_0,
66           APPCORE_RM_PORTRAIT_NORMAL,
67         },
68         {
69          ROTATION_EVENT_90,
70          APPCORE_RM_LANDSCAPE_NORMAL,
71         },
72         {
73          ROTATION_EVENT_180,
74          APPCORE_RM_PORTRAIT_REVERSE,
75         },
76         {
77          ROTATION_EVENT_270,
78          APPCORE_RM_LANDSCAPE_REVERSE,
79         },
80 };
81
82 static enum appcore_rm __get_mode(int event_data)
83 {
84         int i;
85         enum appcore_rm m;
86
87         m = APPCORE_RM_UNKNOWN;
88
89         for (i = 0; i < sizeof(re_to_rm) / sizeof(re_to_rm[0]); i++) {
90                 if (re_to_rm[i].re == event_data) {
91                         m = re_to_rm[i].rm;
92                         break;
93                 }
94         }
95
96         return m;
97 }
98
99 static void __changed_cb(unsigned int event_type, sensor_event_data_t *event,
100                        void *data)
101 {
102         int *cb_event_data;
103         enum appcore_rm m;
104         int ret;
105
106         if (rot.lock)
107                 return;
108
109         if (event_type != ACCELEROMETER_EVENT_ROTATION_CHECK) {
110                 errno = EINVAL;
111                 return;
112         }
113
114         cb_event_data = (int *)(event->event_data);
115
116         m = __get_mode(*cb_event_data);
117
118         _DBG("[APP %d] Rotation: %d -> %d", getpid(), rot.mode, m);
119
120         if (rot.callback) {
121                 if (rot.cb_set && rot.mode != m) {
122                         _DBG("[APP %d] Rotation: %d -> %d", getpid(), rot.mode, m);
123                         rot.callback(m, data);
124                         rot.mode = m;
125                 }
126         }
127 }
128
129 static void __lock_cb(keynode_t *node, void *data)
130 {
131         int r;
132         enum appcore_rm m;
133         int ret;
134
135         rot.lock = !vconf_keynode_get_bool(node);
136
137         if (rot.lock) {
138                 m = APPCORE_RM_PORTRAIT_NORMAL;
139                 if (rot.mode != m) {
140                         rot.callback(m, data);
141                         rot.mode = m;
142                 }
143                 _DBG("[APP %d] Rotation locked", getpid());
144                 return;
145         }
146
147         _DBG("[APP %d] Rotation unlocked", getpid());
148         if (rot.callback) {
149                 if (rot.cb_set) {
150                         r = appcore_get_rotation_state(&m);
151                         _DBG("[APP %d] Rotmode prev %d -> curr %d", getpid(),
152                              rot.mode, m);
153                         if (!r && rot.mode != m) {
154                                 rot.callback(m, data);
155                                 rot.mode = m;
156                         }
157                 }
158         }
159 }
160
161 static void __add_rotlock(void *data)
162 {
163         int r;
164         int lock;
165
166         lock = 0;
167         r = vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
168         if (r) {
169                 _DBG("[APP %d] Rotation vconf get bool failed", getpid());
170         }
171
172         rot.lock = !lock;
173
174         vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, __lock_cb,
175                                  data);
176 }
177
178 static void __del_rotlock(void)
179 {
180         vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, __lock_cb);
181         rot.lock = 0;
182 }
183
184 EXPORT_API int appcore_set_rotation_cb(int (*cb) (enum appcore_rm, void *),
185                                        void *data)
186 {
187         int r;
188         int handle;
189
190         if (cb == NULL) {
191                 errno = EINVAL;
192                 return -1;
193         }
194
195         if (rot.callback != NULL) {
196                 errno = EALREADY;
197                 return -1;
198         }
199
200         handle = sf_connect(ACCELEROMETER_SENSOR);
201         if (handle < 0) {
202                 _ERR("sf_connect failed: %d", handle);
203                 return -1;
204         }
205
206         r = sf_register_event(handle, ACCELEROMETER_EVENT_ROTATION_CHECK,
207                               NULL, __changed_cb, data);
208         if (r < 0) {
209                 _ERR("sf_register_event failed: %d", r);
210                 sf_disconnect(handle);
211                 return -1;
212         }
213
214         rot.cb_set = 1;
215         rot.callback = cb;
216         rot.cbdata = data;
217
218         r = sf_start(handle, 0);
219         if (r < 0) {
220                 _ERR("sf_start failed: %d", r);
221                 sf_unregister_event(handle, ACCELEROMETER_EVENT_ROTATION_CHECK);
222                 rot.callback = NULL;
223                 rot.cbdata = NULL;
224                 rot.cb_set = 0;
225                 rot.sf_started = 0;
226                 sf_disconnect(handle);
227                 return -1;
228         }
229         rot.sf_started = 1;
230
231         rot.handle = handle;
232         __add_rotlock(data);
233
234         _MAKE_ATOM(ATOM_ROTATION_LOCK, STR_ATOM_ROTATION_LOCK );
235         root =  ecore_x_window_root_first_get();
236         XSelectInput(ecore_x_display_get(), root, PropertyChangeMask);
237
238         return 0;
239 }
240
241 EXPORT_API int appcore_unset_rotation_cb(void)
242 {
243         int r;
244
245         _retv_if(rot.callback == NULL, 0);
246
247         __del_rotlock();
248
249         if (rot.cb_set) {
250                 r = sf_unregister_event(rot.handle,
251                                         ACCELEROMETER_EVENT_ROTATION_CHECK);
252                 if (r < 0) {
253                         _ERR("sf_unregister_event failed: %d", r);
254                         return -1;
255                 }
256                 rot.cb_set = 0;
257         }
258         rot.callback = NULL;
259         rot.cbdata = NULL;
260
261         if (rot.sf_started == 1) {
262                 r = sf_stop(rot.handle);
263                 if (r < 0) {
264                         _ERR("sf_stop failed: %d", r);
265                         return -1;
266                 }
267                 rot.sf_started = 0;
268         }
269
270         r = sf_disconnect(rot.handle);
271         if (r < 0) {
272                 _ERR("sf_disconnect failed: %d", r);
273                 return -1;
274         }
275         rot.handle = -1;
276
277         return 0;
278 }
279
280 EXPORT_API int appcore_get_rotation_state(enum appcore_rm *curr)
281 {
282         int r;
283         unsigned long event;
284
285         if (curr == NULL) {
286                 errno = EINVAL;
287                 return -1;
288         }
289
290         r = sf_check_rotation(&event);
291         if (r < 0) {
292                 _ERR("sf_check_rotation failed: %d", r);
293                 *curr = APPCORE_RM_UNKNOWN;
294                 return -1;
295         }
296
297         *curr = __get_mode(event);
298
299         return 0;
300 }
301
302 EXPORT_API int appcore_pause_rotation_cb(void)
303 {
304         int r;
305
306         _retv_if(rot.callback == NULL, 0);
307         _DBG("[APP %d] appcore_pause_rotation_cb is called", getpid());
308
309         __del_rotlock();
310
311         if (rot.cb_set) {
312                 r = sf_unregister_event(rot.handle,
313                                         ACCELEROMETER_EVENT_ROTATION_CHECK);
314                 if (r < 0) {
315                         _ERR("sf_unregister_event in appcore_internal_sf_stop failed: %d", r);
316                         return -1;
317                 }
318                 rot.cb_set = 0;
319         }
320
321         if (rot.sf_started == 1) {
322                 r = sf_stop(rot.handle);
323                 if (r < 0) {
324                         _ERR("sf_stop in appcore_internal_sf_stop failed: %d",
325                              r);
326                         return -1;
327                 }
328                 rot.sf_started = 0;
329         }
330
331         return 0;
332 }
333
334 EXPORT_API int appcore_resume_rotation_cb(void)
335 {
336         int r;
337         enum appcore_rm m;
338
339         _retv_if(rot.callback == NULL, 0);
340         _DBG("[APP %d] appcore_resume_rotation_cb is called", getpid());
341
342         if (rot.cb_set == 0) {
343                 r = sf_register_event(rot.handle,
344                                       ACCELEROMETER_EVENT_ROTATION_CHECK, NULL,
345                                       __changed_cb, rot.cbdata);
346                 if (r < 0) {
347                         _ERR("sf_register_event in appcore_internal_sf_start failed: %d", r);
348                         return -1;
349                 }
350                 rot.cb_set = 1;
351         }
352
353         if (rot.sf_started == 0) {
354                 r = sf_start(rot.handle, 0);
355                 if (r < 0) {
356                         _ERR("sf_start in appcore_internal_sf_start failed: %d",
357                              r);
358                         sf_unregister_event(rot.handle,
359                                             ACCELEROMETER_EVENT_ROTATION_CHECK);
360                         rot.cb_set = 0;
361                         return -1;
362                 }
363                 rot.sf_started = 1;
364         }
365
366         __add_rotlock(rot.cbdata);
367
368         r = appcore_get_rotation_state(&m);
369         _DBG("[APP %d] Rotmode prev %d -> curr %d", getpid(), rot.mode, m);
370         if (!r && rot.mode != m && rot.lock == 0) {
371                 rot.callback(m, rot.cbdata);
372                 rot.mode = m;
373         }
374
375         return 0;
376 }