2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
5 Desc: X11 hidd. Connects to the X server and receives events.
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>
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"
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!)
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)
79 /****************************************************************************************/
81 AROS_INTH1(x11VBlank
, struct Task
*, task
)
85 DB2(bug("[X11] %s()\n", __PRETTY_FUNCTION__
));
87 Signal(task
, SIGBREAKF_CTRL_D
);
94 /****************************************************************************************/
96 VOID
x11task_entry(struct x11task_params
*xtpparam
)
99 struct MinList nmsg_list
;
100 struct MinList xwindowlist
;
101 ULONG hostclipboardmask
;
102 BOOL f12_down
= FALSE
;
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
);
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
));
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
);
149 #if BETTER_REPEAT_HANDLING
150 XEvent keyrelease_event
;
151 BOOL keyrelease_pending
= FALSE
;
153 struct notify_msg
*nmsg
;
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__
));
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
)
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
);
189 node
->xwindow
= nmsg
->xwindow
;
190 node
->masterxwindow
= nmsg
->masterxwindow
;
191 node
->bmobj
= nmsg
->bmobj
;
192 AddTail((struct List
*) &xwindowlist
, (struct Node
*) node
);
196 bug("!!!! CANNOT GET MEMORY FOR X11 WIN NODE\n");
200 ReplyMsg((struct Message
*) nmsg
);
205 D(bug("[X11] %s: NOTY_MAPWINDOW Window @ 0x%p (Display = 0x%p)\n", __PRETTY_FUNCTION__
, nmsg
->xwindow
, nmsg
->xdisplay
));
208 XCALL(XMapWindow
, nmsg
->xdisplay
, nmsg
->xwindow
);
210 XCALL(XMapRaised
, nmsg
->xdisplay
, nmsg
->masterxwindow
);
214 AddTail((struct List
*) &nmsg_list
, (struct Node
*) nmsg
);
216 /* Do not reply message yet */
219 case NOTY_RESIZEWINDOW
:
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
;
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
);
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
)
257 XCALL(XMapWindow
, nmsg
->xdisplay
, nmsg
->xwindow
);
259 XCALL(XMapRaised
, nmsg
->xdisplay
, nmsg
->masterxwindow
);
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
);
270 nmsg
->notify_type
= NOTY_MAPWINDOW
;
271 AddTail((struct List
*) &nmsg_list
, (struct Node
*) nmsg
);
273 /* Do not reply message yet */
283 ReplyMsg((struct Message
*) nmsg
);
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
);
307 } /* if (message from notify port) */
309 if (sigs
& hostclipboardmask
)
311 x11clipboard_handle_commands(xsd
);
316 struct xwinnode
*node
;
318 BOOL window_found
= FALSE
;
321 XCALL(XFlush
, xsd
->display
);
322 XCALL(XSync
, xsd
->display
, FALSE
);
323 pending
= XCALL(XEventsQueued
, xsd
->display
, QueuedAlready
);
328 #if BETTER_REPEAT_HANDLING
329 if (keyrelease_pending
)
332 if (XCALL(XLookupKeysym
, (XKeyEvent
*)&keyrelease_event
, 0)
339 ObtainSemaphoreShared(&xsd
->sema
);
342 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &keyrelease_event
);
344 ReleaseSemaphore(&xsd
->sema
);
345 keyrelease_pending
= FALSE
;
349 /* Get out of for(;;) loop */
354 XCALL(XNextEvent
, xsd
->display
, &event
);
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
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))
376 keyrelease_pending
= FALSE
;
380 /* Drop both previous keyrelease and this keypress event. */
385 if (XCALL(XLookupKeysym
, (XKeyEvent
*)&keyrelease_event
, 0)
392 ObtainSemaphoreShared(&xsd
->sema
);
395 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &keyrelease_event
);
397 ReleaseSemaphore(&xsd
->sema
);
401 if (event
.type
== MappingNotify
)
404 XCALL(XRefreshKeyboardMapping
, (XMappingEvent
*)&event
);
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
)
429 XCALL(XSetInputFocus
, xsd
->display
, node
->xwindow
,
430 RevertToParent
, CurrentTime
);
438 ForeachNode(&xwindowlist
, node
)
440 if (node
->xwindow
== event
.xany
.window
)
447 if (x11clipboard_want_event(&event
))
449 x11clipboard_handle_event(xsd
, &event
);
454 D(bug("Got event for window %x\n", event
.xany
.window
));
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
);
467 case ConfigureRequest
:
468 bug("!!! CONFIGURE REQUEST !!\n");
472 /* stegerg: not needed */
473 case ConfigureNotify
:
475 /* The window has been resized */
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.
489 Remove((struct Node
*)nmsg
);
490 ReplyMsg((struct Message
*)nmsg
);
499 xsd
->x_time
= event
.xbutton
.time
;
500 D(bug("ButtonPress event\n"));
502 ObtainSemaphoreShared(&xsd
->sema
);
504 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
505 ReleaseSemaphore(&xsd
->sema
);
509 xsd
->x_time
= event
.xbutton
.time
;
510 D(bug("ButtonRelease event\n"));
512 ObtainSemaphoreShared(&xsd
->sema
);
514 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
515 ReleaseSemaphore(&xsd
->sema
);
519 xsd
->x_time
= event
.xmotion
.time
;
520 D(bug("Motionnotify event\n"));
522 ObtainSemaphoreShared(&xsd
->sema
);
524 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
525 ReleaseSemaphore(&xsd
->sema
);
529 #if !BETTER_REPEAT_HANDLING
531 XCALL(XAutoRepeatOn
, xsd
->display
);
537 /* Call the user supplied callback func, if supplied */
538 if (NULL
!= xsd
->activecallback
)
540 xsd
->activecallback(xsd
->callbackdata
, NULL
);
545 xsd
->x_time
= event
.xkey
.time
;
548 #if !BETTER_REPEAT_HANDLING
549 XCALL(XAutoRepeatOff
, XSD(cl
)->display
);
551 ks
= XCALL(XLookupKeysym
, (XKeyEvent
*)&event
, 0);
556 else if (f12_down
&& ((ks
== XK_Q
) || (ks
== XK_q
)))
558 CCALL(raise
, SIGINT
);
562 ObtainSemaphoreShared(&xsd
->sema
);
565 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &event
);
567 ReleaseSemaphore(&xsd
->sema
);
571 xsd
->x_time
= event
.xkey
.time
;
573 #if BETTER_REPEAT_HANDLING
574 keyrelease_pending
= TRUE
;
575 keyrelease_event
= event
;
578 if (XCALL(XLookupKeysym
, &event
, 0) == XK_F12
)
582 XCALL(XAutoRepeatOn
, XSD(cl
)->display
);
585 ObtainSemaphoreShared( &xsd
->sema
);
588 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &event
);
590 ReleaseSemaphore( &xsd
->sema
);
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.
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
;
634 #if !ADJUST_XWIN_SIZE
636 if (event
.xclient
.data
.l
[0] == xsd
->delete_win_atom
)
638 CCALL(raise
, SIGINT
);
643 } /* switch (X11 event type) */
645 } /* if (is event for HIDD window) */
647 } /* while (events from X) */
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
)
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
);
671 D(bug("[X11] %s: task @ 0x%p\n", __PRETTY_FUNCTION__
, task
));
673 /* Everything went OK. Wait for task to initialize */
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__
));
687 /****************************************************************************************/