1 /* Copyright (C) 2000, 2002, 2003 Free Software Foundation 2 3 This file is part of libgcj. 4 5 This software is copyrighted work licensed under the terms of the 6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for 7 details. */ 8 9 package gnu.awt.xlib; 10 11 import java.awt.Dimension; 12 import java.awt.BufferCapabilities; 13 import java.awt.Component; 14 import java.awt.EventQueue; 15 import java.awt.Rectangle; 16 import java.awt.Color; 17 import java.awt.Container; 18 import java.awt.Image; 19 import java.awt.GraphicsConfiguration; 20 import java.awt.Font; 21 import java.awt.FontMetrics; 22 import java.awt.Graphics; 23 import java.awt.Point; 24 import java.awt.Toolkit; 25 import java.awt.AWTEvent; 26 import java.awt.Cursor; 27 import java.awt.Shape; 28 29 import java.awt.peer.*; 30 import java.awt.image.*; 31 32 import java.awt.event.MouseListener; 33 import java.awt.event.PaintEvent; 34 35 import java.util.EventListener; 36 37 import gnu.gcj.xlib.WMSizeHints; 38 import gnu.gcj.xlib.Window; 39 import gnu.gcj.xlib.WindowAttributes; 40 import gnu.gcj.xlib.Display; 41 import gnu.gcj.xlib.Visual; 42 import gnu.gcj.xlib.Screen; 43 import gnu.gcj.xlib.XImage; 44 45 import gnu.awt.j2d.*; 46 47 public class XCanvasPeer implements CanvasPeer 48 { 49 static final Dimension MIN_SIZE = new Dimension(1, 1); 50 51 public // temporary 52 53 Window window; 54 Window parent; 55 56 Component component; 57 XGraphicsConfiguration config; 58 XCanvasPeer(Component component)59 public XCanvasPeer(Component component) 60 { 61 this.component = component; 62 63 // Set up graphics configuration (ie. screen + visual): 64 65 config = (XGraphicsConfiguration) 66 component.getGraphicsConfiguration(); 67 68 if (config == null) 69 { 70 // This will usually only happen for toplevel windows 71 config = getXToolkit().getDefaultXGraphicsConfiguration(); 72 } 73 74 Rectangle bounds = component.getBounds(); 75 parent = locateParentWindow(bounds); 76 77 // Windows in X must atleast be of size 1x1 78 boolean boundsChanged = false; 79 if (bounds.width < 1) 80 { 81 boundsChanged = true; 82 bounds.width = 1; 83 } 84 if (bounds.height < 1) 85 { 86 boundsChanged = true; 87 bounds.height = 1; 88 } 89 90 /* don't worry about this calling back to us, since the real 91 component object has not yet received a reference to this peer 92 object. */ 93 component.setBounds(bounds); 94 95 WindowAttributes attributes = new WindowAttributes(); 96 97 /* Set background color */ 98 Color bg = component.getBackground(); 99 if (bg != null) 100 { 101 int[] components = 102 { 103 bg.getRed(), 104 bg.getGreen(), 105 bg.getBlue(), 106 0xff 107 }; 108 109 ColorModel cm = config.getColorModel(); 110 long pixel = cm.getDataElement(components, 0); 111 attributes.setBackground(pixel); 112 } 113 114 /* Set exposure mask so that we get exposure events 115 that can be translated into paint() calls. */ 116 long eventMask = WindowAttributes.MASK_EXPOSURE; 117 118 /* It would be nice to set up all other required events here, but 119 it is not possible to do so before after all the children of 120 this component has been realized. The reason is that it is not 121 determined whether a component is lightweight before after the 122 addNotify() method has been called. Thus, it is not possible 123 for parent component to determine what events it needs to 124 furnish for lightweight children. Instead, we currently rely 125 on the component calling our setEventMask() method after the 126 correct event mask has been determined. */ 127 128 attributes.setEventMask(eventMask); 129 130 131 // TODO: set more window attributes? 132 133 /* don't allow event queue to process events from the newly 134 created window before this peer has been registered as client 135 data. */ 136 synchronized (getXToolkit().eventLoop) 137 { 138 window = new gnu.gcj.xlib.Window(parent, bounds, attributes); 139 window.setClientData(this); /* make it possible to find back 140 to this peer object. Used by 141 XEventQueue. */ 142 } 143 144 initWindowProperties(); 145 146 if (component.isVisible()) 147 EventQueue.invokeLater(new DoMap(window)); 148 } 149 150 /** 151 * Override this in subclasses to implement other ways of obtaining 152 * parent windows. Toplevel windows will typically have a different 153 * implementation. 154 */ locateParentWindow(Rectangle bounds)155 gnu.gcj.xlib.Window locateParentWindow(Rectangle bounds) 156 { 157 Container parent = component.getParent(); 158 while (parent.isLightweight()) 159 { 160 bounds.x += parent.getX(); 161 bounds.y += parent.getY(); 162 parent = parent.getParent(); 163 // a null pointer here is a genuine error 164 } 165 166 XCanvasPeer parentPeer = (XCanvasPeer) parent.getPeer(); 167 if (parentPeer == null) 168 throw new NullPointerException("Parent has no peer. This should " + 169 "not be possible, since the " + 170 "calls leading here should come " + 171 "from parent, after it has " + 172 "set the parent peer."); 173 return parentPeer.window; 174 } 175 176 177 /** 178 * Template method to allow subclasses to apply properties to X11 179 * window right after creation. 180 */ initWindowProperties()181 void initWindowProperties() 182 { 183 } 184 getXToolkit()185 XToolkit getXToolkit() 186 { 187 return XToolkit.INSTANCE; 188 } 189 ensureFlush()190 protected void ensureFlush() 191 { 192 getXToolkit().flushIfIdle(); 193 } 194 getComponent()195 public Component getComponent() 196 { 197 return component; 198 } 199 getBasicEventMask()200 long getBasicEventMask() 201 { 202 return WindowAttributes.MASK_EXPOSURE; 203 } 204 205 // -------- java.awt.peer.ComponentPeer implementation 206 checkImage(Image img, int width, int height, ImageObserver o)207 public int checkImage(Image img, int width, int height, ImageObserver o) 208 { 209 throw new UnsupportedOperationException("FIXME, not implemented"); 210 } createImage(ImageProducer prod)211 public Image createImage(ImageProducer prod) 212 { 213 throw new UnsupportedOperationException("FIXME, not implemented"); 214 } createImage(int width, int height)215 public Image createImage(int width, int height) 216 { 217 return new XOffScreenImage (config, window, width, height); 218 } dispose()219 public void dispose() 220 { 221 throw new UnsupportedOperationException("FIXME, not implemented"); 222 } 223 getGraphicsConfiguration()224 public GraphicsConfiguration getGraphicsConfiguration() 225 { 226 return config; 227 } 228 getFontMetrics(Font f)229 public FontMetrics getFontMetrics(Font f) 230 { 231 throw new UnsupportedOperationException("FIXME, not implemented"); 232 } 233 getColorModel()234 public ColorModel getColorModel () 235 { 236 return null; 237 } 238 getGraphics()239 public Graphics getGraphics() 240 { 241 DirectRasterGraphics gfxDevice = new XGraphics(window, config); 242 IntegerGraphicsState igState = new IntegerGraphicsState(gfxDevice); 243 Graphics2DImpl gfx2d = new Graphics2DImpl(config); 244 245 gfx2d.setState(igState); 246 gfx2d.setColor(component.getBackground()); 247 return gfx2d; 248 } 249 getLocationOnScreen()250 public Point getLocationOnScreen() 251 { 252 throw new UnsupportedOperationException("FIXME, not implemented"); 253 } 254 getMinimumSize()255 public Dimension getMinimumSize () 256 { 257 return MIN_SIZE; 258 } 259 minimumSize()260 public Dimension minimumSize () 261 { 262 return getMinimumSize (); 263 } 264 getPreferredSize()265 public Dimension getPreferredSize () 266 { 267 return component.getSize(); 268 } 269 preferredSize()270 public Dimension preferredSize () 271 { 272 return getPreferredSize(); 273 } 274 getToolkit()275 public Toolkit getToolkit() 276 { 277 return getXToolkit(); 278 } 279 handleEvent(AWTEvent event)280 public void handleEvent(AWTEvent event) 281 { 282 } 283 isFocusTraversable()284 public boolean isFocusTraversable() 285 { 286 throw new UnsupportedOperationException("FIXME, not implemented"); 287 } 288 paint(Graphics gfx)289 public void paint(Graphics gfx) 290 { 291 // do nothing by default 292 } 293 prepareImage(Image img, int width, int height, ImageObserver o)294 public boolean prepareImage(Image img, int width, int height, 295 ImageObserver o) 296 { 297 throw new UnsupportedOperationException("FIXME, not implemented"); 298 } 299 print(Graphics graphics)300 public void print(Graphics graphics) 301 { 302 paint(graphics); 303 } 304 repaint(long tm, int x, int y, int w, int h)305 public void repaint(long tm, int x, int y, int w, int h) 306 { 307 /* TODO? 308 309 X allows intelligent X servers to do smart 310 refreshing. Perhaps involve X in repainting of components, 311 rather that keeping it all within the local event queue. */ 312 313 PaintEvent updateEvent = new PaintEvent(component, 314 PaintEvent.UPDATE, 315 new Rectangle(x, y, w, h)); 316 getXToolkit().queue.postEvent(updateEvent); 317 } 318 requestFocus()319 public void requestFocus() 320 { 321 throw new UnsupportedOperationException("FIXME, not implemented"); 322 } 323 setBackground(Color color)324 public void setBackground(Color color) 325 { 326 throw new UnsupportedOperationException("not implemented"); 327 } 328 setBounds(int x, int y, int width, int height)329 public void setBounds(int x, int y, int width, int height) 330 { 331 width = Math.max(width, 1); 332 height = Math.max(height, 1); 333 window.setBounds(x, y, width, height); 334 ensureFlush(); 335 } 336 reshape(int x, int y, int width, int height)337 public void reshape (int x, int y, int width, int height) 338 { 339 setBounds (x, y, width, height); 340 } 341 setCursor(Cursor cursor)342 public void setCursor(Cursor cursor) 343 { 344 throw new UnsupportedOperationException("FIXME, not implemented"); 345 } 346 setEnabled(boolean enabled)347 public void setEnabled(boolean enabled) 348 { 349 throw new UnsupportedOperationException("FIXME, not implemented"); 350 } 351 enable()352 public void enable () 353 { 354 setEnabled (true); 355 } 356 disable()357 public void disable () 358 { 359 setEnabled (false); 360 } 361 setEventMask(long eventMask)362 public void setEventMask(long eventMask) 363 { 364 WindowAttributes attributes = new WindowAttributes(); 365 366 long xEventMask = getBasicEventMask(); 367 368 if ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0) 369 { 370 xEventMask |= 371 WindowAttributes.MASK_BUTTON_PRESS | 372 WindowAttributes.MASK_BUTTON_RELEASE; 373 } 374 375 attributes.setEventMask(xEventMask); 376 window.setAttributes(attributes); 377 ensureFlush(); 378 } 379 setFont(Font font)380 public void setFont(Font font) 381 { 382 /* default canvas peer does keep track of font, since it won't 383 write anything. */ 384 } 385 setForeground(Color color)386 public void setForeground(Color color) 387 { 388 /* default canvas peer does keep track of foreground, since it won't 389 paint anything. */ 390 } 391 setVisible(boolean visible)392 public void setVisible(boolean visible) 393 { 394 if (visible) 395 { 396 window.map(); 397 ensureFlush(); 398 } 399 else 400 { 401 throw new UnsupportedOperationException("unmap not implemented"); 402 } 403 } 404 show()405 public void show () 406 { 407 setVisible (true); 408 } 409 hide()410 public void hide () 411 { 412 setVisible (false); 413 } 414 isFocusable()415 public boolean isFocusable () 416 { 417 return false; 418 } 419 requestFocus(Component source, boolean b1, boolean b2, long x)420 public boolean requestFocus (Component source, boolean b1, 421 boolean b2, long x) 422 { 423 return false; 424 } 425 isObscured()426 public boolean isObscured () 427 { 428 return false; 429 } 430 canDetermineObscurity()431 public boolean canDetermineObscurity () 432 { 433 return false; 434 } 435 coalescePaintEvent(PaintEvent e)436 public void coalescePaintEvent (PaintEvent e) 437 { 438 } 439 updateCursorImmediately()440 public void updateCursorImmediately () 441 { 442 } 443 createVolatileImage(int width, int height)444 public VolatileImage createVolatileImage (int width, int height) 445 { 446 return null; 447 } 448 handlesWheelScrolling()449 public boolean handlesWheelScrolling () 450 { 451 return false; 452 } 453 createBuffers(int x, BufferCapabilities capabilities)454 public void createBuffers (int x, BufferCapabilities capabilities) 455 throws java.awt.AWTException 456 457 { 458 } 459 getBackBuffer()460 public Image getBackBuffer () 461 { 462 return null; 463 } 464 flip(BufferCapabilities.FlipContents contents)465 public void flip (BufferCapabilities.FlipContents contents) 466 { 467 } 468 destroyBuffers()469 public void destroyBuffers () 470 { 471 } 472 473 static class DoMap implements Runnable 474 { 475 Window window; DoMap(Window w)476 public DoMap(Window w) 477 { 478 this.window = w; 479 } 480 run()481 public void run() 482 { 483 window.map(); 484 } 485 } 486 } 487 488