Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/awt/X11/InfoWindow.java
32288 views
/*1* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.awt.X11;2627import java.awt.*;28import java.awt.event.*;29import java.awt.peer.TrayIconPeer;30import sun.awt.*;31import java.awt.image.*;32import java.text.BreakIterator;33import java.util.concurrent.ArrayBlockingQueue;34import java.security.AccessController;35import java.security.PrivilegedAction;36import java.lang.reflect.InvocationTargetException;3738/**39* An utility window class. This is a base class for Tooltip and Balloon.40*/41public abstract class InfoWindow extends Window {42private Container container;43private Closer closer;4445protected InfoWindow(Frame parent, Color borderColor) {46super(parent);47setType(Window.Type.POPUP);48container = new Container() {49@Override50public Insets getInsets() {51return new Insets(1, 1, 1, 1);52}53};54setLayout(new BorderLayout());55setBackground(borderColor);56add(container, BorderLayout.CENTER);57container.setLayout(new BorderLayout());5859closer = new Closer();60}6162public Component add(Component c) {63container.add(c, BorderLayout.CENTER);64return c;65}6667protected void setCloser(Runnable action, int time) {68closer.set(action, time);69}7071// Must be executed on EDT.72protected void show(Point corner, int indent) {73assert SunToolkit.isDispatchThreadForAppContext(this);7475pack();7677Dimension size = getSize();78// TODO: When 6356322 is fixed we should get screen bounds in79// this way: eframe.getGraphicsConfiguration().getBounds().80Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize();8182if (corner.x < scrSize.width/2 && corner.y < scrSize.height/2) { // 1st square83setLocation(corner.x + indent, corner.y + indent);8485} else if (corner.x >= scrSize.width/2 && corner.y < scrSize.height/2) { // 2nd square86setLocation(corner.x - indent - size.width, corner.y + indent);8788} else if (corner.x < scrSize.width/2 && corner.y >= scrSize.height/2) { // 3rd square89setLocation(corner.x + indent, corner.y - indent - size.height);9091} else if (corner.x >= scrSize.width/2 && corner.y >= scrSize.height/2) { // 4th square92setLocation(corner.x - indent - size.width, corner.y - indent - size.height);93}9495super.show();96closer.schedule();97}9899public void hide() {100closer.close();101}102103private class Closer implements Runnable {104Runnable action;105int time;106107public void run() {108doClose();109}110111void set(Runnable action, int time) {112this.action = action;113this.time = time;114}115116void schedule() {117XToolkit.schedule(this, time);118}119120void close() {121XToolkit.remove(this);122doClose();123}124125// WARNING: this method may be executed on Toolkit thread.126private void doClose() {127SunToolkit.executeOnEventHandlerThread(InfoWindow.this, new Runnable() {128public void run() {129InfoWindow.super.hide();130invalidate();131if (action != null) {132action.run();133}134}135});136}137}138139140private interface LiveArguments {141/** Whether the target of the InfoWindow is disposed. */142boolean isDisposed();143144/** The bounds of the target of the InfoWindow. */145Rectangle getBounds();146}147148public static class Tooltip extends InfoWindow {149150public interface LiveArguments extends InfoWindow.LiveArguments {151/** The tooltip to be displayed. */152String getTooltipString();153}154155private final Object target;156private final LiveArguments liveArguments;157158private final Label textLabel = new Label("");159private final Runnable starter = new Runnable() {160public void run() {161display();162}};163164private final static int TOOLTIP_SHOW_TIME = 10000;165private final static int TOOLTIP_START_DELAY_TIME = 1000;166private final static int TOOLTIP_MAX_LENGTH = 64;167private final static int TOOLTIP_MOUSE_CURSOR_INDENT = 5;168private final static Color TOOLTIP_BACKGROUND_COLOR = new Color(255, 255, 220);169private final static Font TOOLTIP_TEXT_FONT = XWindow.getDefaultFont();170171public Tooltip(Frame parent, Object target,172LiveArguments liveArguments)173{174super(parent, Color.black);175176this.target = target;177this.liveArguments = liveArguments;178179XTrayIconPeer.suppressWarningString(this);180181setCloser(null, TOOLTIP_SHOW_TIME);182textLabel.setBackground(TOOLTIP_BACKGROUND_COLOR);183textLabel.setFont(TOOLTIP_TEXT_FONT);184add(textLabel);185}186187/*188* WARNING: this method is executed on Toolkit thread!189*/190private void display() {191// Execute on EDT to avoid deadlock (see 6280857).192SunToolkit.executeOnEventHandlerThread(target, new Runnable() {193public void run() {194if (liveArguments.isDisposed()) {195return;196}197198String tooltipString = liveArguments.getTooltipString();199if (tooltipString == null) {200return;201} else if (tooltipString.length() > TOOLTIP_MAX_LENGTH) {202textLabel.setText(tooltipString.substring(0, TOOLTIP_MAX_LENGTH));203} else {204textLabel.setText(tooltipString);205}206207Point pointer = (Point)AccessController.doPrivileged(new PrivilegedAction() {208public Object run() {209if (!isPointerOverTrayIcon(liveArguments.getBounds())) {210return null;211}212return MouseInfo.getPointerInfo().getLocation();213}214});215if (pointer == null) {216return;217}218show(new Point(pointer.x, pointer.y), TOOLTIP_MOUSE_CURSOR_INDENT);219}220});221}222223public void enter() {224XToolkit.schedule(starter, TOOLTIP_START_DELAY_TIME);225}226227public void exit() {228XToolkit.remove(starter);229if (isVisible()) {230hide();231}232}233234private boolean isPointerOverTrayIcon(Rectangle trayRect) {235Point p = MouseInfo.getPointerInfo().getLocation();236return !(p.x < trayRect.x || p.x > (trayRect.x + trayRect.width) ||237p.y < trayRect.y || p.y > (trayRect.y + trayRect.height));238}239}240241public static class Balloon extends InfoWindow {242243public interface LiveArguments extends InfoWindow.LiveArguments {244/** The action to be performed upon clicking the baloon. */245String getActionCommand();246}247248private final LiveArguments liveArguments;249private final Object target;250251private final static int BALLOON_SHOW_TIME = 10000;252private final static int BALLOON_TEXT_MAX_LENGTH = 256;253private final static int BALLOON_WORD_LINE_MAX_LENGTH = 16;254private final static int BALLOON_WORD_LINE_MAX_COUNT = 4;255private final static int BALLOON_ICON_WIDTH = 32;256private final static int BALLOON_ICON_HEIGHT = 32;257private final static int BALLOON_TRAY_ICON_INDENT = 0;258private final static Color BALLOON_CAPTION_BACKGROUND_COLOR = new Color(200, 200 ,255);259private final static Font BALLOON_CAPTION_FONT = new Font(Font.DIALOG, Font.BOLD, 12);260261private Panel mainPanel = new Panel();262private Panel captionPanel = new Panel();263private Label captionLabel = new Label("");264private Button closeButton = new Button("X");265private Panel textPanel = new Panel();266private XTrayIconPeer.IconCanvas iconCanvas = new XTrayIconPeer.IconCanvas(BALLOON_ICON_WIDTH, BALLOON_ICON_HEIGHT);267private Label[] lineLabels = new Label[BALLOON_WORD_LINE_MAX_COUNT];268private ActionPerformer ap = new ActionPerformer();269270private Image iconImage;271private Image errorImage;272private Image warnImage;273private Image infoImage;274private boolean gtkImagesLoaded;275276private Displayer displayer = new Displayer();277278public Balloon(Frame parent, Object target, LiveArguments liveArguments) {279super(parent, new Color(90, 80 ,190));280this.liveArguments = liveArguments;281this.target = target;282283XTrayIconPeer.suppressWarningString(this);284285setCloser(new Runnable() {286public void run() {287if (textPanel != null) {288textPanel.removeAll();289textPanel.setSize(0, 0);290iconCanvas.setSize(0, 0);291XToolkit.awtLock();292try {293displayer.isDisplayed = false;294XToolkit.awtLockNotifyAll();295} finally {296XToolkit.awtUnlock();297}298}299}300}, BALLOON_SHOW_TIME);301302add(mainPanel);303304captionLabel.setFont(BALLOON_CAPTION_FONT);305captionLabel.addMouseListener(ap);306307captionPanel.setLayout(new BorderLayout());308captionPanel.add(captionLabel, BorderLayout.WEST);309captionPanel.add(closeButton, BorderLayout.EAST);310captionPanel.setBackground(BALLOON_CAPTION_BACKGROUND_COLOR);311captionPanel.addMouseListener(ap);312313closeButton.addActionListener(new ActionListener() {314public void actionPerformed(ActionEvent e) {315hide();316}317});318319mainPanel.setLayout(new BorderLayout());320mainPanel.setBackground(Color.white);321mainPanel.add(captionPanel, BorderLayout.NORTH);322mainPanel.add(iconCanvas, BorderLayout.WEST);323mainPanel.add(textPanel, BorderLayout.CENTER);324325iconCanvas.addMouseListener(ap);326327for (int i = 0; i < BALLOON_WORD_LINE_MAX_COUNT; i++) {328lineLabels[i] = new Label();329lineLabels[i].addMouseListener(ap);330lineLabels[i].setBackground(Color.white);331}332333displayer.start();334}335336public void display(String caption, String text, String messageType) {337if (!gtkImagesLoaded) {338loadGtkImages();339}340displayer.display(caption, text, messageType);341}342343private void _display(String caption, String text, String messageType) {344captionLabel.setText(caption);345346BreakIterator iter = BreakIterator.getWordInstance();347if (text != null) {348iter.setText(text);349int start = iter.first(), end;350int nLines = 0;351352do {353end = iter.next();354355if (end == BreakIterator.DONE ||356text.substring(start, end).length() >= 50)357{358lineLabels[nLines].setText(text.substring(start, end == BreakIterator.DONE ?359iter.last() : end));360textPanel.add(lineLabels[nLines++]);361start = end;362}363if (nLines == BALLOON_WORD_LINE_MAX_COUNT) {364if (end != BreakIterator.DONE) {365lineLabels[nLines - 1].setText(366new String(lineLabels[nLines - 1].getText() + " ..."));367}368break;369}370} while (end != BreakIterator.DONE);371372373textPanel.setLayout(new GridLayout(nLines, 1));374}375376if ("ERROR".equals(messageType)) {377iconImage = errorImage;378} else if ("WARNING".equals(messageType)) {379iconImage = warnImage;380} else if ("INFO".equals(messageType)) {381iconImage = infoImage;382} else {383iconImage = null;384}385386if (iconImage != null) {387Dimension tpSize = textPanel.getSize();388iconCanvas.setSize(BALLOON_ICON_WIDTH, (BALLOON_ICON_HEIGHT > tpSize.height ?389BALLOON_ICON_HEIGHT : tpSize.height));390iconCanvas.validate();391}392393SunToolkit.executeOnEventHandlerThread(target, new Runnable() {394public void run() {395if (liveArguments.isDisposed()) {396return;397}398Point parLoc = getParent().getLocationOnScreen();399Dimension parSize = getParent().getSize();400show(new Point(parLoc.x + parSize.width/2, parLoc.y + parSize.height/2),401BALLOON_TRAY_ICON_INDENT);402if (iconImage != null) {403iconCanvas.updateImage(iconImage); // call it after the show(..) above404}405}406});407}408409public void dispose() {410displayer.interrupt();411super.dispose();412}413414private void loadGtkImages() {415if (!gtkImagesLoaded) {416//check whether the gtk version is >= 3.10 as the Icon names were417//changed from this release418UNIXToolkit tk = (UNIXToolkit) Toolkit.getDefaultToolkit();419if (tk.checkGtkVersion(3, 10, 0)) {420errorImage = (Image) tk.getDesktopProperty(421"gtk.icon.dialog-error.6.rtl");422warnImage = (Image) tk.getDesktopProperty(423"gtk.icon.dialog-warning.6.rtl");424infoImage = (Image) tk.getDesktopProperty(425"gtk.icon.dialog-information.6.rtl");426} else {427errorImage = (Image) tk.getDesktopProperty(428"gtk.icon.gtk-dialog-error.6.rtl");429warnImage = (Image) tk.getDesktopProperty(430"gtk.icon.gtk-dialog-warning.6.rtl");431infoImage = (Image) tk.getDesktopProperty(432"gtk.icon.gtk-dialog-info.6.rtl");433}434gtkImagesLoaded = true;435}436}437438private class ActionPerformer extends MouseAdapter {439public void mouseClicked(MouseEvent e) {440// hide the balloon by any click441hide();442if (e.getButton() == MouseEvent.BUTTON1) {443ActionEvent aev = new ActionEvent(target, ActionEvent.ACTION_PERFORMED,444liveArguments.getActionCommand(),445e.getWhen(), e.getModifiers());446XToolkit.postEvent(XToolkit.targetToAppContext(aev.getSource()), aev);447}448}449}450451private class Displayer extends Thread {452final int MAX_CONCURRENT_MSGS = 10;453454ArrayBlockingQueue<Message> messageQueue = new ArrayBlockingQueue<Message>(MAX_CONCURRENT_MSGS);455boolean isDisplayed;456457Displayer() {458setDaemon(true);459}460461public void run() {462while (true) {463Message msg = null;464try {465msg = (Message)messageQueue.take();466} catch (InterruptedException e) {467return;468}469470/*471* Wait till the previous message is displayed if any472*/473XToolkit.awtLock();474try {475while (isDisplayed) {476try {477XToolkit.awtLockWait();478} catch (InterruptedException e) {479return;480}481}482isDisplayed = true;483} finally {484XToolkit.awtUnlock();485}486_display(msg.caption, msg.text, msg.messageType);487}488}489490void display(String caption, String text, String messageType) {491messageQueue.offer(new Message(caption, text, messageType));492}493}494495private static class Message {496String caption, text, messageType;497498Message(String caption, String text, String messageType) {499this.caption = caption;500this.text = text;501this.messageType = messageType;502}503}504}505}506507508