1 19 20 package org.netbeans.modules.applemenu; 21 22 import java.awt.Component ; 23 import java.awt.Container ; 24 import java.awt.Dimension ; 25 import java.awt.Point ; 26 import java.awt.Rectangle ; 27 import java.lang.ref.Reference ; 28 import java.lang.ref.SoftReference ; 29 import java.lang.reflect.Method ; 30 import java.util.HashSet ; 31 import java.util.Iterator ; 32 import java.util.Set ; 33 import javax.swing.JComponent ; 34 import javax.swing.JDialog ; 35 import javax.swing.JFrame ; 36 import javax.swing.JWindow ; 37 import javax.swing.Popup ; 38 import javax.swing.PopupFactory ; 39 import javax.swing.SwingUtilities ; 40 import org.openide.ErrorManager; 41 42 43 44 72 public class ApplePopupFactory extends PopupFactory { 73 private static final boolean APPLE_HEAVYWEIGHT = 74 Boolean.getBoolean ("nb.explorer.hw.completions"); 76 private static final boolean APPLE_COCOA_HACK = APPLE_HEAVYWEIGHT && 77 Boolean.getBoolean ("nb.explorer.hw.cocoahack"); 79 private static Set windowPool = new HashSet (); 80 81 public ApplePopupFactory() { 88 } 89 90 public Popup getPopup(Component owner, Component contents, 91 int x, int y) throws IllegalArgumentException { 92 assert owner instanceof JComponent ; 93 Dimension d = contents.getPreferredSize(); 94 Container c = ((JComponent ) owner).getTopLevelAncestor(); 95 if (c == null) { 96 throw new IllegalArgumentException ("Not onscreen: " + owner); 97 } 98 Point p = new Point (x, y); 99 SwingUtilities.convertPointFromScreen(p, c); 100 Rectangle r = new Rectangle (p.x, p.y, d.width, d.height); 101 if (c.getBounds().contains(r)) { 102 return new LWPopup (owner, contents, x, y); 106 } else { 107 return APPLE_HEAVYWEIGHT ? 108 (Popup ) new HWPopup (owner, contents, x, y) : 109 (Popup ) new NullPopup(); 110 } 111 } 112 113 private static final class NullPopup extends Popup { 114 public void show() {} 115 public void hide() {} 116 } 117 118 private static abstract class OurPopup extends Popup { 119 protected Component owner = null; 120 protected Component contents = null; 121 protected int x = -1; 122 protected int y = -1; 123 public OurPopup (Component owner, Component contents, int x, int y) { 124 configure (owner, contents, x, y); 125 } 126 127 final void configure (Component owner, Component contents, int x, int y) { 128 this.owner = owner; 129 this.contents = contents; 130 this.x = x; 131 this.y = y; 132 } 133 134 protected abstract void prepareResources(); 135 protected abstract void doShow(); 136 public abstract boolean isShowing(); 137 protected abstract void doHide(); 138 139 public final void show() { 140 prepareResources(); 141 doShow(); 142 } 143 144 public final void hide() { 145 doHide(); 146 } 147 148 void dispose() { 149 owner = null; 150 contents = null; 151 x = -1; 152 y = -1; 153 } 154 155 private boolean canReuse = false; 156 public final void clear() { 157 canReuse = true; 158 dispose(); 159 } 160 161 boolean isInUse() { 162 return canReuse; 163 } 164 } 165 166 private static class LWPopup extends OurPopup { 167 public LWPopup (Component owner, Component contents, int x, int y) { 168 super (owner, contents, x, y); 169 } 170 171 private Rectangle bounds = null; 172 protected void prepareResources() { 173 JComponent jc = (JComponent ) owner; 174 Container w = jc.getTopLevelAncestor(); 175 JComponent pane = null; 176 if (w instanceof JFrame ) { 177 pane = (JComponent ) ((JFrame ) w).getGlassPane(); 178 } else if (w instanceof JDialog ) { 179 pane = (JComponent ) ((JDialog ) w).getGlassPane(); 180 } else if (w instanceof JWindow ) { 181 pane = (JComponent ) ((JWindow ) w).getGlassPane(); 182 } 183 if (w == null) { 184 throw new IllegalArgumentException ("Not a JFrame/" + "JWindow/JDialog: " + owner); } 187 Point p = new Point (x, y); 188 SwingUtilities.convertPointFromScreen(p, pane); 189 if (pane.getLayout() != null) { 190 pane.setLayout (null); 191 } 192 pane.setVisible(true); 193 contents.setVisible (false); 194 Dimension d = contents.getPreferredSize(); 195 pane.add (contents); 196 bounds = new Rectangle (p.x, p.y, d.width, d.height); 197 contents.setBounds (p.x, p.y, d.width, d.height); 198 } 199 200 protected void doShow() { 201 contents.setVisible (true); 202 } 203 204 public boolean isShowing() { 205 return contents != null && contents.isShowing(); 206 } 207 208 protected void doHide() { 209 Container parent = contents.getParent(); 210 if (parent != null) { 211 contents.getParent().remove (contents); 212 parent.repaint(bounds.x, bounds.y, bounds.width, bounds.height); 213 } 214 contents.setVisible (true); 217 } 218 } 219 220 private static class HWPopup extends OurPopup { 221 private JWindow window = null; 222 public HWPopup (Component owner, Component contents, int x, int y) { 223 super (owner, contents, x, y); 224 } 225 226 public boolean isShowing() { 227 return window != null && window.isShowing(); 228 } 229 230 void dispose() { 231 if (window != null) { 232 checkInWindow (window); 233 window = null; 234 } 235 super.dispose(); 236 } 237 238 protected void prepareResources() { 239 window = checkOutWindow(); 240 window.getContentPane().add (contents); 241 window.setLocation (new Point (x, y)); 242 window.pack(); 243 window.setBackground (new java.awt.Color (255, 255, 255, 0)); 244 } 245 246 protected void doShow() { 247 window.setVisible(true); 248 } 249 250 protected void doHide() { 251 if (window != null) { 252 window.setVisible(false); 253 window.getContentPane().remove (contents); 254 dispose(); 256 } 257 } 258 } 259 260 private static JWindow checkOutWindow() { 261 if (windowPool != null) { 262 if (!windowPool.isEmpty()) { 263 for (Iterator i=windowPool.iterator(); i.hasNext();) { 264 Reference ref = (Reference ) i.next(); 265 JWindow win = (JWindow ) ref.get(); 266 i.remove(); 267 if (win != null) { 268 assert !win.isShowing(); 269 win.setBounds (0, 0, 1, 1); 270 win.getContentPane().removeAll(); 271 win.setBackground (new java.awt.Color (255, 255, 255, 0)); 272 return win; 273 } 274 } 275 } 276 } 277 JWindow nue = APPLE_COCOA_HACK ? (JWindow ) new HackedJWindow() : new JWindow (); 278 279 nue.setBackground (new java.awt.Color (255, 255, 255, 0)); 280 return nue; 281 } 282 283 private static void checkInWindow (JWindow win) { 284 if (!APPLE_COCOA_HACK) { 285 win.dispose(); 286 } 287 windowPool.add (new SoftReference (win)); 288 } 289 290 private static int ct = 0; 292 private static boolean hackBroken = false; 295 private static boolean warned = false; 297 298 static boolean broken() { 299 return hackBroken; 300 } 301 302 314 private static final class HackedJWindow extends JWindow { 315 private String title = "none"; 316 HackedJWindow() {} 317 318 public void addNotify() { 319 super.addNotify(); 320 hackTitle(); 321 hackNativeWindow(); 322 } 323 324 private void hackTitle() { 325 if (!hackBroken) { 326 try { 327 Object o = getPeer(); 333 if (o != null) { 334 Method m = o.getClass().getDeclaredMethod ("setTitle", 335 new Class [] { String .class }); 336 m.setAccessible(true); 337 title = "hw popup" + (ct++); 338 m.invoke (o, new Object [] { title }); 339 } 340 } catch (Exception e) { 341 warn(e); 342 } 343 } 344 } 345 346 private void hackNativeWindow() { 347 if (!hackBroken) { 348 try { 349 Class c = Class.forName ("com.apple.cocoa.application." + 351 "NSApplication"); 352 353 Method m = c.getDeclaredMethod ("sharedApplication", null); 354 Object nsapplication = m.invoke (null, null); 355 356 m = nsapplication.getClass().getMethod ("windows", null); 358 Object nsarray_of_nswindows = m.invoke (nsapplication, null); 359 m = nsarray_of_nswindows.getClass().getMethod("count", null); 361 int arrSize = ((Integer ) m.invoke (nsarray_of_nswindows, 362 null)).intValue(); 363 364 Object [] windows = new Object [arrSize]; 366 m = nsarray_of_nswindows.getClass().getMethod( 367 "getObjects", new Class [] { Object [].class }); 368 369 m.invoke (nsarray_of_nswindows, new Object [] { windows }); 371 if (windows.length > 0) { 372 c = windows[0].getClass(); 375 Method titleMethod = c.getMethod("title", null); 376 Method setHasShadowMethod = c.getMethod ("setHasShadow", 377 new Class [] { Boolean.TYPE}); 378 379 for (int i=0; i < windows.length; i++) { 380 String ttl = (String ) titleMethod.invoke (windows[i], 382 null); 383 384 if (title.equals (ttl)) { 385 setHasShadowMethod.invoke (windows[i], 388 new Object [] { Boolean.FALSE }); 389 } 390 } 391 } 392 } catch (Exception e) { 393 warn(e); 394 } 395 } 396 } 397 398 private void warn(Exception e) { 399 hackBroken = true; 400 if (!warned) { 401 warned = true; 402 ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, 403 "Cannot turn off popup drop shadow, " + 404 "reverting to standard swing popup factory"); 405 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 406 e.printStackTrace(); 407 } 408 } 409 } 410 } 411 | Popular Tags |