define __KERNEL_STRICT_NAMES to avoid inclusion of kernel types on systems that carry...
[cake.git] / arch / all-hosted / hidd / x11 / x11.c
blob5c3ee6972dc06b80d47210f5f0a8f203bf27e4bb
1 /*
2 Copyright © 1995-2009, 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 */
10 #include <proto/exec.h>
11 #include <proto/oop.h>
12 #include <proto/utility.h>
14 #define size_t aros_size_t
15 #include <hidd/unixio.h>
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 #define DEBUG 0
53 #include <aros/debug.h>
55 /****************************************************************************************/
57 #define NOUNIXIO 1
58 #define BETTER_REPEAT_HANDLING 1
60 #define XTASK_NAME "x11hidd task"
62 /* We need to have highest priotity for this task, because we
63 are simulating an interrupt. Ie. an "interrupt handler" called
64 but this task should NEVER be interrupted by a task (for example input.device),
65 otherwize it will give strange effects, especially in the circular-buffer handling
66 in gameport/keyboard. (Writing to the buffer is not atomic even
67 from within the IRQ handler!)
69 Instead of calling
70 the irq handler directly from the task, we should instead
71 Cause() a software irq, but Cause() does not work at the moment..
74 #define XTASK_PRIORITY 50
76 #define XTASK_STACKSIZE (AROS_STACKSIZE)
78 #undef XSD
79 #define XSD(cl) xsd
81 /****************************************************************************************/
83 #if NOUNIXIO
85 /****************************************************************************************/
87 AROS_UFH4(ULONG, x11VBlank,
88 AROS_UFHA(ULONG, dummy, A0),
89 AROS_UFHA(void *, data, A1),
90 AROS_UFHA(ULONG, dummy2, A5),
91 AROS_UFHA(struct ExecBase *, SysBase, A6))
93 AROS_USERFUNC_INIT
95 Signal((struct Task *)data, SIGBREAKF_CTRL_D);
97 return 0;
99 AROS_USERFUNC_EXIT
102 /****************************************************************************************/
104 #else
106 /****************************************************************************************/
108 static int unixio_callback(int displayfd, struct x11_staticdata *xsd)
110 int pending;
112 LOCK_X11
113 pending = XCALL(XPending, xsd->display);
114 UNLOCK_X11
116 return pending;
119 /****************************************************************************************/
121 #endif
123 /****************************************************************************************/
125 VOID x11task_entry(struct x11task_params *xtpparam)
127 struct x11_staticdata *xsd;
128 struct MinList nmsg_list;
129 struct MinList xwindowlist;
130 struct x11task_params xtp;
131 ULONG hostclipboardmask;
132 BOOL f12_down = FALSE;
133 KeySym ks;
135 #if NOUNIXIO
136 struct Interrupt myint;
137 #else
138 struct MsgPort *unixio_port = NULL;
139 HIDD *unixio = NULL;
140 IPTR ret;
141 ULONG unixiosig;
142 BOOL domouse = FALSE;
143 LONG last_mouse_x;
144 LONG last_mouse_y;
145 BOOL dounixio = TRUE;
146 #endif
148 /* We must copy the parameter struct because they are allocated
149 on the parent's stack */
150 xtp = *xtpparam;
151 xsd = xtp.xsd;
154 xsd->x11task_notify_port = CreateMsgPort();
155 if (NULL == xsd->x11task_notify_port)
156 goto failexit;
158 NEWLIST(&nmsg_list);
159 NEWLIST(&xwindowlist);
161 #if NOUNIXIO
163 myint.is_Code = (APTR)&x11VBlank;
164 myint.is_Data = FindTask(NULL);
165 myint.is_Node.ln_Name = "X11 VBlank server";
166 myint.is_Node.ln_Pri = 0;
167 myint.is_Node.ln_Type = NT_INTERRUPT;
169 AddIntServer(INTB_TIMERTICK, &myint);
172 Signal(xtp.parent, xtp.ok_signal);
174 #else
176 unixio = (HIDD)New_UnixIO(OOPBase, SysBase);
177 if (unixio)
179 unixio_port = CreateMsgPort();
180 if (unixio_port)
182 unixiosig = 1L << unixio_port->mp_SigBit;
183 Signal(xtp.parent, xtp.ok_signal);
186 else goto failexit;
188 else goto failexit;
189 #endif
191 hostclipboardmask = x11clipboard_init(xsd);
193 for (;;)
195 XEvent event;
196 #if BETTER_REPEAT_HANDLING
197 XEvent keyrelease_event;
198 BOOL keyrelease_pending = FALSE;
199 #endif
200 struct notify_msg *nmsg;
201 ULONG notifysig = 1L << xsd->x11task_notify_port->mp_SigBit;
202 ULONG sigs;
204 #if NOUNIXIO
206 sigs = Wait(SIGBREAKF_CTRL_D | notifysig | xtp.kill_signal | hostclipboardmask);
208 #else
211 #if 0
214 ret = (int)Hidd_UnixIO_Wait(unixio,
215 ConnectionNumber( xsd->display ),
216 vHidd_UnixIO_Read,
217 unixio_callback,
218 (APTR)xsd,
219 xtp.kill_signal | notifysig | hostclipboardmask);
222 #else
224 if (dounixio)
226 ret = Hidd_UnixIO_AsyncIO(unixio,
227 ConnectionNumber(xsd->display), vHidd_UnixIO_Terminal,
228 unixio_port, vHidd_UnixIO_Read, SysBase);
230 if (ret)
233 kprintf("ERROR WHEN CALLING UNIXIO: %d\n", ret);
234 dounixio = TRUE;
236 continue;
238 else
240 dounixio = FALSE;
244 sigs = Wait(notifysig | unixiosig | xtp.kill_signal | hostclipboardmask);
245 D(bug("Got input from unixio\n"));
247 if (ret != 0)
249 continue;
255 if (sigs & unixiosig)
257 struct uioMessage *uiomsg;
258 int result;
260 uiomsg = (struct uioMessage *)GetMsg(unixio_port);
261 result = uiomsg->result;
263 FreeMem(uiomsg, sizeof (struct uioMessage));
265 dounixio = TRUE;
267 if (result)
268 continue;
271 #endif
274 #endif
275 if (sigs & xtp.kill_signal)
276 goto failexit;
278 if (sigs & notifysig)
281 while ((nmsg = (struct notify_msg *)GetMsg(xsd->x11task_notify_port)))
283 /* Add the messages to an internal list */
285 switch (nmsg->notify_type)
287 case NOTY_WINCREATE:
289 struct xwinnode * node;
290 /* Maintain a list of open windows for the X11 event handler in x11.c */
292 node = AllocMem(sizeof (struct xwinnode), MEMF_CLEAR);
294 if (NULL != node)
297 node->xwindow = nmsg->xwindow;
298 node->bmobj = nmsg->bmobj;
299 AddTail( (struct List *)&xwindowlist, (struct Node *)node );
301 else
303 kprintf("!!!! CANNOT GET MEMORY FOR X11 WIN NODE\n");
304 CCALL(raise, 19);
307 ReplyMsg((struct Message *)nmsg);
308 break;
311 case NOTY_MAPWINDOW:
312 LOCK_X11
313 XCALL(XMapWindow, nmsg->xdisplay, nmsg->xwindow);
314 #if ADJUST_XWIN_SIZE
315 XCALL(XMapRaised, nmsg->xdisplay, nmsg->masterxwindow);
316 #endif
317 UNLOCK_X11
319 AddTail((struct List *)&nmsg_list, (struct Node *)nmsg);
321 /* Do not reply message yet */
322 break;
324 case NOTY_RESIZEWINDOW:
326 XWindowChanges xwc;
327 BOOL replymsg = TRUE;
328 struct xwinnode *node;
330 xwc.width = nmsg->width;
331 xwc.height = nmsg->height;
333 LOCK_X11
334 if (xsd->fullscreen)
336 x11_fullscreen_switchmode(nmsg->xdisplay, &xwc.width, &xwc.height);
338 XCALL(XConfigureWindow, nmsg->xdisplay
339 , nmsg->masterxwindow
340 , CWWidth | CWHeight
341 , &xwc
343 XCALL(XFlush, nmsg->xdisplay);
344 UNLOCK_X11
346 #if DELAY_XWIN_MAPPING
347 ForeachNode(&xwindowlist, node)
349 if (node->xwindow == nmsg->xwindow)
351 if (!node->window_mapped)
353 LOCK_X11
354 XCALL(XMapWindow, nmsg->xdisplay, nmsg->xwindow);
355 #if ADJUST_XWIN_SIZE
356 XCALL(XMapRaised, nmsg->xdisplay, nmsg->masterxwindow);
357 #endif
358 if (xsd->fullscreen)
360 XCALL(XGrabKeyboard, nmsg->xdisplay,nmsg->xwindow,False,GrabModeAsync,GrabModeAsync,CurrentTime);
361 XCALL(XGrabPointer, nmsg->xdisplay,nmsg->xwindow, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
362 GrabModeAsync, GrabModeAsync, nmsg->xwindow, None, CurrentTime);
364 XCALL(XFlush, nmsg->xdisplay);
365 UNLOCK_X11
367 nmsg->notify_type = NOTY_MAPWINDOW;
368 AddTail((struct List *)&nmsg_list, (struct Node *)nmsg);
370 /* Do not reply message yet */
371 replymsg = FALSE;
373 break;
377 #endif
379 if (replymsg) ReplyMsg((struct Message *)nmsg);
381 break;
384 case NOTY_WINDISPOSE:
386 struct xwinnode *node, *safe;
389 ForeachNodeSafe(&xwindowlist, node, safe)
391 if (node->xwindow == nmsg->xwindow)
393 Remove((struct Node *)node);
394 FreeMem(node, sizeof (struct xwinnode));
398 ReplyMsg((struct Message *)nmsg);
400 break;
403 } /* switch() */
405 } /* while () */
407 //continue;
409 } /* if (message from notify port) */
411 if (sigs & hostclipboardmask)
413 x11clipboard_handle_commands(xsd);
416 for (;;)
418 struct xwinnode *node;
419 int pending;
420 BOOL window_found = FALSE;
422 LOCK_X11
423 XCALL(XFlush, xsd->display);
424 XCALL(XSync, xsd->display, FALSE);
425 pending = XCALL(XEventsQueued, xsd->display, QueuedAlready);
426 UNLOCK_X11
428 if (pending == 0)
430 #if BETTER_REPEAT_HANDLING
431 if (keyrelease_pending)
433 if (XCALL(XLookupKeysym, (XKeyEvent *)&keyrelease_event, 0) == XK_F12)
435 f12_down = FALSE;
438 ObtainSemaphoreShared( &xsd->sema );
439 if (xsd->kbdhidd)
441 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &keyrelease_event);
443 ReleaseSemaphore( &xsd->sema );
444 keyrelease_pending = FALSE;
446 #endif
448 /* Get out of for(;;) loop */
449 break;
452 LOCK_X11
453 XCALL(XNextEvent, xsd->display, &event);
454 UNLOCK_X11
456 D(bug("Got Event for X=%d\n", event.xany.window));
458 #if BETTER_REPEAT_HANDLING
459 if (keyrelease_pending)
461 BOOL repeated_key = FALSE;
463 /* Saw this in SDL/X11 code, where a comment says that
464 the idea for this was coming from GII, whatever that
465 is. */
467 if ((event.xany.window == keyrelease_event.xany.window) &&
468 (event.type == KeyPress) &&
469 (event.xkey.keycode == keyrelease_event.xkey.keycode) &&
470 ((event.xkey.time - keyrelease_event.xkey.time) < 2))
472 repeated_key = TRUE;
475 keyrelease_pending = FALSE;
477 if (repeated_key)
479 /* Drop both previous keyrelease and this keypress event. */
480 continue;
483 LOCK_X11
484 if (XCALL(XLookupKeysym, (XKeyEvent *)&keyrelease_event, 0) == XK_F12)
486 f12_down = FALSE;
488 UNLOCK_X11
490 ObtainSemaphoreShared( &xsd->sema );
491 if (xsd->kbdhidd)
493 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &keyrelease_event);
495 ReleaseSemaphore( &xsd->sema );
497 #endif
499 if (event.type == MappingNotify)
501 LOCK_X11
502 XCALL(XRefreshKeyboardMapping, (XMappingEvent*)&event);
503 UNLOCK_X11
505 continue;
508 #if ADJUST_XWIN_SIZE
509 /* Must check this here, because below only the inner
510 window events are recognized */
512 if ((event.type == ClientMessage) &&
513 (event.xclient.data.l[0] == xsd->delete_win_atom))
515 CCALL(raise, SIGINT);
517 #endif
519 ForeachNode( &xwindowlist, node)
521 if (node->xwindow == event.xany.window)
523 window_found = TRUE;
524 break;
528 if (x11clipboard_want_event(&event))
530 x11clipboard_handle_event(xsd, &event);
533 if (window_found)
535 D(bug("Got event for window %x\n", event.xany.window));
536 switch (event.type)
538 case GraphicsExpose:
539 case Expose:
540 break;
542 case ConfigureRequest:
543 kprintf("!!! CONFIGURE REQUEST !!\n");
544 break;
546 #if 0
547 /* stegerg: not needed */
548 case ConfigureNotify:
550 /* The window has been resized */
552 XConfigureEvent *me;
553 struct notify_msg *nmsg, *safe;
555 me = (XConfigureEvent *)&event;
556 ForeachNodeSafe(&nmsg_list, nmsg, safe)
558 if ( me->window == nmsg->xwindow
559 && nmsg->notify_type == NOTY_RESIZEWINDOW)
561 /* The window has now been mapped.
562 Send reply to app */
564 Remove((struct Node *)nmsg);
565 ReplyMsg((struct Message *)nmsg);
571 break;
573 #endif
575 case ButtonPress:
576 xsd->x_time = event.xbutton.time;
577 D(bug("ButtonPress event\n"));
579 ObtainSemaphoreShared( &xsd->sema );
580 if (xsd->mousehidd)
581 Hidd_X11Mouse_HandleEvent(xsd->mousehidd, &event);
582 ReleaseSemaphore( &xsd->sema );
583 break;
585 case ButtonRelease:
586 xsd->x_time = event.xbutton.time;
587 D(bug("ButtonRelease event\n"));
589 ObtainSemaphoreShared( &xsd->sema );
590 if (xsd->mousehidd)
591 Hidd_X11Mouse_HandleEvent(xsd->mousehidd, &event);
592 ReleaseSemaphore( &xsd->sema );
593 break;
595 case MotionNotify:
596 xsd->x_time = event.xmotion.time;
597 D(bug("Motionnotify event\n"));
599 ObtainSemaphoreShared( &xsd->sema );
600 if (xsd->mousehidd)
601 Hidd_X11Mouse_HandleEvent(xsd->mousehidd, &event);
602 ReleaseSemaphore( &xsd->sema );
603 break;
605 case FocusOut:
606 #if !BETTER_REPEAT_HANDLING
607 LOCK_X11
608 XCALL(XAutoRepeatOn, xsd->display);
609 UNLOCK_X11
610 #endif
612 #if 0
613 ObtainSemaphoreShared(&xsd->sema);
614 /* Call the user supplied callback func, if supplied */
615 if (NULL != xsd->activecallback)
617 xsd->activecallback(xsd->callbackdata, node->bmobj, FALSE);
619 ReleaseSemaphore(&xsd->sema);
620 #endif
621 break;
623 case FocusIn:
624 #if 0
625 ObtainSemaphoreShared(&xsd->sema);
626 /* Call the user supplied callback func, if supplied */
627 if (NULL != xsd->activecallback)
629 xsd->activecallback(xsd->callbackdata, node->bmobj, TRUE);
631 ReleaseSemaphore(&xsd->sema);
632 #endif
633 break;
635 case KeyPress:
636 xsd->x_time = event.xkey.time;
638 LOCK_X11
639 #if !BETTER_REPEAT_HANDLING
640 XCALL(XAutoRepeatOff, XSD(cl)->display);
641 #endif
642 ks = XCALL(XLookupKeysym, (XKeyEvent *)&event, 0);
643 if (ks == XK_F12)
645 f12_down = TRUE;
647 else if (f12_down && ((ks == XK_Q) || (ks == XK_q)))
649 CCALL(raise, SIGINT);
651 UNLOCK_X11
653 ObtainSemaphoreShared( &xsd->sema );
654 if (xsd->kbdhidd)
656 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &event);
658 ReleaseSemaphore( &xsd->sema );
659 break;
662 case KeyRelease:
663 xsd->x_time = event.xkey.time;
665 #if BETTER_REPEAT_HANDLING
666 keyrelease_pending = TRUE;
667 keyrelease_event = event;
668 #else
669 LOCK_X11
670 if (XCALL(XLookupKeysym, &event, 0) == XK_F12)
672 f12_down = FALSE;
674 XCALL(XAutoRepeatOn, XSD(cl)->display);
675 UNLOCK_X11
677 ObtainSemaphoreShared( &xsd->sema );
678 if (xsd->kbdhidd)
680 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &event);
682 ReleaseSemaphore( &xsd->sema );
683 #endif
684 break;
686 case EnterNotify:
687 break;
689 case LeaveNotify:
690 break;
692 case MapNotify:
695 XMapEvent *me;
696 struct notify_msg *nmsg, *safe;
697 struct xwinnode *node;
698 BOOL found = FALSE;
700 me = (XMapEvent *)&event;
702 ForeachNodeSafe(&nmsg_list, nmsg, safe)
704 if (me->window == nmsg->xwindow
705 && nmsg->notify_type == NOTY_MAPWINDOW)
707 /* The window has now been mapped.
708 Send reply to app */
710 found = TRUE;
711 Remove((struct Node *)nmsg);
712 ReplyMsg((struct Message *)nmsg);
716 /* Find it in thw window list and mark it as mapped */
718 ForeachNode(&xwindowlist, node)
720 if (node->xwindow == me->window)
722 node->window_mapped = TRUE;
727 break;
730 #if !ADJUST_XWIN_SIZE
731 case ClientMessage:
732 if (event.xclient.data.l[0] == xsd->delete_win_atom)
734 CCALL(raise, SIGINT);
736 break;
737 #endif
739 } /* switch (X11 event type) */
741 } /* if (is event for HIDD window) */
743 } /* while (events from X) */
745 } /* Forever */
747 failexit:
748 #warning "Also try to free window node list ?"
750 if (xsd->x11task_notify_port)
752 DeleteMsgPort(xsd->x11task_notify_port);
756 #if (!NOUNIXIO)
757 if (NULL != unixio_port)
759 DeleteMsgPort(unixio_port);
762 if (NULL != unixio)
764 OOP_DisposeObject(unixio);
766 #endif
768 Signal(xtp.parent, xtp.fail_signal);
772 /****************************************************************************************/
774 struct Task *create_x11task( struct x11task_params *params)
776 struct Task *task;
777 APTR stack;
779 task = AllocMem(sizeof (struct Task), MEMF_PUBLIC|MEMF_CLEAR);
780 if (task)
782 NEWLIST(&task->tc_MemEntry);
783 task->tc_Node.ln_Type =NT_TASK;
784 task->tc_Node.ln_Name = XTASK_NAME;
785 task->tc_Node.ln_Pri = XTASK_PRIORITY;
787 stack = AllocMem(XTASK_STACKSIZE, MEMF_PUBLIC);
788 if(stack != NULL)
790 struct TagItem tags[] =
792 {TASKTAG_ARG1, (IPTR)params},
793 {TAG_DONE }
796 task->tc_SPLower = stack;
797 task->tc_SPUpper = (UBYTE *)stack + XTASK_STACKSIZE;
799 #if AROS_STACK_GROWS_DOWNWARDS
800 task->tc_SPReg = (UBYTE *)task->tc_SPUpper-SP_OFFSET;
801 #else
802 task->tc_SPReg = (UBYTE *)task->tc_SPLower+SP_OFFSET;
803 #endif
805 /* You have to clear signals first. */
806 SetSignal(0, params->ok_signal | params->fail_signal);
808 if(NewAddTask(task, x11task_entry, NULL, tags) != NULL)
810 /* Everything went OK. Wait for task to initialize */
811 ULONG sigset;
814 sigset = Wait( params->ok_signal | params->fail_signal );
815 if (sigset & params->ok_signal)
817 return task;
821 FreeMem(stack, XTASK_STACKSIZE);
824 FreeMem(task,sizeof(struct Task));
827 return NULL;
830 /****************************************************************************************/