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