1 /*
2 * Copyright (c) 2005, 2015, 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
26 package sun.awt.X11;
27
28 import java.awt.*;
29 import java.awt.event.*;
30 import java.awt.peer.TrayIconPeer;
31 import sun.awt.*;
32 import java.awt.image.*;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.lang.reflect.InvocationTargetException;
36 import sun.util.logging.PlatformLogger;
37
38 public class XTrayIconPeer implements TrayIconPeer,
39 InfoWindow.Balloon.LiveArguments,
40 InfoWindow.Tooltip.LiveArguments
41 {
42 private static final PlatformLogger ctrLog = PlatformLogger.getLogger("sun.awt.X11.XTrayIconPeer.centering");
43
44 TrayIcon target;
45 TrayIconEventProxy eventProxy;
46 XTrayIconEmbeddedFrame eframe;
47 TrayIconCanvas canvas;
48 InfoWindow.Balloon balloon;
49 InfoWindow.Tooltip tooltip;
50 PopupMenu popup;
51 String tooltipString;
52 boolean isTrayIconDisplayed;
53 long eframeParentID;
54 final XEventDispatcher parentXED, eframeXED;
55
56 static final XEventDispatcher dummyXED = new XEventDispatcher() {
57 public void dispatchEvent(XEvent ev) {}
58 };
59
60 volatile boolean isDisposed;
61
62 boolean isParentWindowLocated;
63 int old_x, old_y;
64 int ex_width, ex_height;
65
66 static final int TRAY_ICON_WIDTH = 24;
67 static final int TRAY_ICON_HEIGHT = 24;
68
69 XTrayIconPeer(TrayIcon target)
70 throws AWTException
71 {
72 this.target = target;
73
74 eventProxy = new TrayIconEventProxy(this);
75
76 canvas = new TrayIconCanvas(target, TRAY_ICON_WIDTH, TRAY_ICON_HEIGHT);
77
78 eframe = new XTrayIconEmbeddedFrame();
79
80 eframe.setSize(TRAY_ICON_WIDTH, TRAY_ICON_HEIGHT);
81 eframe.add(canvas);
82
83 // Fix for 6317038: as EmbeddedFrame is instance of Frame, it is blocked
84 // by modal dialogs, but in the case of TrayIcon it shouldn't. So we
85 // set ModalExclusion property on it.
86 AccessController.doPrivileged(new PrivilegedAction<Object>() {
87 public Object run() {
88 eframe.setModalExclusionType(Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
89 return null;
90 }
91 });
92
93
94 if (XWM.getWMID() != XWM.METACITY_WM) {
95 parentXED = dummyXED; // We don't like to leave it 'null'.
96 } else {
97 parentXED = new XEventDispatcher() {
98 // It's executed under AWTLock.
99 public void dispatchEvent(XEvent ev) {
100 if (isDisposed() || ev.get_type() != XConstants.ConfigureNotify) {
105
106 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
107 ctrLog.fine("ConfigureNotify on parent of {0}: {1}x{2}+{3}+{4} (old: {5}+{6})",
108 XTrayIconPeer.this, ce.get_width(), ce.get_height(),
109 ce.get_x(), ce.get_y(), old_x, old_y);
110 }
111
112 // A workaround for Gnome/Metacity (it doesn't affect the behaviour on KDE).
113 // On Metacity the EmbeddedFrame's parent window bounds are larger
114 // than TrayIcon size required (that is we need a square but a rectangle
115 // is provided by the Panel Notification Area). The parent's background color
116 // differs from the Panel's one. To hide the background we resize parent
117 // window so that it fits the EmbeddedFrame.
118 // However due to resizing the parent window it loses centering in the Panel.
119 // We center it when discovering that some of its side is of size greater
120 // than the fixed value. Centering is being done by "X" (when the parent's width
121 // is greater) and by "Y" (when the parent's height is greater).
122
123 // Actually we need this workaround until we could detect taskbar color.
124
125 if (ce.get_height() != TRAY_ICON_HEIGHT && ce.get_width() != TRAY_ICON_WIDTH) {
126
127 // If both the height and the width differ from the fixed size then WM
128 // must level at least one side to the fixed size. For some reason it may take
129 // a few hops (even after reparenting) and we have to skip the intermediate ones.
130 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
131 ctrLog.fine("ConfigureNotify on parent of {0}. Skipping as intermediate resizing.",
132 XTrayIconPeer.this);
133 }
134 return;
135
136 } else if (ce.get_height() > TRAY_ICON_HEIGHT) {
137
138 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
139 ctrLog.fine("ConfigureNotify on parent of {0}. Centering by \"Y\".",
140 XTrayIconPeer.this);
141 }
142
143 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), eframeParentID,
144 ce.get_x(),
145 ce.get_y()+ce.get_height()/2-TRAY_ICON_HEIGHT/2,
146 TRAY_ICON_WIDTH,
147 TRAY_ICON_HEIGHT);
148 ex_height = ce.get_height();
149 ex_width = 0;
150
151 } else if (ce.get_width() > TRAY_ICON_WIDTH) {
152
153 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
154 ctrLog.fine("ConfigureNotify on parent of {0}. Centering by \"X\".",
155 XTrayIconPeer.this);
156 }
157
158 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), eframeParentID,
159 ce.get_x()+ce.get_width()/2 - TRAY_ICON_WIDTH/2,
160 ce.get_y(),
161 TRAY_ICON_WIDTH,
162 TRAY_ICON_HEIGHT);
163 ex_width = ce.get_width();
164 ex_height = 0;
165
166 } else if (isParentWindowLocated && ce.get_x() != old_x && ce.get_y() != old_y) {
167 // If moving by both "X" and "Y".
168 // When some tray icon gets removed from the tray, a Java icon may be repositioned.
169 // In this case the parent window also lose centering. We have to restore it.
170
171 if (ex_height != 0) {
172
173 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
174 ctrLog.fine("ConfigureNotify on parent of {0}. Move detected. Centering by \"Y\".",
175 XTrayIconPeer.this);
176 }
177
178 XlibWrapper.XMoveWindow(XToolkit.getDisplay(), eframeParentID,
179 ce.get_x(),
180 ce.get_y() + ex_height/2 - TRAY_ICON_HEIGHT/2);
181
182 } else if (ex_width != 0) {
183
184 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
185 ctrLog.fine("ConfigureNotify on parent of {0}. Move detected. Centering by \"X\".",
186 XTrayIconPeer.this);
187 }
188
189 XlibWrapper.XMoveWindow(XToolkit.getDisplay(), eframeParentID,
190 ce.get_x() + ex_width/2 - TRAY_ICON_WIDTH/2,
191 ce.get_y());
192 } else {
193 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
194 ctrLog.fine("ConfigureNotify on parent of {0}. Move detected. Skipping.",
195 XTrayIconPeer.this);
196 }
197 }
198 }
199 old_x = ce.get_x();
200 old_y = ce.get_y();
201 isParentWindowLocated = true;
202 }
203 };
204 }
205 eframeXED = new XEventDispatcher() {
206 // It's executed under AWTLock.
207 XTrayIconPeer xtiPeer = XTrayIconPeer.this;
208
209 public void dispatchEvent(XEvent ev) {
210 if (isDisposed() || ev.get_type() != XConstants.ReparentNotify) {
211 return;
212 }
213
214 XReparentEvent re = ev.get_xreparent();
215 eframeParentID = re.get_parent();
216
217 if (eframeParentID == XToolkit.getDefaultRootWindow()) {
218
219 if (isTrayIconDisplayed) { // most likely Notification Area was removed
220 SunToolkit.executeOnEventHandlerThread(xtiPeer.target, new Runnable() {
221 public void run() {
222 SystemTray.getSystemTray().remove(xtiPeer.target);
223 }
224 });
225 }
226 return;
227 }
228
229 if (!isTrayIconDisplayed) {
230 addXED(eframeParentID, parentXED, XConstants.StructureNotifyMask);
231
232 isTrayIconDisplayed = true;
233 XToolkit.awtLockNotifyAll();
234 }
235 }
236 };
237
238 addXED(getWindow(), eframeXED, XConstants.StructureNotifyMask);
239
240 XSystemTrayPeer.getPeerInstance().addTrayIcon(this); // throws AWTException
241
242 // Wait till the EmbeddedFrame is reparented
243 long start = System.currentTimeMillis();
244 final long PERIOD = XToolkit.getTrayIconDisplayTimeout();
245 XToolkit.awtLock();
246 try {
247 while (!isTrayIconDisplayed) {
248 try {
249 XToolkit.awtLockWait(PERIOD);
250 } catch (InterruptedException e) {
251 break;
252 }
253 if (System.currentTimeMillis() - start > PERIOD) {
254 break;
255 }
256 }
257 } finally {
258 XToolkit.awtUnlock();
259 }
260
261 // This is unlikely to happen.
398
399 private void removeXED(long window, XEventDispatcher xed) {
400 if (window == 0) {
401 return;
402 }
403 XToolkit.awtLock();
404 try {
405 XToolkit.removeEventDispatcher(window, xed);
406 } finally {
407 XToolkit.awtUnlock();
408 }
409 }
410
411 // Private method for testing purposes.
412 private Point getLocationOnScreen() {
413 return eframe.getLocationOnScreen();
414 }
415
416 public Rectangle getBounds() {
417 Point loc = getLocationOnScreen();
418 return new Rectangle(loc.x, loc.y, loc.x + TRAY_ICON_WIDTH, loc.y + TRAY_ICON_HEIGHT);
419 }
420
421 void addListeners() {
422 canvas.addMouseListener(eventProxy);
423 canvas.addMouseMotionListener(eventProxy);
424 eframe.addMouseListener(eventProxy);
425 }
426
427 void removeListeners() {
428 canvas.removeMouseListener(eventProxy);
429 canvas.removeMouseMotionListener(eventProxy);
430 eframe.removeMouseListener(eventProxy);
431 }
432
433 long getWindow() {
434 return AWTAccessor.getComponentAccessor()
435 .<XEmbeddedFramePeer>getPeer(eframe).getWindow();
436 }
437
438 public boolean isDisposed() {
532 return false;
533 }
534
535 // embedded frame for tray icon shouldn't be disposed by anyone except tray icon
536 public void dispose(){
537 }
538
539 public void realDispose(){
540 super.dispose();
541 }
542 };
543
544 // ***************************************
545 // Classes for painting an image on canvas
546 // ***************************************
547
548 @SuppressWarnings("serial") // JDK-implementation class
549 static class TrayIconCanvas extends IconCanvas {
550 TrayIcon target;
551 boolean autosize;
552
553 TrayIconCanvas(TrayIcon target, int width, int height) {
554 super(width, height);
555 this.target = target;
556 }
557
558 // Invoke on EDT.
559 protected void repaintImage(boolean doClear) {
560 boolean old_autosize = autosize;
561 autosize = target.isImageAutoSize();
562
563 curW = autosize ? width : image.getWidth(observer);
564 curH = autosize ? height : image.getHeight(observer);
565
566 super.repaintImage(doClear || (old_autosize != autosize));
567 }
568
569 public void dispose() {
570 super.dispose();
571 target = null;
572 }
573 }
574
575 @SuppressWarnings("serial") // JDK-implementation class
576 public static class IconCanvas extends Canvas {
577 volatile Image image;
578 IconObserver observer;
579 int width, height;
580 int curW, curH;
581
582 IconCanvas(int width, int height) {
583 this.width = curW = width;
584 this.height = curH = height;
585 }
586
587 // Invoke on EDT.
588 public void updateImage(Image image) {
589 this.image = image;
590 if (observer == null) {
591 observer = new IconObserver();
592 }
593 repaintImage(true);
594 }
595
596 public void dispose() {
597 observer = null;
598 }
599
600 // Invoke on EDT.
601 protected void repaintImage(boolean doClear) {
602 Graphics g = getGraphics();
603 if (g != null) {
604 try {
|
1 /*
2 * Copyright (c) 2005, 2017, 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
26 package sun.awt.X11;
27
28 import java.awt.*;
29 import java.awt.event.*;
30 import java.awt.peer.TrayIconPeer;
31 import sun.awt.*;
32 import java.awt.image.*;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.lang.reflect.InvocationTargetException;
36 import sun.util.logging.PlatformLogger;
37 import java.awt.geom.AffineTransform;
38 import sun.java2d.pipe.Region;
39
40 public class XTrayIconPeer implements TrayIconPeer,
41 InfoWindow.Balloon.LiveArguments,
42 InfoWindow.Tooltip.LiveArguments
43 {
44 private static final PlatformLogger ctrLog = PlatformLogger.getLogger("sun.awt.X11.XTrayIconPeer.centering");
45
46 TrayIcon target;
47 TrayIconEventProxy eventProxy;
48 XTrayIconEmbeddedFrame eframe;
49 TrayIconCanvas canvas;
50 InfoWindow.Balloon balloon;
51 InfoWindow.Tooltip tooltip;
52 PopupMenu popup;
53 String tooltipString;
54 boolean isTrayIconDisplayed;
55 long eframeParentID;
56 final XEventDispatcher parentXED, eframeXED;
57
58 static final XEventDispatcher dummyXED = new XEventDispatcher() {
59 public void dispatchEvent(XEvent ev) {}
60 };
61
62 volatile boolean isDisposed;
63
64 boolean isParentWindowLocated;
65 int old_x, old_y;
66 int ex_width, ex_height;
67
68 static final int TRAY_ICON_WIDTH = 24;
69 static final int TRAY_ICON_HEIGHT = 24;
70 int tray_icon_width = TRAY_ICON_WIDTH;
71 int tray_icon_height = TRAY_ICON_HEIGHT;
72
73 XTrayIconPeer(TrayIcon target)
74 throws AWTException
75 {
76 this.target = target;
77 AffineTransform tx = GraphicsEnvironment.getLocalGraphicsEnvironment().
78 getDefaultScreenDevice().getDefaultConfiguration().
79 getDefaultTransform();
80 tray_icon_width = Region.clipScale(TRAY_ICON_WIDTH, tx.getScaleX());
81 tray_icon_height = Region.clipScale(TRAY_ICON_HEIGHT, tx.getScaleY());
82
83 eventProxy = new TrayIconEventProxy(this);
84
85 canvas = new TrayIconCanvas(target, tray_icon_width, tray_icon_height);
86
87 eframe = new XTrayIconEmbeddedFrame();
88
89 eframe.setSize(tray_icon_width, tray_icon_height);
90 eframe.add(canvas);
91
92 // Fix for 6317038: as EmbeddedFrame is instance of Frame, it is blocked
93 // by modal dialogs, but in the case of TrayIcon it shouldn't. So we
94 // set ModalExclusion property on it.
95 AccessController.doPrivileged(new PrivilegedAction<Object>() {
96 public Object run() {
97 eframe.setModalExclusionType(Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
98 return null;
99 }
100 });
101
102
103 if (XWM.getWMID() != XWM.METACITY_WM) {
104 parentXED = dummyXED; // We don't like to leave it 'null'.
105 } else {
106 parentXED = new XEventDispatcher() {
107 // It's executed under AWTLock.
108 public void dispatchEvent(XEvent ev) {
109 if (isDisposed() || ev.get_type() != XConstants.ConfigureNotify) {
114
115 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
116 ctrLog.fine("ConfigureNotify on parent of {0}: {1}x{2}+{3}+{4} (old: {5}+{6})",
117 XTrayIconPeer.this, ce.get_width(), ce.get_height(),
118 ce.get_x(), ce.get_y(), old_x, old_y);
119 }
120
121 // A workaround for Gnome/Metacity (it doesn't affect the behaviour on KDE).
122 // On Metacity the EmbeddedFrame's parent window bounds are larger
123 // than TrayIcon size required (that is we need a square but a rectangle
124 // is provided by the Panel Notification Area). The parent's background color
125 // differs from the Panel's one. To hide the background we resize parent
126 // window so that it fits the EmbeddedFrame.
127 // However due to resizing the parent window it loses centering in the Panel.
128 // We center it when discovering that some of its side is of size greater
129 // than the fixed value. Centering is being done by "X" (when the parent's width
130 // is greater) and by "Y" (when the parent's height is greater).
131
132 // Actually we need this workaround until we could detect taskbar color.
133
134 if (ce.get_height() != tray_icon_height && ce.get_width() != tray_icon_width) {
135
136 // If both the height and the width differ from the fixed size then WM
137 // must level at least one side to the fixed size. For some reason it may take
138 // a few hops (even after reparenting) and we have to skip the intermediate ones.
139 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
140 ctrLog.fine("ConfigureNotify on parent of {0}. Skipping as intermediate resizing.",
141 XTrayIconPeer.this);
142 }
143 return;
144
145 } else if (ce.get_height() > tray_icon_height) {
146
147 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
148 ctrLog.fine("ConfigureNotify on parent of {0}. Centering by \"Y\".",
149 XTrayIconPeer.this);
150 }
151
152 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), eframeParentID,
153 ce.get_x(),
154 ce.get_y()+ce.get_height()/2-tray_icon_height/2,
155 tray_icon_width,
156 tray_icon_height);
157 ex_height = ce.get_height();
158 ex_width = 0;
159
160 } else if (ce.get_width() > tray_icon_width) {
161
162 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
163 ctrLog.fine("ConfigureNotify on parent of {0}. Centering by \"X\".",
164 XTrayIconPeer.this);
165 }
166
167 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), eframeParentID,
168 ce.get_x()+ce.get_width()/2 - tray_icon_width/2,
169 ce.get_y(),
170 tray_icon_width,
171 tray_icon_height);
172 ex_width = ce.get_width();
173 ex_height = 0;
174
175 } else if (isParentWindowLocated && ce.get_x() != old_x && ce.get_y() != old_y) {
176 // If moving by both "X" and "Y".
177 // When some tray icon gets removed from the tray, a Java icon may be repositioned.
178 // In this case the parent window also lose centering. We have to restore it.
179
180 if (ex_height != 0) {
181
182 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
183 ctrLog.fine("ConfigureNotify on parent of {0}. Move detected. Centering by \"Y\".",
184 XTrayIconPeer.this);
185 }
186
187 XlibWrapper.XMoveWindow(XToolkit.getDisplay(), eframeParentID,
188 ce.get_x(),
189 ce.get_y() + ex_height/2 - tray_icon_height/2);
190
191 } else if (ex_width != 0) {
192
193 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
194 ctrLog.fine("ConfigureNotify on parent of {0}. Move detected. Centering by \"X\".",
195 XTrayIconPeer.this);
196 }
197
198 XlibWrapper.XMoveWindow(XToolkit.getDisplay(), eframeParentID,
199 ce.get_x() + ex_width/2 - tray_icon_width/2,
200 ce.get_y());
201 } else {
202 if (ctrLog.isLoggable(PlatformLogger.Level.FINE)) {
203 ctrLog.fine("ConfigureNotify on parent of {0}. Move detected. Skipping.",
204 XTrayIconPeer.this);
205 }
206 }
207 }
208 old_x = ce.get_x();
209 old_y = ce.get_y();
210 isParentWindowLocated = true;
211 }
212 };
213 }
214 eframeXED = new XEventDispatcher() {
215 // It's executed under AWTLock.
216 XTrayIconPeer xtiPeer = XTrayIconPeer.this;
217
218 public void dispatchEvent(XEvent ev) {
219 if (isDisposed() || ev.get_type() != XConstants.ReparentNotify) {
220 return;
221 }
222
223 XReparentEvent re = ev.get_xreparent();
224 eframeParentID = re.get_parent();
225 if (eframeParentID == XToolkit.getDefaultRootWindow()) {
226
227 if (isTrayIconDisplayed) { // most likely Notification Area was removed
228 SunToolkit.executeOnEventHandlerThread(xtiPeer.target, new Runnable() {
229 public void run() {
230 SystemTray.getSystemTray().remove(xtiPeer.target);
231 }
232 });
233 }
234 return;
235 }
236
237 if (!isTrayIconDisplayed) {
238 addXED(eframeParentID, parentXED, XConstants.StructureNotifyMask);
239
240 isTrayIconDisplayed = true;
241 XToolkit.awtLockNotifyAll();
242 }
243 }
244 };
245
246 addXED(getWindow(), eframeXED, XConstants.StructureNotifyMask);
247
248 XSystemTrayPeer.getPeerInstance().addTrayIcon(this); // throws AWTException
249 // Wait till the EmbeddedFrame is reparented
250 long start = System.currentTimeMillis();
251 final long PERIOD = XToolkit.getTrayIconDisplayTimeout();
252 XToolkit.awtLock();
253 try {
254 while (!isTrayIconDisplayed) {
255 try {
256 XToolkit.awtLockWait(PERIOD);
257 } catch (InterruptedException e) {
258 break;
259 }
260 if (System.currentTimeMillis() - start > PERIOD) {
261 break;
262 }
263 }
264 } finally {
265 XToolkit.awtUnlock();
266 }
267
268 // This is unlikely to happen.
405
406 private void removeXED(long window, XEventDispatcher xed) {
407 if (window == 0) {
408 return;
409 }
410 XToolkit.awtLock();
411 try {
412 XToolkit.removeEventDispatcher(window, xed);
413 } finally {
414 XToolkit.awtUnlock();
415 }
416 }
417
418 // Private method for testing purposes.
419 private Point getLocationOnScreen() {
420 return eframe.getLocationOnScreen();
421 }
422
423 public Rectangle getBounds() {
424 Point loc = getLocationOnScreen();
425 return new Rectangle(loc.x, loc.y, loc.x + tray_icon_width, loc.y + tray_icon_height);
426 }
427
428 void addListeners() {
429 canvas.addMouseListener(eventProxy);
430 canvas.addMouseMotionListener(eventProxy);
431 eframe.addMouseListener(eventProxy);
432 }
433
434 void removeListeners() {
435 canvas.removeMouseListener(eventProxy);
436 canvas.removeMouseMotionListener(eventProxy);
437 eframe.removeMouseListener(eventProxy);
438 }
439
440 long getWindow() {
441 return AWTAccessor.getComponentAccessor()
442 .<XEmbeddedFramePeer>getPeer(eframe).getWindow();
443 }
444
445 public boolean isDisposed() {
539 return false;
540 }
541
542 // embedded frame for tray icon shouldn't be disposed by anyone except tray icon
543 public void dispose(){
544 }
545
546 public void realDispose(){
547 super.dispose();
548 }
549 };
550
551 // ***************************************
552 // Classes for painting an image on canvas
553 // ***************************************
554
555 @SuppressWarnings("serial") // JDK-implementation class
556 static class TrayIconCanvas extends IconCanvas {
557 TrayIcon target;
558 boolean autosize;
559 final int width, height;
560
561 TrayIconCanvas(TrayIcon target, int width, int height) {
562 super(width, height);
563 this.target = target;
564 this.width = width;
565 this.height = height;
566 }
567
568 // Invoke on EDT.
569 protected void repaintImage(boolean doClear) {
570 boolean old_autosize = autosize;
571 int old_curW = curW, old_curH = curH;
572 autosize = target.isImageAutoSize();
573 AffineTransform tx = GraphicsEnvironment.getLocalGraphicsEnvironment().
574 getDefaultScreenDevice().getDefaultConfiguration().
575 getDefaultTransform();
576 int imgWidth = Region.clipScale(image.getWidth(observer), tx.getScaleX());
577 int imgHeight = Region.clipScale(image.getHeight(observer), tx.getScaleY());
578
579 curW = autosize ? width : imgWidth;
580 curH = autosize ? height : imgHeight;
581
582 // update the size before repainting
583 super.updateSize(curW, curH);
584 super.repaintImage(doClear || (old_autosize != autosize) ||
585 (old_curW != curW || old_curH != curH));
586 }
587
588 public void dispose() {
589 super.dispose();
590 target = null;
591 }
592 }
593
594 @SuppressWarnings("serial") // JDK-implementation class
595 public static class IconCanvas extends Canvas {
596 volatile Image image;
597 IconObserver observer;
598 int curW, curH;
599
600 IconCanvas(int width, int height) {
601 curW = width;
602 curH = height;
603 }
604
605 public void updateSize(int width, int height) {
606 curW = width;
607 curH = height;
608 }
609
610 // Invoke on EDT.
611 public void updateImage(Image image) {
612 this.image = image;
613 if (observer == null) {
614 observer = new IconObserver();
615 }
616 repaintImage(true);
617 }
618
619 public void dispose() {
620 observer = null;
621 }
622
623 // Invoke on EDT.
624 protected void repaintImage(boolean doClear) {
625 Graphics g = getGraphics();
626 if (g != null) {
627 try {
|