1 /* XEventPump.java -- Pumps events from X to AWT
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu
.java
.awt
.peer
.x
;
41 import java
.awt
.Graphics
;
42 import java
.awt
.Insets
;
43 import java
.awt
.Rectangle
;
44 import java
.awt
.Toolkit
;
45 import java
.awt
.Window
;
46 import java
.awt
.event
.ComponentEvent
;
47 import java
.awt
.event
.KeyEvent
;
48 import java
.awt
.event
.MouseEvent
;
49 import java
.awt
.event
.PaintEvent
;
50 import java
.util
.HashMap
;
52 import gnu
.x11
.Display
;
53 import gnu
.x11
.event
.ButtonPress
;
54 import gnu
.x11
.event
.ButtonRelease
;
55 import gnu
.x11
.event
.ConfigureNotify
;
56 import gnu
.x11
.event
.Event
;
57 import gnu
.x11
.event
.Expose
;
58 import gnu
.x11
.event
.Input
;
59 import gnu
.x11
.event
.KeyPress
;
60 import gnu
.x11
.event
.KeyRelease
;
61 import gnu
.x11
.event
.MotionNotify
;
64 * Fetches events from X, translates them to AWT events and pumps them up
65 * into the AWT event queue.
67 * @author Roman Kennke (kennke@aicas.com)
69 public class XEventPump
74 * The X Display from which we fetch and pump up events.
76 private Display display
;
79 * Maps X Windows to AWT Windows to be able to correctly determine the
82 private HashMap windows
;
85 * Indicates if we are currently inside a drag operation. This is
86 * set to the button ID when a button is pressed and to -1 (indicating
87 * that no drag is active) when the mouse is released.
92 * Creates a new XEventPump for the specified X Display.
94 * @param d the X Display
99 windows
= new HashMap();
101 Thread thread
= new Thread(this, "X Event Pump");
102 thread
.setDaemon(true);
107 * The main event pump loop. This basically fetches events from the
108 * X Display and pumps them into the system event queue.
112 while (display
.connected
)
116 Event xEvent
= display
.next_event();
119 catch (ThreadDeath death
)
121 // If someone wants to kill us, let them.
126 System
.err
.println("Exception during event dispatch:");
127 x
.printStackTrace(System
.err
);
133 * Adds an X Window to AWT Window mapping. This is required so that the
134 * event pump can correctly determine the event targets.
136 * @param xWindow the X Window
137 * @param awtWindow the AWT Window
139 void registerWindow(gnu
.x11
.Window xWindow
, Window awtWindow
)
142 System
.err
.println("registering window id: " + xWindow
.id
);
143 windows
.put(new Integer(xWindow
.id
), awtWindow
);
146 void unregisterWindow(gnu
.x11
.Window xWindow
)
148 windows
.remove(new Integer(xWindow
.id
));
151 private void handleEvent(Event xEvent
)
155 Window awtWindow
= null;
158 System
.err
.println("fetched event: " + xEvent
);
159 switch (xEvent
.code())
161 case ButtonPress
.CODE
:
162 ButtonPress bp
= (ButtonPress
) xEvent
;
163 key
= new Integer(bp
.event_window_id
);
164 awtWindow
= (Window
) windows
.get(key
);
165 // Create and post the mouse event.
166 int button
= bp
.detail();
168 // AWT cannot handle more than 3 buttons and expects 0 instead.
169 if (button
>= gnu
.x11
.Input
.BUTTON3
)
173 MouseEvent mp
= new MouseEvent(awtWindow
, MouseEvent
.MOUSE_PRESSED
,
174 System
.currentTimeMillis(),
175 KeyboardMapping
.mapModifiers(bp
.state()) | buttonToModifier(button
),
176 bp
.event_x(), bp
.event_y(),
178 Toolkit
.getDefaultToolkit().getSystemEventQueue().postEvent(mp
);
180 case ButtonRelease
.CODE
:
181 ButtonRelease br
= (ButtonRelease
) xEvent
;
182 key
= new Integer(br
.event_window_id
);
183 awtWindow
= (Window
) windows
.get(key
);
185 button
= br
.detail();
186 // AWT cannot handle more than 3 buttons and expects 0 instead.
187 if (button
>= gnu
.x11
.Input
.BUTTON3
)
190 MouseEvent mr
= new MouseEvent(awtWindow
, MouseEvent
.MOUSE_RELEASED
,
191 System
.currentTimeMillis(),
192 KeyboardMapping
.mapModifiers(br
.state()) | buttonToModifier(button
),
193 br
.event_x(), br
.event_y(),
195 Toolkit
.getDefaultToolkit().getSystemEventQueue().postEvent(mr
);
197 case MotionNotify
.CODE
:
198 MotionNotify mn
= (MotionNotify
) xEvent
;
199 key
= new Integer(mn
.event_window_id
);
200 awtWindow
= (Window
) windows
.get(key
);
205 mm
= new MouseEvent(awtWindow
, MouseEvent
.MOUSE_MOVED
,
206 System
.currentTimeMillis(), 0,
207 mn
.event_x(), mn
.event_y(),
212 mm
= new MouseEvent(awtWindow
, MouseEvent
.MOUSE_DRAGGED
,
213 System
.currentTimeMillis(), 0,
214 mn
.event_x(), mn
.event_y(),
217 Toolkit
.getDefaultToolkit().getSystemEventQueue().postEvent(mm
);
219 case ConfigureNotify
.CODE
:
220 key
= new Integer(((ConfigureNotify
) xEvent
).event_window_id
);
221 awtWindow
= (Window
) windows
.get(key
);
222 ConfigureNotify c
= (ConfigureNotify
) xEvent
;
224 System
.err
.println("resize request for window id: " + key
);
226 // Detect and report size changes.
227 XWindowPeer xwindow
= (XWindowPeer
) awtWindow
.getPeer();
228 Insets i
= xwindow
.insets();
229 if (c
.width() != awtWindow
.getWidth() - i
.left
- i
.right
230 || c
.height() != awtWindow
.getHeight() - i
.top
- i
.bottom
)
233 System
.err
.println("Setting size on AWT window: " + c
.width()
234 + ", " + c
.height() + ", " + awtWindow
.getWidth()
235 + ", " + awtWindow
.getHeight());
236 xwindow
.callback
= true;
237 xwindow
.xwindow
.width
= c
.width();
238 xwindow
.xwindow
.height
= c
.height();
239 awtWindow
.setSize(c
.width() + i
.left
+ i
.right
,
240 c
.height() + i
.top
+ i
.bottom
);
241 xwindow
.callback
= false;
245 key
= new Integer(((Expose
) xEvent
).window_id
);
246 awtWindow
= (Window
) windows
.get(key
);
247 Expose exp
= (Expose
) xEvent
;
249 System
.err
.println("expose request for window id: " + key
);
250 Rectangle r
= new Rectangle(exp
.x(), exp
.y(), exp
.width(),
252 //System.err.println("expose paint: " + r);
253 // We need to clear the background of the exposed rectangle.
254 assert awtWindow
!= null : "awtWindow == null for window ID: " + key
;
255 Graphics g
= awtWindow
.getGraphics();
256 g
.clearRect(r
.x
, r
.y
, r
.width
, r
.height
);
258 PaintEvent pev
= new PaintEvent(awtWindow
, PaintEvent
.PAINT
, r
);
259 Toolkit
.getDefaultToolkit().getSystemEventQueue().postEvent(pev
);
262 case KeyRelease
.CODE
:
263 key
= new Integer(((Input
) xEvent
).event_window_id
);
264 awtWindow
= (Window
) windows
.get(key
);
265 handleKeyEvent(xEvent
, awtWindow
);
269 System
.err
.println("Unhandled X event: " + xEvent
);
274 * Handles key events from X.
276 * @param xEvent the X event
277 * @param awtWindow the AWT window to which the event gets posted
279 private void handleKeyEvent(Event xEvent
, Window awtWindow
)
281 Input keyEvent
= (Input
) xEvent
;
282 int xKeyCode
= keyEvent
.detail();
283 int xMods
= keyEvent
.state();
284 int keyCode
= KeyboardMapping
.mapToKeyCode(xEvent
.display
.input
, xKeyCode
,
286 char keyChar
= KeyboardMapping
.mapToKeyChar(xEvent
.display
.input
, xKeyCode
,
289 System
.err
.println("XEventPump.handleKeyEvent: " + xKeyCode
+ ", "
290 + xMods
+ ": " + ((int) keyChar
) + ", " + keyCode
);
291 int awtMods
= KeyboardMapping
.mapModifiers(xMods
);
292 long when
= System
.currentTimeMillis();
294 if (keyEvent
.code() == KeyPress
.CODE
)
296 ke
= new KeyEvent(awtWindow
, KeyEvent
.KEY_PRESSED
, when
,
298 KeyEvent
.CHAR_UNDEFINED
);
299 Toolkit
.getDefaultToolkit().getSystemEventQueue().postEvent(ke
);
300 if (keyChar
!= KeyEvent
.CHAR_UNDEFINED
)
302 ke
= new KeyEvent(awtWindow
, KeyEvent
.KEY_TYPED
, when
,
303 awtMods
, KeyEvent
.VK_UNDEFINED
,
305 Toolkit
.getDefaultToolkit().getSystemEventQueue().postEvent(ke
);
311 ke
= new KeyEvent(awtWindow
, KeyEvent
.KEY_RELEASED
, when
,
313 KeyEvent
.CHAR_UNDEFINED
);
314 Toolkit
.getDefaultToolkit().getSystemEventQueue().postEvent(ke
);
319 /** Translates an X button identifier to the AWT's MouseEvent modifier
320 * mask. As the AWT cannot handle more than 3 buttons those return
323 static int buttonToModifier(int button
)
327 case gnu
.x11
.Input
.BUTTON1
:
328 return MouseEvent
.BUTTON1_DOWN_MASK
| MouseEvent
.BUTTON1_MASK
;
329 case gnu
.x11
.Input
.BUTTON2
:
330 return MouseEvent
.BUTTON2_DOWN_MASK
| MouseEvent
.BUTTON2_MASK
;
331 case gnu
.x11
.Input
.BUTTON3
:
332 return MouseEvent
.BUTTON3_DOWN_MASK
| MouseEvent
.BUTTON3_MASK
;