1/*
2 * Copyright (c) 2003, 2014, 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
26package sun.awt.X11;
27
28import jdk.internal.misc.Unsafe;
29
30import sun.util.logging.PlatformLogger;
31
32import java.awt.AWTKeyStroke;
33import java.awt.event.InputEvent;
34
35/**
36 * Common class for all XEmbed protocol participating classes.
37 * Contains constant definitions and helper routines.
38 */
39public class XEmbedHelper {
40    private static final PlatformLogger xembedLog = PlatformLogger.getLogger("sun.awt.X11.xembed");
41    static final Unsafe unsafe = Unsafe.getUnsafe();
42
43    static final int XEMBED_VERSION = 0,
44        XEMBED_MAPPED = (1 << 0);
45/* XEMBED messages */
46    static final int XEMBED_EMBEDDED_NOTIFY     =       0;
47    static final int XEMBED_WINDOW_ACTIVATE  =  1;
48    static final int XEMBED_WINDOW_DEACTIVATE =         2;
49    static final int XEMBED_REQUEST_FOCUS               =3;
50    static final int XEMBED_FOCUS_IN    =       4;
51    static final int XEMBED_FOCUS_OUT   =       5;
52    static final int XEMBED_FOCUS_NEXT  =       6;
53    static final int XEMBED_FOCUS_PREV  =       7;
54/* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
55    static final int XEMBED_GRAB_KEY = 8;
56    static final int XEMBED_UNGRAB_KEY = 9;
57    static final int XEMBED_MODALITY_ON         =       10;
58    static final int XEMBED_MODALITY_OFF        =       11;
59    static final int XEMBED_REGISTER_ACCELERATOR =    12;
60    static final int XEMBED_UNREGISTER_ACCELERATOR=   13;
61    static final int XEMBED_ACTIVATE_ACCELERATOR  =   14;
62
63    static final int NON_STANDARD_XEMBED_GTK_GRAB_KEY = 108;
64    static final int NON_STANDARD_XEMBED_GTK_UNGRAB_KEY = 109;
65
66//     A detail code is required for XEMBED_FOCUS_IN. The following values are valid:
67/* Details for  XEMBED_FOCUS_IN: */
68    static final int XEMBED_FOCUS_CURRENT       =       0;
69    static final int XEMBED_FOCUS_FIRST         =       1;
70    static final int XEMBED_FOCUS_LAST  =       2;
71
72// Modifiers bits
73    static final int XEMBED_MODIFIER_SHIFT   = (1 << 0);
74    static final int XEMBED_MODIFIER_CONTROL = (1 << 1);
75    static final int XEMBED_MODIFIER_ALT     = (1 << 2);
76    static final int XEMBED_MODIFIER_SUPER   = (1 << 3);
77    static final int XEMBED_MODIFIER_HYPER   = (1 << 4);
78
79    static XAtom XEmbedInfo;
80    static XAtom XEmbed;
81
82    XEmbedHelper() {
83        if (XEmbed == null) {
84            XEmbed = XAtom.get("_XEMBED");
85            if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) {
86                xembedLog.finer("Created atom " + XEmbed.toString());
87            }
88        }
89        if (XEmbedInfo == null) {
90            XEmbedInfo = XAtom.get("_XEMBED_INFO");
91            if (xembedLog.isLoggable(PlatformLogger.Level.FINER)) {
92                xembedLog.finer("Created atom " + XEmbedInfo.toString());
93            }
94        }
95    }
96
97    void sendMessage(long window, int message) {
98        sendMessage(window, message, 0, 0, 0);
99    }
100    void sendMessage(long window, int message, long detail, long data1, long data2) {
101        XClientMessageEvent msg = new XClientMessageEvent();
102        msg.set_type(XConstants.ClientMessage);
103        msg.set_window(window);
104        msg.set_message_type(XEmbed.getAtom());
105        msg.set_format(32);
106        msg.set_data(0, XToolkit.getCurrentServerTime());
107        msg.set_data(1, message);
108        msg.set_data(2, detail);
109        msg.set_data(3, data1);
110        msg.set_data(4, data2);
111        XToolkit.awtLock();
112        try {
113            if (xembedLog.isLoggable(PlatformLogger.Level.FINE)) {
114                xembedLog.fine("Sending " + XEmbedMessageToString(msg));
115            }
116            XlibWrapper.XSendEvent(XToolkit.getDisplay(), window, false, XConstants.NoEventMask, msg.pData);
117        }
118        finally {
119            XToolkit.awtUnlock();
120        }
121        msg.dispose();
122    }
123
124    static String msgidToString(int msg_id) {
125        switch (msg_id) {
126          case XEMBED_EMBEDDED_NOTIFY:
127              return "XEMBED_EMBEDDED_NOTIFY";
128          case XEMBED_WINDOW_ACTIVATE:
129              return "XEMBED_WINDOW_ACTIVATE";
130          case XEMBED_WINDOW_DEACTIVATE:
131              return "XEMBED_WINDOW_DEACTIVATE";
132          case XEMBED_FOCUS_IN:
133              return "XEMBED_FOCUS_IN";
134          case XEMBED_FOCUS_OUT:
135              return "XEMBED_FOCUS_OUT";
136          case XEMBED_REQUEST_FOCUS:
137              return "XEMBED_REQUEST_FOCUS";
138          case XEMBED_FOCUS_NEXT:
139              return "XEMBED_FOCUS_NEXT";
140          case XEMBED_FOCUS_PREV:
141              return "XEMBED_FOCUS_PREV";
142          case XEMBED_MODALITY_ON:
143              return "XEMBED_MODALITY_ON";
144          case XEMBED_MODALITY_OFF:
145              return "XEMBED_MODALITY_OFF";
146          case XEMBED_REGISTER_ACCELERATOR:
147              return "XEMBED_REGISTER_ACCELERATOR";
148          case XEMBED_UNREGISTER_ACCELERATOR:
149              return "XEMBED_UNREGISTER_ACCELERATOR";
150          case XEMBED_ACTIVATE_ACCELERATOR:
151              return "XEMBED_ACTIVATE_ACCELERATOR";
152          case XEMBED_GRAB_KEY:
153              return "XEMBED_GRAB_KEY";
154          case XEMBED_UNGRAB_KEY:
155              return "XEMBED_UNGRAB_KEY";
156          case NON_STANDARD_XEMBED_GTK_UNGRAB_KEY:
157              return "NON_STANDARD_XEMBED_GTK_UNGRAB_KEY";
158          case NON_STANDARD_XEMBED_GTK_GRAB_KEY:
159              return "NON_STANDARD_XEMBED_GTK_GRAB_KEY";
160          case XConstants.KeyPress | XEmbedServerTester.SYSTEM_EVENT_MASK:
161              return "KeyPress";
162          case XConstants.MapNotify | XEmbedServerTester.SYSTEM_EVENT_MASK:
163              return "MapNotify";
164          case XConstants.PropertyNotify | XEmbedServerTester.SYSTEM_EVENT_MASK:
165              return "PropertyNotify";
166          default:
167              return "unknown XEMBED id " + msg_id;
168        }
169    }
170
171    static String focusIdToString(int focus_id) {
172        switch(focus_id) {
173          case XEMBED_FOCUS_CURRENT:
174              return "XEMBED_FOCUS_CURRENT";
175          case XEMBED_FOCUS_FIRST:
176              return "XEMBED_FOCUS_FIRST";
177          case XEMBED_FOCUS_LAST:
178              return "XEMBED_FOCUS_LAST";
179          default:
180              return "unknown focus id " + focus_id;
181        }
182    }
183
184    static String XEmbedMessageToString(XClientMessageEvent msg) {
185        return ("XEmbed message to " + Long.toHexString(msg.get_window()) + ": " + msgidToString((int)msg.get_data(1)) +
186                ", detail: " + msg.get_data(2) +
187                ", data:[" + msg.get_data(3) + "," + msg.get_data(4) + "]");
188
189    }
190
191
192    /**
193     * Converts XEMBED modifiers mask into AWT InputEvent mask
194     */
195    int getModifiers(int state) {
196        int mods = 0;
197        if ((state & XEMBED_MODIFIER_SHIFT) != 0) {
198            mods |= InputEvent.SHIFT_DOWN_MASK;
199        }
200        if ((state & XEMBED_MODIFIER_CONTROL) != 0) {
201            mods |= InputEvent.CTRL_DOWN_MASK;
202        }
203        if ((state & XEMBED_MODIFIER_ALT) != 0) {
204            mods |= InputEvent.ALT_DOWN_MASK;
205        }
206        // FIXME: What is super/hyper?
207        // FIXME: Experiments show that SUPER is ALT. So what is Alt then?
208        if ((state & XEMBED_MODIFIER_SUPER) != 0) {
209            mods |= InputEvent.ALT_DOWN_MASK;
210        }
211//         if ((state & XEMBED_MODIFIER_HYPER) != 0) {
212//             mods |= InputEvent.DOWN_MASK;
213//         }
214        return mods;
215    }
216
217    // Shouldn't be called on Toolkit thread.
218    AWTKeyStroke getKeyStrokeForKeySym(long keysym, long state) {
219        XBaseWindow.checkSecurity();
220
221        int keycode;
222
223        XToolkit.awtLock();
224        try {
225            XKeysym.Keysym2JavaKeycode kc = XKeysym.getJavaKeycode( keysym );
226            if(kc == null) {
227                keycode = java.awt.event.KeyEvent.VK_UNDEFINED;
228            }else{
229                keycode = kc.getJavaKeycode();
230            }
231        } finally {
232            XToolkit.awtUnlock();
233        }
234
235        int modifiers = getModifiers((int)state);
236        return AWTKeyStroke.getAWTKeyStroke(keycode, modifiers);
237    }
238}
239