Merge with trank @ 137446
[official-gcc.git] / libjava / classpath / gnu / java / awt / peer / x / XEventPump.java
blob7f9843533168c6ba2d3f9b8b54bb1d3d13a30fc8
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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;
63 /**
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
70 implements Runnable
73 /**
74 * The X Display from which we fetch and pump up events.
76 private Display display;
78 /**
79 * Maps X Windows to AWT Windows to be able to correctly determine the
80 * event targets.
82 private HashMap windows;
84 /**
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.
89 private int drag;
91 /**
92 * Creates a new XEventPump for the specified X Display.
94 * @param d the X Display
96 XEventPump(Display d)
98 display = d;
99 windows = new HashMap();
100 drag = -1;
101 Thread thread = new Thread(this, "X Event Pump");
102 thread.setDaemon(true);
103 thread.start();
107 * The main event pump loop. This basically fetches events from the
108 * X Display and pumps them into the system event queue.
110 public void run()
112 while (display.connected)
116 Event xEvent = display.next_event();
117 handleEvent(xEvent);
119 catch (ThreadDeath death)
121 // If someone wants to kill us, let them.
122 return;
124 catch (Throwable x)
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)
141 if (XToolkit.DEBUG)
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)
154 Integer key = null;
155 Window awtWindow = null;
157 if (XToolkit.DEBUG)
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)
170 button = 0;
171 drag = button;
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(),
177 1, false, button);
178 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mp);
179 break;
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)
188 button = 0;
189 drag = -1;
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(),
194 1, false, button);
195 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mr);
196 break;
197 case MotionNotify.CODE:
198 MotionNotify mn = (MotionNotify) xEvent;
199 key= new Integer(mn.event_window_id);
200 awtWindow = (Window) windows.get(key);
202 MouseEvent mm;
203 if (drag == -1)
205 mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_MOVED,
206 System.currentTimeMillis(), 0,
207 mn.event_x(), mn.event_y(),
208 1, false);
210 else
212 mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_DRAGGED,
213 System.currentTimeMillis(), 0,
214 mn.event_x(), mn.event_y(),
215 1, false);
217 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mm);
218 break;
219 case ConfigureNotify.CODE:
220 key= new Integer(((ConfigureNotify) xEvent).event_window_id);
221 awtWindow = (Window) windows.get(key);
222 ConfigureNotify c = (ConfigureNotify) xEvent;
223 if (XToolkit.DEBUG)
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)
232 if (XToolkit.DEBUG)
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;
243 break;
244 case Expose.CODE:
245 key= new Integer(((Expose) xEvent).window_id);
246 awtWindow = (Window) windows.get(key);
247 Expose exp = (Expose) xEvent;
248 if (XToolkit.DEBUG)
249 System.err.println("expose request for window id: " + key);
250 Rectangle r = new Rectangle(exp.x(), exp.y(), exp.width(),
251 exp.height());
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);
257 g.dispose();
258 PaintEvent pev = new PaintEvent(awtWindow, PaintEvent.PAINT, r);
259 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(pev);
260 break;
261 case KeyPress.CODE:
262 case KeyRelease.CODE:
263 key = new Integer(((Input) xEvent).event_window_id);
264 awtWindow = (Window) windows.get(key);
265 handleKeyEvent(xEvent, awtWindow);
266 break;
267 default:
268 if (XToolkit.DEBUG)
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,
285 xMods);
286 char keyChar = KeyboardMapping.mapToKeyChar(xEvent.display.input, xKeyCode,
287 xMods);
288 if (XToolkit.DEBUG)
289 System.err.println("XEventPump.handleKeyEvent: " + xKeyCode + ", "
290 + xMods + ": " + ((int) keyChar) + ", " + keyCode);
291 int awtMods = KeyboardMapping.mapModifiers(xMods);
292 long when = System.currentTimeMillis();
293 KeyEvent ke;
294 if (keyEvent.code() == KeyPress.CODE)
296 ke = new KeyEvent(awtWindow, KeyEvent.KEY_PRESSED, when,
297 awtMods, keyCode,
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,
304 keyChar);
305 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke);
309 else
311 ke = new KeyEvent(awtWindow, KeyEvent.KEY_RELEASED, when,
312 awtMods, keyCode,
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
321 * <code>0</code>.
323 static int buttonToModifier(int button)
325 switch (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;
335 return 0;