libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / gnu / java / awt / peer / x / XEventPump.java
blob379839196b2f79898c267deb2b467a524e3d265e
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.AWTEvent;
42 import java.awt.Component;
43 import java.awt.Container;
44 import java.awt.Graphics;
45 import java.awt.Insets;
46 import java.awt.Rectangle;
47 import java.awt.Toolkit;
48 import java.awt.Window;
49 import java.awt.event.ComponentEvent;
50 import java.awt.event.KeyEvent;
51 import java.awt.event.MouseEvent;
52 import java.awt.event.PaintEvent;
53 import java.awt.event.WindowEvent;
54 import java.util.HashMap;
56 import gnu.java.awt.ComponentReshapeEvent;
57 import gnu.x11.Atom;
58 import gnu.x11.Display;
59 import gnu.x11.event.ButtonPress;
60 import gnu.x11.event.ButtonRelease;
61 import gnu.x11.event.ClientMessage;
62 import gnu.x11.event.ConfigureNotify;
63 import gnu.x11.event.DestroyNotify;
64 import gnu.x11.event.Event;
65 import gnu.x11.event.Expose;
66 import gnu.x11.event.Input;
67 import gnu.x11.event.KeyPress;
68 import gnu.x11.event.KeyRelease;
69 import gnu.x11.event.MotionNotify;
70 import gnu.x11.event.PropertyNotify;
71 import gnu.x11.event.ResizeRequest;
72 import gnu.x11.event.UnmapNotify;
74 /**
75 * Fetches events from X, translates them to AWT events and pumps them up
76 * into the AWT event queue.
78 * @author Roman Kennke (kennke@aicas.com)
80 public class XEventPump
81 implements Runnable
84 /**
85 * The X Display from which we fetch and pump up events.
87 private Display display;
89 /**
90 * Maps X Windows to AWT Windows to be able to correctly determine the
91 * event targets.
93 private HashMap windows;
95 /**
96 * Indicates if we are currently inside a drag operation. This is
97 * set to the button ID when a button is pressed and to -1 (indicating
98 * that no drag is active) when the mouse is released.
100 private int drag;
103 * Creates a new XEventPump for the specified X Display.
105 * @param d the X Display
107 XEventPump(Display d)
109 display = d;
110 windows = new HashMap();
111 drag = -1;
112 Thread thread = new Thread(this, "X Event Pump");
113 thread.setDaemon(true);
114 thread.start();
118 * The main event pump loop. This basically fetches events from the
119 * X Display and pumps them into the system event queue.
121 public void run()
123 while (display.connected)
127 Event xEvent = display.next_event();
128 handleEvent(xEvent);
130 catch (ThreadDeath death)
132 // If someone wants to kill us, let them.
133 return;
135 catch (Throwable x)
137 System.err.println("Exception during event dispatch:");
138 x.printStackTrace(System.err);
144 * Adds an X Window to AWT Window mapping. This is required so that the
145 * event pump can correctly determine the event targets.
147 * @param xWindow the X Window
148 * @param awtWindow the AWT Window
150 void registerWindow(gnu.x11.Window xWindow, Window awtWindow)
152 if (XToolkit.DEBUG)
153 System.err.println("registering window id: " + xWindow.id);
154 windows.put(new Integer(xWindow.id), awtWindow);
157 void unregisterWindow(gnu.x11.Window xWindow)
159 windows.remove(new Integer(xWindow.id));
162 private void handleButtonPress(ButtonPress event)
164 Integer key = new Integer(event.getEventWindowID());
165 Window awtWindow = (Window) windows.get(key);
167 // Create and post the mouse event.
168 int button = event.detail();
170 // AWT cannot handle more than 3 buttons and expects 0 instead.
171 if (button >= gnu.x11.Input.BUTTON3)
172 button = 0;
173 drag = button;
175 Component target =
176 findMouseEventTarget(awtWindow, event.getEventX(), event.getEventY());
177 if(target == null)
179 target = awtWindow;
182 MouseEvent mp = new MouseEvent(target, MouseEvent.MOUSE_PRESSED,
183 System.currentTimeMillis(),
184 KeyboardMapping.mapModifiers(event.getState())
185 | buttonToModifier(button),
186 event.getEventX(), event.getEventY(),
187 1, false, button);
188 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mp);
191 private void handleButtonRelease(ButtonRelease event)
193 Integer key = new Integer(event.getEventWindowID());
194 Window awtWindow = (Window) windows.get(key);
196 int button = event.detail();
198 // AWT cannot handle more than 3 buttons and expects 0 instead.
199 if (button >= gnu.x11.Input.BUTTON3)
200 button = 0;
201 drag = -1;
203 Component target =
204 findMouseEventTarget(awtWindow, event.getEventX(), event.getEventY());
205 if(target == null)
207 target = awtWindow;
210 MouseEvent mr = new MouseEvent(target, MouseEvent.MOUSE_RELEASED,
211 System.currentTimeMillis(),
212 KeyboardMapping.mapModifiers(event.getState())
213 | buttonToModifier(button),
214 event.getEventX(), event.getEventY(),
215 1, false, button);
216 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mr);
220 private void handleMotionNotify(MotionNotify event)
222 Integer key = new Integer(event.getEventWindowID());
223 Window awtWindow = (Window) windows.get(key);
225 int button = event.detail();
227 // AWT cannot handle more than 3 buttons and expects 0 instead.
228 if (button >= gnu.x11.Input.BUTTON3)
229 button = 0;
231 MouseEvent mm = null;
232 if (drag == -1)
234 mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_MOVED,
235 System.currentTimeMillis(),
236 KeyboardMapping.mapModifiers(event.getState())
237 | buttonToModifier(button),
238 event.getEventX(), event.getEventY(),
239 1, false);
242 else
244 mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_DRAGGED,
245 System.currentTimeMillis(),
246 KeyboardMapping.mapModifiers(event.getState())
247 | buttonToModifier(drag),
248 event.getEventX(), event.getEventY(),
249 1, false);
251 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mm);
254 // FIME: refactor and make faster, maybe caching the event and handle
255 // and/or check timing (timing is generated for PropertyChange)?
256 private void handleExpose(Expose event)
258 Integer key = new Integer(event.window_id);
259 Window awtWindow = (Window) windows.get(key);
261 if (XToolkit.DEBUG)
262 System.err.println("expose request for window id: " + key);
264 Rectangle r = new Rectangle(event.x(), event.y(), event.width(),
265 event.height());
266 // We need to clear the background of the exposed rectangle.
267 assert awtWindow != null : "awtWindow == null for window ID: " + key;
269 Graphics g = awtWindow.getGraphics();
270 g.clearRect(r.x, r.y, r.width, r.height);
271 g.dispose();
273 XWindowPeer xwindow = (XWindowPeer) awtWindow.getPeer();
274 Insets i = xwindow.insets();
275 if (event.width() != awtWindow.getWidth() - i.left - i.right
276 || event.height() != awtWindow.getHeight() - i.top - i.bottom)
278 int w = event.width();
279 int h = event.height();
280 int x = xwindow.xwindow.x;
281 int y = xwindow.xwindow.y;
283 if (XToolkit.DEBUG)
284 System.err.println("Setting size on AWT window: " + w
285 + ", " + h + ", " + awtWindow.getWidth()
286 + ", " + awtWindow.getHeight());
288 // new width and height
289 xwindow.xwindow.width = w;
290 xwindow.xwindow.height = h;
292 // reshape the window
293 ComponentReshapeEvent cre =
294 new ComponentReshapeEvent(awtWindow, x, y, w, h);
295 awtWindow.dispatchEvent(cre);
298 ComponentEvent ce =
299 new ComponentEvent(awtWindow, ComponentEvent.COMPONENT_RESIZED);
300 awtWindow.dispatchEvent(ce);
302 PaintEvent pev = new PaintEvent(awtWindow, PaintEvent.UPDATE, r);
303 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(pev);
306 private void handleDestroyNotify(DestroyNotify destroyNotify)
308 if (XToolkit.DEBUG)
309 System.err.println("DestroyNotify event: " + destroyNotify);
311 Integer key = new Integer(destroyNotify.event_window_id);
312 Window awtWindow = (Window) windows.get(key);
314 AWTEvent event = new WindowEvent(awtWindow, WindowEvent.WINDOW_CLOSED);
315 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event);
318 private void handleClientMessage(ClientMessage clientMessage)
320 if (XToolkit.DEBUG)
321 System.err.println("ClientMessage event: " + clientMessage);
323 if (clientMessage.delete_window())
325 if (XToolkit.DEBUG)
326 System.err.println("ClientMessage is a delete_window event");
328 Integer key = new Integer(clientMessage.window_id);
329 Window awtWindow = (Window) windows.get(key);
331 AWTEvent event = new WindowEvent(awtWindow, WindowEvent.WINDOW_CLOSING);
332 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event);
336 private void handleEvent(Event xEvent)
338 if (XToolkit.DEBUG)
339 System.err.println("fetched event: " + xEvent);
341 switch (xEvent.code() & 0x7f)
343 case ButtonPress.CODE:
344 this.handleButtonPress((ButtonPress) xEvent);
345 break;
346 case ButtonRelease.CODE:
347 this.handleButtonRelease((ButtonRelease) xEvent);
348 break;
349 case MotionNotify.CODE:
350 this.handleMotionNotify((MotionNotify) xEvent);
351 break;
352 case Expose.CODE:
353 this.handleExpose((Expose) xEvent);
354 break;
355 case KeyPress.CODE:
356 case KeyRelease.CODE:
357 Integer key = new Integer(((Input) xEvent).getEventWindowID());
358 Window awtWindow = (Window) windows.get(key);
359 handleKeyEvent(xEvent, awtWindow);
360 break;
361 case DestroyNotify.CODE:
362 this.handleDestroyNotify((DestroyNotify) xEvent);
363 break;
364 case ClientMessage.CODE:
365 this.handleClientMessage((ClientMessage) xEvent);
366 break;
367 case PropertyNotify.CODE:
368 key = new Integer (((PropertyNotify) xEvent).getWindowID());
369 awtWindow = (Window) windows.get(key);
370 AWTEvent event = new WindowEvent(awtWindow, WindowEvent.WINDOW_STATE_CHANGED);
371 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event);
372 break;
373 default:
374 if (XToolkit.DEBUG)
375 System.err.println("Unhandled X event: " + xEvent);
380 * Handles key events from X.
382 * @param xEvent the X event
383 * @param awtWindow the AWT window to which the event gets posted
385 private void handleKeyEvent(Event xEvent, Window awtWindow)
387 Input keyEvent = (Input) xEvent;
388 int xKeyCode = keyEvent.detail();
389 int xMods = keyEvent.getState();
390 int keyCode = KeyboardMapping.mapToKeyCode(xEvent.display.input, xKeyCode,
391 xMods);
392 char keyChar = KeyboardMapping.mapToKeyChar(xEvent.display.input, xKeyCode,
393 xMods);
394 if (XToolkit.DEBUG)
395 System.err.println("XEventPump.handleKeyEvent: " + xKeyCode + ", "
396 + xMods + ": " + ((int) keyChar) + ", " + keyCode);
397 int awtMods = KeyboardMapping.mapModifiers(xMods);
398 long when = System.currentTimeMillis();
399 KeyEvent ke;
400 if (keyEvent.code() == KeyPress.CODE)
402 ke = new KeyEvent(awtWindow, KeyEvent.KEY_PRESSED, when,
403 awtMods, keyCode,
404 KeyEvent.CHAR_UNDEFINED);
405 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke);
406 if (keyChar != KeyEvent.CHAR_UNDEFINED)
408 ke = new KeyEvent(awtWindow, KeyEvent.KEY_TYPED, when,
409 awtMods, KeyEvent.VK_UNDEFINED,
410 keyChar);
411 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke);
415 else
417 ke = new KeyEvent(awtWindow, KeyEvent.KEY_RELEASED, when,
418 awtMods, keyCode,
419 KeyEvent.CHAR_UNDEFINED);
420 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke);
425 /** Translates an X button identifier to the AWT's MouseEvent modifier
426 * mask. As the AWT cannot handle more than 3 buttons those return
427 * <code>0</code>.
429 static int buttonToModifier(int button)
431 switch (button)
433 case gnu.x11.Input.BUTTON1:
434 return MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON1_MASK;
435 case gnu.x11.Input.BUTTON2:
436 return MouseEvent.BUTTON2_DOWN_MASK | MouseEvent.BUTTON2_MASK;
437 case gnu.x11.Input.BUTTON3:
438 return MouseEvent.BUTTON3_DOWN_MASK | MouseEvent.BUTTON3_MASK;
441 return 0;
445 * Finds the heavyweight mouse event target.
447 * @param src the original source of the event
449 * @param pt the event coordinates
451 * @return the real mouse event target
453 private Component findMouseEventTarget(Component src, int x, int y)
455 Component found = null;
456 if (src instanceof Container)
458 Container cont = (Container) src;
459 int numChildren = cont.getComponentCount();
460 for (int i = 0; i < numChildren && found == null; i++)
462 Component child = cont.getComponent(i);
463 if (child != null && child.isVisible()
464 && child.contains(x - child.getX(), y - child.getY()))
466 if (child instanceof Container)
468 Component deeper = findMouseEventTarget(child,
469 x - child.getX(),
470 y - child.getY());
471 if (deeper != null)
472 found = deeper;
474 else if (! child.isLightweight())
475 found = child;
480 // Consider the source itself.
481 if (found == null && src.contains(x, y) && ! src.isLightweight())
482 found = src;
484 return found;