2 Copyright © 1995-2016, 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 "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 (AROS_STACKSIZE)
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
);
276 } /* if (message from notify port) */
278 if (sigs
& hostclipboardmask
)
280 x11clipboard_handle_commands(xsd
);
285 struct xwinnode
*node
;
287 BOOL window_found
= FALSE
;
290 XCALL(XFlush
, xsd
->display
);
291 XCALL(XSync
, xsd
->display
, FALSE
);
292 pending
= XCALL(XEventsQueued
, xsd
->display
, QueuedAlready
);
297 #if BETTER_REPEAT_HANDLING
298 if (keyrelease_pending
)
301 if (XCALL(XLookupKeysym
, (XKeyEvent
*)&keyrelease_event
, 0)
308 ObtainSemaphoreShared(&xsd
->sema
);
311 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &keyrelease_event
);
313 ReleaseSemaphore(&xsd
->sema
);
314 keyrelease_pending
= FALSE
;
318 /* Get out of for(;;) loop */
323 XCALL(XNextEvent
, xsd
->display
, &event
);
326 D(bug("Got Event for X=%d\n", event
.xany
.window
));
328 #if BETTER_REPEAT_HANDLING
329 if (keyrelease_pending
)
331 BOOL repeated_key
= FALSE
;
333 /* Saw this in SDL/X11 code, where a comment says that
334 the idea for this was coming from GII, whatever that
337 if ((event
.xany
.window
== keyrelease_event
.xany
.window
)
338 && (event
.type
== KeyPress
)
339 && (event
.xkey
.keycode
== keyrelease_event
.xkey
.keycode
)
340 && ((event
.xkey
.time
- keyrelease_event
.xkey
.time
) < 2))
345 keyrelease_pending
= FALSE
;
349 /* Drop both previous keyrelease and this keypress event. */
354 if (XCALL(XLookupKeysym
, (XKeyEvent
*)&keyrelease_event
, 0)
361 ObtainSemaphoreShared(&xsd
->sema
);
364 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &keyrelease_event
);
366 ReleaseSemaphore(&xsd
->sema
);
370 if (event
.type
== MappingNotify
)
373 XCALL(XRefreshKeyboardMapping
, (XMappingEvent
*)&event
);
380 /* Must check this here, because below only the inner
381 window events are recognized */
383 if ((event
.type
== ClientMessage
) && (event
.xclient
.data
.l
[0] == xsd
->delete_win_atom
))
385 D(bug("Shutting down AROS\n"));
386 CCALL(raise
, SIGINT
);
389 /* Redirect focus from outer window to inner window. This allows
390 keys to be seen without the mouse hovering over the window */
391 if (event
.type
== FocusIn
)
393 ForeachNode(&xwindowlist
, node
)
395 if (node
->masterxwindow
== event
.xfocus
.window
)
398 XCALL(XSetInputFocus
, xsd
->display
, node
->xwindow
,
399 RevertToParent
, CurrentTime
);
407 ForeachNode(&xwindowlist
, node
)
409 if (node
->xwindow
== event
.xany
.window
)
416 if (x11clipboard_want_event(&event
))
418 x11clipboard_handle_event(xsd
, &event
);
423 D(bug("Got event for window %x\n", event
.xany
.window
));
431 X11BM_ExposeFB(OOP_INST_DATA(OOP_OCLASS(node
->bmobj
), node
->bmobj
), event
.xexpose
.x
,
432 event
.xexpose
.y
, event
.xexpose
.width
, event
.xexpose
.height
);
436 case ConfigureRequest
:
437 bug("!!! CONFIGURE REQUEST !!\n");
441 /* stegerg: not needed */
442 case ConfigureNotify
:
444 /* The window has been resized */
447 struct notify_msg
*nmsg
, *safe
;
449 me
= (XConfigureEvent
*)&event
;
450 ForeachNodeSafe(&nmsg_list
, nmsg
, safe
)
452 if ( me
->window
== nmsg
->xwindow
453 && nmsg
->notify_type
== NOTY_RESIZEWINDOW
)
455 /* The window has now been mapped.
458 Remove((struct Node
*)nmsg
);
459 ReplyMsg((struct Message
*)nmsg
);
468 xsd
->x_time
= event
.xbutton
.time
;
469 D(bug("ButtonPress event\n"));
471 ObtainSemaphoreShared(&xsd
->sema
);
473 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
474 ReleaseSemaphore(&xsd
->sema
);
478 xsd
->x_time
= event
.xbutton
.time
;
479 D(bug("ButtonRelease event\n"));
481 ObtainSemaphoreShared(&xsd
->sema
);
483 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
484 ReleaseSemaphore(&xsd
->sema
);
488 xsd
->x_time
= event
.xmotion
.time
;
489 D(bug("Motionnotify event\n"));
491 ObtainSemaphoreShared(&xsd
->sema
);
493 Hidd_X11Mouse_HandleEvent(xsd
->mousehidd
, &event
);
494 ReleaseSemaphore(&xsd
->sema
);
498 #if !BETTER_REPEAT_HANDLING
500 XCALL(XAutoRepeatOn
, xsd
->display
);
506 /* Call the user supplied callback func, if supplied */
507 if (NULL
!= xsd
->activecallback
)
509 xsd
->activecallback(xsd
->callbackdata
, NULL
);
514 xsd
->x_time
= event
.xkey
.time
;
517 #if !BETTER_REPEAT_HANDLING
518 XCALL(XAutoRepeatOff
, XSD(cl
)->display
);
520 ks
= XCALL(XLookupKeysym
, (XKeyEvent
*)&event
, 0);
525 else if (f12_down
&& ((ks
== XK_Q
) || (ks
== XK_q
)))
527 CCALL(raise
, SIGINT
);
531 ObtainSemaphoreShared(&xsd
->sema
);
534 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &event
);
536 ReleaseSemaphore(&xsd
->sema
);
540 xsd
->x_time
= event
.xkey
.time
;
542 #if BETTER_REPEAT_HANDLING
543 keyrelease_pending
= TRUE
;
544 keyrelease_event
= event
;
547 if (XCALL(XLookupKeysym
, &event
, 0) == XK_F12
)
551 XCALL(XAutoRepeatOn
, XSD(cl
)->display
);
554 ObtainSemaphoreShared( &xsd
->sema
);
557 Hidd_X11Kbd_HandleEvent(xsd
->kbdhidd
, &event
);
559 ReleaseSemaphore( &xsd
->sema
);
573 struct notify_msg
*nmsg
, *safe
;
574 struct xwinnode
*node
;
576 me
= (XMapEvent
*) &event
;
578 ForeachNodeSafe(&nmsg_list
, nmsg
, safe
)
580 if (me
->window
== nmsg
->xwindow
&& nmsg
->notify_type
== NOTY_MAPWINDOW
)
582 /* The window has now been mapped.
585 Remove((struct Node
*) nmsg
);
586 ReplyMsg((struct Message
*) nmsg
);
590 /* Find it in the window list and mark it as mapped */
592 ForeachNode(&xwindowlist
, node
)
594 if (node
->xwindow
== me
->window
)
596 node
->window_mapped
= TRUE
;
603 #if !ADJUST_XWIN_SIZE
605 if (event
.xclient
.data
.l
[0] == xsd
->delete_win_atom
)
607 CCALL(raise
, SIGINT
);
612 } /* switch (X11 event type) */
614 } /* if (is event for HIDD window) */
616 } /* while (events from X) */
620 /* Also try to free window node list ? */
621 if (xsd
->x11task_notify_port
)
623 DeleteMsgPort(xsd
->x11task_notify_port
);
627 /****************************************************************************************/
629 struct Task
*create_x11task(struct x11task_params
*params
)
633 D(bug("[X11] %s()\n", __PRETTY_FUNCTION__
));
635 task
= NewCreateTask(TASKTAG_PC
, x11task_entry
, TASKTAG_STACKSIZE
,
636 XTASK_STACKSIZE
, TASKTAG_NAME
, XTASK_NAME
, TASKTAG_PRI
,
637 XTASK_PRIORITY
, TASKTAG_ARG1
, params
, TAG_DONE
);
640 D(bug("[X11] %s: task @ 0x%p\n", __PRETTY_FUNCTION__
, task
));
642 /* Everything went OK. Wait for task to initialize */
645 sigset
= Wait(params
->ok_signal
| params
->fail_signal
);
646 if (sigset
& params
->ok_signal
)
648 D(bug("[X11] %s: got ok signal\n", __PRETTY_FUNCTION__
));
656 /****************************************************************************************/