2 Copyright © 1995-2009, The AROS Development Team. All rights reserved.
5 Desc: X11 hidd. Connects to the X server and receives events.
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>
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>
33 #define timeval sys_timevalinit_x11class
34 #include <sys/types.h>
44 #include <X11/Xutil.h>
45 #include <X11/Xatom.h>
46 #include <X11/keysym.h>
49 #include "fullscreen.h"
50 #include "x11gfx_intern.h"
53 #include <aros/debug.h>
55 /****************************************************************************************/
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!)
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)
81 /****************************************************************************************/
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
))
95 Signal((struct Task
*)data
, SIGBREAKF_CTRL_D
);
102 /****************************************************************************************/
106 /****************************************************************************************/
108 static int unixio_callback(int displayfd
, struct x11_staticdata
*xsd
)
113 pending
= XCALL(XPending
, xsd
->display
);
119 /****************************************************************************************/
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
;
136 struct Interrupt myint
;
138 struct MsgPort
*unixio_port
= NULL
;
142 BOOL domouse
= FALSE
;
145 BOOL dounixio
= TRUE
;
148 /* We must copy the parameter struct because they are allocated
149 on the parent's stack */
154 xsd
->x11task_notify_port
= CreateMsgPort();
155 if (NULL
== xsd
->x11task_notify_port
)
159 NEWLIST(&xwindowlist
);
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
);
176 unixio
= (HIDD
)New_UnixIO(OOPBase
, SysBase
);
179 unixio_port
= CreateMsgPort();
182 unixiosig
= 1L << unixio_port
->mp_SigBit
;
183 Signal(xtp
.parent
, xtp
.ok_signal
);
191 hostclipboardmask
= x11clipboard_init(xsd
);
196 #if BETTER_REPEAT_HANDLING
197 XEvent keyrelease_event
;
198 BOOL keyrelease_pending
= FALSE
;
200 struct notify_msg
*nmsg
;
201 ULONG notifysig
= 1L << xsd
->x11task_notify_port
->mp_SigBit
;
206 sigs
= Wait(SIGBREAKF_CTRL_D
| notifysig
| xtp
.kill_signal
| hostclipboardmask
);
214 ret
= (int)Hidd_UnixIO_Wait(unixio
,
215 ConnectionNumber( xsd
->display
),
219 xtp
.kill_signal
| notifysig
| hostclipboardmask
);
226 ret
= Hidd_UnixIO_AsyncIO(unixio
,
227 ConnectionNumber(xsd
->display
), vHidd_UnixIO_Terminal
,
228 unixio_port
, vHidd_UnixIO_Read
, SysBase
);
233 kprintf("ERROR WHEN CALLING UNIXIO: %d\n", ret
);
244 sigs
= Wait(notifysig
| unixiosig
| xtp
.kill_signal
| hostclipboardmask
);
245 D(bug("Got input from unixio\n"));
255 if (sigs
& unixiosig
)
257 struct uioMessage
*uiomsg
;
260 uiomsg
= (struct uioMessage
*)GetMsg(unixio_port
);
261 result
= uiomsg
->result
;
263 FreeMem(uiomsg
, sizeof (struct uioMessage
));
275 if (sigs
& xtp
.kill_signal
)
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
)
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
);
297 node
->xwindow
= nmsg
->xwindow
;
298 node
->bmobj
= nmsg
->bmobj
;
299 AddTail( (struct List
*)&xwindowlist
, (struct Node
*)node
);
303 kprintf("!!!! CANNOT GET MEMORY FOR X11 WIN NODE\n");
307 ReplyMsg((struct Message
*)nmsg
);
313 XCALL(XMapWindow
, nmsg
->xdisplay
, nmsg
->xwindow
);
315 XCALL(XMapRaised
, nmsg
->xdisplay
, nmsg
->masterxwindow
);
319 AddTail((struct List
*)&nmsg_list
, (struct Node
*)nmsg
);
321 /* Do not reply message yet */
324 case NOTY_RESIZEWINDOW
:
327 BOOL replymsg
= TRUE
;
328 struct xwinnode
*node
;
330 xwc
.width
= nmsg
->width
;
331 xwc
.height
= nmsg
->height
;
336 x11_fullscreen_switchmode(nmsg
->xdisplay
, &xwc
.width
, &xwc
.height
);
338 XCALL(XConfigureWindow
, nmsg
->xdisplay
339 , nmsg
->masterxwindow
343 XCALL(XFlush
, nmsg
->xdisplay
);
346 #if DELAY_XWIN_MAPPING
347 ForeachNode(&xwindowlist
, node
)
349 if (node
->xwindow
== nmsg
->xwindow
)
351 if (!node
->window_mapped
)
354 XCALL(XMapWindow
, nmsg
->xdisplay
, nmsg
->xwindow
);
356 XCALL(XMapRaised
, nmsg
->xdisplay
, nmsg
->masterxwindow
);
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
);
367 nmsg
->notify_type
= NOTY_MAPWINDOW
;
368 AddTail((struct List
*)&nmsg_list
, (struct Node
*)nmsg
);
370 /* Do not reply message yet */
379 if (replymsg
) ReplyMsg((struct Message
*)nmsg
);
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
);
409 } /* if (message from notify port) */
411 if (sigs
& hostclipboardmask
)
413 x11clipboard_handle_commands(xsd
);
418 struct xwinnode
*node
;
420 BOOL window_found
= FALSE
;
423 XCALL(XFlush
, xsd
->display
);
424 XCALL(XSync
, xsd
->display
, FALSE
);
425 pending
= XCALL(XEventsQueued
, xsd
->display
, QueuedAlready
);
430 #if BETTER_REPEAT_HANDLING
431 if (keyrelease_pending
)
433 if (XCALL(XLookupKeysym
, (XKeyEvent
*)&keyrelease_event
, 0) == XK_F12
)
438 ObtainSemaphoreShared( &xsd
->sema
);
441 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &keyrelease_event
);
443 ReleaseSemaphore( &xsd
->sema
);
444 keyrelease_pending
= FALSE
;
448 /* Get out of for(;;) loop */
453 XCALL(XNextEvent
, xsd
->display
, &event
);
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
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))
475 keyrelease_pending
= FALSE
;
479 /* Drop both previous keyrelease and this keypress event. */
484 if (XCALL(XLookupKeysym
, (XKeyEvent
*)&keyrelease_event
, 0) == XK_F12
)
490 ObtainSemaphoreShared( &xsd
->sema
);
493 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &keyrelease_event
);
495 ReleaseSemaphore( &xsd
->sema
);
499 if (event
.type
== MappingNotify
)
502 XCALL(XRefreshKeyboardMapping
, (XMappingEvent
*)&event
);
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
);
519 ForeachNode( &xwindowlist
, node
)
521 if (node
->xwindow
== event
.xany
.window
)
528 if (x11clipboard_want_event(&event
))
530 x11clipboard_handle_event(xsd
, &event
);
535 D(bug("Got event for window %x\n", event
.xany
.window
));
542 case ConfigureRequest
:
543 kprintf("!!! CONFIGURE REQUEST !!\n");
547 /* stegerg: not needed */
548 case ConfigureNotify
:
550 /* The window has been resized */
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.
564 Remove((struct Node
*)nmsg
);
565 ReplyMsg((struct Message
*)nmsg
);
576 xsd
->x_time
= event
.xbutton
.time
;
577 D(bug("ButtonPress event\n"));
579 ObtainSemaphoreShared( &xsd
->sema
);
581 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
582 ReleaseSemaphore( &xsd
->sema
);
586 xsd
->x_time
= event
.xbutton
.time
;
587 D(bug("ButtonRelease event\n"));
589 ObtainSemaphoreShared( &xsd
->sema
);
591 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
592 ReleaseSemaphore( &xsd
->sema
);
596 xsd
->x_time
= event
.xmotion
.time
;
597 D(bug("Motionnotify event\n"));
599 ObtainSemaphoreShared( &xsd
->sema
);
601 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
602 ReleaseSemaphore( &xsd
->sema
);
606 #if !BETTER_REPEAT_HANDLING
608 XCALL(XAutoRepeatOn
, xsd
->display
);
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
);
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
);
636 xsd
->x_time
= event
.xkey
.time
;
639 #if !BETTER_REPEAT_HANDLING
640 XCALL(XAutoRepeatOff
, XSD(cl
)->display
);
642 ks
= XCALL(XLookupKeysym
, (XKeyEvent
*)&event
, 0);
647 else if (f12_down
&& ((ks
== XK_Q
) || (ks
== XK_q
)))
649 CCALL(raise
, SIGINT
);
653 ObtainSemaphoreShared( &xsd
->sema
);
656 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &event
);
658 ReleaseSemaphore( &xsd
->sema
);
663 xsd
->x_time
= event
.xkey
.time
;
665 #if BETTER_REPEAT_HANDLING
666 keyrelease_pending
= TRUE
;
667 keyrelease_event
= event
;
670 if (XCALL(XLookupKeysym
, &event
, 0) == XK_F12
)
674 XCALL(XAutoRepeatOn
, XSD(cl
)->display
);
677 ObtainSemaphoreShared( &xsd
->sema
);
680 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &event
);
682 ReleaseSemaphore( &xsd
->sema
);
696 struct notify_msg
*nmsg
, *safe
;
697 struct xwinnode
*node
;
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.
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
;
730 #if !ADJUST_XWIN_SIZE
732 if (event
.xclient
.data
.l
[0] == xsd
->delete_win_atom
)
734 CCALL(raise
, SIGINT
);
739 } /* switch (X11 event type) */
741 } /* if (is event for HIDD window) */
743 } /* while (events from X) */
748 #warning "Also try to free window node list ?"
750 if (xsd
->x11task_notify_port
)
752 DeleteMsgPort(xsd
->x11task_notify_port
);
757 if (NULL
!= unixio_port
)
759 DeleteMsgPort(unixio_port
);
764 OOP_DisposeObject(unixio
);
768 Signal(xtp
.parent
, xtp
.fail_signal
);
772 /****************************************************************************************/
774 struct Task
*create_x11task( struct x11task_params
*params
)
779 task
= AllocMem(sizeof (struct Task
), MEMF_PUBLIC
|MEMF_CLEAR
);
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
);
790 struct TagItem tags
[] =
792 {TASKTAG_ARG1
, (IPTR
)params
},
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
;
802 task
->tc_SPReg
= (UBYTE
*)task
->tc_SPLower
+SP_OFFSET
;
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 */
814 sigset
= Wait( params
->ok_signal
| params
->fail_signal
);
815 if (sigset
& params
->ok_signal
)
821 FreeMem(stack
, XTASK_STACKSIZE
);
824 FreeMem(task
,sizeof(struct Task
));
830 /****************************************************************************************/