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 import sun.awt.CausedFocusEvent; 48 49 public class XCanvasPeer implements CanvasPeer 50 { 51 static final Dimension MIN_SIZE = new Dimension(1, 1); 52 53 public // temporary 54 55 Window window; 56 Window parent; 57 58 Component component; 59 XGraphicsConfiguration config; 60 private WindowAttributes attributes = new WindowAttributes(); 61 private long eventMask; 62 XCanvasPeer(Component component)63 public XCanvasPeer(Component component) 64 { 65 this.component = component; 66 67 // Set up graphics configuration (ie. screen + visual): 68 69 config = (XGraphicsConfiguration) 70 component.getGraphicsConfiguration(); 71 72 if (config == null) 73 { 74 // This will usually only happen for toplevel windows 75 config = getXToolkit().getDefaultXGraphicsConfiguration(); 76 } 77 78 Rectangle bounds = component.getBounds(); 79 parent = locateParentWindow(bounds); 80 81 // Windows in X must atleast be of size 1x1 82 boolean boundsChanged = false; 83 if (bounds.width < 1) 84 { 85 boundsChanged = true; 86 bounds.width = 1; 87 } 88 if (bounds.height < 1) 89 { 90 boundsChanged = true; 91 bounds.height = 1; 92 } 93 94 /* don't worry about this calling back to us, since the real 95 component object has not yet received a reference to this peer 96 object. */ 97 component.setBounds(bounds); 98 99 100 /* Set background color */ 101 Color bg = component.getBackground(); 102 if (bg != null) 103 { 104 int[] components = 105 { 106 bg.getRed(), 107 bg.getGreen(), 108 bg.getBlue(), 109 0xff 110 }; 111 112 ColorModel cm = config.getColorModel(); 113 long pixel = cm.getDataElement(components, 0); 114 attributes.setBackground(pixel); 115 } 116 117 /* Set exposure mask so that we get exposure events 118 that can be translated into paint() calls. */ 119 long eventMask = WindowAttributes.MASK_EXPOSURE; 120 121 /* It would be nice to set up all other required events here, but 122 it is not possible to do so before after all the children of 123 this component has been realized. The reason is that it is not 124 determined whether a component is lightweight before after the 125 addNotify() method has been called. Thus, it is not possible 126 for parent component to determine what events it needs to 127 furnish for lightweight children. Instead, we currently rely 128 on the component calling our setEventMask() method after the 129 correct event mask has been determined. */ 130 131 attributes.setEventMask(eventMask); 132 133 134 // TODO: set more window attributes? 135 136 /* don't allow event queue to process events from the newly 137 created window before this peer has been registered as client 138 data. */ 139 synchronized (getXToolkit().eventLoop) 140 { 141 window = new gnu.gcj.xlib.Window(parent, bounds, attributes); 142 window.setClientData(this); /* make it possible to find back 143 to this peer object. Used by 144 XEventQueue. */ 145 } 146 147 initWindowProperties(); 148 149 if (component.isVisible()) 150 EventQueue.invokeLater(new DoMap(window)); 151 } 152 153 /** 154 * Override this in subclasses to implement other ways of obtaining 155 * parent windows. Toplevel windows will typically have a different 156 * implementation. 157 */ locateParentWindow(Rectangle bounds)158 gnu.gcj.xlib.Window locateParentWindow(Rectangle bounds) 159 { 160 Container parent = component.getParent(); 161 while (parent.isLightweight()) 162 { 163 bounds.x += parent.getX(); 164 bounds.y += parent.getY(); 165 parent = parent.getParent(); 166 // a null pointer here is a genuine error 167 } 168 169 XCanvasPeer parentPeer = (XCanvasPeer) parent.getPeer(); 170 if (parentPeer == null) 171 throw new NullPointerException("Parent has no peer. This should " + 172 "not be possible, since the " + 173 "calls leading here should come " + 174 "from parent, after it has " + 175 "set the parent peer."); 176 return parentPeer.window; 177 } 178 179 180 /** 181 * Template method to allow subclasses to apply properties to X11 182 * window right after creation. 183 */ initWindowProperties()184 void initWindowProperties() 185 { 186 } 187 getXToolkit()188 XToolkit getXToolkit() 189 { 190 return XToolkit.INSTANCE; 191 } 192 ensureFlush()193 protected void ensureFlush() 194 { 195 getXToolkit().flushIfIdle(); 196 } 197 getComponent()198 public Component getComponent() 199 { 200 return component; 201 } 202 getBasicEventMask()203 long getBasicEventMask() 204 { 205 return WindowAttributes.MASK_EXPOSURE; 206 } 207 208 // -------- java.awt.peer.ComponentPeer implementation 209 checkImage(Image img, int width, int height, ImageObserver o)210 public int checkImage(Image img, int width, int height, ImageObserver o) 211 { 212 throw new UnsupportedOperationException("FIXME, not implemented"); 213 } createImage(ImageProducer prod)214 public Image createImage(ImageProducer prod) 215 { 216 return new XOffScreenImage (config, window, prod, config.getColorModel()); 217 } createImage(int width, int height)218 public Image createImage(int width, int height) 219 { 220 return new XOffScreenImage (config, window, width, height, config.getColorModel()); 221 } dispose()222 public void dispose() 223 { 224 throw new UnsupportedOperationException("FIXME, not implemented"); 225 } 226 getGraphicsConfiguration()227 public GraphicsConfiguration getGraphicsConfiguration() 228 { 229 return config; 230 } 231 getFontMetrics(Font f)232 public FontMetrics getFontMetrics(Font f) 233 { 234 throw new UnsupportedOperationException("FIXME, not implemented"); 235 } 236 getColorModel()237 public ColorModel getColorModel () 238 { 239 return null; 240 } 241 getGraphics()242 public Graphics getGraphics() 243 { 244 DirectRasterGraphics gfxDevice = new XGraphics(window, config); 245 IntegerGraphicsState igState = new IntegerGraphicsState(gfxDevice); 246 Graphics2DImpl gfx2d = new Graphics2DImpl(config); 247 248 gfx2d.setState(igState); 249 gfx2d.setColor(component.getBackground()); 250 return gfx2d; 251 } 252 253 private Rectangle locationBounds; getLocationOnScreen()254 public Point getLocationOnScreen() 255 { 256 locationBounds = window.getBounds (locationBounds); 257 return new Point (locationBounds.x,locationBounds.y); 258 } 259 getMinimumSize()260 public Dimension getMinimumSize () 261 { 262 return MIN_SIZE; 263 } 264 minimumSize()265 public Dimension minimumSize () 266 { 267 return getMinimumSize (); 268 } 269 getPreferredSize()270 public Dimension getPreferredSize () 271 { 272 return component.getSize(); 273 } 274 preferredSize()275 public Dimension preferredSize () 276 { 277 return getPreferredSize(); 278 } 279 getToolkit()280 public Toolkit getToolkit() 281 { 282 return getXToolkit(); 283 } 284 handleEvent(AWTEvent event)285 public void handleEvent(AWTEvent event) 286 { 287 int id = event.getID (); 288 289 switch (id) 290 { 291 case PaintEvent.PAINT: 292 case PaintEvent.UPDATE: 293 { 294 try 295 { 296 Graphics g = getGraphics (); 297 g.setClip (((PaintEvent)event).getUpdateRect ()); 298 299 if (id == PaintEvent.PAINT) 300 component.paint (g); 301 else 302 component.update (g); 303 304 g.dispose (); 305 } 306 catch (InternalError e) 307 { 308 System.err.println (e); 309 } 310 } 311 break; 312 } 313 } 314 isFocusTraversable()315 public boolean isFocusTraversable() 316 { 317 throw new UnsupportedOperationException("FIXME, not implemented"); 318 } 319 paint(Graphics gfx)320 public void paint(Graphics gfx) 321 { 322 // do nothing by default 323 } 324 prepareImage(Image img, int width, int height, ImageObserver o)325 public boolean prepareImage(Image img, int width, int height, 326 ImageObserver o) 327 { 328 throw new UnsupportedOperationException("FIXME, not implemented"); 329 } 330 print(Graphics graphics)331 public void print(Graphics graphics) 332 { 333 paint(graphics); 334 } 335 repaint(long tm, int x, int y, int w, int h)336 public void repaint(long tm, int x, int y, int w, int h) 337 { 338 /* TODO? 339 340 X allows intelligent X servers to do smart 341 refreshing. Perhaps involve X in repainting of components, 342 rather that keeping it all within the local event queue. */ 343 344 PaintEvent updateEvent = new PaintEvent(component, 345 PaintEvent.UPDATE, 346 new Rectangle(x, y, w, h)); 347 getXToolkit().queue.postEvent(updateEvent); 348 } 349 requestFocus()350 public void requestFocus() 351 { 352 throw new UnsupportedOperationException("FIXME, not implemented"); 353 } 354 setBackground(Color color)355 public void setBackground(Color color) 356 { 357 if (color != null) 358 { 359 int[] components = 360 { 361 color.getRed (), 362 color.getGreen (), 363 color.getBlue (), 364 0xff 365 }; 366 367 ColorModel cm = config.getColorModel (); 368 long pixel = cm.getDataElement (components, 0); 369 attributes.setBackground (pixel); 370 window.setAttributes (attributes); 371 } 372 } 373 setBounds(int x, int y, int width, int height)374 public void setBounds(int x, int y, int width, int height) 375 { 376 width = Math.max(width, 1); 377 height = Math.max(height, 1); 378 window.setBounds(x, y, width, height); 379 ensureFlush(); 380 } 381 reshape(int x, int y, int width, int height)382 public void reshape (int x, int y, int width, int height) 383 { 384 setBounds (x, y, width, height); 385 } 386 setCursor(Cursor cursor)387 public void setCursor(Cursor cursor) 388 { 389 throw new UnsupportedOperationException("FIXME, not implemented"); 390 } 391 setEnabled(boolean enabled)392 public void setEnabled(boolean enabled) 393 { 394 throw new UnsupportedOperationException("FIXME, not implemented"); 395 } 396 enable()397 public void enable () 398 { 399 setEnabled (true); 400 } 401 disable()402 public void disable () 403 { 404 setEnabled (false); 405 } 406 setEventMask(long eventMask)407 public void setEventMask(long eventMask) 408 { 409 if (this.eventMask != eventMask) 410 { 411 this.eventMask = eventMask; 412 long xEventMask = getBasicEventMask (); 413 414 if ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0) 415 { 416 xEventMask |= 417 WindowAttributes.MASK_BUTTON_PRESS | 418 WindowAttributes.MASK_BUTTON_RELEASE; 419 } 420 421 attributes.setEventMask (xEventMask); 422 window.setAttributes (attributes); 423 ensureFlush (); 424 } 425 } 426 setFont(Font font)427 public void setFont(Font font) 428 { 429 /* default canvas peer does not keep track of font, since it won't 430 paint anything. */ 431 } 432 setForeground(Color color)433 public void setForeground(Color color) 434 { 435 /* default canvas peer does not keep track of foreground, since it won't 436 paint anything. */ 437 } 438 setVisible(boolean visible)439 public void setVisible(boolean visible) 440 { 441 if (visible) 442 { 443 window.map(); 444 ensureFlush(); 445 } 446 else 447 { 448 window.unmap(); 449 ensureFlush(); 450 } 451 } 452 show()453 public void show () 454 { 455 setVisible (true); 456 } 457 hide()458 public void hide () 459 { 460 setVisible (false); 461 } 462 isFocusable()463 public boolean isFocusable () 464 { 465 return false; 466 } 467 requestFocus(Component source, boolean b1, boolean b2, long x)468 public boolean requestFocus (Component source, boolean b1, 469 boolean b2, long x) 470 { 471 return false; 472 } 473 requestFocus(Component source, boolean b1, boolean b2, long x, CausedFocusEvent.Cause cause)474 public boolean requestFocus (Component source, boolean b1, 475 boolean b2, long x, 476 CausedFocusEvent.Cause cause) 477 { 478 return false; 479 } 480 isObscured()481 public boolean isObscured () 482 { 483 return false; 484 } 485 canDetermineObscurity()486 public boolean canDetermineObscurity () 487 { 488 return false; 489 } 490 coalescePaintEvent(PaintEvent e)491 public void coalescePaintEvent (PaintEvent e) 492 { 493 } 494 updateCursorImmediately()495 public void updateCursorImmediately () 496 { 497 } 498 createVolatileImage(int width, int height)499 public VolatileImage createVolatileImage (int width, int height) 500 { 501 return null; 502 } 503 handlesWheelScrolling()504 public boolean handlesWheelScrolling () 505 { 506 return false; 507 } 508 createBuffers(int x, BufferCapabilities capabilities)509 public void createBuffers (int x, BufferCapabilities capabilities) 510 throws java.awt.AWTException 511 512 { 513 } 514 getBackBuffer()515 public Image getBackBuffer () 516 { 517 return null; 518 } 519 flip(BufferCapabilities.FlipContents contents)520 public void flip (BufferCapabilities.FlipContents contents) 521 { 522 } 523 destroyBuffers()524 public void destroyBuffers () 525 { 526 } 527 528 static class DoMap implements Runnable 529 { 530 Window window; DoMap(Window w)531 public DoMap(Window w) 532 { 533 this.window = w; 534 } 535 run()536 public void run() 537 { 538 window.map(); 539 } 540 } 541 542 /** 543 * @since 1.5 544 */ isRestackSupported()545 public boolean isRestackSupported () 546 { 547 return false; 548 } 549 550 /** 551 * @since 1.5 552 */ cancelPendingPaint(int x, int y, int width, int height)553 public void cancelPendingPaint (int x, int y, int width, int height) 554 { 555 } 556 557 /** 558 * @since 1.5 559 */ restack()560 public void restack () 561 { 562 } 563 564 /** 565 * @since 1.5 566 */ getBounds()567 public Rectangle getBounds () 568 { 569 return null; 570 } 571 572 /** 573 * @since 1.5 574 */ reparent(ContainerPeer parent)575 public void reparent (ContainerPeer parent) 576 { 577 } 578 579 /** 580 * @since 1.5 581 */ setBounds(int x, int y, int width, int height, int z)582 public void setBounds (int x, int y, int width, int height, int z) 583 { 584 } 585 586 /** 587 * @since 1.5 588 */ isReparentSupported()589 public boolean isReparentSupported () 590 { 591 return false; 592 } 593 594 /** 595 * @since 1.5 596 */ layout()597 public void layout () 598 { 599 } 600 } 601