29c6839f7aeae52afd21bec4b0ce2cf0d2f7071f
[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 = 0;
11 static int _ecore_fb_vt_tty_fd = 0;
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 static void _ecore_fb_vt_switch(int vt);
38
39 static Eina_Bool
40 _ecore_fb_signal_usr_handler(void *data __UNUSED__, int type __UNUSED__, void *ev)
41 {
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 static void
63 _ecore_fb_vt_switch(int vt)
64 {
65         vt++;
66         if (_ecore_fb_vt_tty_fd != 0)
67         {
68                 if (vt != _ecore_fb_vt_current_vt)
69                 {
70                         tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode);
71                         ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode);
72                         ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode);
73                 }
74         }
75         ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, vt);
76 }
77
78 static int
79 _ecore_fb_vt_setup(void)
80 {
81         char buf[64];
82         struct termios tio;
83         struct vt_mode new_vtmode;
84
85         if(_ecore_fb_vt_current_vt != _ecore_fb_vt_prev_vt)
86         {
87                 snprintf(buf, sizeof(buf), "/dev/tty%i", _ecore_fb_vt_current_vt);
88                 if((_ecore_fb_vt_tty_fd = open(buf, O_RDWR)) < 0)
89                 {
90                         printf("[ecore_fb:vt_setup] cant open tty %d\n", _ecore_fb_vt_current_vt);
91                         return 0;
92                 }
93                 close(_ecore_fb_vt_tty0_fd);
94                 _ecore_fb_vt_tty0_fd = 0;
95                 /* FIXME detach the process from current tty ? */
96         }
97         else
98                 _ecore_fb_vt_tty_fd = _ecore_fb_vt_tty0_fd;
99         /* for backup */
100         tcgetattr(_ecore_fb_vt_tty_fd, &_ecore_fb_tty_prev_tio_mode);
101         ioctl(_ecore_fb_vt_tty_fd, KDGETMODE, &_ecore_fb_tty_prev_kd_mode);
102         ioctl(_ecore_fb_vt_tty_fd, VT_GETMODE, &_ecore_fb_vt_prev_mode);
103
104         if(ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, KD_GRAPHICS) < 0)
105         {
106                 perror("[ecore_fb:vt_setup] cant set the mode to KD_GRAPHICS");
107                 close(_ecore_fb_vt_tty_fd);
108                 return 0;
109         }
110         ioctl(_ecore_fb_vt_tty_fd, KDGKBMODE, &_ecore_fb_tty_prev_mode);
111         
112         /* support of switching */
113         new_vtmode.mode = VT_PROCESS;
114         new_vtmode.waitv = 0;
115         new_vtmode.relsig = SIGUSR1;
116         new_vtmode.acqsig = SIGUSR2;
117         if(ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &new_vtmode) < 0)
118         {
119                 perror("[ecore_fb:vt_setup] cant set the tty mode");
120                 close(_ecore_fb_vt_tty_fd);
121                 return 0;
122         }
123         /* register signal handlers when alloc/detach of vt */
124         _ecore_fb_user_handler = ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER,
125                                                     _ecore_fb_signal_usr_handler,
126                                                     NULL);
127         /* What does this does? */
128         _ecore_fb_filter_handler = ecore_event_filter_add(_ecore_fb_event_filter_start, _ecore_fb_event_filter_filter, _ecore_fb_event_filter_end, NULL);
129         
130         usleep(40000);
131         if(ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, _ecore_fb_vt_current_vt) < 0)
132         {
133                 perror("[ecore_fb:vt_setup] error on VT_ACTIVATE");
134                 close(_ecore_fb_vt_tty_fd);
135                 return 0;
136         }
137         if(ioctl(_ecore_fb_vt_tty_fd, VT_WAITACTIVE, _ecore_fb_vt_current_vt) < 0)
138         {
139                 perror("[ecore_fb:vt_setup] error on VT_WAITACTIVE");
140                 close(_ecore_fb_vt_tty_fd);
141                 return 0;
142         }
143         /* FIXME assign the fb to the tty in case isnt setup */
144         return 1;
145 }
146
147 int
148 ecore_fb_vt_init(void)
149 {
150         struct vt_stat vtstat;
151
152         /* as root you can allocate another tty */
153         if(!geteuid())
154                 _ecore_fb_vt_do_switch = 1;
155         if((_ecore_fb_vt_tty0_fd = open("/dev/tty0", O_RDONLY)) < 0)
156         {
157                 printf("[ecore_fb:init] cant open /dev/tty0\n");
158                 return 0;
159         }
160         /* query current vt state */
161         if((ioctl(_ecore_fb_vt_tty0_fd, VT_GETSTATE, &vtstat)) < 0)
162         {
163                 printf("[ecore_fb:init] cant get current tty state\n");
164                 return 0;
165         }
166         _ecore_fb_vt_prev_vt = vtstat.v_active;
167         /* switch to another tty */
168         if(_ecore_fb_vt_do_switch)
169         {
170                 int vtno;
171
172                 if ((ioctl(_ecore_fb_vt_tty0_fd, VT_OPENQRY, &vtno) < 0))
173                 {
174                         printf("[ecore_fb:init] cant query for a vt\n");
175                         return 0;
176                 }
177                 _ecore_fb_vt_current_vt = vtno;
178         }
179         /* use current tty */
180         else
181                 _ecore_fb_vt_current_vt = _ecore_fb_vt_prev_vt;
182         if(!_ecore_fb_vt_setup())
183         {
184                 printf("[ecore_fb:init] cant setup the vt, restoring previous mode...\n");
185                 /* TODO finish this */
186                 if(_ecore_fb_vt_do_switch)
187                 {
188                         printf("[ecore_fb:init] switching back to vt %d\n", _ecore_fb_vt_prev_vt);
189                 }
190                 return 0;
191         }
192         return 1;
193 }
194
195 void
196 ecore_fb_vt_shutdown(void)
197 {
198         /* restore the previous mode */
199         if(_ecore_fb_vt_tty_fd != 0)
200         {
201                 tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode);
202                 ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode);
203                 ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode);
204                 ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &_ecore_fb_vt_prev_mode);
205                 /* go back to previous vt */
206                 close(_ecore_fb_vt_tty_fd);
207                 _ecore_fb_vt_tty_fd = 0;
208         }
209         
210         if(_ecore_fb_user_handler)
211                 ecore_event_handler_del(_ecore_fb_user_handler);
212         _ecore_fb_user_handler = NULL;
213
214         if(_ecore_fb_filter_handler)
215                 ecore_event_filter_del(_ecore_fb_filter_handler);
216         _ecore_fb_filter_handler = NULL;
217 }
218
219 /**
220  * To be documented.
221  *
222  * FIXME: To be fixed.
223  * @todo Documentation: Find out what this does.
224  */
225 EAPI void
226 ecore_fb_callback_gain_set(void (*func) (void *data), void *data)
227 {
228    _ecore_fb_func_fb_gain = func;
229    _ecore_fb_func_fb_gain_data = data;
230 }
231
232 /**
233  * To be documented.
234  *
235  * FIXME: To be fixed.
236  * @todo Documentation: Find out what this does.
237  */
238 EAPI void
239 ecore_fb_callback_lose_set(void (*func) (void *data), void *data)
240 {
241    _ecore_fb_func_fb_lost = func;
242    _ecore_fb_func_fb_lost_data = data;
243 }
244 typedef struct _Ecore_Fb_Filter_Data Ecore_Fb_Filter_Data;
245    
246 struct _Ecore_Fb_Filter_Data
247 {
248    int last_event_type;
249 };
250                 
251 static void *
252 _ecore_fb_event_filter_start(void *data __UNUSED__)
253 {
254    Ecore_Fb_Filter_Data *filter_data;
255    
256    filter_data = calloc(1, sizeof(Ecore_Fb_Filter_Data));
257    return filter_data;
258 }
259
260 static Eina_Bool
261 _ecore_fb_event_filter_filter(void *data __UNUSED__, void *loop_data,int type, void *event __UNUSED__)
262 {
263    Ecore_Fb_Filter_Data *filter_data;
264    
265    filter_data = loop_data;
266    if (!filter_data) return EINA_TRUE;
267    if (type == ECORE_FB_EVENT_MOUSE_MOVE)
268      {
269         if ((filter_data->last_event_type) == ECORE_FB_EVENT_MOUSE_MOVE)
270           {
271              filter_data->last_event_type = type;
272              return EINA_FALSE;
273           }
274      }
275    filter_data->last_event_type = type;
276    return EINA_TRUE;
277 }
278
279 static void
280 _ecore_fb_event_filter_end(void *data __UNUSED__, void *loop_data)
281 {
282    Ecore_Fb_Filter_Data *filter_data;
283    
284    filter_data = loop_data;
285    if (filter_data) free(filter_data);
286 }