1 #include "CtrlCore.h"
2 
3 #ifdef GUI_X11
4 
5 namespace Upp {
6 
7 #define LLOG(x)        //DLOG(x)
8 
9 #define LTIMING(x)     //TIMING(x)
10 
11 static dword sKbdState;
12 static dword sModState;
13 
ClearKbdState_()14 void ClearKbdState_()
15 {
16 	GuiLock __;
17 	sKbdState = 0;
18 }
19 
GetMousePos()20 Point GetMousePos()
21 {
22 	GuiLock __;
23 	LTIMING("GetMousePos");
24 	return Ctrl::mousePos;
25 }
26 
SyncMousePos()27 void Ctrl::SyncMousePos()
28 {
29 	GuiLock __;
30 	LTIMING("XQueryPointer");
31 	int x, y, xx, yy;
32 	Window dm1, dm2;
33 	Ctrl::mousePos = Null;
34 	if(XQueryPointer(Xdisplay, Xroot, &dm1, &dm2, &x, &y, &xx, &yy, &sKbdState))
35 		Ctrl::mousePos = Point(x, y);
36 }
37 
GetShift()38 bool GetShift() { GuiLock __; return sKbdState & ShiftMask; }
GetCtrl()39 bool GetCtrl() { GuiLock __; return sKbdState & ControlMask; }
GetAlt()40 bool GetAlt() { GuiLock __; return sKbdState & Mod1Mask; }
GetCapsLock()41 bool GetCapsLock() { GuiLock __; return sKbdState & LockMask; }
GetMouseLeft()42 bool GetMouseLeft() { GuiLock __; return sModState & Button1Mask; }
GetMouseRight()43 bool GetMouseRight() { GuiLock __; return sModState & (Ctrl::Xbuttons >= 3 ? Button3Mask : Button2Mask); }
GetMouseMiddle()44 bool GetMouseMiddle() { GuiLock __; return sModState & (Ctrl::Xbuttons >= 3 ? Button2Mask : 0); }
45 
46 int   Ctrl::Xbuttontime;
47 Point Ctrl::Xbuttonpos;
48 
KEYtoK(dword key)49 dword Ctrl::KEYtoK(dword key)
50 {
51 	if(key != K_CTRL_KEY && key != K_SHIFT_KEY && key != K_ALT_KEY) {
52 		if(GetCtrl()) key |= K_CTRL;
53 		if(GetAlt()) key |= K_ALT;
54 		if(GetShift()) key |= K_SHIFT;
55 	}
56 	return key;
57 }
58 
SetLastActive(XWindow * w,Ctrl * la)59 void Ctrl::SetLastActive(XWindow *w, Ctrl *la)
60 {
61 	GuiLock __;
62 	while(w) {
63 		LLOG("  to " << UPP::Name(w->ctrl));
64 		w->last_active = la;
65 		w = w->owner ? w->owner->GetXWindow() : NULL;
66 	}
67 }
68 
EventProc(XWindow & w,XEvent * event)69 void Ctrl::EventProc(XWindow& w, XEvent *event)
70 {
71 	GuiLock __;
72 	eventid++;
73 	Ptr<Ctrl> _this = this;
74 	bool pressed = false;
75 	int  count = 1;
76 	switch(event->type) {
77 	case NoExpose:
78 		LLOG("NoExpose serial " << event->xnoexpose.serial);
79 		break;
80 	case GraphicsExpose:
81 		LLOG("GraphicsExpose serial " << event->xgraphicsexpose.serial);
82 	case Expose: {
83 			XExposeEvent& e = event->xexpose;
84 			w.exposed = true;
85 			LLOG("Expose " << RectC(e.x, e.y, e.width, e.height));
86 			Invalidate(w, RectC(e.x, e.y, e.width, e.height));
87 		}
88 		return;
89 	case ConfigureNotify: {
90 			XConfigureEvent& e = event->xconfigure;
91 			int x, y;
92 			Window dummy;
93 // 01/12/2007 - mdelfede
94 // added support for windowed controls
95 //			if(top)
96 //				XTranslateCoordinates(Xdisplay, top->window, Xroot, 0, 0, &x, &y, &dummy);
97 			if(top) {
98 				Window DestW = (parent ? GetParentWindow() : Xroot);
99 				XTranslateCoordinates(Xdisplay, top->window, DestW, 0, 0, &x, &y, &dummy);
100 				Rect rect = RectC(x, y, e.width, e.height);
101 				LLOG("CongigureNotify " << rect);
102 				if(GetRect() != rect)
103 					SetWndRect(rect);
104 				// Synchronizes native windows (NOT the main one)
105 			}
106 			SyncNativeWindows();
107 // 01/12/2007 - END
108 
109 		}
110 		return;
111 	default:
112 		if(!IsEnabled()) return;
113 	}
114 	LTIMING("XUserInput");
115 	switch(event->type) {
116 	case FocusIn:
117 		if(w.xic)
118 			XSetICFocus(w.xic);
119 		break;
120 	case FocusOut:
121 		if(w.xic)
122 			XUnsetICFocus(w.xic);
123 		break;
124 	case KeyPress:
125 		pressed = true;
126 		LLOG("event type:" << event->type << " state:" << event->xkey.state <<
127 		     "keycode:" << event->xkey.keycode);
128 		for(;;) {
129 			XEvent ev1[1], ev2[1];
130 			bool hasev2 = false;
131 			if(!IsWaitingEvent()) break;
132 			do
133 				XNextEvent(Xdisplay, ev1);
134 			while(ev1->type == NoExpose && IsWaitingEvent());
135 			LLOG("ev1 type:" << ev1->type << " state:" << ev1->xkey.state <<
136 			     "keycode:" << ev1->xkey.keycode);
137 			if(ev1->type == KeyPress)
138 				*ev2 = *ev1;
139 			else {
140 				if(ev1->type != KeyRelease ||
141 				   ev1->xkey.state != event->xkey.state ||
142 				   ev1->xkey.keycode != event->xkey.keycode ||
143 				   !IsWaitingEvent()) {
144 					XPutBackEvent(Xdisplay, ev1);
145 					break;
146 				}
147 				do
148 					XNextEvent(Xdisplay, ev2);
149 				while(ev2->type == NoExpose && IsWaitingEvent());
150 				LLOG("ev2 type:" << ev2->type << " state:" << ev2->xkey.state <<
151 				     "keycode:" << ev2->xkey.keycode);
152 				hasev2 = true;
153 			}
154 			if(ev2->type != KeyPress ||
155 			   ev2->xkey.state != event->xkey.state ||
156 			   ev2->xkey.keycode != event->xkey.keycode) {
157 				if(hasev2)
158 					XPutBackEvent(Xdisplay, ev2);
159 				XPutBackEvent(Xdisplay, ev1);
160 				break;
161 			}
162 			else {
163 				XFilterEvent(ev1, None);
164 				if(hasev2)
165 					XFilterEvent(ev2, None);
166 			}
167 			count++;
168 		}
169 	case KeyRelease: {
170 			mousePos = Point(event->xkey.x_root, event->xkey.y_root);
171 			char buff[128];
172 			Xeventtime = event->xkey.time;
173 			LLOG("Key Xeventtime: " << Xeventtime << " count:" << count);
174 			KeySym keysym;
175 			int    chr = 0;
176 			WString wtext;
177 			if(pressed && w.xic) {
178 				Status status;
179 				int len = Xutf8LookupString(w.xic, &event->xkey, buff, sizeof(buff), &keysym, &status);
180 				buff[len] = 0;
181 				if(status == XLookupChars || status == XLookupBoth) {
182 					chr = FromUtf8(buff, len)[0];
183 					if(status == XLookupChars)
184 						wtext = FromUtf8(buff, len);
185 				}
186 				else
187 				if(status != XLookupKeySym && status != XLookupBoth)
188 				    keysym = 0;
189 			}
190 			else {
191 				int len = XLookupString(&event->xkey, buff, sizeof(buff), &keysym, NULL);
192 				buff[len] = 0;
193 				chr = FromUtf8(buff, len)[0];
194 				if(len > 1)
195 					wtext = FromUtf8(buff, len);
196 			}
197 			if(keysym == XK_Control_L || keysym == XK_Control_R) {
198 				keysym = XK_Control_L;
199 				if(pressed)
200 					sKbdState |= ControlMask;
201 				else
202 					sKbdState &= ~ControlMask;
203 			}
204 			if(keysym == XK_Shift_L || keysym == XK_Shift_R) {
205 				keysym = XK_Shift_L;
206 				if(pressed)
207 					sKbdState |= ShiftMask;
208 				else
209 					sKbdState &= ~ShiftMask;
210 			}
211 			if(keysym == XK_Meta_L || keysym == XK_Meta_R || keysym == XK_Alt_L ||
212 			   keysym == XK_Alt_R || keysym == XK_Super_L || keysym == XK_Super_R ||
213 			   keysym == XK_Hyper_L || keysym == XK_Hyper_R || keysym == XK_ISO_Prev_Group) {
214 				keysym = XK_Meta_L;
215 				if(pressed)
216 					sKbdState |= Mod1Mask;
217 				else
218 					sKbdState &= ~Mod1Mask;
219 			}
220 			LLOG("KeySym:" << FormatIntHex(keysym) << " " << (char)keysym << " " << count);
221 			dword up = pressed ? 0 : K_KEYUP;
222 			static struct { KeySym keysym; dword key; } tab[] = {
223 				{ XK_ISO_Left_Tab, K_TAB|K_SHIFT },
224 				{ XK_BackSpace, K_BACKSPACE },
225 				{ XK_Tab, K_TAB },
226 				{ XK_Return, K_ENTER },
227 				{ XK_KP_Enter, K_ENTER },
228 				{ XK_Escape, K_ESCAPE },
229 				{ XK_space, K_SPACE },
230 
231 				{ XK_KP_Space, K_SPACE },
232 				{ XK_KP_Tab, K_TAB },
233 				{ XK_KP_Enter, K_ENTER },
234 				{ XK_KP_F1, K_F1 },
235 				{ XK_KP_F2, K_F2 },
236 				{ XK_KP_F3, K_F3 },
237 				{ XK_KP_F4, K_F4 },
238 				{ XK_KP_Home, K_HOME },
239 				{ XK_KP_Left, K_LEFT },
240 				{ XK_KP_Up, K_UP },
241 				{ XK_KP_Right, K_RIGHT },
242 				{ XK_KP_Down, K_DOWN },
243 				{ XK_KP_Page_Up, K_PAGEUP },
244 				{ XK_KP_Page_Down, K_PAGEDOWN },
245 				{ XK_KP_End, K_END },
246 				{ XK_KP_Begin, K_HOME },
247 				{ XK_KP_Insert, K_INSERT },
248 				{ XK_KP_Delete, K_DELETE },
249 			};
250 			for(int i = 0; i < __countof(tab); i++)
251 				if(tab[i].keysym == keysym) {
252 					DispatchKey(KEYtoK(tab[i].key)|up, count);
253 					return;
254 				}
255 			if(GetShift() && chr == 0) {
256 				static dword k[] = { 41, 33, 64, 35, 36, 37, 94, 38, 42, 40 };
257 				for(int i = 0; i < 10; i++)
258 					if(keysym == k[i]) {
259 						DispatchKey(KEYtoK(i + K_0)|up, count);
260 						return;
261 					}
262 			}
263 		#ifndef PLATFORM_OSX11
264 			if(GetCtrl() || GetAlt()) { // fix Ctrl+Shift+1 etc...
265 				keysym = decode((int)event->xkey.keycode, 0xa, '1', 0xb, '2', 0xc, '3', 0xd, '4',
266 				                0xe, '5', 0xf, '6', 0x10, '7', 0x11, '8', 0x12, '9', 0x13, '0',
267 				                keysym);
268 			}
269 		#endif
270 			// DLOG("keysym: " << keysym << " " << (char)keysym);
271 			if(keysym >= '0' && keysym <= '9' && (chr == 0 || GetCtrl() || GetAlt())) {
272 				DispatchKey(KEYtoK(keysym - '0' + K_0)|up, count);
273 				return;
274 			}
275 			if(chr >= 1 && chr < 32) {
276 				DispatchKey(KEYtoK(chr - 1 + K_CTRL_A)|up, count);
277 				return;
278 			}
279 			if(keysym >= 0xff80 && keysym <= 0xffb9 && chr) {
280 				DispatchKey(KEYtoK(chr)|up, count);
281 				return;
282 			}
283 			if(keysym >= 0xff00 && chr < 128 ||
284 			   (GetCtrl() || GetAlt()) && keysym >= 0x20 && keysym < 0x7f) {
285 				if(keysym >= 'a' && keysym <= 'z')
286 					keysym = keysym - 'a' + 'A';
287 				DispatchKey(KEYtoK(keysym|K_DELTA)|up, count);
288 				return;
289 			}
290 
291 			if((chr == 32 || chr == 9 || chr == 13) && !pressed)
292 				DispatchKey(chr|K_KEYUP, count);
293 			if(chr && pressed) {
294 				DispatchKey(chr, count);
295 				for(int ii = 1; ii < wtext.GetLength(); ii++)
296 					DispatchKey(wtext[ii], count);
297 			}
298 		}
299 		break;
300 	case ButtonPress: {
301 			if(!HasWndFocus() && !popup)
302 				SetWndFocus();
303 			ClickActivateWnd();
304 			mousePos = Point(event->xbutton.x_root, event->xbutton.y_root);
305 			ReleaseGrab();
306 			XButtonEvent& e = event->xbutton;
307 			sModState = e.state;
308 			Xeventtime = e.time;
309 			if(ignoreclick) break;
310 			Point p = Point(e.x, e.y);
311 			dword action = DOWN;
312 			if((dword)e.time - (dword)Xbuttontime < 800) {
313 				action = DOUBLE;
314 				Xbuttontime = Xeventtime - 0x80000000;
315 			}
316 			else {
317 				Xbuttontime = e.time;
318 				Xbuttonpos = mousePos;
319 			}
320 			switch(e.button) {
321 			case Button1:
322 				sModState |= Button1Mask;
323 				DispatchMouse(LEFT|action, p, 0);
324 				break;
325 			case Button2:
326 				sModState |= Button2Mask;
327 				if(Xbuttons < 3)
328 					DispatchMouse(RIGHT|action, p, 0);
329 				else
330 					DispatchMouse(MIDDLE|action, p, 0);
331 				break;
332 			case Button3:
333 				sModState |= Button3Mask;
334 				DispatchMouse(RIGHT|action, p, 0);
335 				break;
336 			}
337 			if(_this) PostInput();
338 		}
339 		break;
340 	case ButtonRelease: {
341 			mousePos = Point(event->xbutton.x_root, event->xbutton.y_root);
342 			XButtonEvent& e = event->xbutton;
343 			sModState = e.state;
344 			Xeventtime = e.time;
345 			Point p = Point(e.x, e.y);
346 			switch(e.button) {
347 			case Button1:
348 				sModState &= ~Button1Mask;
349 				break;
350 			case Button2:
351 				sModState &= ~Button2Mask;
352 				break;
353 			case Button3:
354 				sModState &= ~Button3Mask;
355 				break;
356 			}
357 			if(ignoreclick)
358 				EndIgnore();
359 			else
360 				switch(e.button) {
361 				case Button1:
362 					DispatchMouse(LEFTUP, p, 0);
363 					break;
364 				case Button2:
365 					if(Xbuttons < 3)
366 						DispatchMouse(RIGHTUP, p, 0);
367 					else
368 						DispatchMouse(MIDDLEUP, p, 0);
369 					break;
370 				case Button3:
371 					DispatchMouse(RIGHTUP, p, 0);
372 					break;
373 				case Button4:
374 					DispatchMouse(MOUSEWHEEL, p, 120);
375 					break;
376 				case Button5:
377 					DispatchMouse(MOUSEWHEEL, p, -120);
378 					break;
379 				}
380 			if(_this) PostInput();
381 		}
382 		break;
383 	case MotionNotify:
384 		while(XCheckWindowEvent(Xdisplay, top->window, PointerMotionMask, event));
385 		EndIgnore();
386 		mousePos = Point(event->xmotion.x_root, event->xmotion.y_root);
387 		Xeventtime = event->xmotion.time;
388 		Point p = mousePos - Xbuttonpos;
389 		if(max(abs(p.x), abs(p.y)) > 4)
390 			Xbuttontime = Xeventtime - 0x80000000;
391 		sModState = event->xmotion.state;
392 		DispatchMouse(MOUSEMOVE, Point(event->xmotion.x, event->xmotion.y));
393 		DoCursorShape();
394 		break;
395 	}
396 	DropEvent(w, event);
397 }
398 
399 }
400 
401 #endif
402