Spelling corrections.
[cake.git] / arch / all-hosted / hidd / x11 / x11.c
blobe6d1bccd1b3c4364b282c9bdf20727e290a90e80
1 /*
2 Copyright © 1995-2008, 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 xsd->x11task_quit_port = CreateMsgPort();
159 if (xsd->x11task_quit_port)
161 xsd->x11task_quit_port->mp_Node.ln_Name = "AROS Hosted Power Switch";
162 xsd->x11task_quit_port->mp_Node.ln_Pri = -128;
164 AddPort(xsd->x11task_quit_port);
168 NEWLIST(&nmsg_list);
169 NEWLIST(&xwindowlist);
171 #if NOUNIXIO
173 myint.is_Code = (APTR)&x11VBlank;
174 myint.is_Data = FindTask(NULL);
175 myint.is_Node.ln_Name = "X11 VBlank server";
176 myint.is_Node.ln_Pri = 0;
177 myint.is_Node.ln_Type = NT_INTERRUPT;
179 AddIntServer(INTB_TIMERTICK, &myint);
182 Signal(xtp.parent, xtp.ok_signal);
184 #else
186 unixio = (HIDD)New_UnixIO(OOPBase);
187 if (unixio)
189 unixio_port = CreateMsgPort();
190 if (unixio_port)
192 unixiosig = 1L << unixio_port->mp_SigBit;
193 Signal(xtp.parent, xtp.ok_signal);
196 else goto failexit;
198 else goto failexit;
199 #endif
201 hostclipboardmask = x11clipboard_init(xsd);
203 for (;;)
205 XEvent event;
206 #if BETTER_REPEAT_HANDLING
207 XEvent keyrelease_event;
208 BOOL keyrelease_pending = FALSE;
209 #endif
210 struct notify_msg *nmsg;
211 ULONG notifysig = 1L << xsd->x11task_notify_port->mp_SigBit;
212 ULONG quitsig = xsd->x11task_quit_port ? (1L << xsd->x11task_quit_port->mp_SigBit) : 0;
213 ULONG sigs;
215 #if NOUNIXIO
217 sigs = Wait(SIGBREAKF_CTRL_D | notifysig | xtp.kill_signal | hostclipboardmask | quitsig);
219 #else
222 #if 0
225 ret = (int)Hidd_UnixIO_Wait(unixio,
226 ConnectionNumber( xsd->display ),
227 vHidd_UnixIO_Read,
228 unixio_callback,
229 (APTR)xsd,
230 xtp.kill_signal | notifysig | hostclipboardmask | quitsig);
233 #else
235 if (dounixio)
237 ret = Hidd_UnixIO_AsyncIO(unixio,
238 ConnectionNumber(xsd->display),
239 unixio_port, vHidd_UnixIO_Read);
241 if (ret)
244 kprintf("ERROR WHEN CALLING UNIXIO: %d\n", ret);
245 dounixio = TRUE;
247 continue;
249 else
251 dounixio = FALSE;
255 sigs = Wait(notifysig | unixiosig | xtp.kill_signal | hostclipboardmask | quitsig);
256 D(bug("Got input from unixio\n"));
258 if (ret != 0)
260 continue;
266 if (sigs & unixiosig)
268 struct uioMessage *uiomsg;
269 int result;
271 uiomsg = (struct uioMessage *)GetMsg(unixio_port);
272 result = uiomsg->result;
274 FreeMem(uiomsg, sizeof (struct uioMessage));
276 dounixio = TRUE;
278 if (result)
279 continue;
282 #endif
285 #endif
286 if (sigs & quitsig)
288 CCALL(raise, SIGINT);
291 if (sigs & xtp.kill_signal)
292 goto failexit;
294 if (sigs & notifysig)
297 while ((nmsg = (struct notify_msg *)GetMsg(xsd->x11task_notify_port)))
299 /* Add the messages to an internal list */
301 switch (nmsg->notify_type)
303 case NOTY_WINCREATE:
305 struct xwinnode * node;
306 /* Maintain a list of open windows for the X11 event handler in x11.c */
308 node = AllocMem(sizeof (struct xwinnode), MEMF_CLEAR);
310 if (NULL != node)
313 node->xwindow = nmsg->xwindow;
314 node->bmobj = nmsg->bmobj;
315 AddTail( (struct List *)&xwindowlist, (struct Node *)node );
317 else
319 kprintf("!!!! CANNOT GET MEMORY FOR X11 WIN NODE\n");
320 CCALL(raise, 19);
323 ReplyMsg((struct Message *)nmsg);
324 break;
327 case NOTY_MAPWINDOW:
328 LOCK_X11
329 XCALL(XMapWindow, nmsg->xdisplay, nmsg->xwindow);
330 #if ADJUST_XWIN_SIZE
331 XCALL(XMapRaised, nmsg->xdisplay, nmsg->masterxwindow);
332 #endif
333 UNLOCK_X11
335 AddTail((struct List *)&nmsg_list, (struct Node *)nmsg);
337 /* Do not reply message yet */
338 break;
340 case NOTY_RESIZEWINDOW:
342 XWindowChanges xwc;
343 BOOL replymsg = TRUE;
344 struct xwinnode *node;
346 xwc.width = nmsg->width;
347 xwc.height = nmsg->height;
349 LOCK_X11
350 if (xsd->fullscreen)
352 x11_fullscreen_switchmode(nmsg->xdisplay, &xwc.width, &xwc.height);
354 XCALL(XConfigureWindow, nmsg->xdisplay
355 , nmsg->masterxwindow
356 , CWWidth | CWHeight
357 , &xwc
359 XCALL(XFlush, nmsg->xdisplay);
360 UNLOCK_X11
362 #if DELAY_XWIN_MAPPING
363 ForeachNode(&xwindowlist, node)
365 if (node->xwindow == nmsg->xwindow)
367 if (!node->window_mapped)
369 LOCK_X11
370 XCALL(XMapWindow, nmsg->xdisplay, nmsg->xwindow);
371 #if ADJUST_XWIN_SIZE
372 XCALL(XMapRaised, nmsg->xdisplay, nmsg->masterxwindow);
373 #endif
374 if (xsd->fullscreen)
376 XCALL(XGrabKeyboard, nmsg->xdisplay,nmsg->xwindow,False,GrabModeAsync,GrabModeAsync,CurrentTime);
377 XCALL(XGrabPointer, nmsg->xdisplay,nmsg->xwindow, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
378 GrabModeAsync, GrabModeAsync, nmsg->xwindow, None, CurrentTime);
380 XCALL(XFlush, nmsg->xdisplay);
381 UNLOCK_X11
383 nmsg->notify_type = NOTY_MAPWINDOW;
384 AddTail((struct List *)&nmsg_list, (struct Node *)nmsg);
386 /* Do not reply message yet */
387 replymsg = FALSE;
389 break;
393 #endif
395 if (replymsg) ReplyMsg((struct Message *)nmsg);
397 break;
400 case NOTY_WINDISPOSE:
402 struct xwinnode *node, *safe;
405 ForeachNodeSafe(&xwindowlist, node, safe)
407 if (node->xwindow == nmsg->xwindow)
409 Remove((struct Node *)node);
410 FreeMem(node, sizeof (struct xwinnode));
414 ReplyMsg((struct Message *)nmsg);
416 break;
419 } /* switch() */
421 } /* while () */
423 //continue;
425 } /* if (message from notify port) */
427 if (sigs & hostclipboardmask)
429 x11clipboard_handle_commands(xsd);
432 for (;;)
434 struct xwinnode *node;
435 int pending;
436 BOOL window_found = FALSE;
438 LOCK_X11
439 XCALL(XFlush, xsd->display);
440 XCALL(XSync, xsd->display, FALSE);
441 pending = XCALL(XEventsQueued, xsd->display, QueuedAlready);
442 UNLOCK_X11
444 if (pending == 0)
446 #if BETTER_REPEAT_HANDLING
447 if (keyrelease_pending)
449 if (XCALL(XLookupKeysym, (XKeyEvent *)&keyrelease_event, 0) == XK_F12)
451 f12_down = FALSE;
454 ObtainSemaphoreShared( &xsd->sema );
455 if (xsd->kbdhidd)
457 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &keyrelease_event);
459 ReleaseSemaphore( &xsd->sema );
460 keyrelease_pending = FALSE;
462 #endif
464 /* Get out of for(;;) loop */
465 break;
468 LOCK_X11
469 XCALL(XNextEvent, xsd->display, &event);
470 UNLOCK_X11
472 D(bug("Got Event for X=%d\n", event.xany.window));
474 #if BETTER_REPEAT_HANDLING
475 if (keyrelease_pending)
477 BOOL repeated_key = FALSE;
479 /* Saw this in SDL/X11 code, where a comment says that
480 the idea for this was coming from GII, whatever that
481 is. */
483 if ((event.xany.window == keyrelease_event.xany.window) &&
484 (event.type == KeyPress) &&
485 (event.xkey.keycode == keyrelease_event.xkey.keycode) &&
486 ((event.xkey.time - keyrelease_event.xkey.time) < 2))
488 repeated_key = TRUE;
491 keyrelease_pending = FALSE;
493 if (repeated_key)
495 /* Drop both previous keyrelease and this keypress event. */
496 continue;
499 LOCK_X11
500 if (XCALL(XLookupKeysym, (XKeyEvent *)&keyrelease_event, 0) == XK_F12)
502 f12_down = FALSE;
504 UNLOCK_X11
506 ObtainSemaphoreShared( &xsd->sema );
507 if (xsd->kbdhidd)
509 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &keyrelease_event);
511 ReleaseSemaphore( &xsd->sema );
513 #endif
515 if (event.type == MappingNotify)
517 LOCK_X11
518 XCALL(XRefreshKeyboardMapping, (XMappingEvent*)&event);
519 UNLOCK_X11
521 continue;
524 #if ADJUST_XWIN_SIZE
525 /* Must check this here, because below only the inner
526 window events are recognized */
528 if ((event.type == ClientMessage) &&
529 (event.xclient.data.l[0] == xsd->delete_win_atom))
531 CCALL(raise, SIGINT);
533 #endif
535 ForeachNode( &xwindowlist, node)
537 if (node->xwindow == event.xany.window)
539 window_found = TRUE;
540 break;
544 if (x11clipboard_want_event(&event))
546 x11clipboard_handle_event(xsd, &event);
549 if (window_found)
551 D(bug("Got event for window %x\n", event.xany.window));
552 switch (event.type)
554 case GraphicsExpose:
555 case Expose:
556 break;
558 case ConfigureRequest:
559 kprintf("!!! CONFIGURE REQUEST !!\n");
560 break;
562 #if 0
563 /* stegerg: not needed */
564 case ConfigureNotify:
566 /* The window has been resized */
568 XConfigureEvent *me;
569 struct notify_msg *nmsg, *safe;
571 me = (XConfigureEvent *)&event;
572 ForeachNodeSafe(&nmsg_list, nmsg, safe)
574 if ( me->window == nmsg->xwindow
575 && nmsg->notify_type == NOTY_RESIZEWINDOW)
577 /* The window has now been mapped.
578 Send reply to app */
580 Remove((struct Node *)nmsg);
581 ReplyMsg((struct Message *)nmsg);
587 break;
589 #endif
591 case ButtonPress:
592 xsd->x_time = event.xbutton.time;
593 D(bug("ButtonPress event\n"));
595 ObtainSemaphoreShared( &xsd->sema );
596 if (xsd->mousehidd)
597 Hidd_X11Mouse_HandleEvent(xsd->mousehidd, &event);
598 ReleaseSemaphore( &xsd->sema );
599 break;
601 case ButtonRelease:
602 xsd->x_time = event.xbutton.time;
603 D(bug("ButtonRelease event\n"));
605 ObtainSemaphoreShared( &xsd->sema );
606 if (xsd->mousehidd)
607 Hidd_X11Mouse_HandleEvent(xsd->mousehidd, &event);
608 ReleaseSemaphore( &xsd->sema );
609 break;
611 case MotionNotify:
612 xsd->x_time = event.xmotion.time;
613 D(bug("Motionnotify event\n"));
615 ObtainSemaphoreShared( &xsd->sema );
616 if (xsd->mousehidd)
617 Hidd_X11Mouse_HandleEvent(xsd->mousehidd, &event);
618 ReleaseSemaphore( &xsd->sema );
619 break;
621 case FocusOut:
622 #if !BETTER_REPEAT_HANDLING
623 LOCK_X11
624 XCALL(XAutoRepeatOn, xsd->display);
625 UNLOCK_X11
626 #endif
628 #if 0
629 ObtainSemaphoreShared(&xsd->sema);
630 /* Call the user supplied callback func, if supplied */
631 if (NULL != xsd->activecallback)
633 xsd->activecallback(xsd->callbackdata, node->bmobj, FALSE);
635 ReleaseSemaphore(&xsd->sema);
636 #endif
637 break;
639 case FocusIn:
640 #if 0
641 ObtainSemaphoreShared(&xsd->sema);
642 /* Call the user supplied callback func, if supplied */
643 if (NULL != xsd->activecallback)
645 xsd->activecallback(xsd->callbackdata, node->bmobj, TRUE);
647 ReleaseSemaphore(&xsd->sema);
648 #endif
649 break;
651 case KeyPress:
652 xsd->x_time = event.xkey.time;
654 LOCK_X11
655 #if !BETTER_REPEAT_HANDLING
656 XCALL(XAutoRepeatOff, XSD(cl)->display);
657 #endif
658 ks = XCALL(XLookupKeysym, (XKeyEvent *)&event, 0);
659 if (ks == XK_F12)
661 f12_down = TRUE;
663 else if (f12_down && ((ks == XK_Q) || (ks == XK_q)))
665 CCALL(raise, SIGINT);
667 UNLOCK_X11
669 ObtainSemaphoreShared( &xsd->sema );
670 if (xsd->kbdhidd)
672 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &event);
674 ReleaseSemaphore( &xsd->sema );
675 break;
678 case KeyRelease:
679 xsd->x_time = event.xkey.time;
681 #if BETTER_REPEAT_HANDLING
682 keyrelease_pending = TRUE;
683 keyrelease_event = event;
684 #else
685 LOCK_X11
686 if (XCALL(XLookupKeysym, &event, 0) == XK_F12)
688 f12_down = FALSE;
690 XCALL(XAutoRepeatOn, XSD(cl)->display);
691 UNLOCK_X11
693 ObtainSemaphoreShared( &xsd->sema );
694 if (xsd->kbdhidd)
696 Hidd_X11Kbd_HandleEvent(xsd->kbdhidd, &event);
698 ReleaseSemaphore( &xsd->sema );
699 #endif
700 break;
702 case EnterNotify:
703 break;
705 case LeaveNotify:
706 break;
708 case MapNotify:
711 XMapEvent *me;
712 struct notify_msg *nmsg, *safe;
713 struct xwinnode *node;
714 BOOL found = FALSE;
716 me = (XMapEvent *)&event;
718 ForeachNodeSafe(&nmsg_list, nmsg, safe)
720 if (me->window == nmsg->xwindow
721 && nmsg->notify_type == NOTY_MAPWINDOW)
723 /* The window has now been mapped.
724 Send reply to app */
726 found = TRUE;
727 Remove((struct Node *)nmsg);
728 ReplyMsg((struct Message *)nmsg);
732 /* Find it in thw window list and mark it as mapped */
734 ForeachNode(&xwindowlist, node)
736 if (node->xwindow == me->window)
738 node->window_mapped = TRUE;
743 break;
746 #if !ADJUST_XWIN_SIZE
747 case ClientMessage:
748 if (event.xclient.data.l[0] == xsd->delete_win_atom)
750 CCALL(raise, SIGINT);
752 break;
753 #endif
755 } /* switch (X11 event type) */
757 } /* if (is event for HIDD window) */
759 } /* while (events from X) */
761 } /* Forever */
763 failexit:
764 #warning "Also try to free window node list ?"
766 if (xsd->x11task_quit_port)
768 RemPort(xsd->x11task_quit_port);
769 DeleteMsgPort(xsd->x11task_quit_port);
772 if (xsd->x11task_notify_port)
774 DeleteMsgPort(xsd->x11task_notify_port);
778 #if (!NOUNIXIO)
779 if (NULL != unixio_port)
781 DeleteMsgPort(unixio_port);
784 if (NULL != unixio)
786 OOP_DisposeObject(unixio);
788 #endif
790 Signal(xtp.parent, xtp.fail_signal);
794 /****************************************************************************************/
796 struct Task *create_x11task( struct x11task_params *params)
798 struct Task *task;
799 APTR stack;
801 task = AllocMem(sizeof (struct Task), MEMF_PUBLIC|MEMF_CLEAR);
802 if (task)
804 NEWLIST(&task->tc_MemEntry);
805 task->tc_Node.ln_Type =NT_TASK;
806 task->tc_Node.ln_Name = XTASK_NAME;
807 task->tc_Node.ln_Pri = XTASK_PRIORITY;
809 stack = AllocMem(XTASK_STACKSIZE, MEMF_PUBLIC);
810 if(stack != NULL)
812 struct TagItem tags[] =
814 {TASKTAG_ARG1, (IPTR)params},
815 {TAG_DONE }
818 task->tc_SPLower = stack;
819 task->tc_SPUpper = (UBYTE *)stack + XTASK_STACKSIZE;
821 #if AROS_STACK_GROWS_DOWNWARDS
822 task->tc_SPReg = (UBYTE *)task->tc_SPUpper-SP_OFFSET;
823 #else
824 task->tc_SPReg = (UBYTE *)task->tc_SPLower+SP_OFFSET;
825 #endif
827 /* You have to clear signals first. */
828 SetSignal(0, params->ok_signal | params->fail_signal);
830 if(NewAddTask(task, x11task_entry, NULL, tags) != NULL)
832 /* Everything went OK. Wait for task to initialize */
833 ULONG sigset;
836 sigset = Wait( params->ok_signal | params->fail_signal );
837 if (sigset & params->ok_signal)
839 return task;
843 FreeMem(stack, XTASK_STACKSIZE);
846 FreeMem(task,sizeof(struct Task));
849 return NULL;
852 /****************************************************************************************/