Added a test for MUIA_Listview_SelectChange.
[AROS.git] / arch / all-hosted / hidd / x11 / x11.c
blob847c1ae24b49a7ddb3a650a40a7d3e54734eaa33
1 /*
2 Copyright © 1995-2015, 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 <proto/exec.h>
12 #include <proto/oop.h>
13 #include <proto/utility.h>
15 #define size_t aros_size_t
16 #include <hidd/hidd.h>
18 #include <oop/ifmeta.h>
20 #include <dos/dos.h>
22 #include <exec/types.h>
23 #include <exec/lists.h>
24 #include <exec/memory.h>
25 #include <exec/libraries.h>
26 #include <exec/resident.h>
27 #include <hardware/intbits.h>
28 #include <utility/utility.h>
30 #include <aros/asmcall.h>
31 #undef size_t
33 #define timeval sys_timevalinit_x11class
34 #include <sys/types.h>
35 #include <signal.h>
36 #include <stddef.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #undef timeval
43 #include <X11/Xlib.h>
44 #include <X11/Xutil.h>
45 #include <X11/Xatom.h>
46 #include <X11/keysym.h>
48 #include "x11.h"
49 #include "fullscreen.h"
50 #include "x11gfx_intern.h"
52 VOID X11BM_ExposeFB(APTR data, WORD x, WORD y, WORD width, WORD height);
54 /****************************************************************************************/
56 #define BETTER_REPEAT_HANDLING 1
58 #define XTASK_NAME "x11hidd task"
60 /* We need to have highest priority for this task, because we
61 are simulating an interrupt. I.e. an "interrupt handler" called
62 by this task should NEVER be interrupted by a task (for example input.device),
63 otherwise it will give strange effects, especially in the circular-buffer
64 handling in gameport/keyboard. (Writing to the buffer is not atomic even
65 from within the IRQ handler!)
67 Instead of calling
68 the irq handler directly from the task, we should instead
69 Cause() a software irq, but Cause() does not work at the moment..
72 #define XTASK_PRIORITY 50
74 #define XTASK_STACKSIZE (AROS_STACKSIZE)
76 #undef XSD
77 #define XSD(cl) xsd
79 /****************************************************************************************/
81 AROS_INTH1(x11VBlank, struct Task *, task)
83 AROS_INTFUNC_INIT
85 DB2(bug("[X11] %s()\n", __PRETTY_FUNCTION__));
87 Signal(task, SIGBREAKF_CTRL_D);
89 return FALSE;
91 AROS_INTFUNC_EXIT
94 /****************************************************************************************/
96 VOID x11task_entry(struct x11task_params *xtpparam)
98 ULONG notifysig;
99 struct MinList nmsg_list;
100 struct MinList xwindowlist;
101 ULONG hostclipboardmask;
102 BOOL f12_down = FALSE;
103 KeySym ks;
105 /* copy needed parameter's because they are allocated on the parent's stack */
107 struct Task *task_Parent = xtpparam->parent;
108 ULONG task_SigKill = xtpparam->kill_signal;
109 struct x11_staticdata *xsd = xtpparam->xsd;
111 struct Interrupt myint;
113 D(bug("[X11] %s()\n", __PRETTY_FUNCTION__));
115 xsd->x11task_notify_port = CreateMsgPort();
116 if (NULL == xsd->x11task_notify_port)
118 D(bug("[X11] %s: failed to create notification port!\n", __PRETTY_FUNCTION__));
119 Signal(task_Parent, xtpparam->fail_signal);
120 return;
123 D(bug("[X11] %s: notification port @ 0x%p\n", __PRETTY_FUNCTION__, xsd->x11task_notify_port));
125 notifysig = 1L << xsd->x11task_notify_port->mp_SigBit;
127 D(bug("[X11] %s: notification signal = %08x (bit %d)\n", __PRETTY_FUNCTION__, notifysig, xsd->x11task_notify_port->mp_SigBit));
129 NEWLIST(&nmsg_list);
130 NEWLIST(&xwindowlist);
132 myint.is_Code = (VOID_FUNC) x11VBlank;
133 myint.is_Data = FindTask(NULL);
134 myint.is_Node.ln_Name = "X11 VBlank server";
135 myint.is_Node.ln_Pri = 0;
136 myint.is_Node.ln_Type = NT_INTERRUPT;
138 AddIntServer(INTB_VERTB, &myint);
140 Signal(task_Parent, xtpparam->ok_signal);
142 /* N.B : do not attempt to use xtpparam after this point! */
144 hostclipboardmask = x11clipboard_init(xsd);
146 for (;;)
148 XEvent event;
149 #if BETTER_REPEAT_HANDLING
150 XEvent keyrelease_event;
151 BOOL keyrelease_pending = FALSE;
152 #endif
153 struct notify_msg *nmsg;
154 ULONG sigs;
156 DB2(bug("[X11] %s: waiting for signals...\n", __PRETTY_FUNCTION__));
158 sigs = Wait(SIGBREAKF_CTRL_D | notifysig | task_SigKill| hostclipboardmask);
160 DB2(bug("[X11] %s: signal %08x received\n", __PRETTY_FUNCTION__, sigs));
162 if (sigs & task_SigKill)
164 D(bug("[X11] %s: kill signal received - exiting\n", __PRETTY_FUNCTION__));
165 break;
168 if (sigs & notifysig)
170 D(bug("[X11] %s: notification signal received\n", __PRETTY_FUNCTION__));
172 while ((nmsg = (struct notify_msg *) GetMsg(xsd->x11task_notify_port)))
174 /* Add the messages to an internal list */
176 switch (nmsg->notify_type)
178 case NOTY_WINCREATE:
180 struct xwinnode * node;
181 /* Maintain a list of open windows for the X11 event handler in x11.c */
183 D(bug("[X11] %s: NOTY_WINCREATE\n", __PRETTY_FUNCTION__));
185 node = AllocMem(sizeof(struct xwinnode), MEMF_CLEAR);
187 if (NULL != node)
189 node->xwindow = nmsg->xwindow;
190 node->masterxwindow = nmsg->masterxwindow;
191 node->bmobj = nmsg->bmobj;
192 AddTail((struct List *) &xwindowlist, (struct Node *) node);
194 else
196 bug("!!!! CANNOT GET MEMORY FOR X11 WIN NODE\n");
197 CCALL(raise, 19);
200 ReplyMsg((struct Message *) nmsg);
201 break;
203 case NOTY_MAPWINDOW:
205 D(bug("[X11] %s: NOTY_MAPWINDOW Window @ 0x%p (Display = 0x%p)\n", __PRETTY_FUNCTION__, nmsg->xwindow, nmsg->xdisplay));
207 LOCK_X11
208 XCALL(XMapWindow, nmsg->xdisplay, nmsg->xwindow);
209 #if ADJUST_XWIN_SIZE
210 XCALL(XMapRaised, nmsg->xdisplay, nmsg->masterxwindow);
211 #endif
212 UNLOCK_X11
214 AddTail((struct List *) &nmsg_list, (struct Node *) nmsg);
216 /* Do not reply message yet */
217 break;
219 case NOTY_RESIZEWINDOW:
221 XWindowChanges xwc;
222 XSizeHints sizehint;
223 BOOL replymsg = TRUE;
225 D(bug("[X11] %s: NOTY_RESIZEWINDOW\n", __PRETTY_FUNCTION__));
227 xwc.width = nmsg->width;
228 xwc.height = nmsg->height;
230 sizehint.flags = PMinSize | PMaxSize;
231 sizehint.min_width = nmsg->width;
232 sizehint.min_height = nmsg->height;
233 sizehint.max_width = nmsg->width;
234 sizehint.max_height = nmsg->height;
236 LOCK_X11
237 if (xsd->options & OPTION_FULLSCREEN)
239 x11_fullscreen_switchmode(nmsg->xdisplay, &xwc.width, &xwc.height);
242 XCALL(XSetWMNormalHints, nmsg->xdisplay, nmsg->masterxwindow, &sizehint);
243 XCALL(XConfigureWindow, nmsg->xdisplay, nmsg->masterxwindow, CWWidth | CWHeight, &xwc);
244 XCALL(XFlush, nmsg->xdisplay);
245 UNLOCK_X11
247 if (xsd->options & OPTION_DELAYXWINMAPPING)
249 struct xwinnode *node;
250 ForeachNode(&xwindowlist, node)
252 if (node->xwindow == nmsg->xwindow)
254 if (!node->window_mapped)
256 LOCK_X11
257 XCALL(XMapWindow, nmsg->xdisplay, nmsg->xwindow);
258 #if ADJUST_XWIN_SIZE
259 XCALL(XMapRaised, nmsg->xdisplay, nmsg->masterxwindow);
260 #endif
261 if (xsd->options & OPTION_FULLSCREEN)
263 XCALL(XGrabKeyboard, nmsg->xdisplay, nmsg->xwindow, False, GrabModeAsync, GrabModeAsync, CurrentTime);
264 XCALL(XGrabPointer, nmsg->xdisplay, nmsg->xwindow, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, nmsg->xwindow, None, CurrentTime);
267 XCALL(XFlush, nmsg->xdisplay);
268 UNLOCK_X11
270 nmsg->notify_type = NOTY_MAPWINDOW;
271 AddTail((struct List *) &nmsg_list, (struct Node *) nmsg);
273 /* Do not reply message yet */
274 replymsg = FALSE;
276 break;
282 if (replymsg)
283 ReplyMsg((struct Message *) nmsg);
285 break;
287 case NOTY_WINDISPOSE:
289 struct xwinnode *node, *safe;
291 D(bug("[X11] %s: NOTY_WINDISPOSE\n", __PRETTY_FUNCTION__));
293 ForeachNodeSafe(&xwindowlist, node, safe)
295 if (node->xwindow == nmsg->xwindow)
297 Remove((struct Node *) node);
298 FreeMem(node, sizeof(struct xwinnode));
301 ReplyMsg((struct Message *) nmsg);
302 break;
304 } /* switch() */
305 } /* while () */
306 //continue;
307 } /* if (message from notify port) */
309 if (sigs & hostclipboardmask)
311 x11clipboard_handle_commands(xsd);
314 for (;;)
316 struct xwinnode *node;
317 int pending;
318 BOOL window_found = FALSE;
320 LOCK_X11
321 XCALL(XFlush, xsd->display);
322 XCALL(XSync, xsd->display, FALSE);
323 pending = XCALL(XEventsQueued, xsd->display, QueuedAlready);
324 UNLOCK_X11
326 if (pending == 0)
328 #if BETTER_REPEAT_HANDLING
329 if (keyrelease_pending)
331 LOCK_X11
332 if (XCALL(XLookupKeysym, (XKeyEvent *)&keyrelease_event, 0)
333 == XK_F12)
335 f12_down = FALSE;
337 UNLOCK_X11
339 ObtainSemaphoreShared(&xsd->sema);
340 if (xsd->kbdhidd)
342 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &keyrelease_event);
344 ReleaseSemaphore(&xsd->sema);
345 keyrelease_pending = FALSE;
347 #endif
349 /* Get out of for(;;) loop */
350 break;
353 LOCK_X11
354 XCALL(XNextEvent, xsd->display, &event);
355 UNLOCK_X11
357 D(bug("Got Event for X=%d\n", event.xany.window));
359 #if BETTER_REPEAT_HANDLING
360 if (keyrelease_pending)
362 BOOL repeated_key = FALSE;
364 /* Saw this in SDL/X11 code, where a comment says that
365 the idea for this was coming from GII, whatever that
366 is. */
368 if ((event.xany.window == keyrelease_event.xany.window)
369 && (event.type == KeyPress)
370 && (event.xkey.keycode == keyrelease_event.xkey.keycode)
371 && ((event.xkey.time - keyrelease_event.xkey.time) < 2))
373 repeated_key = TRUE;
376 keyrelease_pending = FALSE;
378 if (repeated_key)
380 /* Drop both previous keyrelease and this keypress event. */
381 continue;
384 LOCK_X11
385 if (XCALL(XLookupKeysym, (XKeyEvent *)&keyrelease_event, 0)
386 == XK_F12)
388 f12_down = FALSE;
390 UNLOCK_X11
392 ObtainSemaphoreShared(&xsd->sema);
393 if (xsd->kbdhidd)
395 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &keyrelease_event);
397 ReleaseSemaphore(&xsd->sema);
399 #endif
401 if (event.type == MappingNotify)
403 LOCK_X11
404 XCALL(XRefreshKeyboardMapping, (XMappingEvent*)&event);
405 UNLOCK_X11
407 continue;
410 #if ADJUST_XWIN_SIZE
411 /* Must check this here, because below only the inner
412 window events are recognized */
414 if ((event.type == ClientMessage) && (event.xclient.data.l[0] == xsd->delete_win_atom))
416 D(bug("Shutting down AROS\n"));
417 CCALL(raise, SIGINT);
420 /* Redirect focus from outer window to inner window. This allows
421 keys to be seen without the mouse hovering over the window */
422 if (event.type == FocusIn)
424 ForeachNode(&xwindowlist, node)
426 if (node->masterxwindow == event.xfocus.window)
428 LOCK_X11
429 XCALL(XSetInputFocus, xsd->display, node->xwindow,
430 RevertToParent, CurrentTime);
431 UNLOCK_X11
432 break;
436 #endif
438 ForeachNode(&xwindowlist, node)
440 if (node->xwindow == event.xany.window)
442 window_found = TRUE;
443 break;
447 if (x11clipboard_want_event(&event))
449 x11clipboard_handle_event(xsd, &event);
452 if (window_found)
454 D(bug("Got event for window %x\n", event.xany.window));
455 switch (event.type)
457 case GraphicsExpose:
458 break;
460 case Expose:
461 LOCK_X11
462 X11BM_ExposeFB(OOP_INST_DATA(OOP_OCLASS(node->bmobj), node->bmobj), event.xexpose.x,
463 event.xexpose.y, event.xexpose.width, event.xexpose.height);
464 UNLOCK_X11
465 break;
467 case ConfigureRequest:
468 bug("!!! CONFIGURE REQUEST !!\n");
469 break;
471 #if 0
472 /* stegerg: not needed */
473 case ConfigureNotify:
475 /* The window has been resized */
477 XConfigureEvent *me;
478 struct notify_msg *nmsg, *safe;
480 me = (XConfigureEvent *)&event;
481 ForeachNodeSafe(&nmsg_list, nmsg, safe)
483 if ( me->window == nmsg->xwindow
484 && nmsg->notify_type == NOTY_RESIZEWINDOW)
486 /* The window has now been mapped.
487 Send reply to app */
489 Remove((struct Node *)nmsg);
490 ReplyMsg((struct Message *)nmsg);
494 break;
496 #endif
498 case ButtonPress:
499 xsd->x_time = event.xbutton.time;
500 D(bug("ButtonPress event\n"));
502 ObtainSemaphoreShared(&xsd->sema);
503 if (xsd->mousehidd)
504 Hidd_X11Mouse_HandleEvent(xsd->mousehidd, &event);
505 ReleaseSemaphore(&xsd->sema);
506 break;
508 case ButtonRelease:
509 xsd->x_time = event.xbutton.time;
510 D(bug("ButtonRelease event\n"));
512 ObtainSemaphoreShared(&xsd->sema);
513 if (xsd->mousehidd)
514 Hidd_X11Mouse_HandleEvent(xsd->mousehidd, &event);
515 ReleaseSemaphore(&xsd->sema);
516 break;
518 case MotionNotify:
519 xsd->x_time = event.xmotion.time;
520 D(bug("Motionnotify event\n"));
522 ObtainSemaphoreShared(&xsd->sema);
523 if (xsd->mousehidd)
524 Hidd_X11Mouse_HandleEvent(xsd->mousehidd, &event);
525 ReleaseSemaphore(&xsd->sema);
526 break;
528 case FocusOut:
529 #if !BETTER_REPEAT_HANDLING
530 LOCK_X11
531 XCALL(XAutoRepeatOn, xsd->display);
532 UNLOCK_X11
533 #endif
534 break;
536 case FocusIn:
537 /* Call the user supplied callback func, if supplied */
538 if (NULL != xsd->activecallback)
540 xsd->activecallback(xsd->callbackdata, NULL);
542 break;
544 case KeyPress:
545 xsd->x_time = event.xkey.time;
547 LOCK_X11
548 #if !BETTER_REPEAT_HANDLING
549 XCALL(XAutoRepeatOff, XSD(cl)->display);
550 #endif
551 ks = XCALL(XLookupKeysym, (XKeyEvent *)&event, 0);
552 if (ks == XK_F12)
554 f12_down = TRUE;
556 else if (f12_down && ((ks == XK_Q) || (ks == XK_q)))
558 CCALL(raise, SIGINT);
560 UNLOCK_X11
562 ObtainSemaphoreShared(&xsd->sema);
563 if (xsd->kbdhidd)
565 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &event);
567 ReleaseSemaphore(&xsd->sema);
568 break;
570 case KeyRelease:
571 xsd->x_time = event.xkey.time;
573 #if BETTER_REPEAT_HANDLING
574 keyrelease_pending = TRUE;
575 keyrelease_event = event;
576 #else
577 LOCK_X11
578 if (XCALL(XLookupKeysym, &event, 0) == XK_F12)
580 f12_down = FALSE;
582 XCALL(XAutoRepeatOn, XSD(cl)->display);
583 UNLOCK_X11
585 ObtainSemaphoreShared( &xsd->sema );
586 if (xsd->kbdhidd)
588 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &event);
590 ReleaseSemaphore( &xsd->sema );
591 #endif
592 break;
594 case EnterNotify:
595 break;
597 case LeaveNotify:
598 break;
600 case MapNotify:
603 XMapEvent *me;
604 struct notify_msg *nmsg, *safe;
605 struct xwinnode *node;
607 me = (XMapEvent *) &event;
609 ForeachNodeSafe(&nmsg_list, nmsg, safe)
611 if (me->window == nmsg->xwindow && nmsg->notify_type == NOTY_MAPWINDOW)
613 /* The window has now been mapped.
614 Send reply to app */
616 Remove((struct Node *) nmsg);
617 ReplyMsg((struct Message *) nmsg);
621 /* Find it in the window list and mark it as mapped */
623 ForeachNode(&xwindowlist, node)
625 if (node->xwindow == me->window)
627 node->window_mapped = TRUE;
631 break;
634 #if !ADJUST_XWIN_SIZE
635 case ClientMessage:
636 if (event.xclient.data.l[0] == xsd->delete_win_atom)
638 CCALL(raise, SIGINT);
640 break;
641 #endif
643 } /* switch (X11 event type) */
645 } /* if (is event for HIDD window) */
647 } /* while (events from X) */
649 } /* Forever */
651 /* Also try to free window node list ? */
652 if (xsd->x11task_notify_port)
654 DeleteMsgPort(xsd->x11task_notify_port);
658 /****************************************************************************************/
660 struct Task *create_x11task(struct x11task_params *params)
662 struct Task *task;
664 D(bug("[X11] %s()\n", __PRETTY_FUNCTION__));
666 task = NewCreateTask(TASKTAG_PC, x11task_entry, TASKTAG_STACKSIZE,
667 XTASK_STACKSIZE, TASKTAG_NAME, XTASK_NAME, TASKTAG_PRI,
668 XTASK_PRIORITY, TASKTAG_ARG1, params, TAG_DONE);
669 if (task)
671 D(bug("[X11] %s: task @ 0x%p\n", __PRETTY_FUNCTION__, task));
673 /* Everything went OK. Wait for task to initialize */
674 ULONG sigset;
676 sigset = Wait(params->ok_signal | params->fail_signal);
677 if (sigset & params->ok_signal)
679 D(bug("[X11] %s: got ok signal\n", __PRETTY_FUNCTION__));
681 return task;
684 return NULL;
687 /****************************************************************************************/