summaryrefslogtreecommitdiff
path: root/legacy/ecore/src/lib/ecore_fb/ecore_fb_vt.c
blob: 29c6839f7aeae52afd21bec4b0ce2cf0d2f7071f (plain) (blame)
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
#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 = 0;
static int _ecore_fb_vt_tty_fd = 0;
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;

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);

/* prototypes */
static void _ecore_fb_vt_switch(int vt);

static Eina_Bool
_ecore_fb_signal_usr_handler(void *data __UNUSED__, int type __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;
}

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];
	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] cant open tty %d\n", _ecore_fb_vt_current_vt);
			return 0;
		}
		close(_ecore_fb_vt_tty0_fd);
		_ecore_fb_vt_tty0_fd = 0;
		/* 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] cant set the mode to KD_GRAPHICS");
		close(_ecore_fb_vt_tty_fd);
		return 0;
	}
	ioctl(_ecore_fb_vt_tty_fd, KDGKBMODE, &_ecore_fb_tty_prev_mode);
	
	/* support of switching */
	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] cant set the tty mode");
		close(_ecore_fb_vt_tty_fd);
		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 does? */
	_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);
		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);
		return 0;
	}
	/* FIXME assign the fb to the tty in case isnt 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] cant 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] cant 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] cant 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] cant 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 != 0)
	{
		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 = 0;
	}
	
	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;
}

/**
 * To be documented.
 *
 * FIXME: To be fixed.
 * @todo Documentation: Find out what this does.
 */
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;
}

/**
 * To be documented.
 *
 * FIXME: To be fixed.
 * @todo Documentation: Find out what this does.
 */
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;
}
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 __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 __UNUSED__, void *loop_data,int type, void *event __UNUSED__)
{
   Ecore_Fb_Filter_Data *filter_data;
   
   filter_data = loop_data;
   if (!filter_data) return EINA_TRUE;
   if (type == ECORE_FB_EVENT_MOUSE_MOVE)
     {
	if ((filter_data->last_event_type) == ECORE_FB_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 __UNUSED__, void *loop_data)
{
   Ecore_Fb_Filter_Data *filter_data;
   
   filter_data = loop_data;
   if (filter_data) free(filter_data);
}