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