1 /*
   2  * Copyright (c) 2016, 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.X11;
  26 
  27 import java.awt.MenuItem;
  28 import java.awt.PopupMenu;
  29 import java.awt.Taskbar.Feature;
  30 import java.awt.peer.TaskbarPeer;
  31 import java.awt.event.ActionEvent;
  32 
  33 import sun.awt.UNIXToolkit;
  34 import java.security.AccessController;
  35 import sun.security.action.GetPropertyAction;
  36 
  37 final class XTaskbarPeer implements TaskbarPeer {
  38 
  39     private static boolean nativeLibraryLoaded = false;
  40     private static boolean initExecuted = false;
  41 
  42     private PopupMenu menu = null;
  43 
  44     private static void initWithLock() {
  45         XToolkit.awtLock();
  46         try {
  47             if (!initExecuted) {
  48                 String dname = AccessController.doPrivileged(
  49                                 new GetPropertyAction("java.desktop.appName", ""));
  50                 nativeLibraryLoaded = init(dname,
  51                         UNIXToolkit.getEnabledGtkVersion().ordinal(),
  52                         UNIXToolkit.isGtkVerbose());
  53                 if (nativeLibraryLoaded) {
  54                     Thread t = new Thread(null, () -> { runloop(); },
  55                                           "TaskBar", 0, false);
  56                     t.setDaemon(true);
  57                     t.start();
  58                 }
  59             }
  60         } finally {
  61             initExecuted = true;
  62             XToolkit.awtUnlock();
  63         }
  64     }
  65 
  66     XTaskbarPeer() {
  67         initWithLock();
  68     }
  69 
  70     static boolean isTaskbarSupported() {
  71         initWithLock();
  72         return nativeLibraryLoaded;
  73     }
  74 
  75     @Override
  76     public boolean isSupported(Feature feature) {
  77         switch (feature) {
  78             case ICON_BADGE_NUMBER:
  79             case MENU:
  80             case PROGRESS_VALUE:
  81             case USER_ATTENTION:
  82                 return true;
  83             default:
  84                 return false;
  85         }
  86     }
  87 
  88     @Override
  89     public void setProgressValue(int value) {
  90         boolean visible
  91                 = value >= 0
  92                 && value <= 100;
  93 
  94         double v = visible
  95                 ? (double) value / 100
  96                 : 0d;
  97 
  98         updateProgress(v, visible);
  99     }
 100 
 101     @Override
 102     public void setIconBadge(String badge) {
 103         boolean visible = false;
 104         long val = 0;
 105         if (badge != null) {
 106             try {
 107                 val = Long.parseLong(badge);
 108                 visible = true;
 109             } catch (NumberFormatException e) {
 110                 throw new UnsupportedOperationException("The " + Feature.ICON_BADGE_TEXT
 111                     + " feature is not supported on the current platform!");
 112             }
 113         }
 114         setBadge(val, visible);
 115     }
 116 
 117     @Override
 118     public PopupMenu getMenu() {
 119         return menu;
 120     }
 121 
 122     @Override
 123     public synchronized void setMenu(PopupMenu m) {
 124         this.menu = m;
 125 
 126         if (menu != null && menu.getItemCount() > 0) {
 127             int msize = menu.getItemCount();
 128             MenuItem[] items = new MenuItem[msize];
 129             for (int i = 0; i < msize; i++) {
 130                 items[i] = menu.getItem(i);
 131             }
 132             setNativeMenu(items);
 133         } else {
 134             setNativeMenu(null);
 135         }
 136     }
 137 
 138     @Override
 139     public void requestUserAttention(boolean enabled, boolean critical) {
 140         setUrgent(enabled);
 141     }
 142 
 143     private static void menuItemCallback(MenuItem mi) {
 144         if (mi != null) {
 145             ActionEvent ae = new ActionEvent(mi, ActionEvent.ACTION_PERFORMED,
 146                     mi.getActionCommand());
 147             try {
 148                 XToolkit.awtLock();
 149                 XToolkit.postEvent(XToolkit.targetToAppContext(ae.getSource()), ae);
 150             } finally {
 151                 XToolkit.awtUnlock();
 152             }
 153         }
 154     }
 155 
 156     private static native boolean init(String name, int version,
 157                                                                boolean verbose);
 158 
 159     private static native void runloop();
 160 
 161     private native void setBadge(long value, boolean visible);
 162 
 163     private native void updateProgress(double value, boolean visible);
 164 
 165     private native void setUrgent(boolean urgent);
 166 
 167     private native void setNativeMenu(MenuItem[] items);
 168 }