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 */
25package sun.awt.X11;
26
27import java.awt.MenuItem;
28import java.awt.PopupMenu;
29import java.awt.Taskbar.Feature;
30import java.awt.peer.TaskbarPeer;
31import java.awt.event.ActionEvent;
32
33import sun.awt.UNIXToolkit;
34import java.security.AccessController;
35import java.security.PrivilegedAction;
36import sun.security.action.GetPropertyAction;
37
38final 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
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
75    XTaskbarPeer() {
76        initWithLock();
77    }
78
79    static boolean isTaskbarSupported() {
80        if (!isUnity) {
81            return false;
82        }
83        initWithLock();
84        return nativeLibraryLoaded;
85    }
86
87    @Override
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
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
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
130    public PopupMenu getMenu() {
131        return menu;
132    }
133
134    @Override
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
151    public void requestUserAttention(boolean enabled, boolean critical) {
152        setUrgent(enabled);
153    }
154
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
168    private static native boolean init(String name, int version,
169                                                               boolean verbose);
170
171    private static native void runloop();
172
173    private native void setBadge(long value, boolean visible);
174
175    private native void updateProgress(double value, boolean visible);
176
177    private native void setUrgent(boolean urgent);
178
179    private native void setNativeMenu(MenuItem[] items);
180}
181