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