svn update: 48958 (latest:48959)
[framework/uifw/ecore.git] / src / lib / ecore_fb / ecore_fb_vt.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include "Ecore_Fb.h"
10 #include "ecore_fb_private.h"
11
12 static int _ecore_fb_vt_do_switch = 0;
13
14 static int _ecore_fb_vt_tty0_fd = 0;
15 static int _ecore_fb_vt_tty_fd = 0;
16 static int _ecore_fb_vt_current_vt = 0;
17 static int _ecore_fb_vt_prev_vt = 0;
18
19 static struct termios _ecore_fb_tty_prev_tio_mode;
20 static struct vt_mode _ecore_fb_vt_prev_mode;
21
22 static int _ecore_fb_signal_usr_handler(void *data, int type, void *ev);
23 static Ecore_Event_Handler *_ecore_fb_user_handler = NULL;
24 static int _ecore_fb_tty_prev_mode = 0;
25 static int _ecore_fb_tty_prev_kd_mode = 0;
26
27 /* callbacks for an attach/release of a vt */
28 static void (*_ecore_fb_func_fb_lost) (void *data) = NULL;
29 static void *_ecore_fb_func_fb_lost_data = NULL;
30 static void (*_ecore_fb_func_fb_gain) (void *data) = NULL;
31 static void *_ecore_fb_func_fb_gain_data = NULL;
32
33 /* FIXME what is the filter for? */
34 static Ecore_Event_Filter *_ecore_fb_filter_handler = NULL;
35
36 static void *_ecore_fb_event_filter_start(void *data);
37 static int   _ecore_fb_event_filter_filter(void *data, void *loop_data, int type, void *event);
38 static void  _ecore_fb_event_filter_end(void *data, void *loop_data);
39
40 /* prototypes */
41 static void _ecore_fb_vt_switch(int vt);
42
43 static int
44 _ecore_fb_signal_usr_handler(void *data __UNUSED__, int type __UNUSED__, void *ev)
45 {
46
47         Ecore_Event_Signal_User *e;
48    
49         e = (Ecore_Event_Signal_User *)ev;
50         if (e->number == 1)
51         {
52                 /* release vt */
53                 if (_ecore_fb_func_fb_lost) _ecore_fb_func_fb_lost(_ecore_fb_func_fb_lost_data);
54                 /* TODO stop listening from the devices? let the callback do it? */
55                 ioctl(_ecore_fb_vt_tty_fd, VT_RELDISP, 1);
56         }
57         else if (e->number == 2)
58         {
59                 /* attach vt */
60                 if (_ecore_fb_func_fb_gain) _ecore_fb_func_fb_gain(_ecore_fb_func_fb_gain_data);
61                 /* TODO reattach all devices */
62         }
63         return 1;
64 }
65
66 static void
67 _ecore_fb_vt_switch(int vt)
68 {
69         vt++;
70         if (_ecore_fb_vt_tty_fd != 0)
71         {
72                 if (vt != _ecore_fb_vt_current_vt)
73                 {
74                         tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode);
75                         ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode);
76                         ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode);
77                 }
78         }
79         ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, vt);
80 }
81
82 static int
83 _ecore_fb_vt_setup(void)
84 {
85         char buf[64];
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] cant 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 = 0;
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] cant set the mode to KD_GRAPHICS");
111                 close(_ecore_fb_vt_tty_fd);
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] cant set the tty mode");
124                 close(_ecore_fb_vt_tty_fd);
125                 return 0;
126         }
127         /* register signal handlers when alloc/detach of vt */
128         _ecore_fb_user_handler = ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER,
129                                                     _ecore_fb_signal_usr_handler,
130                                                     NULL);
131         /* What does this does? */
132         _ecore_fb_filter_handler = ecore_event_filter_add(_ecore_fb_event_filter_start, _ecore_fb_event_filter_filter, _ecore_fb_event_filter_end, NULL);
133         
134         usleep(40000);
135         if(ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, _ecore_fb_vt_current_vt) < 0)
136         {
137                 perror("[ecore_fb:vt_setup] error on VT_ACTIVATE");
138                 close(_ecore_fb_vt_tty_fd);
139                 return 0;
140         }
141         if(ioctl(_ecore_fb_vt_tty_fd, VT_WAITACTIVE, _ecore_fb_vt_current_vt) < 0)
142         {
143                 perror("[ecore_fb:vt_setup] error on VT_WAITACTIVE");
144                 close(_ecore_fb_vt_tty_fd);
145                 return 0;
146         }
147         /* FIXME assign the fb to the tty in case isnt setup */
148         return 1;
149 }
150
151 int
152 ecore_fb_vt_init(void)
153 {
154         struct vt_stat vtstat;
155
156         /* as root you can allocate another tty */
157         if(!geteuid())
158                 _ecore_fb_vt_do_switch = 1;
159         if((_ecore_fb_vt_tty0_fd = open("/dev/tty0", O_RDONLY)) < 0)
160         {
161                 printf("[ecore_fb:init] cant open /dev/tty0\n");
162                 return 0;
163         }
164         /* query current vt state */
165         if((ioctl(_ecore_fb_vt_tty0_fd, VT_GETSTATE, &vtstat)) < 0)
166         {
167                 printf("[ecore_fb:init] cant get current tty state\n");
168                 return 0;
169         }
170         _ecore_fb_vt_prev_vt = vtstat.v_active;
171         /* switch to another tty */
172         if(_ecore_fb_vt_do_switch)
173         {
174                 int vtno;
175
176                 if ((ioctl(_ecore_fb_vt_tty0_fd, VT_OPENQRY, &vtno) < 0))
177                 {
178                         printf("[ecore_fb:init] cant query for a vt\n");
179                         return 0;
180                 }
181                 _ecore_fb_vt_current_vt = vtno;
182         }
183         /* use current tty */
184         else
185                 _ecore_fb_vt_current_vt = _ecore_fb_vt_prev_vt;
186         if(!_ecore_fb_vt_setup())
187         {
188                 printf("[ecore_fb:init] cant setup the vt, restoring previous mode...\n");
189                 /* TODO finish this */
190                 if(_ecore_fb_vt_do_switch)
191                 {
192                         printf("[ecore_fb:init] switching back to vt %d\n", _ecore_fb_vt_prev_vt);
193                 }
194                 return 0;
195         }
196         return 1;
197 }
198
199 void
200 ecore_fb_vt_shutdown(void)
201 {
202         /* restore the previous mode */
203         if(_ecore_fb_vt_tty_fd != 0)
204         {
205                 tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode);
206                 ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode);
207                 ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode);
208                 ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &_ecore_fb_vt_prev_mode);
209                 /* go back to previous vt */
210                 close(_ecore_fb_vt_tty_fd);
211                 _ecore_fb_vt_tty_fd = 0;
212         }
213         
214         if(_ecore_fb_user_handler)
215                 ecore_event_handler_del(_ecore_fb_user_handler);
216         _ecore_fb_user_handler = NULL;
217
218         if(_ecore_fb_filter_handler)
219                 ecore_event_filter_del(_ecore_fb_filter_handler);
220         _ecore_fb_filter_handler = NULL;
221 }
222
223 /**
224  * To be documented.
225  *
226  * FIXME: To be fixed.
227  * @todo Documentation: Find out what this does.
228  */
229 EAPI void
230 ecore_fb_callback_gain_set(void (*func) (void *data), void *data)
231 {
232    _ecore_fb_func_fb_gain = func;
233    _ecore_fb_func_fb_gain_data = data;
234 }
235
236 /**
237  * To be documented.
238  *
239  * FIXME: To be fixed.
240  * @todo Documentation: Find out what this does.
241  */
242 EAPI void
243 ecore_fb_callback_lose_set(void (*func) (void *data), void *data)
244 {
245    _ecore_fb_func_fb_lost = func;
246    _ecore_fb_func_fb_lost_data = data;
247 }
248 typedef struct _Ecore_Fb_Filter_Data Ecore_Fb_Filter_Data;
249    
250 struct _Ecore_Fb_Filter_Data
251 {
252    int last_event_type;
253 };
254                 
255 static void *
256 _ecore_fb_event_filter_start(void *data __UNUSED__)
257 {
258    Ecore_Fb_Filter_Data *filter_data;
259    
260    filter_data = calloc(1, sizeof(Ecore_Fb_Filter_Data));
261    return filter_data;
262 }
263
264 static int
265 _ecore_fb_event_filter_filter(void *data __UNUSED__, void *loop_data,int type, void *event __UNUSED__)
266 {
267    Ecore_Fb_Filter_Data *filter_data;
268    
269    filter_data = loop_data;
270    if (!filter_data) return 1;
271    if (type == ECORE_FB_EVENT_MOUSE_MOVE)
272      {
273         if ((filter_data->last_event_type) == ECORE_FB_EVENT_MOUSE_MOVE)
274           {
275              filter_data->last_event_type = type;
276              return 0;
277           }
278      }
279    filter_data->last_event_type = type;
280    return 1;
281 }
282
283 static void
284 _ecore_fb_event_filter_end(void *data __UNUSED__, void *loop_data)
285 {
286    Ecore_Fb_Filter_Data *filter_data;
287    
288    filter_data = loop_data;
289    if (filter_data) free(filter_data);
290 }