1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20// in_sun.c -- SUN/X mouse input handler
21
22#include <sys/time.h>
23#include <sys/types.h>
24#include <unistd.h>
25#include <signal.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <sys/ipc.h>
30#include <sys/shm.h>
31#include <X11/Xlib.h>
32#include <X11/Xutil.h>
33#include <X11/Xatom.h>
34#include <X11/keysym.h>
35
36#include "quakedef.h"
37
38
39//
40// typedefs and defines
41//
42
43#define MOUSE_SCALE		4
44
45//
46// externs
47//
48
49extern Display			*x_disp;
50extern int				x_screen, x_screen_width, x_screen_height;
51extern int			x_center_height, x_center_width;
52extern int				x_std_event_mask;
53extern Window			x_win, x_root_win;
54extern qboolean			x_fullscreen;
55extern qboolean			x_focus;
56extern int			global_dx, global_dy;
57//
58// globals
59//
60
61cvar_t					_windowed_mouse = {"_windowed_mouse","1", true};
62int					x_root, y_root;
63int					x_root_old, y_root_old;
64//
65// locals
66//
67
68static int				x_mouse_num, x_mouse_denom, x_mouse_thresh;
69
70
71static qboolean x_grabbed = false;
72
73//
74// IN_CenterMouse - center the mouse in the screen
75//
76
77void IN_CenterMouse( void )
78{
79	CheckMouseState();
80
81	if (!x_grabbed)
82		return;
83
84	XSelectInput( x_disp, x_win, x_std_event_mask & ~PointerMotionMask );
85	XWarpPointer( x_disp, None, x_root_win, 0, 0, 0, 0, x_center_width,
86		      x_center_height );
87	XSelectInput( x_disp, x_win, x_std_event_mask );
88}
89
90//
91// Check to see if we have grabbed the mouse or not and deal with it
92// appropriately
93//
94static void CheckMouseState(void)
95{
96	if (x_focus && _windowed_mouse.value && !x_grabbed) {
97		x_grabbed = true;
98		printf("fooling with mouse!\n");
99		if (XGetPointerControl( x_disp, &x_mouse_num, &x_mouse_denom, &x_mouse_thresh ))
100			printf( "XGetPointerControl failed!\n" );
101		//printf( "mouse %d/%d thresh %d\n", x_mouse_num, x_mouse_denom, x_mouse_thresh );
102
103		// make input rawer
104		XAutoRepeatOff(x_disp);
105		XGrabKeyboard(x_disp, x_win, True, GrabModeAsync, GrabModeAsync, CurrentTime);
106		XGrabPointer(x_disp, x_win, True,
107			     PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
108			     GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
109
110//		if (XChangePointerControl( x_disp, True, True, 1, MOUSE_SCALE, x_mouse_thresh ))
111//			printf( "XChangePointerControl failed!\n" );
112
113		IN_CenterMouse();
114
115		// safe initial values
116		x_root = x_root_old = vid.width >> 1;
117		y_root = y_root_old = vid.height >> 1;
118	} else if (x_grabbed && (!_windowed_mouse.value || !x_focus)) {
119		printf("fooling with mouse!\n");
120		x_grabbed = false;
121		// undo mouse warp
122		if (XChangePointerControl( x_disp, True, True, x_mouse_num, x_mouse_denom, x_mouse_thresh ))
123			printf( "XChangePointerControl failed!\n" );
124
125		XUngrabPointer( x_disp, CurrentTime );
126		XUngrabKeyboard( x_disp, CurrentTime );
127		XAutoRepeatOn( x_disp );
128	}
129}
130
131
132//
133// IN_Init - setup mouse input
134//
135
136void IN_Init (void)
137{
138    if (!x_disp) Sys_Error( "X display not open!\n" );
139
140    Cvar_RegisterVariable (&_windowed_mouse);
141
142	// we really really want to clean these up...
143    atexit( IN_Shutdown );
144}
145
146//
147// IN_Shutdown - clean up mouse settings (must be done from signal handler too!)
148//
149
150void IN_Shutdown (void)
151{
152    if (!x_disp) return;
153
154	// undo mouse warp
155	if (XChangePointerControl( x_disp, True, True, x_mouse_num, x_mouse_denom, x_mouse_thresh ))
156		printf( "XChangePointerControl failed!\n" );
157
158	XUngrabPointer( x_disp, CurrentTime );
159	XUngrabKeyboard( x_disp, CurrentTime );
160	XAutoRepeatOn( x_disp );
161}
162
163//
164// IN_Commands - process buttons
165//
166
167void IN_Commands (void)
168{
169	// done in X event handler
170}
171
172//
173// IN_Move - process mouse moves
174//
175
176void
177IN_Move (usercmd_t *cmd)
178{
179	static int last_dx, last_dy;
180	static long long last_movement;
181	long long now, gethrtime();
182
183	int dx, dy;
184
185	CheckMouseState();
186
187
188	if (!x_grabbed)
189		return; // no mouse movement
190
191
192	now = gethrtime();
193
194	dx = global_dx;
195	global_dx = 0;
196
197	dy = global_dy;
198	global_dy = 0;
199
200//	printf("GOT: dx %d dy %d\n", dx, dy);
201
202	dx *= sensitivity.value;
203	dy *= sensitivity.value;
204
205//
206//	implement low pass filter to smooth motion a bit
207//
208	if (now - last_movement > 100000000) {
209		dx = .6 * dx;
210		dy = .6 * dy;
211	}
212	last_movement = now;
213
214	dx = .6 * dx + .4 * last_dx;
215	dy = .6 * dy + .4 * last_dy;
216
217
218	last_dx = dx;
219	last_dy = dy;
220
221	if (!dx && !dy) {
222		if (in_mlook.state & 1)
223			V_StopPitchDrift ();
224		return;
225	}
226
227	// add mouse X/Y movement to cmd
228	if ((in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1)))
229		cmd->sidemove += m_side.value * dx;
230	else
231		cl.viewangles[YAW] -= m_yaw.value * dx;
232
233	if (in_mlook.state & 1)
234		V_StopPitchDrift ();
235
236	if ((in_mlook.state & 1) && !(in_strafe.state & 1)) {
237		cl.viewangles[PITCH] += m_pitch.value * dy;
238		if (cl.viewangles[PITCH] > 80) cl.viewangles[PITCH] = 80;
239		if (cl.viewangles[PITCH] < -70) cl.viewangles[PITCH] = -70;
240	}
241	else {
242		if ((in_strafe.state & 1) && noclip_anglehack) cmd->upmove -= m_forward.value * dy;
243		else cmd->forwardmove -= m_forward.value * dy;
244	}
245}
246