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