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