wip prep commit in lieu of gfx subsystem update changes.
[AROS.git] / arch / all-hosted / hidd / x11 / x11.c
blob393fc74eec1678c2f0e039d20d4b98e1f8c1601d
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: X11 hidd. Connects to the X server and receives events.
6 Lang: English.
7 */
9 #include "x11_debug.h"
11 #include <hardware/intbits.h>
13 #include <X11/keysym.h>
14 #include <signal.h>
16 #include "x11_types.h"
17 #include "x11.h"
18 #include "x11_hostlib.h"
19 #include "x11gfx_fullscreen.h"
21 VOID X11BM_ExposeFB(APTR data, WORD x, WORD y, WORD width, WORD height);
23 /****************************************************************************************/
25 #define BETTER_REPEAT_HANDLING 1
27 #define XTASK_NAME "x11hidd task"
29 /* We need to have highest priority for this task, because we
30 are simulating an interrupt. I.e. an "interrupt handler" called
31 by this task should NEVER be interrupted by a task (for example input.device),
32 otherwise it will give strange effects, especially in the circular-buffer
33 handling in gameport/keyboard. (Writing to the buffer is not atomic even
34 from within the IRQ handler!)
36 Instead of calling
37 the irq handler directly from the task, we should instead
38 Cause() a software irq, but Cause() does not work at the moment..
41 #define XTASK_PRIORITY 50
43 #define XTASK_STACKSIZE 100000
45 #undef XSD
46 #define XSD(cl) xsd
48 /****************************************************************************************/
50 AROS_INTH1(x11VBlank, struct Task *, task)
52 AROS_INTFUNC_INIT
54 DB2(bug("[X11] %s()\n", __PRETTY_FUNCTION__));
56 Signal(task, SIGBREAKF_CTRL_D);
58 return FALSE;
60 AROS_INTFUNC_EXIT
63 /****************************************************************************************/
65 VOID x11task_entry(struct x11task_params *xtpparam)
67 ULONG notifysig;
68 struct MinList nmsg_list;
69 struct MinList xwindowlist;
70 ULONG hostclipboardmask;
71 BOOL f12_down = FALSE;
72 KeySym ks;
74 /* copy needed parameter's because they are allocated on the parent's stack */
76 struct Task *task_Parent = xtpparam->parent;
77 ULONG task_SigKill = xtpparam->kill_signal;
78 struct x11_staticdata *xsd = xtpparam->xsd;
80 struct Interrupt myint;
82 D(bug("[X11] %s()\n", __PRETTY_FUNCTION__));
84 xsd->x11task_notify_port = CreateMsgPort();
85 if (NULL == xsd->x11task_notify_port)
87 D(bug("[X11] %s: failed to create notification port!\n", __PRETTY_FUNCTION__));
88 Signal(task_Parent, xtpparam->fail_signal);
89 return;
92 D(bug("[X11] %s: notification port @ 0x%p\n", __PRETTY_FUNCTION__, xsd->x11task_notify_port));
94 notifysig = 1L << xsd->x11task_notify_port->mp_SigBit;
96 D(bug("[X11] %s: notification signal = %08x (bit %d)\n", __PRETTY_FUNCTION__, notifysig, xsd->x11task_notify_port->mp_SigBit));
98 NEWLIST(&nmsg_list);
99 NEWLIST(&xwindowlist);
101 myint.is_Code = (VOID_FUNC) x11VBlank;
102 myint.is_Data = FindTask(NULL);
103 myint.is_Node.ln_Name = "X11 VBlank server";
104 myint.is_Node.ln_Pri = 0;
105 myint.is_Node.ln_Type = NT_INTERRUPT;
107 AddIntServer(INTB_VERTB, &myint);
109 Signal(task_Parent, xtpparam->ok_signal);
111 /* N.B : do not attempt to use xtpparam after this point! */
113 hostclipboardmask = x11clipboard_init(xsd);
115 for (;;)
117 XEvent event;
118 #if BETTER_REPEAT_HANDLING
119 XEvent keyrelease_event;
120 BOOL keyrelease_pending = FALSE;
121 #endif
122 struct notify_msg *nmsg;
123 ULONG sigs;
125 DB2(bug("[X11] %s: waiting for signals...\n", __PRETTY_FUNCTION__));
127 sigs = Wait(SIGBREAKF_CTRL_D | notifysig | task_SigKill| hostclipboardmask);
129 DB2(bug("[X11] %s: signal %08x received\n", __PRETTY_FUNCTION__, sigs));
131 if (sigs & task_SigKill)
133 D(bug("[X11] %s: kill signal received - exiting\n", __PRETTY_FUNCTION__));
134 break;
137 if (sigs & notifysig)
139 D(bug("[X11] %s: notification signal received\n", __PRETTY_FUNCTION__));
141 while ((nmsg = (struct notify_msg *) GetMsg(xsd->x11task_notify_port)))
143 /* Add the messages to an internal list */
145 switch (nmsg->notify_type)
147 case NOTY_WINCREATE:
149 struct xwinnode * node;
150 /* Maintain a list of open windows for the X11 event handler in x11.c */
152 D(bug("[X11] %s: NOTY_WINCREATE\n", __PRETTY_FUNCTION__));
154 node = AllocMem(sizeof(struct xwinnode), MEMF_CLEAR);
156 if (NULL != node)
158 node->xwindow = nmsg->xwindow;
159 node->masterxwindow = nmsg->masterxwindow;
160 node->bmobj = nmsg->bmobj;
161 AddTail((struct List *) &xwindowlist, (struct Node *) node);
163 else
165 bug("!!!! CANNOT GET MEMORY FOR X11 WIN NODE\n");
166 CCALL(raise, 19);
169 ReplyMsg((struct Message *) nmsg);
170 break;
172 case NOTY_MAPWINDOW:
174 D(bug("[X11] %s: NOTY_MAPWINDOW Window @ 0x%p (Display = 0x%p)\n", __PRETTY_FUNCTION__, nmsg->xwindow, nmsg->xdisplay));
176 LOCK_X11
177 XCALL(XMapWindow, nmsg->xdisplay, nmsg->xwindow);
178 #if ADJUST_XWIN_SIZE
179 XCALL(XMapRaised, nmsg->xdisplay, nmsg->masterxwindow);
180 #endif
181 UNLOCK_X11
183 AddTail((struct List *) &nmsg_list, (struct Node *) nmsg);
185 /* Do not reply message yet */
186 break;
188 case NOTY_RESIZEWINDOW:
190 XWindowChanges xwc;
191 XSizeHints sizehint;
192 BOOL replymsg = TRUE;
194 D(bug("[X11] %s: NOTY_RESIZEWINDOW\n", __PRETTY_FUNCTION__));
196 xwc.width = nmsg->width;
197 xwc.height = nmsg->height;
199 sizehint.flags = PMinSize | PMaxSize;
200 sizehint.min_width = nmsg->width;
201 sizehint.min_height = nmsg->height;
202 sizehint.max_width = nmsg->width;
203 sizehint.max_height = nmsg->height;
205 LOCK_X11
206 if (xsd->options & OPTION_FULLSCREEN)
208 x11_fullscreen_switchmode(nmsg->xdisplay, &xwc.width, &xwc.height);
211 XCALL(XSetWMNormalHints, nmsg->xdisplay, nmsg->masterxwindow, &sizehint);
212 XCALL(XConfigureWindow, nmsg->xdisplay, nmsg->masterxwindow, CWWidth | CWHeight, &xwc);
213 XCALL(XFlush, nmsg->xdisplay);
214 UNLOCK_X11
216 if (xsd->options & OPTION_DELAYXWINMAPPING)
218 struct xwinnode *node;
219 ForeachNode(&xwindowlist, node)
221 if (node->xwindow == nmsg->xwindow)
223 if (!node->window_mapped)
225 LOCK_X11
226 XCALL(XMapWindow, nmsg->xdisplay, nmsg->xwindow);
227 #if ADJUST_XWIN_SIZE
228 XCALL(XMapRaised, nmsg->xdisplay, nmsg->masterxwindow);
229 #endif
230 if (xsd->options & OPTION_FULLSCREEN)
232 XCALL(XGrabKeyboard, nmsg->xdisplay, nmsg->xwindow, False, GrabModeAsync, GrabModeAsync, CurrentTime);
233 XCALL(XGrabPointer, nmsg->xdisplay, nmsg->xwindow, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, nmsg->xwindow, None, CurrentTime);
236 XCALL(XFlush, nmsg->xdisplay);
237 UNLOCK_X11
239 nmsg->notify_type = NOTY_MAPWINDOW;
240 AddTail((struct List *) &nmsg_list, (struct Node *) nmsg);
242 /* Do not reply message yet */
243 replymsg = FALSE;
245 break;
251 if (replymsg)
252 ReplyMsg((struct Message *) nmsg);
254 break;
256 case NOTY_WINDISPOSE:
258 struct xwinnode *node, *safe;
260 D(bug("[X11] %s: NOTY_WINDISPOSE\n", __PRETTY_FUNCTION__));
262 ForeachNodeSafe(&xwindowlist, node, safe)
264 if (node->xwindow == nmsg->xwindow)
266 Remove((struct Node *) node);
267 FreeMem(node, sizeof(struct xwinnode));
270 ReplyMsg((struct Message *) nmsg);
271 break;
273 case NOTY_NEWCURSOR:
275 struct xwinnode *node;
277 D(bug("[X11] %s: NOTY_NEWCURSOR\n",
278 __PRETTY_FUNCTION__));
280 LOCK_X11
281 ForeachNode(&xwindowlist, node)
283 XCALL(XDefineCursor, nmsg->xdisplay, node->xwindow,
284 (Cursor) nmsg->xwindow);
286 XCALL(XFlush, nmsg->xdisplay);
287 UNLOCK_X11
289 ReplyMsg((struct Message *) nmsg);
291 break;
293 } /* switch() */
294 } /* while () */
295 //continue;
296 } /* if (message from notify port) */
298 if (sigs & hostclipboardmask)
300 x11clipboard_handle_commands(xsd);
303 for (;;)
305 struct xwinnode *node;
306 int pending;
307 BOOL window_found = FALSE;
309 LOCK_X11
310 XCALL(XFlush, xsd->display);
311 XCALL(XSync, xsd->display, FALSE);
312 pending = XCALL(XEventsQueued, xsd->display, QueuedAlready);
313 UNLOCK_X11
315 if (pending == 0)
317 #if BETTER_REPEAT_HANDLING
318 if (keyrelease_pending)
320 LOCK_X11
321 if (XCALL(XLookupKeysym, (XKeyEvent *)&keyrelease_event, 0)
322 == XK_F12)
324 f12_down = FALSE;
326 UNLOCK_X11
328 ObtainSemaphoreShared(&xsd->sema);
329 if (xsd->kbdhidd)
331 Hidd_Kbd_X11_HandleEvent(xsd->kbdhidd, &keyrelease_event);
333 ReleaseSemaphore(&xsd->sema);
334 keyrelease_pending = FALSE;
336 #endif
338 /* Get out of for(;;) loop */
339 break;
342 LOCK_X11
343 XCALL(XNextEvent, xsd->display, &event);
344 UNLOCK_X11
346 D(bug("Got Event for X=%d\n", event.xany.window));
348 #if BETTER_REPEAT_HANDLING
349 if (keyrelease_pending)
351 BOOL repeated_key = FALSE;
353 /* Saw this in SDL/X11 code, where a comment says that
354 the idea for this was coming from GII, whatever that
355 is. */
357 if ((event.xany.window == keyrelease_event.xany.window)
358 && (event.type == KeyPress)
359 && (event.xkey.keycode == keyrelease_event.xkey.keycode)
360 && ((event.xkey.time - keyrelease_event.xkey.time) < 2))
362 repeated_key = TRUE;
365 keyrelease_pending = FALSE;
367 if (repeated_key)
369 /* Drop both previous keyrelease and this keypress event. */
370 continue;
373 LOCK_X11
374 if (XCALL(XLookupKeysym, (XKeyEvent *)&keyrelease_event, 0)
375 == XK_F12)
377 f12_down = FALSE;
379 UNLOCK_X11
381 ObtainSemaphoreShared(&xsd->sema);
382 if (xsd->kbdhidd)
384 Hidd_Kbd_X11_HandleEvent(xsd->kbdhidd, &keyrelease_event);
386 ReleaseSemaphore(&xsd->sema);
388 #endif
390 if (event.type == MappingNotify)
392 LOCK_X11
393 XCALL(XRefreshKeyboardMapping, (XMappingEvent*)&event);
394 UNLOCK_X11
396 continue;
399 #if ADJUST_XWIN_SIZE
400 /* Must check this here, because below only the inner
401 window events are recognized */
403 if ((event.type == ClientMessage) && (event.xclient.data.l[0] == xsd->delete_win_atom))
405 D(bug("Shutting down AROS\n"));
406 CCALL(raise, SIGINT);
409 /* Redirect focus from outer window to inner window. This allows
410 keys to be seen without the mouse hovering over the window */
411 if (event.type == FocusIn)
413 ForeachNode(&xwindowlist, node)
415 if (node->masterxwindow == event.xfocus.window)
417 LOCK_X11
418 XCALL(XSetInputFocus, xsd->display, node->xwindow,
419 RevertToParent, CurrentTime);
420 UNLOCK_X11
421 break;
425 #endif
427 ForeachNode(&xwindowlist, node)
429 if (node->xwindow == event.xany.window)
431 window_found = TRUE;
432 break;
436 if (x11clipboard_want_event(&event))
438 x11clipboard_handle_event(xsd, &event);
441 if (window_found)
443 D(bug("Got event for window %x\n", event.xany.window));
444 switch (event.type)
446 case GraphicsExpose:
447 break;
449 case Expose:
450 LOCK_X11
451 X11BM_ExposeFB(OOP_INST_DATA(OOP_OCLASS(node->bmobj), node->bmobj), event.xexpose.x,
452 event.xexpose.y, event.xexpose.width, event.xexpose.height);
453 UNLOCK_X11
454 break;
456 case ConfigureRequest:
457 bug("!!! CONFIGURE REQUEST !!\n");
458 break;
460 #if 0
461 /* stegerg: not needed */
462 case ConfigureNotify:
464 /* The window has been resized */
466 XConfigureEvent *me;
467 struct notify_msg *nmsg, *safe;
469 me = (XConfigureEvent *)&event;
470 ForeachNodeSafe(&nmsg_list, nmsg, safe)
472 if ( me->window == nmsg->xwindow
473 && nmsg->notify_type == NOTY_RESIZEWINDOW)
475 /* The window has now been mapped.
476 Send reply to app */
478 Remove((struct Node *)nmsg);
479 ReplyMsg((struct Message *)nmsg);
483 break;
485 #endif
487 case ButtonPress:
488 xsd->x_time = event.xbutton.time;
489 D(bug("ButtonPress event\n"));
491 ObtainSemaphoreShared(&xsd->sema);
492 if (xsd->mousehidd)
493 Hidd_Mouse_X11_HandleEvent(xsd->mousehidd, &event);
494 ReleaseSemaphore(&xsd->sema);
495 break;
497 case ButtonRelease:
498 xsd->x_time = event.xbutton.time;
499 D(bug("ButtonRelease event\n"));
501 ObtainSemaphoreShared(&xsd->sema);
502 if (xsd->mousehidd)
503 Hidd_Mouse_X11_HandleEvent(xsd->mousehidd, &event);
504 ReleaseSemaphore(&xsd->sema);
505 break;
507 case MotionNotify:
508 xsd->x_time = event.xmotion.time;
509 D(bug("Motionnotify event\n"));
511 ObtainSemaphoreShared(&xsd->sema);
512 if (xsd->mousehidd)
513 Hidd_Mouse_X11_HandleEvent(xsd->mousehidd, &event);
514 ReleaseSemaphore(&xsd->sema);
515 break;
517 case FocusOut:
518 #if !BETTER_REPEAT_HANDLING
519 LOCK_X11
520 XCALL(XAutoRepeatOn, xsd->display);
521 UNLOCK_X11
522 #endif
523 break;
525 case FocusIn:
526 /* Call the user supplied callback func, if supplied */
527 if (NULL != xsd->activecallback)
529 xsd->activecallback(xsd->callbackdata, NULL);
531 break;
533 case KeyPress:
534 xsd->x_time = event.xkey.time;
536 LOCK_X11
537 #if !BETTER_REPEAT_HANDLING
538 XCALL(XAutoRepeatOff, XSD(cl)->display);
539 #endif
540 ks = XCALL(XLookupKeysym, (XKeyEvent *)&event, 0);
541 if (ks == XK_F12)
543 f12_down = TRUE;
545 else if (f12_down && ((ks == XK_Q) || (ks == XK_q)))
547 CCALL(raise, SIGINT);
549 UNLOCK_X11
551 ObtainSemaphoreShared(&xsd->sema);
552 if (xsd->kbdhidd)
554 Hidd_Kbd_X11_HandleEvent(xsd->kbdhidd, &event);
556 ReleaseSemaphore(&xsd->sema);
557 break;
559 case KeyRelease:
560 xsd->x_time = event.xkey.time;
562 #if BETTER_REPEAT_HANDLING
563 keyrelease_pending = TRUE;
564 keyrelease_event = event;
565 #else
566 LOCK_X11
567 if (XCALL(XLookupKeysym, &event, 0) == XK_F12)
569 f12_down = FALSE;
571 XCALL(XAutoRepeatOn, XSD(cl)->display);
572 UNLOCK_X11
574 ObtainSemaphoreShared( &xsd->sema );
575 if (xsd->kbdhidd)
577 Hidd_Kbd_X11_HandleEvent(xsd->kbdhidd, &event);
579 ReleaseSemaphore( &xsd->sema );
580 #endif
581 break;
583 case EnterNotify:
584 break;
586 case LeaveNotify:
587 break;
589 case MapNotify:
592 XMapEvent *me;
593 struct notify_msg *nmsg, *safe;
594 struct xwinnode *node;
596 me = (XMapEvent *) &event;
598 ForeachNodeSafe(&nmsg_list, nmsg, safe)
600 if (me->window == nmsg->xwindow && nmsg->notify_type == NOTY_MAPWINDOW)
602 /* The window has now been mapped.
603 Send reply to app */
605 Remove((struct Node *) nmsg);
606 ReplyMsg((struct Message *) nmsg);
610 /* Find it in the window list and mark it as mapped */
612 ForeachNode(&xwindowlist, node)
614 if (node->xwindow == me->window)
616 node->window_mapped = TRUE;
620 break;
623 #if !ADJUST_XWIN_SIZE
624 case ClientMessage:
625 if (event.xclient.data.l[0] == xsd->delete_win_atom)
627 CCALL(raise, SIGINT);
629 break;
630 #endif
632 } /* switch (X11 event type) */
634 } /* if (is event for HIDD window) */
636 } /* while (events from X) */
638 } /* Forever */
640 /* Also try to free window node list ? */
641 if (xsd->x11task_notify_port)
643 DeleteMsgPort(xsd->x11task_notify_port);
647 /****************************************************************************************/
649 struct Task *create_x11task(struct x11task_params *params)
651 struct Task *task;
653 D(bug("[X11] %s()\n", __PRETTY_FUNCTION__));
655 task = NewCreateTask(TASKTAG_PC, x11task_entry, TASKTAG_STACKSIZE,
656 XTASK_STACKSIZE, TASKTAG_NAME, XTASK_NAME, TASKTAG_PRI,
657 XTASK_PRIORITY, TASKTAG_ARG1, params, TAG_DONE);
658 if (task)
660 D(bug("[X11] %s: task @ 0x%p\n", __PRETTY_FUNCTION__, task));
662 /* Everything went OK. Wait for task to initialize */
663 ULONG sigset;
665 sigset = Wait(params->ok_signal | params->fail_signal);
666 if (sigset & params->ok_signal)
668 D(bug("[X11] %s: got ok signal\n", __PRETTY_FUNCTION__));
670 return task;
673 return NULL;
676 /****************************************************************************************/