2 Copyright © 1995-2008, 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
)
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
);
169 NEWLIST(&xwindowlist
);
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
);
186 unixio
= (HIDD
)New_UnixIO(OOPBase
);
189 unixio_port
= CreateMsgPort();
192 unixiosig
= 1L << unixio_port
->mp_SigBit
;
193 Signal(xtp
.parent
, xtp
.ok_signal
);
201 hostclipboardmask
= x11clipboard_init(xsd
);
206 #if BETTER_REPEAT_HANDLING
207 XEvent keyrelease_event
;
208 BOOL keyrelease_pending
= FALSE
;
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;
217 sigs
= Wait(SIGBREAKF_CTRL_D
| notifysig
| xtp
.kill_signal
| hostclipboardmask
| quitsig
);
225 ret
= (int)Hidd_UnixIO_Wait(unixio
,
226 ConnectionNumber( xsd
->display
),
230 xtp
.kill_signal
| notifysig
| hostclipboardmask
| quitsig
);
237 ret
= Hidd_UnixIO_AsyncIO(unixio
,
238 ConnectionNumber(xsd
->display
),
239 unixio_port
, vHidd_UnixIO_Read
);
244 kprintf("ERROR WHEN CALLING UNIXIO: %d\n", ret
);
255 sigs
= Wait(notifysig
| unixiosig
| xtp
.kill_signal
| hostclipboardmask
| quitsig
);
256 D(bug("Got input from unixio\n"));
266 if (sigs
& unixiosig
)
268 struct uioMessage
*uiomsg
;
271 uiomsg
= (struct uioMessage
*)GetMsg(unixio_port
);
272 result
= uiomsg
->result
;
274 FreeMem(uiomsg
, sizeof (struct uioMessage
));
288 CCALL(raise
, SIGINT
);
291 if (sigs
& xtp
.kill_signal
)
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
)
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
);
313 node
->xwindow
= nmsg
->xwindow
;
314 node
->bmobj
= nmsg
->bmobj
;
315 AddTail( (struct List
*)&xwindowlist
, (struct Node
*)node
);
319 kprintf("!!!! CANNOT GET MEMORY FOR X11 WIN NODE\n");
323 ReplyMsg((struct Message
*)nmsg
);
329 XCALL(XMapWindow
, nmsg
->xdisplay
, nmsg
->xwindow
);
331 XCALL(XMapRaised
, nmsg
->xdisplay
, nmsg
->masterxwindow
);
335 AddTail((struct List
*)&nmsg_list
, (struct Node
*)nmsg
);
337 /* Do not reply message yet */
340 case NOTY_RESIZEWINDOW
:
343 BOOL replymsg
= TRUE
;
344 struct xwinnode
*node
;
346 xwc
.width
= nmsg
->width
;
347 xwc
.height
= nmsg
->height
;
352 x11_fullscreen_switchmode(nmsg
->xdisplay
, &xwc
.width
, &xwc
.height
);
354 XCALL(XConfigureWindow
, nmsg
->xdisplay
355 , nmsg
->masterxwindow
359 XCALL(XFlush
, nmsg
->xdisplay
);
362 #if DELAY_XWIN_MAPPING
363 ForeachNode(&xwindowlist
, node
)
365 if (node
->xwindow
== nmsg
->xwindow
)
367 if (!node
->window_mapped
)
370 XCALL(XMapWindow
, nmsg
->xdisplay
, nmsg
->xwindow
);
372 XCALL(XMapRaised
, nmsg
->xdisplay
, nmsg
->masterxwindow
);
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
);
383 nmsg
->notify_type
= NOTY_MAPWINDOW
;
384 AddTail((struct List
*)&nmsg_list
, (struct Node
*)nmsg
);
386 /* Do not reply message yet */
395 if (replymsg
) ReplyMsg((struct Message
*)nmsg
);
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
);
425 } /* if (message from notify port) */
427 if (sigs
& hostclipboardmask
)
429 x11clipboard_handle_commands(xsd
);
434 struct xwinnode
*node
;
436 BOOL window_found
= FALSE
;
439 XCALL(XFlush
, xsd
->display
);
440 XCALL(XSync
, xsd
->display
, FALSE
);
441 pending
= XCALL(XEventsQueued
, xsd
->display
, QueuedAlready
);
446 #if BETTER_REPEAT_HANDLING
447 if (keyrelease_pending
)
449 if (XCALL(XLookupKeysym
, (XKeyEvent
*)&keyrelease_event
, 0) == XK_F12
)
454 ObtainSemaphoreShared( &xsd
->sema
);
457 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &keyrelease_event
);
459 ReleaseSemaphore( &xsd
->sema
);
460 keyrelease_pending
= FALSE
;
464 /* Get out of for(;;) loop */
469 XCALL(XNextEvent
, xsd
->display
, &event
);
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
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))
491 keyrelease_pending
= FALSE
;
495 /* Drop both previous keyrelease and this keypress event. */
500 if (XCALL(XLookupKeysym
, (XKeyEvent
*)&keyrelease_event
, 0) == XK_F12
)
506 ObtainSemaphoreShared( &xsd
->sema
);
509 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &keyrelease_event
);
511 ReleaseSemaphore( &xsd
->sema
);
515 if (event
.type
== MappingNotify
)
518 XCALL(XRefreshKeyboardMapping
, (XMappingEvent
*)&event
);
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
);
535 ForeachNode( &xwindowlist
, node
)
537 if (node
->xwindow
== event
.xany
.window
)
544 if (x11clipboard_want_event(&event
))
546 x11clipboard_handle_event(xsd
, &event
);
551 D(bug("Got event for window %x\n", event
.xany
.window
));
558 case ConfigureRequest
:
559 kprintf("!!! CONFIGURE REQUEST !!\n");
563 /* stegerg: not needed */
564 case ConfigureNotify
:
566 /* The window has been resized */
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.
580 Remove((struct Node
*)nmsg
);
581 ReplyMsg((struct Message
*)nmsg
);
592 xsd
->x_time
= event
.xbutton
.time
;
593 D(bug("ButtonPress event\n"));
595 ObtainSemaphoreShared( &xsd
->sema
);
597 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
598 ReleaseSemaphore( &xsd
->sema
);
602 xsd
->x_time
= event
.xbutton
.time
;
603 D(bug("ButtonRelease event\n"));
605 ObtainSemaphoreShared( &xsd
->sema
);
607 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
608 ReleaseSemaphore( &xsd
->sema
);
612 xsd
->x_time
= event
.xmotion
.time
;
613 D(bug("Motionnotify event\n"));
615 ObtainSemaphoreShared( &xsd
->sema
);
617 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
618 ReleaseSemaphore( &xsd
->sema
);
622 #if !BETTER_REPEAT_HANDLING
624 XCALL(XAutoRepeatOn
, xsd
->display
);
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
);
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
);
652 xsd
->x_time
= event
.xkey
.time
;
655 #if !BETTER_REPEAT_HANDLING
656 XCALL(XAutoRepeatOff
, XSD(cl
)->display
);
658 ks
= XCALL(XLookupKeysym
, (XKeyEvent
*)&event
, 0);
663 else if (f12_down
&& ((ks
== XK_Q
) || (ks
== XK_q
)))
665 CCALL(raise
, SIGINT
);
669 ObtainSemaphoreShared( &xsd
->sema
);
672 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &event
);
674 ReleaseSemaphore( &xsd
->sema
);
679 xsd
->x_time
= event
.xkey
.time
;
681 #if BETTER_REPEAT_HANDLING
682 keyrelease_pending
= TRUE
;
683 keyrelease_event
= event
;
686 if (XCALL(XLookupKeysym
, &event
, 0) == XK_F12
)
690 XCALL(XAutoRepeatOn
, XSD(cl
)->display
);
693 ObtainSemaphoreShared( &xsd
->sema
);
696 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &event
);
698 ReleaseSemaphore( &xsd
->sema
);
712 struct notify_msg
*nmsg
, *safe
;
713 struct xwinnode
*node
;
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.
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
;
746 #if !ADJUST_XWIN_SIZE
748 if (event
.xclient
.data
.l
[0] == xsd
->delete_win_atom
)
750 CCALL(raise
, SIGINT
);
755 } /* switch (X11 event type) */
757 } /* if (is event for HIDD window) */
759 } /* while (events from X) */
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
);
779 if (NULL
!= unixio_port
)
781 DeleteMsgPort(unixio_port
);
786 OOP_DisposeObject(unixio
);
790 Signal(xtp
.parent
, xtp
.fail_signal
);
794 /****************************************************************************************/
796 struct Task
*create_x11task( struct x11task_params
*params
)
801 task
= AllocMem(sizeof (struct Task
), MEMF_PUBLIC
|MEMF_CLEAR
);
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
);
812 struct TagItem tags
[] =
814 {TASKTAG_ARG1
, (IPTR
)params
},
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
;
824 task
->tc_SPReg
= (UBYTE
*)task
->tc_SPLower
+SP_OFFSET
;
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 */
836 sigset
= Wait( params
->ok_signal
| params
->fail_signal
);
837 if (sigset
& params
->ok_signal
)
843 FreeMem(stack
, XTASK_STACKSIZE
);
846 FreeMem(task
,sizeof(struct Task
));
852 /****************************************************************************************/