2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
5 Desc: X11 hidd. Connects to the X server and receives events.
11 #include <hardware/intbits.h>
13 #include <X11/keysym.h>
16 #include "x11_types.h"
18 #include "x11_hostlib.h"
19 #include "x11gfx_fullscreen.h"
21 VOID
X11BM_ExposeFB(APTR data
, WORD x
, WORD y
, WORD width
, WORD height
);
23 /****************************************************************************************/
25 #define BETTER_REPEAT_HANDLING 1
27 #define XTASK_NAME "x11hidd task"
29 /* We need to have highest priority for this task, because we
30 are simulating an interrupt. I.e. an "interrupt handler" called
31 by this task should NEVER be interrupted by a task (for example input.device),
32 otherwise it will give strange effects, especially in the circular-buffer
33 handling in gameport/keyboard. (Writing to the buffer is not atomic even
34 from within the IRQ handler!)
37 the irq handler directly from the task, we should instead
38 Cause() a software irq, but Cause() does not work at the moment..
41 #define XTASK_PRIORITY 50
43 #define XTASK_STACKSIZE 100000
48 /****************************************************************************************/
50 AROS_INTH1(x11VBlank
, struct Task
*, task
)
54 DB2(bug("[X11] %s()\n", __PRETTY_FUNCTION__
));
56 Signal(task
, SIGBREAKF_CTRL_D
);
63 /****************************************************************************************/
65 VOID
x11task_entry(struct x11task_params
*xtpparam
)
68 struct MinList nmsg_list
;
69 struct MinList xwindowlist
;
70 ULONG hostclipboardmask
;
71 BOOL f12_down
= FALSE
;
74 /* copy needed parameter's because they are allocated on the parent's stack */
76 struct Task
*task_Parent
= xtpparam
->parent
;
77 ULONG task_SigKill
= xtpparam
->kill_signal
;
78 struct x11_staticdata
*xsd
= xtpparam
->xsd
;
80 struct Interrupt myint
;
82 D(bug("[X11] %s()\n", __PRETTY_FUNCTION__
));
84 xsd
->x11task_notify_port
= CreateMsgPort();
85 if (NULL
== xsd
->x11task_notify_port
)
87 D(bug("[X11] %s: failed to create notification port!\n", __PRETTY_FUNCTION__
));
88 Signal(task_Parent
, xtpparam
->fail_signal
);
92 D(bug("[X11] %s: notification port @ 0x%p\n", __PRETTY_FUNCTION__
, xsd
->x11task_notify_port
));
94 notifysig
= 1L << xsd
->x11task_notify_port
->mp_SigBit
;
96 D(bug("[X11] %s: notification signal = %08x (bit %d)\n", __PRETTY_FUNCTION__
, notifysig
, xsd
->x11task_notify_port
->mp_SigBit
));
99 NEWLIST(&xwindowlist
);
101 myint
.is_Code
= (VOID_FUNC
) x11VBlank
;
102 myint
.is_Data
= FindTask(NULL
);
103 myint
.is_Node
.ln_Name
= "X11 VBlank server";
104 myint
.is_Node
.ln_Pri
= 0;
105 myint
.is_Node
.ln_Type
= NT_INTERRUPT
;
107 AddIntServer(INTB_VERTB
, &myint
);
109 Signal(task_Parent
, xtpparam
->ok_signal
);
111 /* N.B : do not attempt to use xtpparam after this point! */
113 hostclipboardmask
= x11clipboard_init(xsd
);
118 #if BETTER_REPEAT_HANDLING
119 XEvent keyrelease_event
;
120 BOOL keyrelease_pending
= FALSE
;
122 struct notify_msg
*nmsg
;
125 DB2(bug("[X11] %s: waiting for signals...\n", __PRETTY_FUNCTION__
));
127 sigs
= Wait(SIGBREAKF_CTRL_D
| notifysig
| task_SigKill
| hostclipboardmask
);
129 DB2(bug("[X11] %s: signal %08x received\n", __PRETTY_FUNCTION__
, sigs
));
131 if (sigs
& task_SigKill
)
133 D(bug("[X11] %s: kill signal received - exiting\n", __PRETTY_FUNCTION__
));
137 if (sigs
& notifysig
)
139 D(bug("[X11] %s: notification signal received\n", __PRETTY_FUNCTION__
));
141 while ((nmsg
= (struct notify_msg
*) GetMsg(xsd
->x11task_notify_port
)))
143 /* Add the messages to an internal list */
145 switch (nmsg
->notify_type
)
149 struct xwinnode
* node
;
150 /* Maintain a list of open windows for the X11 event handler in x11.c */
152 D(bug("[X11] %s: NOTY_WINCREATE\n", __PRETTY_FUNCTION__
));
154 node
= AllocMem(sizeof(struct xwinnode
), MEMF_CLEAR
);
158 node
->xwindow
= nmsg
->xwindow
;
159 node
->masterxwindow
= nmsg
->masterxwindow
;
160 node
->bmobj
= nmsg
->bmobj
;
161 AddTail((struct List
*) &xwindowlist
, (struct Node
*) node
);
165 bug("!!!! CANNOT GET MEMORY FOR X11 WIN NODE\n");
169 ReplyMsg((struct Message
*) nmsg
);
174 D(bug("[X11] %s: NOTY_MAPWINDOW Window @ 0x%p (Display = 0x%p)\n", __PRETTY_FUNCTION__
, nmsg
->xwindow
, nmsg
->xdisplay
));
177 XCALL(XMapWindow
, nmsg
->xdisplay
, nmsg
->xwindow
);
179 XCALL(XMapRaised
, nmsg
->xdisplay
, nmsg
->masterxwindow
);
183 AddTail((struct List
*) &nmsg_list
, (struct Node
*) nmsg
);
185 /* Do not reply message yet */
188 case NOTY_RESIZEWINDOW
:
192 BOOL replymsg
= TRUE
;
194 D(bug("[X11] %s: NOTY_RESIZEWINDOW\n", __PRETTY_FUNCTION__
));
196 xwc
.width
= nmsg
->width
;
197 xwc
.height
= nmsg
->height
;
199 sizehint
.flags
= PMinSize
| PMaxSize
;
200 sizehint
.min_width
= nmsg
->width
;
201 sizehint
.min_height
= nmsg
->height
;
202 sizehint
.max_width
= nmsg
->width
;
203 sizehint
.max_height
= nmsg
->height
;
206 if (xsd
->options
& OPTION_FULLSCREEN
)
208 x11_fullscreen_switchmode(nmsg
->xdisplay
, &xwc
.width
, &xwc
.height
);
211 XCALL(XSetWMNormalHints
, nmsg
->xdisplay
, nmsg
->masterxwindow
, &sizehint
);
212 XCALL(XConfigureWindow
, nmsg
->xdisplay
, nmsg
->masterxwindow
, CWWidth
| CWHeight
, &xwc
);
213 XCALL(XFlush
, nmsg
->xdisplay
);
216 if (xsd
->options
& OPTION_DELAYXWINMAPPING
)
218 struct xwinnode
*node
;
219 ForeachNode(&xwindowlist
, node
)
221 if (node
->xwindow
== nmsg
->xwindow
)
223 if (!node
->window_mapped
)
226 XCALL(XMapWindow
, nmsg
->xdisplay
, nmsg
->xwindow
);
228 XCALL(XMapRaised
, nmsg
->xdisplay
, nmsg
->masterxwindow
);
230 if (xsd
->options
& OPTION_FULLSCREEN
)
232 XCALL(XGrabKeyboard
, nmsg
->xdisplay
, nmsg
->xwindow
, False
, GrabModeAsync
, GrabModeAsync
, CurrentTime
);
233 XCALL(XGrabPointer
, nmsg
->xdisplay
, nmsg
->xwindow
, 1, PointerMotionMask
| ButtonPressMask
| ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
, nmsg
->xwindow
, None
, CurrentTime
);
236 XCALL(XFlush
, nmsg
->xdisplay
);
239 nmsg
->notify_type
= NOTY_MAPWINDOW
;
240 AddTail((struct List
*) &nmsg_list
, (struct Node
*) nmsg
);
242 /* Do not reply message yet */
252 ReplyMsg((struct Message
*) nmsg
);
256 case NOTY_WINDISPOSE
:
258 struct xwinnode
*node
, *safe
;
260 D(bug("[X11] %s: NOTY_WINDISPOSE\n", __PRETTY_FUNCTION__
));
262 ForeachNodeSafe(&xwindowlist
, node
, safe
)
264 if (node
->xwindow
== nmsg
->xwindow
)
266 Remove((struct Node
*) node
);
267 FreeMem(node
, sizeof(struct xwinnode
));
270 ReplyMsg((struct Message
*) nmsg
);
275 struct xwinnode
*node
;
277 D(bug("[X11] %s: NOTY_NEWCURSOR\n",
278 __PRETTY_FUNCTION__
));
281 ForeachNode(&xwindowlist
, node
)
283 XCALL(XDefineCursor
, nmsg
->xdisplay
, node
->xwindow
,
284 (Cursor
) nmsg
->xwindow
);
286 XCALL(XFlush
, nmsg
->xdisplay
);
289 ReplyMsg((struct Message
*) nmsg
);
296 } /* if (message from notify port) */
298 if (sigs
& hostclipboardmask
)
300 x11clipboard_handle_commands(xsd
);
305 struct xwinnode
*node
;
307 BOOL window_found
= FALSE
;
310 XCALL(XFlush
, xsd
->display
);
311 XCALL(XSync
, xsd
->display
, FALSE
);
312 pending
= XCALL(XEventsQueued
, xsd
->display
, QueuedAlready
);
317 #if BETTER_REPEAT_HANDLING
318 if (keyrelease_pending
)
321 if (XCALL(XLookupKeysym
, (XKeyEvent
*)&keyrelease_event
, 0)
328 ObtainSemaphoreShared(&xsd
->sema
);
331 Hidd_Kbd_X11_HandleEvent(xsd
->kbdhidd
, &keyrelease_event
);
333 ReleaseSemaphore(&xsd
->sema
);
334 keyrelease_pending
= FALSE
;
338 /* Get out of for(;;) loop */
343 XCALL(XNextEvent
, xsd
->display
, &event
);
346 D(bug("Got Event for X=%d\n", event
.xany
.window
));
348 #if BETTER_REPEAT_HANDLING
349 if (keyrelease_pending
)
351 BOOL repeated_key
= FALSE
;
353 /* Saw this in SDL/X11 code, where a comment says that
354 the idea for this was coming from GII, whatever that
357 if ((event
.xany
.window
== keyrelease_event
.xany
.window
)
358 && (event
.type
== KeyPress
)
359 && (event
.xkey
.keycode
== keyrelease_event
.xkey
.keycode
)
360 && ((event
.xkey
.time
- keyrelease_event
.xkey
.time
) < 2))
365 keyrelease_pending
= FALSE
;
369 /* Drop both previous keyrelease and this keypress event. */
374 if (XCALL(XLookupKeysym
, (XKeyEvent
*)&keyrelease_event
, 0)
381 ObtainSemaphoreShared(&xsd
->sema
);
384 Hidd_Kbd_X11_HandleEvent(xsd
->kbdhidd
, &keyrelease_event
);
386 ReleaseSemaphore(&xsd
->sema
);
390 if (event
.type
== MappingNotify
)
393 XCALL(XRefreshKeyboardMapping
, (XMappingEvent
*)&event
);
400 /* Must check this here, because below only the inner
401 window events are recognized */
403 if ((event
.type
== ClientMessage
) && (event
.xclient
.data
.l
[0] == xsd
->delete_win_atom
))
405 D(bug("Shutting down AROS\n"));
406 CCALL(raise
, SIGINT
);
409 /* Redirect focus from outer window to inner window. This allows
410 keys to be seen without the mouse hovering over the window */
411 if (event
.type
== FocusIn
)
413 ForeachNode(&xwindowlist
, node
)
415 if (node
->masterxwindow
== event
.xfocus
.window
)
418 XCALL(XSetInputFocus
, xsd
->display
, node
->xwindow
,
419 RevertToParent
, CurrentTime
);
427 ForeachNode(&xwindowlist
, node
)
429 if (node
->xwindow
== event
.xany
.window
)
436 if (x11clipboard_want_event(&event
))
438 x11clipboard_handle_event(xsd
, &event
);
443 D(bug("Got event for window %x\n", event
.xany
.window
));
451 X11BM_ExposeFB(OOP_INST_DATA(OOP_OCLASS(node
->bmobj
), node
->bmobj
), event
.xexpose
.x
,
452 event
.xexpose
.y
, event
.xexpose
.width
, event
.xexpose
.height
);
456 case ConfigureRequest
:
457 bug("!!! CONFIGURE REQUEST !!\n");
461 /* stegerg: not needed */
462 case ConfigureNotify
:
464 /* The window has been resized */
467 struct notify_msg
*nmsg
, *safe
;
469 me
= (XConfigureEvent
*)&event
;
470 ForeachNodeSafe(&nmsg_list
, nmsg
, safe
)
472 if ( me
->window
== nmsg
->xwindow
473 && nmsg
->notify_type
== NOTY_RESIZEWINDOW
)
475 /* The window has now been mapped.
478 Remove((struct Node
*)nmsg
);
479 ReplyMsg((struct Message
*)nmsg
);
488 xsd
->x_time
= event
.xbutton
.time
;
489 D(bug("ButtonPress event\n"));
491 ObtainSemaphoreShared(&xsd
->sema
);
493 Hidd_Mouse_X11_HandleEvent(xsd
->mousehidd
, &event
);
494 ReleaseSemaphore(&xsd
->sema
);
498 xsd
->x_time
= event
.xbutton
.time
;
499 D(bug("ButtonRelease event\n"));
501 ObtainSemaphoreShared(&xsd
->sema
);
503 Hidd_Mouse_X11_HandleEvent(xsd
->mousehidd
, &event
);
504 ReleaseSemaphore(&xsd
->sema
);
508 xsd
->x_time
= event
.xmotion
.time
;
509 D(bug("Motionnotify event\n"));
511 ObtainSemaphoreShared(&xsd
->sema
);
513 Hidd_Mouse_X11_HandleEvent(xsd
->mousehidd
, &event
);
514 ReleaseSemaphore(&xsd
->sema
);
518 #if !BETTER_REPEAT_HANDLING
520 XCALL(XAutoRepeatOn
, xsd
->display
);
526 /* Call the user supplied callback func, if supplied */
527 if (NULL
!= xsd
->activecallback
)
529 xsd
->activecallback(xsd
->callbackdata
, NULL
);
534 xsd
->x_time
= event
.xkey
.time
;
537 #if !BETTER_REPEAT_HANDLING
538 XCALL(XAutoRepeatOff
, XSD(cl
)->display
);
540 ks
= XCALL(XLookupKeysym
, (XKeyEvent
*)&event
, 0);
545 else if (f12_down
&& ((ks
== XK_Q
) || (ks
== XK_q
)))
547 CCALL(raise
, SIGINT
);
551 ObtainSemaphoreShared(&xsd
->sema
);
554 Hidd_Kbd_X11_HandleEvent(xsd
->kbdhidd
, &event
);
556 ReleaseSemaphore(&xsd
->sema
);
560 xsd
->x_time
= event
.xkey
.time
;
562 #if BETTER_REPEAT_HANDLING
563 keyrelease_pending
= TRUE
;
564 keyrelease_event
= event
;
567 if (XCALL(XLookupKeysym
, &event
, 0) == XK_F12
)
571 XCALL(XAutoRepeatOn
, XSD(cl
)->display
);
574 ObtainSemaphoreShared( &xsd
->sema
);
577 Hidd_Kbd_X11_HandleEvent(xsd
->kbdhidd
, &event
);
579 ReleaseSemaphore( &xsd
->sema
);
593 struct notify_msg
*nmsg
, *safe
;
594 struct xwinnode
*node
;
596 me
= (XMapEvent
*) &event
;
598 ForeachNodeSafe(&nmsg_list
, nmsg
, safe
)
600 if (me
->window
== nmsg
->xwindow
&& nmsg
->notify_type
== NOTY_MAPWINDOW
)
602 /* The window has now been mapped.
605 Remove((struct Node
*) nmsg
);
606 ReplyMsg((struct Message
*) nmsg
);
610 /* Find it in the window list and mark it as mapped */
612 ForeachNode(&xwindowlist
, node
)
614 if (node
->xwindow
== me
->window
)
616 node
->window_mapped
= TRUE
;
623 #if !ADJUST_XWIN_SIZE
625 if (event
.xclient
.data
.l
[0] == xsd
->delete_win_atom
)
627 CCALL(raise
, SIGINT
);
632 } /* switch (X11 event type) */
634 } /* if (is event for HIDD window) */
636 } /* while (events from X) */
640 /* Also try to free window node list ? */
641 if (xsd
->x11task_notify_port
)
643 DeleteMsgPort(xsd
->x11task_notify_port
);
647 /****************************************************************************************/
649 struct Task
*create_x11task(struct x11task_params
*params
)
653 D(bug("[X11] %s()\n", __PRETTY_FUNCTION__
));
655 task
= NewCreateTask(TASKTAG_PC
, x11task_entry
, TASKTAG_STACKSIZE
,
656 XTASK_STACKSIZE
, TASKTAG_NAME
, XTASK_NAME
, TASKTAG_PRI
,
657 XTASK_PRIORITY
, TASKTAG_ARG1
, params
, TAG_DONE
);
660 D(bug("[X11] %s: task @ 0x%p\n", __PRETTY_FUNCTION__
, task
));
662 /* Everything went OK. Wait for task to initialize */
665 sigset
= Wait(params
->ok_signal
| params
->fail_signal
);
666 if (sigset
& params
->ok_signal
)
668 D(bug("[X11] %s: got ok signal\n", __PRETTY_FUNCTION__
));
676 /****************************************************************************************/