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