OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / java / awt / peer / gtk / GtkWindowPeer.java
1 /* GtkWindowPeer.java -- Implements WindowPeer with GTK
2    Copyright (C) 1998, 1999, 2002, 2005, 2006  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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.
10
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.
15
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.
20
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.
25
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. */
37
38
39 package gnu.java.awt.peer.gtk;
40
41 import gnu.java.awt.ComponentReshapeEvent;
42
43 import java.awt.Component;
44 import java.awt.Font;
45 import java.awt.Frame;
46 import java.awt.Graphics;
47 import java.awt.KeyboardFocusManager;
48 import java.awt.Rectangle;
49 import java.awt.Window;
50 import java.awt.event.ComponentEvent;
51 import java.awt.event.FocusEvent;
52 import java.awt.event.PaintEvent;
53 import java.awt.event.WindowEvent;
54 import java.awt.peer.WindowPeer;
55
56 public class GtkWindowPeer extends GtkContainerPeer
57   implements WindowPeer
58 {
59   protected static final int GDK_WINDOW_TYPE_HINT_NORMAL = 0;
60   protected static final int GDK_WINDOW_TYPE_HINT_DIALOG = 1;
61   protected static final int GDK_WINDOW_TYPE_HINT_MENU = 2;
62   protected static final int GDK_WINDOW_TYPE_HINT_TOOLBAR = 3;
63   protected static final int GDK_WINDOW_TYPE_HINT_SPLASHSCREEN = 4;
64   protected static final int GDK_WINDOW_TYPE_HINT_UTILITY = 5;
65   protected static final int GDK_WINDOW_TYPE_HINT_DOCK = 6;
66   protected static final int GDK_WINDOW_TYPE_HINT_DESKTOP = 7;
67
68   protected int windowState = Frame.NORMAL;
69
70   // Cached awt window component location, width and height.
71   private int x, y, width, height;
72
73   native void gtkWindowSetTitle (String title);
74   native void gtkWindowSetResizable (boolean resizable);
75   native void gtkWindowSetModal (boolean modal);
76   native void gtkWindowSetAlwaysOnTop ( boolean alwaysOnTop );
77   native boolean gtkWindowHasFocus();
78   native void realize ();
79
80   public void dispose()
81   {
82     super.dispose();
83     GtkMainThread.destroyWindow();
84   }
85
86   /** Returns the cached width of the AWT window component. */
87   int getX ()
88   {
89     return x;
90   }
91
92   /** Returns the cached width of the AWT window component. */
93   int getY ()
94   {
95     return y;
96   }
97
98   /** Returns the cached width of the AWT window component. */
99   int getWidth ()
100   {
101     return width;
102   }
103
104   /** Returns the cached height of the AWT window component. */
105   int getHeight ()
106   {
107     return height;
108   }
109
110   native void create (int type, boolean decorated, GtkWindowPeer parent);
111
112   void create (int type, boolean decorated)
113   {
114     Window window = (Window) awtComponent;
115     GtkWindowPeer parent_peer = null;
116     Component parent = awtComponent.getParent();
117     x = awtComponent.getX();
118     y = awtComponent.getY();
119     height = awtComponent.getHeight();
120     width = awtComponent.getWidth();
121     
122     if (!window.isFocusableWindow())
123       type = GDK_WINDOW_TYPE_HINT_MENU;
124     
125     if (parent != null)
126       parent_peer = (GtkWindowPeer) awtComponent.getParent().getPeer();
127     
128     create (type, decorated, parent_peer);
129   }
130
131   void create ()
132   {
133     // Create a normal undecorated window.
134     create (GDK_WINDOW_TYPE_HINT_NORMAL, false);
135   }
136
137   void setParent ()
138   {
139     setVisible (awtComponent.isVisible ());
140     setEnabled (awtComponent.isEnabled ());
141   }
142
143   void setVisibleAndEnabled ()
144   {
145   }
146
147   public native void setVisibleNative (boolean b);
148   public native void setVisibleNativeUnlocked (boolean b);
149
150   native void connectSignals ();
151
152   public GtkWindowPeer (Window window)
153   {
154     super (window);
155     // Set reasonable font for the window.
156     window.setFont(new Font("Dialog", Font.PLAIN, 12));
157   }
158
159   public native void toBack();
160   public native void toFront();
161
162   native void nativeSetBounds (int x, int y, int width, int height);
163   native void nativeSetBoundsUnlocked (int x, int y, int width, int height);
164   native void nativeSetLocation (int x, int y);
165   native void nativeSetLocationUnlocked (int x, int y);
166
167   // Called from show.
168   protected void setLocation (int x, int y)
169   {
170     nativeSetLocation (x, y);
171   }
172
173   public void setBounds (int x, int y, int width, int height)
174   {
175     if (x != getX()
176         || y != getY()
177         || width != getWidth()
178         || height != getHeight())
179       {
180         this.x = x;
181         this.y = y;
182         this.width = width;
183         this.height = height;
184         
185         nativeSetBounds (x, y,
186                          width - insets.left - insets.right,
187                          height - insets.top - insets.bottom);
188       }
189   }
190
191   public void setTitle (String title)
192   {
193     gtkWindowSetTitle (title);
194   }
195
196   // Called from setResizable
197   protected native void setSize (int width, int height);
198   
199   /**
200    * Needed by both GtkFramePeer and GtkDialogPeer subclasses, so
201    * implemented here. But never actually called on a GtkWindowPeer
202    * itself.
203    */
204   public void setResizable (boolean resizable)
205   {
206     // Call setSize; otherwise when resizable is changed from true to
207     // false the window will shrink to the dimensions it had before it
208     // was resizable.
209     x = awtComponent.getX();
210     y = awtComponent.getY();
211     width = awtComponent.getWidth();
212     height = awtComponent.getHeight();
213     setSize (width - insets.left - insets.right,
214              height - insets.top - insets.bottom);
215     gtkWindowSetResizable (resizable);
216   }
217
218   protected void postInsetsChangedEvent (int top, int left,
219                                          int bottom, int right)
220   {
221     insets.top = top;
222     insets.left = left;
223     insets.bottom = bottom;
224     insets.right = right;
225   }
226
227   // called back by native side: window_configure_cb
228   // only called from GTK thread
229   protected void postConfigureEvent (int x, int y, int width, int height)
230   {
231     int frame_x = x - insets.left;
232     int frame_y = y - insets.top;
233     int frame_width = width + insets.left + insets.right;
234     int frame_height = height + insets.top + insets.bottom;
235
236     // Update the component's knowledge about the size.
237     // Important: Please look at the big comment in ComponentReshapeEvent
238     // to learn why we did it this way. If you change this code, make
239     // sure that the peer->AWT bounds update still works.
240     // (for instance: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29448 )
241
242     // We do this befor we post the ComponentEvent, because (in Window)
243     // we invalidate() / revalidate() when a ComponentEvent is seen,
244     // and the AWT must already know about the new size then.
245     if (frame_x != this.x || frame_y != this.y || frame_width != this.width
246         || frame_height != this.height)
247       {
248         ComponentReshapeEvent ev = new ComponentReshapeEvent(awtComponent,
249                                                              frame_x,
250                                                              frame_y,
251                                                              frame_width,
252                                                              frame_height);
253         awtComponent.dispatchEvent(ev);
254       }
255
256     if (frame_width != getWidth()
257         || frame_height != getHeight())
258       {
259         this.width = frame_width;
260         this.height = frame_height;
261         q().postEvent(new ComponentEvent(awtComponent,
262                                          ComponentEvent.COMPONENT_RESIZED));
263       }
264
265     if (frame_x != getX()
266         || frame_y != getY())
267       {
268         this.x = frame_x;
269         this.y = frame_y;
270         q().postEvent(new ComponentEvent(awtComponent,
271                                          ComponentEvent.COMPONENT_MOVED));
272       }
273
274   }
275
276   public void show ()
277   {
278     x = awtComponent.getX();
279     y = awtComponent.getY();
280     width = awtComponent.getWidth();
281     height = awtComponent.getHeight();
282     setLocation(x, y);
283     setVisible (true);
284   }
285
286   void postWindowEvent (int id, Window opposite, int newState)
287   {
288     if (id == WindowEvent.WINDOW_STATE_CHANGED)
289       {
290         if (windowState != newState)
291           {
292             // Post old styleWindowEvent with WINDOW_ICONIFIED or
293             // WINDOW_DEICONIFIED if appropriate.
294             if ((windowState & Frame.ICONIFIED) != 0
295                 && (newState & Frame.ICONIFIED) == 0)
296               q().postEvent(new WindowEvent((Window) awtComponent,
297                                             WindowEvent.WINDOW_DEICONIFIED,
298                                             opposite, 0, 0));
299             else if ((windowState & Frame.ICONIFIED) == 0
300                 && (newState & Frame.ICONIFIED) != 0)
301               q().postEvent(new WindowEvent((Window) awtComponent,
302                                             WindowEvent.WINDOW_ICONIFIED,
303                                             opposite, 0, 0));
304             // Post new-style WindowStateEvent.
305             q().postEvent (new WindowEvent ((Window) awtComponent, id,
306                                             opposite, windowState, newState));
307             windowState = newState;
308           }
309       }
310     else
311       q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite));
312   }
313
314   /**
315    * Update the always-on-top status of the native window.
316    */
317   public void updateAlwaysOnTop()
318   {
319     gtkWindowSetAlwaysOnTop( ((Window)awtComponent).isAlwaysOnTop() );
320   }
321
322   protected void postExposeEvent (int x, int y, int width, int height)
323   {
324     // Translate GTK co-ordinates, which do not include a window
325     // frame's insets, to AWT co-ordinates, which do include a window
326     // frame's insets.  GtkWindowPeer should always have all-zero
327     // insets but GtkFramePeer and GtkDialogPeer insets will be
328     // non-zero.
329     q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
330                                    new Rectangle (x + insets.left, 
331                                                   y + insets.top, 
332                                                   width, height)));
333   }
334
335   public boolean requestWindowFocus()
336   {
337     // TODO Auto-generated method stub
338     return false;
339   }
340
341   public boolean requestFocus (Component request, boolean temporary, 
342                                boolean allowWindowFocus, long time)
343   {
344     assert request == awtComponent || isLightweightDescendant(request);
345     boolean retval = false;
346     if (gtkWindowHasFocus())
347       {
348         KeyboardFocusManager kfm =
349           KeyboardFocusManager.getCurrentKeyboardFocusManager();
350         Component currentFocus = kfm.getFocusOwner();
351         if (currentFocus == request)
352           // Nothing to do in this trivial case.
353           retval = true;
354         else
355           {
356             // Requested component is a lightweight descendant of this one
357             // or the actual heavyweight.
358             // Since this (native) component is already focused, we simply
359             // change the actual focus and be done.
360             postFocusEvent(FocusEvent.FOCUS_GAINED, temporary);
361             retval = true;
362           }
363       }
364     else
365       {
366         if (allowWindowFocus)
367           {
368             retval = requestWindowFocus();
369           }
370       }
371     return retval;
372   }
373
374   public Graphics getGraphics ()
375   {
376     Graphics g = super.getGraphics ();
377     // Translate AWT co-ordinates, which include a window frame's
378     // insets, to GTK co-ordinates, which do not include a window
379     // frame's insets.  GtkWindowPeer should always have all-zero
380     // insets but GtkFramePeer and GtkDialogPeer insets will be
381     // non-zero.
382     g.translate (-insets.left, -insets.top);
383     return g;
384   }
385
386   protected void postMouseEvent(int id, long when, int mods, int x, int y, 
387                                 int clickCount, boolean popupTrigger)
388   {
389     // Translate AWT co-ordinates, which include a window frame's
390     // insets, to GTK co-ordinates, which do not include a window
391     // frame's insets.  GtkWindowPeer should always have all-zero
392     // insets but GtkFramePeer and GtkDialogPeer insets will be
393     // non-zero.
394     super.postMouseEvent (id, when, mods, 
395                           x + insets.left, y + insets.top, 
396                           clickCount, popupTrigger);
397   }
398
399   // We override this to keep it in sync with our internal
400   // representation.
401   public Rectangle getBounds()
402   {
403     return new Rectangle(x, y, width, height);
404   }
405 }