Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_fb / ecore_fb_vt.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include "Ecore_Fb.h"
6 #include "ecore_fb_private.h"
7
8 static int _ecore_fb_vt_do_switch = 0;
9
10 static int _ecore_fb_vt_tty0_fd = -1;
11 static int _ecore_fb_vt_tty_fd = -1;
12 static int _ecore_fb_vt_current_vt = 0;
13 static int _ecore_fb_vt_prev_vt = 0;
14
15 static struct termios _ecore_fb_tty_prev_tio_mode;
16 static struct vt_mode _ecore_fb_vt_prev_mode;
17
18 static Eina_Bool _ecore_fb_signal_usr_handler(void *data, int type, void *ev);
19 static Ecore_Event_Handler *_ecore_fb_user_handler = NULL;
20 static int _ecore_fb_tty_prev_mode = 0;
21 static int _ecore_fb_tty_prev_kd_mode = 0;
22
23 /* callbacks for an attach/release of a vt */
24 static void (*_ecore_fb_func_fb_lost) (void *data) = NULL;
25 static void *_ecore_fb_func_fb_lost_data = NULL;
26 static void (*_ecore_fb_func_fb_gain) (void *data) = NULL;
27 static void *_ecore_fb_func_fb_gain_data = NULL;
28
29 /* FIXME what is the filter for? */
30 static Ecore_Event_Filter *_ecore_fb_filter_handler = NULL;
31
32 /* prototypes */
33 /* XXX: unused
34 static void _ecore_fb_vt_switch(int vt);
35 static void *_ecore_fb_event_filter_start(void *data);
36 static Eina_Bool _ecore_fb_event_filter_filter(void *data, void *loop_data, int type, void *event);
37 static void _ecore_fb_event_filter_end(void *data, void *loop_data);
38 */
39
40 static Eina_Bool
41 _ecore_fb_signal_usr_handler(void *data __UNUSED__, int type __UNUSED__, void *ev)
42 {
43    Ecore_Event_Signal_User *e;
44
45    e = (Ecore_Event_Signal_User *)ev;
46    if (e->number == 1)
47      {
48         /* release vt */
49         if (_ecore_fb_func_fb_lost) _ecore_fb_func_fb_lost(_ecore_fb_func_fb_lost_data);
50         /* TODO stop listening from the devices? let the callback do it? */
51         ioctl(_ecore_fb_vt_tty_fd, VT_RELDISP, 1);
52      }
53    else if (e->number == 2)
54      {
55         /* attach vt */
56         if (_ecore_fb_func_fb_gain) _ecore_fb_func_fb_gain(_ecore_fb_func_fb_gain_data);
57         /* TODO reattach all devices */
58      }
59    return 1;
60 }
61
62 /* XXX: unused
63 static void
64 _ecore_fb_vt_switch(int vt)
65 {
66    vt++;
67    if (_ecore_fb_vt_tty_fd != 0)
68      {
69         if (vt != _ecore_fb_vt_current_vt)
70           {
71              tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode);
72              ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode);
73              ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode);
74           }
75      }
76    ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, vt);
77 }
78 */
79
80 static int
81 _ecore_fb_vt_setup(void)
82 {
83    char buf[64];
84 // XXX: unused
85 //   struct termios tio;
86    struct vt_mode new_vtmode;
87
88    if (_ecore_fb_vt_current_vt != _ecore_fb_vt_prev_vt)
89      {
90         snprintf(buf, sizeof(buf), "/dev/tty%i", _ecore_fb_vt_current_vt);
91         if ((_ecore_fb_vt_tty_fd = open(buf, O_RDWR)) < 0)
92           {
93              printf("[ecore_fb:vt_setup] can't open tty %d\n", _ecore_fb_vt_current_vt);
94              return 0;
95           }
96         close(_ecore_fb_vt_tty0_fd);
97         _ecore_fb_vt_tty0_fd = -1;
98         /* FIXME detach the process from current tty ? */
99      }
100    else
101       _ecore_fb_vt_tty_fd = _ecore_fb_vt_tty0_fd;
102    /* for backup */
103    tcgetattr(_ecore_fb_vt_tty_fd, &_ecore_fb_tty_prev_tio_mode);
104    ioctl(_ecore_fb_vt_tty_fd, KDGETMODE, &_ecore_fb_tty_prev_kd_mode);
105    ioctl(_ecore_fb_vt_tty_fd, VT_GETMODE, &_ecore_fb_vt_prev_mode);
106
107    if (ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, KD_GRAPHICS) < 0)
108      {
109         perror("[ecore_fb:vt_setup] can't set the mode to KD_GRAPHICS");
110         close(_ecore_fb_vt_tty_fd);
111         _ecore_fb_vt_tty_fd = -1;
112         return 0;
113      }
114    ioctl(_ecore_fb_vt_tty_fd, KDGKBMODE, &_ecore_fb_tty_prev_mode);
115
116    /* support of switching */
117    new_vtmode.mode = VT_PROCESS;
118    new_vtmode.waitv = 0;
119    new_vtmode.relsig = SIGUSR1;
120    new_vtmode.acqsig = SIGUSR2;
121    if (ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &new_vtmode) < 0)
122      {
123         perror("[ecore_fb:vt_setup] can't set the tty mode");
124         close(_ecore_fb_vt_tty_fd);
125         _ecore_fb_vt_tty_fd = -1;
126         return 0;
127      }
128    /* register signal handlers when alloc/detach of vt */
129    _ecore_fb_user_handler = ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER,
130                                                     _ecore_fb_signal_usr_handler,
131                                                     NULL);
132    /* What does this do? */
133    /*
134    _ecore_fb_filter_handler = ecore_event_filter_add(_ecore_fb_event_filter_start, _ecore_fb_event_filter_filter, _ecore_fb_event_filter_end, NULL);
135    */
136
137    usleep(40000);
138    if (ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, _ecore_fb_vt_current_vt) < 0)
139      {
140         perror("[ecore_fb:vt_setup] error on VT_ACTIVATE");
141         close(_ecore_fb_vt_tty_fd);
142         _ecore_fb_vt_tty_fd = -1;
143         return 0;
144      }
145    if(ioctl(_ecore_fb_vt_tty_fd, VT_WAITACTIVE, _ecore_fb_vt_current_vt) < 0)
146      {
147         perror("[ecore_fb:vt_setup] error on VT_WAITACTIVE");
148         close(_ecore_fb_vt_tty_fd);
149         _ecore_fb_vt_tty_fd = -1;
150         return 0;
151      }
152    /* FIXME assign the fb to the tty in case isn't setup */
153    return 1;
154 }
155
156 int
157 ecore_fb_vt_init(void)
158 {
159    struct vt_stat vtstat;
160
161    /* as root you can allocate another tty */
162    if (!geteuid())
163       _ecore_fb_vt_do_switch = 1;
164    if ((_ecore_fb_vt_tty0_fd = open("/dev/tty0", O_RDONLY)) < 0)
165      {
166         printf("[ecore_fb:init] can't open /dev/tty0\n");
167         return 0;
168      }
169    /* query current vt state */
170    if ((ioctl(_ecore_fb_vt_tty0_fd, VT_GETSTATE, &vtstat)) < 0)
171      {
172         printf("[ecore_fb:init] can't get current tty state\n");
173         return 0;
174      }
175    _ecore_fb_vt_prev_vt = vtstat.v_active;
176    /* switch to another tty */
177    if (_ecore_fb_vt_do_switch)
178      {
179         int vtno;
180
181         if ((ioctl(_ecore_fb_vt_tty0_fd, VT_OPENQRY, &vtno) < 0))
182           {
183              printf("[ecore_fb:init] can't query for a vt\n");
184              return 0;
185           }
186         _ecore_fb_vt_current_vt = vtno;
187      }
188    /* use current tty */
189    else
190       _ecore_fb_vt_current_vt = _ecore_fb_vt_prev_vt;
191    if (!_ecore_fb_vt_setup())
192      {
193         printf("[ecore_fb:init] can't setup the vt, restoring previous mode...\n");
194         /* TODO finish this */
195         if (_ecore_fb_vt_do_switch)
196           {
197              printf("[ecore_fb:init] switching back to vt %d\n", _ecore_fb_vt_prev_vt);
198           }
199         return 0;
200      }
201    return 1;
202 }
203
204 void
205 ecore_fb_vt_shutdown(void)
206 {
207    /* restore the previous mode */
208    if (_ecore_fb_vt_tty_fd != -1)
209      {
210         tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode);
211         ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode);
212         ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode);
213         ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &_ecore_fb_vt_prev_mode);
214         /* go back to previous vt */
215         close(_ecore_fb_vt_tty_fd);
216         _ecore_fb_vt_tty_fd = -1;
217      }
218
219    if (_ecore_fb_user_handler) ecore_event_handler_del(_ecore_fb_user_handler);
220    _ecore_fb_user_handler = NULL;
221
222    if (_ecore_fb_filter_handler) ecore_event_filter_del(_ecore_fb_filter_handler);
223    _ecore_fb_filter_handler = NULL;
224 }
225
226 /**
227  * @addtogroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions.
228  *
229  * @{
230  */
231
232 /**
233  * @brief Set a callback called when a virtual terminal is gained.
234  *
235  * @param func The callback called when vt is gained.
236  * @param data The data to pass to the callback.
237  *
238  * This function sets the callback @p func which will be called when a
239  * virtual terminal is gained (for example you press Ctrl-Alt-F1 to go
240  * to vt1 and your app was using vt1). @p data will be pass to @p func if
241  * the callback is called.
242  */
243 EAPI void
244 ecore_fb_callback_gain_set(void (*func) (void *data), void *data)
245 {
246    _ecore_fb_func_fb_gain = func;
247    _ecore_fb_func_fb_gain_data = data;
248 }
249
250 /**
251  * @brief Set a callback called when a virtual terminal is lost.
252  *
253  * @param func The callback called when vt is lost.
254  * @param data The data to pass to the callback.
255  *
256  * This function sets the callback @p func which will be called when a
257  * virtual terminal is lost (someone wants the tv from you and you
258  * want to give up that vt). @p data will be pass to @p func if the
259  * callback is called.
260  */
261 EAPI void
262 ecore_fb_callback_lose_set(void (*func) (void *data), void *data)
263 {
264    _ecore_fb_func_fb_lost = func;
265    _ecore_fb_func_fb_lost_data = data;
266
267 }
268
269 /**
270  * @}
271  */
272
273 /*
274  * This filter should take into account that the MOUSE_MOVE event can be
275  * triggered by a mouse, not just a touchscreen device, so you can't discard
276  * them (only those generated by a device that sends events with absolute
277  * coordinates).
278
279 typedef struct _Ecore_Fb_Filter_Data Ecore_Fb_Filter_Data;
280
281 struct _Ecore_Fb_Filter_Data
282 {
283    int last_event_type;
284 };
285
286 static void *
287 _ecore_fb_event_filter_start(void *data __UNUSED__)
288 {
289    Ecore_Fb_Filter_Data *filter_data;
290
291    filter_data = calloc(1, sizeof(Ecore_Fb_Filter_Data));
292    return filter_data;
293 }
294
295 static Eina_Bool
296 _ecore_fb_event_filter_filter(void *data __UNUSED__, void *loop_data,int type, void *event __UNUSED__)
297 {
298    Ecore_Fb_Filter_Data *filter_data;
299
300    filter_data = loop_data;
301    if (!filter_data) return EINA_TRUE;
302    if (type == ECORE_EVENT_MOUSE_MOVE)
303      {
304         if ((filter_data->last_event_type) == ECORE_EVENT_MOUSE_MOVE)
305           {
306              filter_data->last_event_type = type;
307              return EINA_FALSE;
308           }
309      }
310    filter_data->last_event_type = type;
311    return EINA_TRUE;
312 }
313
314 static void
315 _ecore_fb_event_filter_end(void *data __UNUSED__, void *loop_data)
316 {
317    Ecore_Fb_Filter_Data *filter_data;
318
319    filter_data = loop_data;
320    if (filter_data) free(filter_data);
321 }
322 */