Colors customizable - 'w' + 'f' "fix" - Alex
[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         warp_override=false;
63         
64         dpy=XOpenDisplay(NULL);
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         
139         std::list<vtt_class *> :: iterator v;
140         int c=0;
141         
142         for (v=vtt_class::main_list.begin(); v!=vtt_class::main_list.end(); v++) {
143                 if (!(*v)->audio_hidden) {
144                         vtt_class::focus_no(c);
145                         break;
146                 }
147                 c++;
148                 //vtt_class::focus_no(0);
149         }
150         
151         
152         warp=TX_MOUSE_SPEED_NORMAL;
153         
154         tX_debug("tX_mouse::grab(): this: %08x, dpy: %08x", (int) this, (int) dpy);
155         
156         return(0);
157 }
158
159 void tx_mouse :: ungrab()
160 {
161         if (!grabbed) return;
162
163         tX_debug("tX_mouse::ungrab(): this: %08x, dpy: %08x", (int) this, (int) dpy);
164         
165 #ifdef USE_DGA2 
166         XDGASetMode(dpy, DefaultScreen(dpy), 0);
167 #else
168         XF86DGADirectVideo(dpy,DefaultScreen(dpy),0);
169 #endif  
170
171         XUngrabKeyboard(dpy, CurrentTime);              
172         XUngrabPointer (dpy, CurrentTime);
173         XAutoRepeatOn(dpy);
174         
175         XCloseDisplay(dpy);
176
177         if (globals.xinput_enable)
178         {
179                 reset_xinput(); 
180         }
181
182         vtt_class::unfocus();
183
184         tX_debug("tX_mouse::ungrab(): done");
185         
186         grabbed=0;
187 }
188
189 #ifdef USE_XSETPOINTER
190
191 void tx_mouse :: set_x_pointer(char *devname)
192 {
193         pid_t pid;
194         int status;
195                 
196         pid = fork();
197         
198         if (pid==-1) 
199         { 
200                 /* OOPS. fork failed */
201                 perror("tX: Error: Couldn't fork process!");
202                 return; 
203         }
204         
205         if (pid==0) 
206         {
207                 /* The child execlps xsetpointer */
208                 execlp("xsetpointer", "xsetpointer", devname, NULL);
209                 perror("tX: Error: Failed to execute xpointer!");
210                 exit(0);
211         }
212         
213         /* parent waits for xsetpointer to finish */
214         waitpid(pid,  &status, WUNTRACED);
215 }
216
217 #else
218
219 void tx_mouse :: set_x_pointer(char *devname)
220 {
221         XDeviceInfo *devlist;                   
222         XDevice *device;
223         int listmax, i;
224         
225         devlist=XListInputDevices(dpy, &listmax);
226         
227         for (i=0; i<listmax; i++)
228         {
229                 if(strcmp(devlist[i].name, devname)==0)
230                 {
231                         device=XOpenDevice(dpy, devlist[i].id);
232                         if (device)
233                         {
234                                 if (XChangePointerDevice(dpy, device, 0, 1))
235                                 {
236                                         printf("tX: Error: failed to set pointer device.");                     
237                                 }
238                                 XCloseDevice(dpy, device);
239                         }
240                         else
241                         {
242                                 printf("tX: Error: failed to open XInput device.");
243                         }               
244                 }
245         }
246                 
247         XFreeDeviceList(devlist);               
248 }
249
250 #endif
251
252 int tx_mouse :: set_xinput()
253 {
254         XDeviceInfo *devlist;                   
255         int listmax, i;
256         
257         OrgXPointer=0;
258         
259         if (globals.xinput_enable)
260         {       
261                 devlist=XListInputDevices(dpy, &listmax);
262         
263                 for (i=0; i<listmax; i++)
264                 {
265                         if(devlist[i].use == IsXPointer)
266                         {
267                                 OrgXPointer=devlist[i].id;
268                                 strcpy(OrgXPointerName, devlist[i].name);
269                         }
270                 }
271                 
272                 XFreeDeviceList(devlist);               
273                 
274                 set_x_pointer(globals.xinput_device);
275         }
276         
277         if (OrgXPointer==0) printf("tX: Error failed to detect core pointer.");
278         return(0);
279 }
280
281
282 void tx_mouse :: reset_xinput()
283 {
284         if (globals.xinput_enable)
285         {
286                 if (OrgXPointer) set_x_pointer(OrgXPointerName);
287         }
288 }
289
290
291 #define vtt vtt_class::focused_vtt
292
293 int tx_mouse :: check_event()
294 {
295         if (XCheckWindowEvent(dpy, xwindow, mask, &xev))
296         {
297 #ifdef USE_DGA2
298                 puts("Got an event");
299 #endif          
300                 if (vtt)
301                 switch(xev.type)
302                 {
303                         case MotionNotify:
304                                 
305                                 if (warp_override) {
306                                         vtt->sp_speed.handle_mouse_input(((f_prec) xmot->x_root)*globals.mouse_speed*warp);
307                                 } else {
308                                         vtt->xy_input((f_prec) xmot->x_root, (f_prec) xmot->y_root);
309                                 }
310                                 break;
311                         
312                         case ButtonPress:
313                                 switch(xbut->button)
314                                 {
315                                         case 1: if (vtt->is_playing)
316                                                         vtt->set_scratch(1); 
317                                                 else
318                                                         vtt->sp_trigger.receive_input_value(1);
319                                                 break;
320                                         case 2: vtt->sp_mute.receive_input_value(1); break;
321                                         case 3: vtt_class::focus_next(); break;
322                                 }
323                                 break;
324                         
325                         case ButtonRelease:
326                                 switch (xbut->button)
327                                 {       
328                                         case 1: vtt->set_scratch(0); break;
329                                         case 2: vtt->sp_mute.receive_input_value(0); break;
330                                 }
331                                 break;
332                         case KeyPress:
333 #ifdef USE_DGA2
334                                 puts("Yeah its a key");
335                                 XDGAKeyEventToXKeyEvent(xdgakey, (XKeyEvent *) &xev_copy);
336                                 memcpy(&xev, &xev_copy, sizeof(XEvent));
337 #endif                  
338                         {
339                                 key=XKeycodeToKeysym(dpy, xkey->keycode, 0);
340                                 
341                                 switch(key)
342                                 {
343                                         case XK_space: vtt->set_scratch(1); break;
344                                         case XK_Escape: return(1);
345                                         
346                                         case XK_Return: vtt->sp_trigger.receive_input_value(1); break;
347                                         case XK_BackSpace : vtt->sp_trigger.receive_input_value(0); break;
348                                         
349                                         case XK_Tab: vtt_class::focus_next(); break;
350                                         
351                                         case XK_s: vtt->sp_sync_client.receive_input_value(!vtt->is_sync_client); break;
352                                         
353                                         case XK_m:
354                                         case XK_Control_L:
355                                         case XK_Control_R:                                              
356                                         vtt->sp_mute.receive_input_value(1);
357                                         break;
358                                                 
359                                         case XK_Alt_L:
360                                         case XK_Alt_R:
361                                         vtt->sp_mute.receive_input_value(0);
362                                         break;
363                                         
364                                         case XK_w:
365                                         vtt->sp_mute.receive_input_value(1);
366                                         case XK_f: 
367                                         warp_override=true;
368                                         warp=((float) vtt->samples_in_buffer)/TX_MOUSE_SPEED_WARP;      
369                                         vtt->set_scratch(1);
370                                         break;
371                                                 
372                                         case XK_F1: vtt_class::focus_no(0); break;
373                                         case XK_F2: vtt_class::focus_no(1); break;
374                                         case XK_F3: vtt_class::focus_no(2); break;
375                                         case XK_F4: vtt_class::focus_no(3); break;
376                                         case XK_F5: vtt_class::focus_no(4); break;
377                                         case XK_F6: vtt_class::focus_no(5); break;
378                                         case XK_F7: vtt_class::focus_no(6); break;
379                                         case XK_F8: vtt_class::focus_no(7); break;
380                                         case XK_F9: vtt_class::focus_no(8); break;
381                                         case XK_F10: vtt_class::focus_no(9); break;
382                                         case XK_F11: vtt_class::focus_no(10); break;
383                                         case XK_F12: vtt_class::focus_no(11); break;
384                                 }
385                         } break;
386                         
387                         case KeyRelease:
388                         {
389                                 key=XKeycodeToKeysym (dpy, xkey->keycode, 0);
390                                 
391                                 switch(key)
392                                 {
393                                         case XK_space: vtt->set_scratch(0); break;
394                                         
395                                         case XK_m:
396                                         case XK_Control_L:
397                                         case XK_Control_R:                                              
398                                         vtt->sp_mute.receive_input_value(0);
399                                         break;
400                                                 
401                                         case XK_Alt_L:
402                                         case XK_Alt_R:
403                                         vtt->sp_mute.receive_input_value(1);
404                                         break;
405                                         
406                                         case XK_w:
407                                         vtt->sp_mute.receive_input_value(0);
408                                         case XK_f: warp=TX_MOUSE_SPEED_NORMAL;
409                                         warp_override=false;
410                                         vtt->set_scratch(0);
411                                         break;                                  
412                                 }
413                         }
414                 }
415                 else {  puts("no vtt"); return(1); }
416         }
417         return(0);
418 }