e187bfb5a83adbf54c0524d1da860133fa01788e
[terminatorX.git] / src / tX_mouse.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2003  Alexander K├Ânig
4  
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9  
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14  
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  
19     File: tX_mouse.cc
20  
21     Description: This implements the mouse AND keyboard Input handling in
22                  Grab-Mode.
23 */
24
25 #include <sys/wait.h>
26 #include <X11/Xlib.h>
27 #include <X11/extensions/xf86dga.h>
28
29 #include "tX_mouse.h"
30 #include "tX_mastergui.h"
31 #include "tX_global.h"
32 #include "tX_engine.h"
33 #include "tX_vtt.h"
34
35 #define TX_MOUSE_SPEED_NORMAL 0.05
36 #define TX_MOUSE_SPEED_WARP 250000
37
38 tx_mouse :: tx_mouse() {
39         mask=PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask;
40         xmot=(XMotionEvent *) &xev;
41         xkey=(XKeyEvent *) &xev;
42         xbut=(XButtonEvent *) &xev;
43         
44 #ifdef USE_DGA2
45         xdgamot=(XDGAMotionEvent *) &xev;
46         xdgakey=(XDGAKeyEvent *) &xev;
47         xdgabut=(XDGAButtonEvent *) &xev;
48 #endif  
49         
50         grabbed=0;
51         warp=TX_MOUSE_SPEED_NORMAL;
52 }
53
54
55 int tx_mouse :: grab() {        
56 #ifdef USE_DGA2
57         XDGAMode *mode;
58 #endif  
59
60         if (grabbed) return(0);
61
62         dpy=XOpenDisplay(NULL);
63         if (!dpy)
64         {
65                 fputs("GrabMode Error: couldn't connect to XDisplay.", stderr);
66                 return(ENG_ERR_XOPEN);
67         }
68
69
70 #ifdef USE_DGA2
71         mode=XDGAQueryModes(dpy,DefaultScreen(dpy), &num);
72         
73         printf("Found %i DGA2-Modes:\n", num);
74         
75         for(i=0; i<num; i++)
76         {
77                 printf("%2i: %s\n", i, mode[i].name);
78         }
79         XFree(mode);
80 #endif  
81                                 
82         XSelectInput(dpy, xwindow, mask);       
83
84         XSetInputFocus(dpy, xwindow, None, CurrentTime);
85
86         if (globals.xinput_enable)
87         {
88                 if (set_xinput())
89                 {
90                         XCloseDisplay(dpy);
91                         fputs("GrabMode Error: failed to setup XInput.", stderr);
92                         return(ENG_ERR_XINPUT);
93                 }
94         }
95
96         if (GrabSuccess != XGrabPointer(dpy, xwindow, False, ButtonPressMask|ButtonReleaseMask|PointerMotionMask, GrabModeAsync,GrabModeAsync,None,None,CurrentTime))
97         {
98                 reset_xinput();
99                 XCloseDisplay(dpy);
100                 fputs("GrabMode Error: XGrabPointer failed.", stderr);
101                 return(ENG_ERR_GRABMOUSE);
102         }       
103         
104         if (GrabSuccess != XGrabKeyboard(dpy, xwindow, False, GrabModeAsync,GrabModeAsync,CurrentTime))
105         {
106                 XUngrabPointer (dpy, CurrentTime);
107                 reset_xinput();         
108                 XCloseDisplay(dpy);
109                 fputs("GrabMode Error: XGrabKeyboard failed.", stderr);
110                 return(ENG_ERR_GRABKEY);
111         }
112         
113
114 #ifdef USE_DGA2
115         if (!XDGASetMode(dpy, DefaultScreen(dpy), 1))
116 #else   
117         if (!XF86DGADirectVideo(dpy,DefaultScreen(dpy),XF86DGADirectMouse))
118 #endif
119         {
120                 XUngrabKeyboard(dpy, CurrentTime);                              
121                 XUngrabPointer (dpy, CurrentTime);
122                 reset_xinput();         
123                 XCloseDisplay(dpy);
124                 fputs("GrabMode Error: Failed to enable XF86DGA.", stderr);             
125                 return(ENG_ERR_DGA);
126         }
127
128 #ifdef USE_DGA2
129         XDGASelectInput(dpy, DefaultScreen(dpy), mask);
130 #endif  
131
132         XAutoRepeatOff(dpy);    
133         otime=CurrentTime;
134         
135         grabbed=1;
136         
137         std::list<vtt_class *> :: iterator v;
138         int c=0;
139         
140         for (v=vtt_class::main_list.begin(); v!=vtt_class::main_list.end(); v++) {
141                 if (!(*v)->audio_hidden) {
142                         vtt_class::focus_no(c);
143                         break;
144                 }
145                 c++;
146                 //vtt_class::focus_no(0);
147         }
148         
149         
150         warp=TX_MOUSE_SPEED_NORMAL;
151         
152         tX_debug("tX_mouse::grab(): this: %08x, dpy: %08x", (int) this, (int) dpy);
153         
154         return(0);
155 }
156
157 void tx_mouse :: ungrab()
158 {
159         if (!grabbed) return;
160
161         tX_debug("tX_mouse::ungrab(): this: %08x, dpy: %08x", (int) this, (int) dpy);
162         
163 #ifdef USE_DGA2 
164         XDGASetMode(dpy, DefaultScreen(dpy), 0);
165 #else
166         XF86DGADirectVideo(dpy,DefaultScreen(dpy),0);
167 #endif  
168
169         XUngrabKeyboard(dpy, CurrentTime);              
170         XUngrabPointer (dpy, CurrentTime);
171         XAutoRepeatOn(dpy);
172         
173         XCloseDisplay(dpy);
174
175         if (globals.xinput_enable)
176         {
177                 reset_xinput(); 
178         }
179
180         vtt_class::unfocus();
181
182         tX_debug("tX_mouse::ungrab(): done");
183         
184         grabbed=0;
185 }
186
187 #ifdef USE_XSETPOINTER
188
189 void tx_mouse :: set_x_pointer(char *devname)
190 {
191         pid_t pid;
192         int status;
193                 
194         pid = fork();
195         
196         if (pid==-1) 
197         { 
198                 /* OOPS. fork failed */
199                 perror("tX: Error: Couldn't fork process!");
200                 return; 
201         }
202         
203         if (pid==0) 
204         {
205                 /* The child execlps xsetpointer */
206                 execlp("xsetpointer", "xsetpointer", devname, NULL);
207                 perror("tX: Error: Failed to execute xpointer!");
208                 exit(0);
209         }
210         
211         /* parent waits for xsetpointer to finish */
212         waitpid(pid,  &status, WUNTRACED);
213 }
214
215 #else
216
217 void tx_mouse :: set_x_pointer(char *devname)
218 {
219         XDeviceInfo *devlist;                   
220         XDevice *device;
221         int listmax, i;
222         
223         devlist=XListInputDevices(dpy, &listmax);
224         
225         for (i=0; i<listmax; i++)
226         {
227                 if(strcmp(devlist[i].name, devname)==0)
228                 {
229                         device=XOpenDevice(dpy, devlist[i].id);
230                         if (device)
231                         {
232                                 if (XChangePointerDevice(dpy, device, 0, 1))
233                                 {
234                                         printf("tX: Error: failed to set pointer device.");                     
235                                 }
236                                 XCloseDevice(dpy, device);
237                         }
238                         else
239                         {
240                                 printf("tX: Error: failed to open XInput device.");
241                         }               
242                 }
243         }
244                 
245         XFreeDeviceList(devlist);               
246 }
247
248 #endif
249
250 int tx_mouse :: set_xinput()
251 {
252         XDeviceInfo *devlist;                   
253         int listmax, i;
254         
255         OrgXPointer=0;
256         
257         if (globals.xinput_enable)
258         {       
259                 devlist=XListInputDevices(dpy, &listmax);
260         
261                 for (i=0; i<listmax; i++)
262                 {
263                         if(devlist[i].use == IsXPointer)
264                         {
265                                 OrgXPointer=devlist[i].id;
266                                 strcpy(OrgXPointerName, devlist[i].name);
267                         }
268                 }
269                 
270                 XFreeDeviceList(devlist);               
271                 
272                 set_x_pointer(globals.xinput_device);
273         }
274         
275         if (OrgXPointer==0) printf("tX: Error failed to detect core pointer.");
276         return(0);
277 }
278
279
280 void tx_mouse :: reset_xinput()
281 {
282         if (globals.xinput_enable)
283         {
284                 if (OrgXPointer) set_x_pointer(OrgXPointerName);
285         }
286 }
287
288
289 #define vtt vtt_class::focused_vtt
290
291 int tx_mouse :: check_event()
292 {
293         if (XCheckWindowEvent(dpy, xwindow, mask, &xev))
294         {
295 #ifdef USE_DGA2
296                 puts("Got an event");
297 #endif          
298                 if (vtt)
299                 switch(xev.type)
300                 {
301                         case MotionNotify:
302                                 vtt->xy_input(((f_prec) xmot->x_root)*warp,((f_prec) xmot->y_root)*warp);
303                                 break;
304                         
305                         case ButtonPress:
306                                 switch(xbut->button)
307                                 {
308                                         case 1: if (vtt->is_playing)
309                                                         vtt->set_scratch(1); 
310                                                 else
311                                                         vtt->sp_trigger.receive_input_value(1);
312                                                 break;
313                                         case 2: vtt->sp_mute.receive_input_value(1); break;
314                                         case 3: vtt_class::focus_next(); break;
315                                 }
316                                 break;
317                         
318                         case ButtonRelease:
319                                 switch (xbut->button)
320                                 {       
321                                         case 1: vtt->set_scratch(0); break;
322                                         case 2: vtt->sp_mute.receive_input_value(0); break;
323                                 }
324                                 break;
325                         case KeyPress:
326 #ifdef USE_DGA2
327                                 puts("Yeah its a key");
328                                 XDGAKeyEventToXKeyEvent(xdgakey, (XKeyEvent *) &xev_copy);
329                                 memcpy(&xev, &xev_copy, sizeof(XEvent));
330 #endif                  
331                         {
332                                 key=XKeycodeToKeysym(dpy, xkey->keycode, 0);
333                                 
334                                 switch(key)
335                                 {
336                                         case XK_space: vtt->set_scratch(1); break;
337                                         case XK_Escape: return(1);
338                                         
339                                         case XK_Return: vtt->sp_trigger.receive_input_value(1); break;
340                                         case XK_BackSpace : vtt->sp_trigger.receive_input_value(0); break;
341                                         
342                                         case XK_Tab: vtt_class::focus_next(); break;
343                                         
344                                         case XK_s: vtt->sp_sync_client.receive_input_value(!vtt->is_sync_client); break;
345                                         
346                                         case XK_m:
347                                         case XK_Control_L:
348                                         case XK_Control_R:                                              
349                                         vtt->sp_mute.receive_input_value(1);
350                                         break;
351                                                 
352                                         case XK_Alt_L:
353                                         case XK_Alt_R:
354                                         vtt->sp_mute.receive_input_value(0);
355                                         break;
356                                         
357                                         case XK_w:
358                                         vtt->sp_mute.receive_input_value(1);
359                                         case XK_f: 
360                                         warp=((float) vtt->samples_in_buffer)/TX_MOUSE_SPEED_WARP;      
361                                         vtt->set_scratch(1);
362                                         break;
363                                                 
364                                         case XK_F1: vtt_class::focus_no(0); break;
365                                         case XK_F2: vtt_class::focus_no(1); break;
366                                         case XK_F3: vtt_class::focus_no(2); break;
367                                         case XK_F4: vtt_class::focus_no(3); break;
368                                         case XK_F5: vtt_class::focus_no(4); break;
369                                         case XK_F6: vtt_class::focus_no(5); break;
370                                         case XK_F7: vtt_class::focus_no(6); break;
371                                         case XK_F8: vtt_class::focus_no(7); break;
372                                         case XK_F9: vtt_class::focus_no(8); break;
373                                         case XK_F10: vtt_class::focus_no(9); break;
374                                         case XK_F11: vtt_class::focus_no(10); break;
375                                         case XK_F12: vtt_class::focus_no(11); break;
376                                 }
377                         } break;
378                         
379                         case KeyRelease:
380                         {
381                                 key=XKeycodeToKeysym (dpy, xkey->keycode, 0);
382                                 
383                                 switch(key)
384                                 {
385                                         case XK_space: vtt->set_scratch(0); break;
386                                         
387                                         case XK_m:
388                                         case XK_Control_L:
389                                         case XK_Control_R:                                              
390                                         vtt->sp_mute.receive_input_value(0);
391                                         break;
392                                                 
393                                         case XK_Alt_L:
394                                         case XK_Alt_R:
395                                         vtt->sp_mute.receive_input_value(1);
396                                         break;
397                                         
398                                         case XK_w:
399                                         vtt->sp_mute.receive_input_value(0);
400                                         case XK_f: warp=TX_MOUSE_SPEED_NORMAL;
401                                         vtt->set_scratch(0);
402                                         break;                                  
403                                 }
404                         }
405                 }
406                 else {  puts("no vtt"); return(1); }
407         }
408         return(0);
409 }