1 /* 2 * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package sun.awt.motif; 26 27 import java.util.Vector; 28 import java.awt.*; 29 import java.awt.peer.*; 30 import java.awt.event.*; 31 import java.awt.image.BufferedImage; 32 import java.awt.image.DataBuffer; 33 import java.awt.image.DataBufferByte; 34 import java.awt.image.DataBufferInt; 35 import java.awt.image.ImageObserver; 36 import sun.awt.image.ImageRepresentation; 37 import sun.awt.motif.MInputMethod; 38 import sun.awt.motif.MInputMethodControl; 39 import sun.awt.im.*; 40 import sun.awt.DisplayChangedListener; 41 import sun.awt.SunToolkit; 42 import sun.awt.X11GraphicsDevice; 43 44 class MWindowPeer extends MPanelPeer implements WindowPeer, 45 DisplayChangedListener { 46 47 Insets insets = new Insets( 0, 0, 0, 0 ); 48 MWindowAttributes winAttr; 49 static Vector allWindows = new Vector(); 50 int iconWidth = -1; 51 int iconHeight = -1; 52 53 int dropTargetCount = 0; 54 boolean alwaysOnTop; 55 56 native void pCreate(MComponentPeer parent, String targetClassName, boolean isFocusableWindow); 57 native void pShow(); 58 native void pToFront(); 59 native void pShowModal(boolean isModal); 60 native void pHide(); 61 native void pReshape(int x, int y, int width, int height); 62 native void pDispose(); 63 native void pSetTitle(String title); 64 public native void setState(int state); 65 public native int getState(); 66 67 public native void setResizable(boolean resizable); 68 native void addTextComponentNative(MComponentPeer tc); 69 native void removeTextComponentNative(); 70 native void pSetIMMOption(String option); 71 native void pSetMenuBar(MMenuBarPeer mbpeer); 72 native void setSaveUnder(boolean state); 73 74 native void registerX11DropTarget(Component target); 75 native void unregisterX11DropTarget(Component target); 76 native void updateAlwaysOnTop(boolean isAlwaysOnTop); 77 78 private static native void initIDs(); 79 80 static { 81 initIDs(); 82 } 83 84 // this function is privileged! do not change it to public! 85 private static int getInset(final String name, final int def) { 86 Integer tmp = (Integer) java.security.AccessController.doPrivileged( 87 new sun.security.action.GetIntegerAction(name, def)); 88 return tmp.intValue(); 89 } 90 91 MWindowPeer() { 92 insets = new Insets(0,0,0,0); 93 winAttr = new MWindowAttributes(); 94 } 95 96 MWindowPeer(Window target) { 97 98 this(); 99 init(target); 100 101 allWindows.addElement(this); 102 } 103 104 void create(MComponentPeer parent) { 105 pCreate(parent, target.getClass().getName(), ((Window)target).isFocusableWindow()); 106 } 107 108 void init( Window target ) { 109 if ( winAttr.nativeDecor == true ) { 110 insets.top = getInset("awt.frame.topInset", -1); 111 insets.left = getInset("awt.frame.leftInset", -1); 112 insets.bottom = getInset("awt.frame.bottomInset", -1); 113 insets.right = getInset("awt.frame.rightInset", -1); 114 } 115 116 Rectangle bounds = target.getBounds(); 117 sysX = bounds.x; 118 sysY = bounds.y; 119 sysW = bounds.width; 120 sysH = bounds.height; 121 122 super.init(target); 123 InputMethodManager imm = InputMethodManager.getInstance(); 124 String menuString = imm.getTriggerMenuString(); 125 if (menuString != null) 126 { 127 pSetIMMOption(menuString); 128 } 129 pSetTitle(winAttr.title); 130 131 /* 132 * For Windows and undecorated Frames and Dialogs this just 133 * disables/enables resizing functions in the system menu. 134 */ 135 setResizable(winAttr.isResizable); 136 137 setSaveUnder(true); 138 139 Font f = target.getFont(); 140 if (f == null) { 141 f = defaultFont; 142 target.setFont(f); 143 setFont(f); 144 } 145 Color c = target.getBackground(); 146 if (c == null) { 147 target.setBackground(SystemColor.window); 148 setBackground(SystemColor.window); 149 } 150 c = target.getForeground(); 151 if (c == null) { 152 target.setForeground(SystemColor.windowText); 153 setForeground(SystemColor.windowText); 154 } 155 alwaysOnTop = ((Window)target).isAlwaysOnTop() && ((Window)target).isAlwaysOnTopSupported(); 156 157 GraphicsConfiguration gc = getGraphicsConfiguration(); 158 ((X11GraphicsDevice)gc.getDevice()).addDisplayChangedListener(this); 159 160 } 161 162 /* Support for multiple icons is not implemented in MAWT */ 163 public void updateIconImages() { 164 if (this instanceof MFramePeer) { 165 ((MFramePeer)this).setIconImage(((Frame)target).getIconImage()); 166 } 167 } 168 169 170 /* Not implemented in MAWT */ 171 public void updateMinimumSize() { 172 } 173 174 protected void disposeImpl() { 175 allWindows.removeElement(this); 176 super.disposeImpl(); 177 } 178 179 public native void toBack(); 180 181 public void setAlwaysOnTop(boolean alwaysOnTop) { 182 this.alwaysOnTop = alwaysOnTop; 183 updateAlwaysOnTop(alwaysOnTop); 184 } 185 186 public void updateAlwaysOnTopState() { 187 setAlwaysOnTop(((Window)target).isAlwaysOnTop()); 188 } 189 190 public void toFront() { 191 if (target.isVisible()) { 192 updateFocusableWindowState(); 193 pToFront(); 194 } 195 } 196 197 public void updateFocusableWindowState() { 198 setFocusableWindow(((Window)target).isFocusableWindow()); 199 } 200 native void setFocusableWindow(boolean value); 201 202 public void setVisible( boolean b ) { 203 if (b) { 204 updateFocusableWindowState(); 205 } 206 super.setVisible(b); 207 updateAlwaysOnTop(alwaysOnTop); 208 } 209 210 public Insets getInsets() { 211 return insets; 212 } 213 214 public void handleQuit() { 215 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING)); 216 } 217 218 // XXX: nasty WM, foul play. spank WM author. 219 public void handleDestroy() { 220 final Window target = (Window)this.target; 221 SunToolkit.executeOnEventHandlerThread(target, 222 new Runnable() { 223 public void run() { 224 // This seems like the only reasonable thing we 225 // could do in this situation as the native window 226 // is already dead. 227 target.dispose(); 228 } 229 }); 230 } 231 232 233 // NOTE: This method may be called by privileged threads. 234 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 235 public void handleIconify() { 236 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED)); 237 } 238 239 // NOTE: This method may be called by privileged threads. 240 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 241 public void handleDeiconify() { 242 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED)); 243 } 244 245 // NOTE: This method may be called by privileged threads. 246 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 247 public void handleStateChange(int oldState, int newState) { 248 postEvent(new WindowEvent((Window)target, 249 WindowEvent.WINDOW_STATE_CHANGED, 250 oldState, newState)); 251 } 252 253 /** 254 * Called to inform the Window that its size has changed and it 255 * should layout its children. 256 */ 257 // NOTE: This method may be called by privileged threads. 258 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 259 public void handleResize(int width, int height) { 260 sysW = width; 261 sysH = height; 262 263 // REMIND: Is this secure? Can client code subclass input method? 264 if (!tcList.isEmpty() && 265 !imList.isEmpty()){ 266 int i; 267 for (i = 0; i < imList.size(); i++){ 268 ((MInputMethod)imList.elementAt(i)).configureStatus(); 269 } 270 } 271 validateSurface(width, height); 272 postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED)); 273 } 274 275 276 /** 277 * DEPRECATED: Replaced by getInsets(). 278 */ 279 public Insets insets() { 280 return getInsets(); 281 } 282 283 public void handleMoved(int x, int y) { 284 sysX = x; 285 sysY = y; 286 postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); 287 } 288 289 private native AWTEvent wrapInSequenced(AWTEvent event); 290 291 // NOTE: This method may be called by privileged threads. 292 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 293 public void handleWindowFocusIn() { 294 WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_GAINED_FOCUS); 295 /* wrap in Sequenced, then post*/ 296 postEvent(wrapInSequenced((AWTEvent) we)); 297 } 298 299 // NOTE: This method may be called by privileged threads. 300 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 301 public void handleWindowFocusOut(Window oppositeWindow) { 302 WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_LOST_FOCUS, 303 oppositeWindow); 304 /* wrap in Sequenced, then post*/ 305 postEvent(wrapInSequenced((AWTEvent) we)); 306 } 307 308 309 // relocation of Imm stuff 310 private Vector imList = new Vector(); 311 private Vector tcList = new Vector(); 312 313 // NOTE: This method is called by privileged threads. 314 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 315 void notifyIMMOptionChange(){ 316 317 // REMIND: IS THIS SECURE??? CAN USER CODE SUBCLASS INPUTMETHODMGR??? 318 InputMethodManager.getInstance().notifyChangeRequest(target); 319 } 320 321 public void addInputMethod(MInputMethod im) { 322 if (!imList.contains(im)) 323 imList.addElement(im); 324 } 325 326 public void removeInputMethod(MInputMethod im) { 327 if (imList.contains(im)) 328 imList.removeElement(im); 329 } 330 331 public void addTextComponent(MComponentPeer tc) { 332 if (tcList.contains(tc)) 333 return; 334 if (tcList.isEmpty()){ 335 addTextComponentNative(tc); 336 if (!imList.isEmpty()) { 337 for (int i = 0; i < imList.size(); i++) { 338 ((MInputMethod)imList.elementAt(i)).reconfigureXIC((MInputMethodControl)this); 339 } 340 } 341 MToolkit.executeOnEventHandlerThread(target, new Runnable() { 342 public void run() { 343 synchronized(target.getTreeLock()) { 344 target.doLayout(); 345 } 346 } 347 }); 348 } 349 tcList.addElement(tc); 350 351 } 352 353 public void removeTextComponent(MComponentPeer tc) { 354 if (!tcList.contains(tc)) 355 return; 356 tcList.removeElement(tc); 357 if (tcList.isEmpty()){ 358 removeTextComponentNative(); 359 if (!imList.isEmpty()) { 360 for (int i = 0; i < imList.size(); i++) { 361 ((MInputMethod)imList.elementAt(i)).reconfigureXIC((MInputMethodControl)this); 362 } 363 } 364 target.doLayout(); 365 } 366 } 367 368 public MComponentPeer getTextComponent() { 369 if (!tcList.isEmpty()) { 370 return (MComponentPeer)tcList.firstElement(); 371 } else { 372 return null; 373 } 374 } 375 376 boolean hasDecorations(int decor) { 377 if (!winAttr.nativeDecor) { 378 return false; 379 } 380 else { 381 int myDecor = winAttr.decorations; 382 boolean hasBits = ((myDecor & decor) == decor); 383 if ((myDecor & MWindowAttributes.AWT_DECOR_ALL) != 0) 384 return !hasBits; 385 else 386 return hasBits; 387 } 388 } 389 390 /* Returns the native paint should be posted after setting new size 391 */ 392 public boolean checkNativePaintOnSetBounds(int width, int height) { 393 // Fix for 4418155. Window does not repaint 394 // automticaly if shrinking. Should not wait for Expose 395 return (width > oldWidth) || (height > oldHeight); 396 } 397 398 /* --- DisplayChangedListener Stuff --- */ 399 400 native void resetTargetGC(Component target); 401 402 /* Xinerama 403 * called to update our GC when dragged onto another screen 404 */ 405 public void draggedToNewScreen(int screenNum) { 406 final int finalScreenNum = screenNum; 407 408 SunToolkit.executeOnEventHandlerThread((Component)target, new Runnable() 409 { 410 public void run() { 411 displayChanged(finalScreenNum); 412 } 413 }); 414 } 415 416 /* Xinerama 417 * called to update our GC when dragged onto another screen 418 */ 419 public void displayChanged(int screenNum) { 420 // update our GC 421 resetLocalGC(screenNum); /* upcall to MCanvasPeer */ 422 resetTargetGC(target); /* call Window.resetGC() via native */ 423 424 //propagate to children 425 super.displayChanged(screenNum); /* upcall to MPanelPeer */ 426 } 427 428 /** 429 * Helper method that executes the displayChanged(screen) method on 430 * the event dispatch thread. This method is used in the Xinerama case 431 * and after display mode change events. 432 */ 433 private void executeDisplayChangedOnEDT(int screenNum) { 434 final int finalScreenNum = screenNum; 435 Runnable dc = new Runnable() { 436 public void run() { 437 displayChanged(finalScreenNum); 438 } 439 }; 440 SunToolkit.executeOnEventHandlerThread((Component)target, dc); 441 } 442 443 /** 444 * From the DisplayChangedListener interface; called from 445 * X11GraphicsDevice when the display mode has been changed. 446 */ 447 public void displayChanged() { 448 GraphicsConfiguration gc = getGraphicsConfiguration(); 449 int curScreenNum = ((X11GraphicsDevice)gc.getDevice()).getScreen(); 450 executeDisplayChangedOnEDT(curScreenNum); 451 } 452 453 /** 454 * From the DisplayChangedListener interface; top-levels do not need 455 * to react to this event. 456 */ 457 public void paletteChanged() { 458 } 459 460 public synchronized void addDropTarget() { 461 if (dropTargetCount == 0) { 462 registerX11DropTarget(target); 463 } 464 dropTargetCount++; 465 } 466 467 public synchronized void removeDropTarget() { 468 dropTargetCount--; 469 if (dropTargetCount == 0) { 470 unregisterX11DropTarget(target); 471 } 472 } 473 474 protected synchronized void updateDropTarget() { 475 if (dropTargetCount > 0) { 476 unregisterX11DropTarget(target); 477 registerX11DropTarget(target); 478 } 479 } 480 481 public boolean requestWindowFocus() { 482 return false; 483 } 484 485 public void setModalBlocked(Dialog blocker, boolean blocked) { 486 // do nothing 487 } 488 489 public void postUngrabEvent() { 490 postEvent(new sun.awt.UngrabEvent((Window)target)); 491 } 492 493 boolean isOwnerOf(MComponentPeer child) { 494 if (child == null) return false; 495 496 Component comp = child.target; 497 while (comp != null && !(comp instanceof Window)) { 498 comp = getParent_NoClientCode(comp); 499 } 500 if (!(comp instanceof Window)) { 501 return false; 502 } 503 504 while (comp != null && !(comp == target) && !(comp instanceof Dialog)) { 505 comp = getParent_NoClientCode(comp); 506 } 507 return (comp == target); 508 } 509 510 boolean processUngrabMouseEvent(MComponentPeer compPeer, int x_root, int y_root, int type) { 511 switch (type) { 512 case 4: // ButtonPress 513 // Check that the target is the child of the grabbed 514 // window or the child of one of the owned windows of 515 // the grabbed window 516 if (!isOwnerOf(compPeer)) { 517 postUngrabEvent(); 518 return true; 519 } 520 } 521 return false; 522 } 523 524 private final boolean hasWarningWindow() { 525 return ((Window)target).getWarningString() != null; 526 } 527 528 // This method is overriden at Dialog and Frame peers. 529 boolean isTargetUndecorated() { 530 return true; 531 } 532 533 private volatile int sysX = 0; 534 private volatile int sysY = 0; 535 private volatile int sysW = 0; 536 private volatile int sysH = 0; 537 538 Rectangle constrainBounds(int x, int y, int width, int height) { 539 // We don't restrict the setBounds() operation if the code is trusted. 540 if (!hasWarningWindow()) { 541 return new Rectangle(x, y, width, height); 542 } 543 544 int newX = x; 545 int newY = y; 546 int newW = width; 547 int newH = height; 548 549 GraphicsConfiguration gc = ((Window)target).getGraphicsConfiguration(); 550 Rectangle sB = gc.getBounds(); 551 Insets sIn = ((Window)target).getToolkit().getScreenInsets(gc); 552 553 int screenW = sB.width - sIn.left - sIn.right; 554 int screenH = sB.height - sIn.top - sIn.bottom; 555 556 // If it's undecorated or is not currently visible, 557 // then check each point is within the visible part of the screen 558 if (!target.isVisible() || isTargetUndecorated()) { 559 int screenX = sB.x + sIn.left; 560 int screenY = sB.y + sIn.top; 561 562 // First make sure the size is withing the visible part of the screen 563 if (newW > screenW) { 564 newW = screenW; 565 } 566 567 if (newH > screenH) { 568 newH = screenH; 569 } 570 571 // Tweak the location if needed 572 if (newX < screenX) { 573 newX = screenX; 574 } else if (newX + newW > screenX + screenW) { 575 newX = screenX + screenW - newW; 576 } 577 578 if (newY < screenY) { 579 newY = screenY; 580 } else if (newY + newH > screenY + screenH) { 581 newY = screenY + screenH - newH; 582 } 583 } else { 584 int maxW = Math.max(screenW, sysW); 585 int maxH = Math.max(screenH, sysH); 586 587 // Make sure the size is withing the visible part of the screen 588 // OR is less that the current size of the window. 589 if (newW > maxW) { 590 newW = maxW; 591 } 592 593 if (newH > maxH) { 594 newH = maxH; 595 } 596 } 597 598 return new Rectangle(newX, newY, newW, newH); 599 } 600 601 public void setBounds(int x, int y, int width, int height, int op) { 602 Rectangle newBounds = constrainBounds(x, y, width, height); 603 super.setBounds(newBounds.x, newBounds.y, newBounds.width, newBounds.height, op); 604 } 605 606 @Override 607 public void setOpacity(float opacity) { 608 // not implemented 609 } 610 611 @Override 612 public void setOpaque(boolean isOpaque) { 613 // no-op 614 } 615 616 @Override 617 public void updateWindow() { 618 // no-op 619 } 620 621 public void repositionSecurityWarning() { 622 // not implemented 623 } 624 625 }