Changes for the upcomming 3.73 release - Alex
[terminatorX.git] / src / tX_mouse.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2002  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
26 #include "tX_mouse.h"
27 #include "tX_mastergui.h"
28 #include "tX_global.h"
29 #include "tX_engine.h"
30 #include "tX_vtt.h"
31 #include <sys/wait.h>
32 #include <X11/extensions/xf86dga.h>
33
34 #define TX_MOUSE_SPEED_NORMAL 0.05
35 #define TX_MOUSE_SPEED_WARP 250000
36
37 tx_mouse :: tx_mouse()
38 {
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 {       
57 #ifdef USE_DGA2
58         XDGAMode *mode;
59 #endif  
60         int i, num=0;
61
62         if (grabbed) return(0);
63
64         dpy=XOpenDisplay(NULL); // FIXME: use correct display
65         if (!dpy)
66         {
67                 fputs("GrabMode Error: couldn't connect to XDisplay.", stderr);
68                 return(ENG_ERR_XOPEN);
69         }
70
71
72 #ifdef USE_DGA2
73         mode=XDGAQueryModes(dpy,DefaultScreen(dpy), &num);
74         
75         printf("Found %i DGA2-Modes:\n", num);
76         
77         for(i=0; i<num; i++)
78         {
79                 printf("%2i: %s\n", i, mode[i].name);
80         }
81         XFree(mode);
82 #endif  
83                                 
84         XSelectInput(dpy, xwindow, mask);       
85
86         XSetInputFocus(dpy, xwindow, None, CurrentTime);
87
88         if (globals.xinput_enable)
89         {
90                 if (set_xinput())
91                 {
92                         XCloseDisplay(dpy);
93                         fputs("GrabMode Error: failed to setup XInput.", stderr);
94                         return(ENG_ERR_XINPUT);
95                 }
96         }
97
98         if (GrabSuccess != XGrabPointer(dpy, xwindow, False, ButtonPressMask|ButtonReleaseMask|PointerMotionMask, GrabModeAsync,GrabModeAsync,None,None,CurrentTime))
99         {
100                 reset_xinput();
101                 XCloseDisplay(dpy);
102                 fputs("GrabMode Error: XGrabPointer failed.", stderr);
103                 return(ENG_ERR_GRABMOUSE);
104         }       
105         
106         if (GrabSuccess != XGrabKeyboard(dpy, xwindow, False, GrabModeAsync,GrabModeAsync,CurrentTime))
107         {
108                 XUngrabPointer (dpy, CurrentTime);
109                 reset_xinput();         
110                 XCloseDisplay(dpy);
111                 fputs("GrabMode Error: XGrabKeyboard failed.", stderr);
112                 return(ENG_ERR_GRABKEY);
113         }
114         
115
116 #ifdef USE_DGA2
117         if (!XDGASetMode(dpy, DefaultScreen(dpy), 1))
118 #else   
119         if (!XF86DGADirectVideo(dpy,DefaultScreen(dpy),XF86DGADirectMouse))
120 #endif
121         {
122                 XUngrabKeyboard(dpy, CurrentTime);                              
123                 XUngrabPointer (dpy, CurrentTime);
124                 reset_xinput();         
125                 XCloseDisplay(dpy);
126                 fputs("GrabMode Error: Failed to enable XF86DGA.", stderr);             
127                 return(ENG_ERR_DGA);
128         }
129
130 #ifdef USE_DGA2
131         XDGASelectInput(dpy, DefaultScreen(dpy), mask);
132 #endif  
133
134         XAutoRepeatOff(dpy);    
135         otime=CurrentTime;
136         
137         grabbed=1;
138         vtt_class::focus_no(0);
139         warp=TX_MOUSE_SPEED_NORMAL;
140         
141         return(0);
142 }
143
144 void tx_mouse :: ungrab()
145 {
146         if (!grabbed) return;
147         
148 #ifdef USE_DGA2 
149         XDGASetMode(dpy, DefaultScreen(dpy), 0);
150 #else
151         XF86DGADirectVideo(dpy,DefaultScreen(dpy),0);
152 #endif  
153
154         XUngrabKeyboard(dpy, CurrentTime);              
155         XUngrabPointer (dpy, CurrentTime);
156         XAutoRepeatOn(dpy);
157         
158         XCloseDisplay(dpy);
159
160         if (globals.xinput_enable)
161         {
162                 reset_xinput(); 
163         }
164
165         vtt_class::unfocus();
166
167         grabbed=0;
168 }
169
170 #ifdef USE_XSETPOINTER
171
172 void tx_mouse :: set_x_pointer(char *devname)
173 {
174         pid_t pid;
175         int status;
176                 
177         pid = fork();
178         
179         if (pid==-1) 
180         { 
181                 /* OOPS. fork failed */
182                 perror("tX: Error: Couldn't fork process!");
183                 return; 
184         }
185         
186         if (pid==0) 
187         {
188                 /* The child execlps xsetpointer */
189                 execlp("xsetpointer", "xsetpointer", devname, NULL);
190                 perror("tX: Error: Failed to execute xpointer!");
191                 exit(0);
192         }
193         
194         /* parent waits for xsetpointer to finish */
195         waitpid(pid,  &status, WUNTRACED);
196 }
197
198 #else
199
200 void tx_mouse :: set_x_pointer(char *devname)
201 {
202         XDeviceInfo *devlist;                   
203         XDevice *device;
204         int listmax, i;
205         
206         devlist=XListInputDevices(dpy, &listmax);
207         
208         for (i=0; i<listmax; i++)
209         {
210                 if(strcmp(devlist[i].name, devname)==0)
211                 {
212                         device=XOpenDevice(dpy, devlist[i].id);
213                         if (device)
214                         {
215                                 if (XChangePointerDevice(dpy, device, 0, 1))
216                                 {
217                                         printf("tX: Error: failed to set pointer device.");                     
218                                 }
219                                 XCloseDevice(dpy, device);
220                         }
221                         else
222                         {
223                                 printf("tX: Error: failed to open XInput device.");
224                         }               
225                 }
226         }
227                 
228         XFreeDeviceList(devlist);               
229 }
230
231 #endif
232
233 int tx_mouse :: set_xinput()
234 {
235         XDeviceInfo *devlist;                   
236         int listmax, i;
237         
238         OrgXPointer=0;
239         
240         if (globals.xinput_enable)
241         {       
242                 devlist=XListInputDevices(dpy, &listmax);
243         
244                 for (i=0; i<listmax; i++)
245                 {
246                         if(devlist[i].use == IsXPointer)
247                         {
248                                 OrgXPointer=devlist[i].id;
249                                 strcpy(OrgXPointerName, devlist[i].name);
250                         }
251                 }
252                 
253                 XFreeDeviceList(devlist);               
254                 
255                 set_x_pointer(globals.xinput_device);
256         }
257         
258         if (OrgXPointer==0) printf("tX: Error failed to detect core pointer.");
259         return(0);
260 }
261
262
263 void tx_mouse :: reset_xinput()
264 {
265         if (globals.xinput_enable)
266         {
267                 if (OrgXPointer) set_x_pointer(OrgXPointerName);
268         }
269 }
270
271
272 #define vtt vtt_class::focused_vtt
273
274 int tx_mouse :: check_event()
275 {
276         if (XCheckWindowEvent(dpy, xwindow, mask, &xev))
277         {
278 #ifdef USE_DGA2
279                 puts("Got an event");
280 #endif          
281                 if (vtt)
282                 switch(xev.type)
283                 {
284                         case MotionNotify:
285                                 vtt->xy_input(((f_prec) xmot->x_root)*warp,((f_prec) xmot->y_root)*warp);
286                                 break;
287                         
288                         case ButtonPress:
289                                 switch(xbut->button)
290                                 {
291                                         case 1: if (vtt->is_playing)
292                                                         vtt->set_scratch(1); 
293                                                 else
294                                                         vtt->sp_trigger.receive_input_value(1);
295                                                 break;
296                                         case 2: vtt->sp_mute.receive_input_value(1); break;
297                                         case 3: vtt_class::focus_next(); break;
298                                 }
299                                 break;
300                         
301                         case ButtonRelease:
302                                 switch (xbut->button)
303                                 {       
304                                         case 1: vtt->set_scratch(0); break;
305                                         case 2: vtt->sp_mute.receive_input_value(0); break;
306                                 }
307                                 break;
308                         case KeyPress:
309 #ifdef USE_DGA2
310                                 puts("Yeah its a key");
311                                 XDGAKeyEventToXKeyEvent(xdgakey, (XKeyEvent *) &xev_copy);
312                                 memcpy(&xev, &xev_copy, sizeof(XEvent));
313 #endif                  
314                         {
315                                 key=XKeycodeToKeysym(dpy, xkey->keycode, 0);
316                                 
317                                 switch(key)
318                                 {
319                                         case XK_space: vtt->set_scratch(1); break;
320                                         case XK_Escape: return(1);
321                                         
322                                         case XK_Return: vtt->sp_trigger.receive_input_value(1); break;
323                                         case XK_BackSpace : vtt->sp_trigger.receive_input_value(0); break;
324                                         
325                                         case XK_Tab: vtt_class::focus_next(); break;
326                                         
327                                         case XK_s: vtt->sp_sync_client.receive_input_value(!vtt->is_sync_client); break;
328                                         
329                                         case XK_m:
330                                         case XK_Control_L:
331                                         case XK_Control_R:                                              
332                                         vtt->sp_mute.receive_input_value(1);
333                                         break;
334                                                 
335                                         case XK_Alt_L:
336                                         case XK_Alt_R:
337                                         vtt->sp_mute.receive_input_value(0);
338                                         break;
339                                         
340                                         case XK_w:
341                                         vtt->sp_mute.receive_input_value(1);
342                                         case XK_f: 
343                                         warp=((float) vtt->samples_in_buffer)/TX_MOUSE_SPEED_WARP;      
344                                         vtt->set_scratch(1);
345                                         break;
346                                                 
347                                         case XK_F1: vtt_class::focus_no(0); break;
348                                         case XK_F2: vtt_class::focus_no(1); break;
349                                         case XK_F3: vtt_class::focus_no(2); break;
350                                         case XK_F4: vtt_class::focus_no(3); break;
351                                         case XK_F5: vtt_class::focus_no(4); break;
352                                         case XK_F6: vtt_class::focus_no(5); break;
353                                         case XK_F7: vtt_class::focus_no(6); break;
354                                         case XK_F8: vtt_class::focus_no(7); break;
355                                         case XK_F9: vtt_class::focus_no(8); break;
356                                         case XK_F10: vtt_class::focus_no(9); break;
357                                         case XK_F11: vtt_class::focus_no(10); break;
358                                         case XK_F12: vtt_class::focus_no(11); break;
359                                 }
360                         } break;
361                         
362                         case KeyRelease:
363                         {
364                                 key=XKeycodeToKeysym (dpy, xkey->keycode, 0);
365                                 
366                                 switch(key)
367                                 {
368                                         case XK_space: vtt->set_scratch(0); break;
369                                         
370                                         case XK_m:
371                                         case XK_Control_L:
372                                         case XK_Control_R:                                              
373                                         vtt->sp_mute.receive_input_value(0);
374                                         break;
375                                                 
376                                         case XK_Alt_L:
377                                         case XK_Alt_R:
378                                         vtt->sp_mute.receive_input_value(1);
379                                         break;
380                                         
381                                         case XK_w:
382                                         vtt->sp_mute.receive_input_value(0);
383                                         case XK_f: warp=TX_MOUSE_SPEED_NORMAL;
384                                         vtt->set_scratch(0);
385                                         break;                                  
386                                 }
387                         }
388                 }
389                 else {  puts("no vtt"); return(1); }
390         }
391         return(0);
392 }