summaryrefslogtreecommitdiff
path: root/src/lib/ecore_fb/ecore_fb_vt.c
blob: c0c4536751d751ec830bc9b8b8668ce1b0e602de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "Ecore_Fb.h"
#include "ecore_fb_private.h"

static int _ecore_fb_vt_do_switch = 0;

static int _ecore_fb_vt_tty0_fd = -1;
static int _ecore_fb_vt_tty_fd = -1;
static int _ecore_fb_vt_current_vt = 0;
static int _ecore_fb_vt_prev_vt = 0;

static struct termios _ecore_fb_tty_prev_tio_mode;
static struct vt_mode _ecore_fb_vt_prev_mode;

static Eina_Bool _ecore_fb_signal_usr_handler(void *data, int type, void *ev);
static Ecore_Event_Handler *_ecore_fb_user_handler = NULL;
static int _ecore_fb_tty_prev_mode = 0;
static int _ecore_fb_tty_prev_kd_mode = 0;

/* callbacks for an attach/release of a vt */
static void (*_ecore_fb_func_fb_lost) (void *data) = NULL;
static void *_ecore_fb_func_fb_lost_data = NULL;
static void (*_ecore_fb_func_fb_gain) (void *data) = NULL;
static void *_ecore_fb_func_fb_gain_data = NULL;

/* FIXME what is the filter for? */
static Ecore_Event_Filter *_ecore_fb_filter_handler = NULL;

/* prototypes */
/* XXX: unused
static void _ecore_fb_vt_switch(int vt);
static void *_ecore_fb_event_filter_start(void *data);
static Eina_Bool _ecore_fb_event_filter_filter(void *data, void *loop_data, int type, void *event);
static void _ecore_fb_event_filter_end(void *data, void *loop_data);
*/

static Eina_Bool
_ecore_fb_signal_usr_handler(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev)
{
   Ecore_Event_Signal_User *e;

   e = (Ecore_Event_Signal_User *)ev;
   if (e->number == 1)
     {
        /* release vt */
        if (_ecore_fb_func_fb_lost) _ecore_fb_func_fb_lost(_ecore_fb_func_fb_lost_data);
        /* TODO stop listening from the devices? let the callback do it? */
        ioctl(_ecore_fb_vt_tty_fd, VT_RELDISP, 1);
     }
   else if (e->number == 2)
     {
        /* attach vt */
        if (_ecore_fb_func_fb_gain) _ecore_fb_func_fb_gain(_ecore_fb_func_fb_gain_data);
        /* TODO reattach all devices */
     }
   return 1;
}

/* XXX: unused
static void
_ecore_fb_vt_switch(int vt)
{
   vt++;
   if (_ecore_fb_vt_tty_fd != 0)
     {
        if (vt != _ecore_fb_vt_current_vt)
          {
             tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode);
             ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode);
             ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode);
          }
     }
   ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, vt);
}
*/

static int
_ecore_fb_vt_setup(void)
{
   char buf[64];
// XXX: unused
//   struct termios tio;
   struct vt_mode new_vtmode;

   if (_ecore_fb_vt_current_vt != _ecore_fb_vt_prev_vt)
     {
        snprintf(buf, sizeof(buf), "/dev/tty%i", _ecore_fb_vt_current_vt);
        if ((_ecore_fb_vt_tty_fd = open(buf, O_RDWR)) < 0)
          {
             printf("[ecore_fb:vt_setup] can't open tty %d\n", _ecore_fb_vt_current_vt);
             return 0;
          }
        close(_ecore_fb_vt_tty0_fd);
        _ecore_fb_vt_tty0_fd = -1;
        /* FIXME detach the process from current tty ? */
     }
   else
      _ecore_fb_vt_tty_fd = _ecore_fb_vt_tty0_fd;
   /* for backup */
   tcgetattr(_ecore_fb_vt_tty_fd, &_ecore_fb_tty_prev_tio_mode);
   ioctl(_ecore_fb_vt_tty_fd, KDGETMODE, &_ecore_fb_tty_prev_kd_mode);
   ioctl(_ecore_fb_vt_tty_fd, VT_GETMODE, &_ecore_fb_vt_prev_mode);

   if (ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, KD_GRAPHICS) < 0)
     {
        perror("[ecore_fb:vt_setup] can't set the mode to KD_GRAPHICS");
        close(_ecore_fb_vt_tty_fd);
        _ecore_fb_vt_tty_fd = -1;
        return 0;
     }
   ioctl(_ecore_fb_vt_tty_fd, KDGKBMODE, &_ecore_fb_tty_prev_mode);

   /* support of switching */
   memset(&new_vtmode, 0, sizeof(new_vtmode));
   new_vtmode.mode = VT_PROCESS;
   new_vtmode.waitv = 0;
   new_vtmode.relsig = SIGUSR1;
   new_vtmode.acqsig = SIGUSR2;
   if (ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &new_vtmode) < 0)
     {
        perror("[ecore_fb:vt_setup] can't set the tty mode");
        close(_ecore_fb_vt_tty_fd);
        _ecore_fb_vt_tty_fd = -1;
        return 0;
     }
   /* register signal handlers when alloc/detach of vt */
   _ecore_fb_user_handler = ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER,
                                                    _ecore_fb_signal_usr_handler,
                                                    NULL);
   /* What does this do? */
   /*
   _ecore_fb_filter_handler = ecore_event_filter_add(_ecore_fb_event_filter_start, _ecore_fb_event_filter_filter, _ecore_fb_event_filter_end, NULL);
   */

   usleep(40000);
   if (ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, _ecore_fb_vt_current_vt) < 0)
     {
        perror("[ecore_fb:vt_setup] error on VT_ACTIVATE");
        close(_ecore_fb_vt_tty_fd);
        _ecore_fb_vt_tty_fd = -1;
        return 0;
     }
   if(ioctl(_ecore_fb_vt_tty_fd, VT_WAITACTIVE, _ecore_fb_vt_current_vt) < 0)
     {
        perror("[ecore_fb:vt_setup] error on VT_WAITACTIVE");
        close(_ecore_fb_vt_tty_fd);
        _ecore_fb_vt_tty_fd = -1;
        return 0;
     }
   /* FIXME assign the fb to the tty in case isn't setup */
   return 1;
}

int
ecore_fb_vt_init(void)
{
   struct vt_stat vtstat;

   /* as root you can allocate another tty */
   if (!geteuid())
      _ecore_fb_vt_do_switch = 1;
   if ((_ecore_fb_vt_tty0_fd = open("/dev/tty0", O_RDONLY)) < 0)
     {
        printf("[ecore_fb:init] can't open /dev/tty0\n");
        return 0;
     }
   /* query current vt state */
   if ((ioctl(_ecore_fb_vt_tty0_fd, VT_GETSTATE, &vtstat)) < 0)
     {
        printf("[ecore_fb:init] can't get current tty state\n");
        return 0;
     }
   _ecore_fb_vt_prev_vt = vtstat.v_active;
   /* switch to another tty */
   if (_ecore_fb_vt_do_switch)
     {
        int vtno;

        if ((ioctl(_ecore_fb_vt_tty0_fd, VT_OPENQRY, &vtno) < 0))
          {
             printf("[ecore_fb:init] can't query for a vt\n");
             return 0;
          }
        _ecore_fb_vt_current_vt = vtno;
     }
   /* use current tty */
   else
      _ecore_fb_vt_current_vt = _ecore_fb_vt_prev_vt;
   if (!_ecore_fb_vt_setup())
     {
        printf("[ecore_fb:init] can't setup the vt, restoring previous mode...\n");
        /* TODO finish this */
        if (_ecore_fb_vt_do_switch)
          {
             printf("[ecore_fb:init] switching back to vt %d\n", _ecore_fb_vt_prev_vt);
          }
        return 0;
     }
   return 1;
}

void
ecore_fb_vt_shutdown(void)
{
   /* restore the previous mode */
   if (_ecore_fb_vt_tty_fd != -1)
     {
        tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode);
        ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode);
        ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode);
        ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &_ecore_fb_vt_prev_mode);
        /* go back to previous vt */
        close(_ecore_fb_vt_tty_fd);
        _ecore_fb_vt_tty_fd = -1;
     }

   if (_ecore_fb_user_handler) ecore_event_handler_del(_ecore_fb_user_handler);
   _ecore_fb_user_handler = NULL;

   if (_ecore_fb_filter_handler) ecore_event_filter_del(_ecore_fb_filter_handler);
   _ecore_fb_filter_handler = NULL;
}

/**
 * @addtogroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions.
 *
 * @{
 */

/**
 * @brief Set a callback called when a virtual terminal is gained.
 *
 * @param func The callback called when vt is gained.
 * @param data The data to pass to the callback.
 *
 * This function sets the callback @p func which will be called when a
 * virtual terminal is gained (for example you press Ctrl-Alt-F1 to go
 * to vt1 and your app was using vt1). @p data will be pass to @p func if
 * the callback is called.
 */
EAPI void
ecore_fb_callback_gain_set(void (*func) (void *data), void *data)
{
   _ecore_fb_func_fb_gain = func;
   _ecore_fb_func_fb_gain_data = data;
}

/**
 * @brief Set a callback called when a virtual terminal is lost.
 *
 * @param func The callback called when vt is lost.
 * @param data The data to pass to the callback.
 *
 * This function sets the callback @p func which will be called when a
 * virtual terminal is lost (someone wants the vt from you and you
 * want to give up that vt). @p data will be pass to @p func if the
 * callback is called.
 */
EAPI void
ecore_fb_callback_lose_set(void (*func) (void *data), void *data)
{
   _ecore_fb_func_fb_lost = func;
   _ecore_fb_func_fb_lost_data = data;
}

/**
 * @}
 */

/*
 * This filter should take into account that the MOUSE_MOVE event can be
 * triggered by a mouse, not just a touchscreen device, so you can't discard
 * them (only those generated by a device that sends events with absolute
 * coordinates).

typedef struct _Ecore_Fb_Filter_Data Ecore_Fb_Filter_Data;

struct _Ecore_Fb_Filter_Data
{
   int last_event_type;
};

static void *
_ecore_fb_event_filter_start(void *data EINA_UNUSED)
{
   Ecore_Fb_Filter_Data *filter_data;

   filter_data = calloc(1, sizeof(Ecore_Fb_Filter_Data));
   return filter_data;
}

static Eina_Bool
_ecore_fb_event_filter_filter(void *data EINA_UNUSED, void *loop_data,int type, void *event EINA_UNUSED)
{
   Ecore_Fb_Filter_Data *filter_data;

   filter_data = loop_data;
   if (!filter_data) return EINA_TRUE;
   if (type == ECORE_EVENT_MOUSE_MOVE)
     {
        if ((filter_data->last_event_type) == ECORE_EVENT_MOUSE_MOVE)
          {
             filter_data->last_event_type = type;
             return EINA_FALSE;
          }
     }
   filter_data->last_event_type = type;
   return EINA_TRUE;
}

static void
_ecore_fb_event_filter_end(void *data EINA_UNUSED, void *loop_data)
{
   Ecore_Fb_Filter_Data *filter_data;

   filter_data = loop_data;
   if (filter_data) free(filter_data);
}
*/