alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (CTrayIcon.java)

This example Java source code file (CTrayIcon.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

assertionerror, awt, bean, bufferedimage, ctrayicon, dialogeventhandler, exception, geometry, gui, icon, javabean, jdialog, joptionpane, jtextarea, mouseevent, object, override, runnable, string, swing

The CTrayIcon.java Java example source code

/*
 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.lwawt.macosx;

import sun.awt.AWTAccessor;
import sun.awt.SunToolkit;
import sun.lwawt.macosx.event.NSEvent;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.peer.TrayIconPeer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

public class CTrayIcon extends CFRetainedResource implements TrayIconPeer {
    private TrayIcon target;
    private PopupMenu popup;
    private JDialog messageDialog;
    private DialogEventHandler handler;

    // In order to construct MouseEvent object, we need to specify a
    // Component target. Because TrayIcon isn't Component's subclass,
    // we use this dummy frame instead
    private final Frame dummyFrame;

    // A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events
    // on MOUSE_RELEASE. Click events are only generated if there were no drag
    // events between MOUSE_PRESSED and MOUSE_RELEASED for particular button
    private static int mouseClickButtons = 0;

    CTrayIcon(TrayIcon target) {
        super(0, true);

        this.messageDialog = null;
        this.handler = null;
        this.target = target;
        this.popup = target.getPopupMenu();
        this.dummyFrame = new Frame();
        setPtr(createModel());

        //if no one else is creating the peer.
        checkAndCreatePopupPeer();
        updateImage();
    }

    private CPopupMenu checkAndCreatePopupPeer() {
        CPopupMenu menuPeer = null;
        if (popup != null) {
            try {
                menuPeer = (CPopupMenu)popup.getPeer();
                if (menuPeer == null) {
                    popup.addNotify();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return menuPeer;
    }

    private long createModel() {
        return nativeCreate();
    }

    private long getModel() {
        return ptr;
    }

    private native long nativeCreate();

    //invocation from the AWTTrayIcon.m
    public long getPopupMenuModel(){
        if(popup == null) {
            return 0L;
        }
        return checkAndCreatePopupPeer().getModel();
    }

    /**
     * We display tray icon message as a small dialog with OK button.
     * This is lame, but JDK 1.6 does basically the same. There is a new
     * kind of window in Lion, NSPopover, so perhaps it could be used it
     * to implement better looking notifications.
     */
    public void displayMessage(final String caption, final String text,
                               final String messageType) {

        if (SwingUtilities.isEventDispatchThread()) {
            displayMessageOnEDT(caption, text, messageType);
        } else {
            try {
                SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        displayMessageOnEDT(caption, text, messageType);
                    }
                });
            } catch (Exception e) {
                throw new AssertionError(e);
            }
        }
    }

    @Override
    public void dispose() {
        if (messageDialog != null) {
            disposeMessageDialog();
        }

        dummyFrame.dispose();

        LWCToolkit.targetDisposedPeer(target, this);
        target = null;

        super.dispose();
    }

    @Override
    public void setToolTip(String tooltip) {
        nativeSetToolTip(getModel(), tooltip);
    }

    //adds tooltip to the NSStatusBar's NSButton.
    private native void nativeSetToolTip(long trayIconModel, String tooltip);

    @Override
    public void showPopupMenu(int x, int y) {
        //Not used. The popupmenu is shown from the native code.
    }

    @Override
    public void updateImage() {
        Image image = target.getImage();
        if (image == null) return;

        MediaTracker tracker = new MediaTracker(new Button(""));
        tracker.addImage(image, 0);
        try {
            tracker.waitForAll();
        } catch (InterruptedException ignore) { }

        if (image.getWidth(null) <= 0 ||
            image.getHeight(null) <= 0)
        {
            return;
        }

        CImage cimage = CImage.getCreator().createFromImage(image);
        setNativeImage(getModel(), cimage.ptr, target.isImageAutoSize());
    }

    private native void setNativeImage(final long model, final long nsimage, final boolean autosize);

    private void postEvent(final AWTEvent event) {
        SunToolkit.executeOnEventHandlerThread(target, new Runnable() {
            public void run() {
                SunToolkit.postEvent(SunToolkit.targetToAppContext(target), event);
            }
        });
    }

    //invocation from the AWTTrayIcon.m
    private void handleMouseEvent(NSEvent nsEvent) {
        int buttonNumber = nsEvent.getButtonNumber();
        final SunToolkit tk = (SunToolkit)Toolkit.getDefaultToolkit();
        if ((buttonNumber > 2 && !tk.areExtraMouseButtonsEnabled())
                || buttonNumber > tk.getNumberOfButtons() - 1) {
            return;
        }

        int jeventType = NSEvent.nsToJavaEventType(nsEvent.getType());

        int jbuttonNumber = MouseEvent.NOBUTTON;
        int jclickCount = 0;
        if (jeventType != MouseEvent.MOUSE_MOVED) {
            jbuttonNumber = NSEvent.nsToJavaButton(buttonNumber);
            jclickCount = nsEvent.getClickCount();
        }

        int jmodifiers = NSEvent.nsToJavaMouseModifiers(buttonNumber,
                nsEvent.getModifierFlags());
        boolean isPopupTrigger = NSEvent.isPopupTrigger(jmodifiers);

        int eventButtonMask = (jbuttonNumber > 0)?
                MouseEvent.getMaskForButton(jbuttonNumber) : 0;
        long when = System.currentTimeMillis();

        if (jeventType == MouseEvent.MOUSE_PRESSED) {
            mouseClickButtons |= eventButtonMask;
        } else if (jeventType == MouseEvent.MOUSE_DRAGGED) {
            mouseClickButtons = 0;
        }

        // The MouseEvent's coordinates are relative to screen
        int absX = nsEvent.getAbsX();
        int absY = nsEvent.getAbsY();

        MouseEvent mouseEvent = new MouseEvent(dummyFrame, jeventType, when,
                jmodifiers, absX, absY, absX, absY, jclickCount, isPopupTrigger,
                jbuttonNumber);
        mouseEvent.setSource(target);
        postEvent(mouseEvent);

        // fire ACTION event
        if (jeventType == MouseEvent.MOUSE_PRESSED && isPopupTrigger) {
            final String cmd = target.getActionCommand();
            final ActionEvent event = new ActionEvent(target,
                    ActionEvent.ACTION_PERFORMED, cmd);
            postEvent(event);
        }

        // synthesize CLICKED event
        if (jeventType == MouseEvent.MOUSE_RELEASED) {
            if ((mouseClickButtons & eventButtonMask) != 0) {
                MouseEvent clickEvent = new MouseEvent(dummyFrame,
                        MouseEvent.MOUSE_CLICKED, when, jmodifiers, absX, absY,
                        absX, absY, jclickCount, isPopupTrigger, jbuttonNumber);
                clickEvent.setSource(target);
                postEvent(clickEvent);
            }

            mouseClickButtons &= ~eventButtonMask;
        }
    }

    private native Point2D nativeGetIconLocation(long trayIconModel);

    public void displayMessageOnEDT(String caption, String text,
                                    String messageType) {
        if (messageDialog != null) {
            disposeMessageDialog();
        }

        // obtain icon to show along the message
        Icon icon = getIconForMessageType(messageType);
        if (icon != null) {
            icon = new ImageIcon(scaleIcon(icon, 0.75));
        }

        // We want the message dialog text area to be about 1/8 of the screen
        // size. There is nothing special about this value, it's just makes the
        // message dialog to look nice
        Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        int textWidth = screenSize.width / 8;

        // create dialog to show
        messageDialog = createMessageDialog(caption, text, textWidth, icon);

        // finally, show the dialog to user
        showMessageDialog();
    }

    /**
     * Creates dialog window used to display the message
     */
    private JDialog createMessageDialog(String caption, String text,
                                     int textWidth, Icon icon) {
        JDialog dialog;
        handler = new DialogEventHandler();

        JTextArea captionArea = null;
        if (caption != null) {
            captionArea = createTextArea(caption, textWidth, false, true);
        }

        JTextArea textArea = null;
        if (text != null){
            textArea = createTextArea(text, textWidth, true, false);
        }

        Object[] panels = null;
        if (captionArea != null) {
            if (textArea != null) {
                panels = new Object[] {captionArea, new JLabel(), textArea};
            } else {
                panels = new Object[] {captionArea};
            }
        } else {
           if (textArea != null) {
                panels = new Object[] {textArea};
            }
        }

        // We want message dialog with small title bar. There is a client
        // property property that does it, however, it must be set before
        // dialog's native window is created. This is why we create option
        // pane and dialog separately
        final JOptionPane op = new JOptionPane(panels);
        op.setIcon(icon);
        op.addPropertyChangeListener(handler);

        // Make Ok button small. Most likely won't work for L&F other then Aqua
        try {
            JPanel buttonPanel = (JPanel)op.getComponent(1);
            JButton ok = (JButton)buttonPanel.getComponent(0);
            ok.putClientProperty("JComponent.sizeVariant", "small");
        } catch (Throwable t) {
            // do nothing, we tried and failed, no big deal
        }

        dialog = new JDialog((Dialog) null);
        JRootPane rp = dialog.getRootPane();

        // gives us dialog window with small title bar and not zoomable
        rp.putClientProperty(CPlatformWindow.WINDOW_STYLE, "small");
        rp.putClientProperty(CPlatformWindow.WINDOW_ZOOMABLE, "false");

        dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
        dialog.setModal(false);
        dialog.setModalExclusionType(Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
        dialog.setAlwaysOnTop(true);
        dialog.setAutoRequestFocus(false);
        dialog.setResizable(false);
        dialog.setContentPane(op);

        dialog.addWindowListener(handler);

        // suppress security warning for untrusted windows
        AWTAccessor.getWindowAccessor().setTrayIconWindow(dialog, true);

        dialog.pack();

        return dialog;
    }

    private void showMessageDialog() {

        Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        Point2D iconLoc = nativeGetIconLocation(getModel());

        int dialogY = (int)iconLoc.getY();
        int dialogX = (int)iconLoc.getX();
        if (dialogX + messageDialog.getWidth() > screenSize.width) {
            dialogX = screenSize.width - messageDialog.getWidth();
        }

        messageDialog.setLocation(dialogX, dialogY);
        messageDialog.setVisible(true);
    }

   private void disposeMessageDialog() {
        if (SwingUtilities.isEventDispatchThread()) {
            disposeMessageDialogOnEDT();
        } else {
            try {
                SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        disposeMessageDialogOnEDT();
                    }
                });
            } catch (Exception e) {
                throw new AssertionError(e);
            }
        }
   }

    private void disposeMessageDialogOnEDT() {
        if (messageDialog != null) {
            messageDialog.removeWindowListener(handler);
            messageDialog.removePropertyChangeListener(handler);
            messageDialog.dispose();

            messageDialog = null;
            handler = null;
        }
    }

    /**
     * Scales an icon using specified scale factor
     *
     * @param icon        icon to scale
     * @param scaleFactor scale factor to use
     * @return scaled icon as BuffedredImage
     */
    private static BufferedImage scaleIcon(Icon icon, double scaleFactor) {
        if (icon == null) {
            return null;
        }

        int w = icon.getIconWidth();
        int h = icon.getIconHeight();

        GraphicsEnvironment ge =
                GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        GraphicsConfiguration gc = gd.getDefaultConfiguration();

        // convert icon into image
        BufferedImage iconImage = gc.createCompatibleImage(w, h,
                Transparency.TRANSLUCENT);
        Graphics2D g = iconImage.createGraphics();
        icon.paintIcon(null, g, 0, 0);
        g.dispose();

        // and scale it nicely
        int scaledW = (int) (w * scaleFactor);
        int scaledH = (int) (h * scaleFactor);
        BufferedImage scaledImage = gc.createCompatibleImage(scaledW, scaledH,
                Transparency.TRANSLUCENT);
        g = scaledImage.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(iconImage, 0, 0, scaledW, scaledH, null);
        g.dispose();

        return scaledImage;
    }


    /**
     * Gets Aqua icon used in message dialog.
     */
    private static Icon getIconForMessageType(String messageType) {
        if (messageType.equals("ERROR")) {
            return UIManager.getIcon("OptionPane.errorIcon");
        } else if (messageType.equals("WARNING")) {
            return UIManager.getIcon("OptionPane.warningIcon");
        } else {
            // this is just an application icon
            return UIManager.getIcon("OptionPane.informationIcon");
        }
    }

    private static JTextArea createTextArea(String text, int width,
                                            boolean isSmall, boolean isBold) {
        JTextArea textArea = new JTextArea(text);

        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        textArea.setEditable(false);
        textArea.setFocusable(false);
        textArea.setBorder(null);
        textArea.setBackground(new JLabel().getBackground());

        if (isSmall) {
            textArea.putClientProperty("JComponent.sizeVariant", "small");
        }

        if (isBold) {
            Font font = textArea.getFont();
            Font boldFont = new Font(font.getName(), Font.BOLD, font.getSize());
            textArea.setFont(boldFont);
        }

        textArea.setSize(width, 1);

        return textArea;
    }

    /**
     * Implements all the Listeners needed by message dialog
     */
    private final class DialogEventHandler extends WindowAdapter
            implements PropertyChangeListener {

        public void windowClosing(WindowEvent we) {
                disposeMessageDialog();
        }

        public void propertyChange(PropertyChangeEvent e) {
            if (messageDialog == null) {
                return;
            }

            String prop = e.getPropertyName();
            Container cp = messageDialog.getContentPane();

            if (messageDialog.isVisible() && e.getSource() == cp &&
                    (prop.equals(JOptionPane.VALUE_PROPERTY))) {
                disposeMessageDialog();
            }
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java CTrayIcon.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.