Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/aix/classes/sun/awt/X11InputMethod.java
41153 views
1
/*
2
* Copyright (c) 1997, 2021, 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
26
package sun.awt;
27
28
import java.awt.AWTException;
29
import java.awt.EventQueue;
30
import java.awt.event.InputMethodEvent;
31
import java.awt.font.TextAttribute;
32
import java.awt.font.TextHitInfo;
33
import java.awt.peer.ComponentPeer;
34
import java.text.AttributedString;
35
36
import sun.util.logging.PlatformLogger;
37
38
/**
39
* Input Method Adapter for XIM for AIX
40
*
41
* @author JavaSoft International
42
*/
43
public abstract class X11InputMethod extends X11InputMethodBase {
44
45
// to keep the instance of activating if IM resumed
46
protected static X11InputMethod activatedInstance = null;
47
48
/**
49
* Constructs an X11InputMethod instance. It initializes the XIM
50
* environment if it's not done yet.
51
*
52
* @exception AWTException if XOpenIM() failed.
53
*/
54
public X11InputMethod() throws AWTException {
55
super();
56
}
57
58
/**
59
* Reset the composition state to the current composition state.
60
*/
61
protected void resetCompositionState() {
62
if (compositionEnableSupported && haveActiveClient()) {
63
try {
64
/* Restore the composition mode to the last saved composition
65
mode. */
66
setCompositionEnabled(savedCompositionState);
67
} catch (UnsupportedOperationException e) {
68
compositionEnableSupported = false;
69
}
70
}
71
}
72
73
/**
74
* Activate input method.
75
*/
76
public synchronized void activate() {
77
activatedInstance = this;
78
clientComponentWindow = getClientComponentWindow();
79
if (clientComponentWindow == null)
80
return;
81
82
if (lastXICFocussedComponent != null) {
83
if (log.isLoggable(PlatformLogger.Level.FINE)) {
84
log.fine("XICFocused {0}, AWTFocused {1}",
85
lastXICFocussedComponent, awtFocussedComponent);
86
}
87
if (lastXICFocussedComponent != awtFocussedComponent) {
88
ComponentPeer lastXICFocussedComponentPeer = getPeer(lastXICFocussedComponent);
89
if (lastXICFocussedComponentPeer != null) {
90
setXICFocus(lastXICFocussedComponentPeer, false, isLastXICActive);
91
}
92
}
93
lastXICFocussedComponent = null;
94
}
95
96
if (pData == 0) {
97
if (!createXIC()) {
98
return;
99
}
100
disposed = false;
101
}
102
103
/* reset input context if necessary and set the XIC focus
104
*/
105
resetXICifneeded();
106
ComponentPeer awtFocussedComponentPeer = getPeer(awtFocussedComponent);
107
setStatusAreaVisible(true, pData);
108
109
if (awtFocussedComponentPeer != null) {
110
setXICFocus(awtFocussedComponentPeer, true, haveActiveClient());
111
}
112
lastXICFocussedComponent = awtFocussedComponent;
113
isLastXICActive = haveActiveClient();
114
isActive = true;
115
if (savedCompositionState) {
116
resetCompositionState();
117
}
118
}
119
120
/**
121
* Deactivate input method.
122
*/
123
public synchronized void deactivate(boolean isTemporary) {
124
boolean isAc = haveActiveClient();
125
/* Usually as the client component, let's call it component A,
126
loses the focus, this method is called. Then when another client
127
component, let's call it component B, gets the focus, activate is first called on
128
the previous focused compoent which is A, then endComposition is called on A,
129
deactivate is called on A again. And finally activate is called on the newly
130
focused component B. Here is the call sequence.
131
132
A loses focus B gains focus
133
-------------> deactivate A -------------> activate A -> endComposition A ->
134
deactivate A -> activate B ----....
135
136
So in order to carry the composition mode across the components sharing the same
137
input context, we save it when deactivate is called so that when activate is
138
called, it can be restored correctly till activate is called on the newly focused
139
component. (See also sun/awt/im/InputContext and bug 6184471).
140
Last note, getCompositionState should be called before setXICFocus since
141
setXICFocus here sets the XIC to 0.
142
*/
143
activatedInstance = null;
144
savedCompositionState = getCompositionState();
145
146
if (isTemporary) {
147
//turn the status window off...
148
turnoffStatusWindow();
149
/* Delay resetting the XIC focus until activate is called and the newly
150
* Focused component has a different peer as the last focused component.
151
*/
152
lastXICFocussedComponent = awtFocussedComponent;
153
} else {
154
if (awtFocussedComponent != null ) {
155
ComponentPeer awtFocussedComponentPeer = getPeer(awtFocussedComponent);
156
if (awtFocussedComponentPeer != null) {
157
setXICFocus(awtFocussedComponentPeer, false, isAc);
158
}
159
}
160
lastXICFocussedComponent = null;
161
}
162
163
isLastXICActive = isAc;
164
isLastTemporary = isTemporary;
165
isActive = false;
166
setStatusAreaVisible(false, pData);
167
}
168
169
// implements java.awt.im.spi.InputMethod.hideWindows
170
public void hideWindows() {
171
if (pData != 0) {
172
setStatusAreaVisible(false, pData);
173
turnoffStatusWindow();
174
}
175
}
176
177
/**
178
* Updates composed text with XIM preedit information and
179
* posts composed text to the awt event queue. The args of
180
* this method correspond to the XIM preedit callback
181
* information. The XIM highlight attributes are translated via
182
* fixed mapping (i.e., independent from any underlying input
183
* method engine). This method is invoked in the AWT Toolkit
184
* (X event loop) thread context and thus inside the AWT Lock.
185
*/
186
// NOTE: This method may be called by privileged threads.
187
// This functionality is implemented in a package-private method
188
// to insure that it cannot be overridden by client subclasses.
189
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
190
void dispatchComposedText(String chgText,
191
int[] chgStyles,
192
int chgOffset,
193
int chgLength,
194
int caretPosition,
195
long when) {
196
if (disposed) {
197
return;
198
}
199
200
// Workaround for deadlock bug on solaris2.6_zh bug#4170760
201
if (chgText == null
202
&& chgStyles == null
203
&& chgOffset == 0
204
&& chgLength == 0
205
&& caretPosition == 0
206
&& composedText == null
207
&& committedText == null)
208
return;
209
210
// Recalculate chgOffset and chgLength for supplementary char
211
if (composedText != null) {
212
int tmpChgOffset=chgOffset;
213
int tmpChgLength=chgLength;
214
int index = 0;
215
for (int i=0;i < tmpChgOffset; i++,index++){
216
if (index < composedText.length()
217
&& Character.charCount(composedText.codePointAt(index))==2){
218
index++;
219
chgOffset++;
220
}
221
}
222
// The index keeps value
223
for (int i=0;i < tmpChgLength; i++,index++){
224
if (index < composedText.length()
225
&& Character.charCount(composedText.codePointAt(index))==2){
226
index++;
227
chgLength++;
228
}
229
}
230
}
231
232
// Replace control character with a square box
233
if (chgText != null) {
234
StringBuilder newChgText = new StringBuilder();
235
for (int i=0; i < chgText.length(); i++){
236
char c = chgText.charAt(i);
237
if (Character.isISOControl(c)){
238
c = '\u25A1';
239
}
240
newChgText.append(c);
241
}
242
chgText = new String(newChgText);
243
}
244
245
if (composedText == null) {
246
// TODO: avoid reallocation of those buffers
247
composedText = new StringBuffer(INITIAL_SIZE);
248
rawFeedbacks = new IntBuffer(INITIAL_SIZE);
249
}
250
if (chgLength > 0) {
251
if (chgText == null && chgStyles != null) {
252
rawFeedbacks.replace(chgOffset, chgStyles);
253
} else {
254
if (chgLength == composedText.length()) {
255
// optimization for the special case to replace the
256
// entire previous text
257
composedText = new StringBuffer(INITIAL_SIZE);
258
rawFeedbacks = new IntBuffer(INITIAL_SIZE);
259
} else {
260
if (composedText.length() > 0) {
261
if (chgOffset+chgLength < composedText.length()) {
262
String text;
263
text = composedText.toString().substring(chgOffset+chgLength,
264
composedText.length());
265
composedText.setLength(chgOffset);
266
composedText.append(text);
267
} else {
268
// in case to remove substring from chgOffset
269
// to the end
270
composedText.setLength(chgOffset);
271
}
272
rawFeedbacks.remove(chgOffset, chgLength);
273
}
274
}
275
}
276
}
277
if (chgText != null) {
278
composedText.insert(chgOffset, chgText);
279
if (chgStyles != null) {
280
// Recalculate chgStyles for supplementary char
281
if (chgText.length() > chgStyles.length){
282
int index=0;
283
int[] newStyles = new int[chgText.length()];
284
for (int i=0; i < chgStyles.length; i++, index++){
285
newStyles[index]=chgStyles[i];
286
if (index < chgText.length()
287
&& Character.charCount(chgText.codePointAt(index))==2){
288
newStyles[++index]=chgStyles[i];
289
}
290
}
291
chgStyles=newStyles;
292
}
293
rawFeedbacks.insert(chgOffset, chgStyles);
294
}
295
296
}
297
298
else if (chgStyles != null) {
299
// Recalculate chgStyles to support supplementary char
300
int count=0;
301
for (int i=0; i < chgStyles.length; i++){
302
if (composedText.length() > chgOffset+i+count
303
&& Character.charCount(composedText.codePointAt(chgOffset+i+count))==2){
304
count++;
305
}
306
}
307
if (count>0){
308
int index=0;
309
int[] newStyles = new int[chgStyles.length+count];
310
for (int i=0; i < chgStyles.length; i++, index++){
311
newStyles[index]=chgStyles[i];
312
if (composedText.length() > chgOffset+index
313
&& Character.charCount(composedText.codePointAt(chgOffset+index))==2){
314
newStyles[++index]=chgStyles[i];
315
}
316
}
317
chgStyles=newStyles;
318
}
319
rawFeedbacks.replace(chgOffset, chgStyles);
320
}
321
322
if (composedText.length() == 0) {
323
composedText = null;
324
rawFeedbacks = null;
325
326
// if there is any outstanding committed text stored by
327
// dispatchCommittedText(), it has to be sent to the
328
// client component.
329
if (committedText != null) {
330
dispatchCommittedText(committedText, when);
331
committedText = null;
332
return;
333
}
334
335
// otherwise, send null text to delete client's composed
336
// text.
337
postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
338
null,
339
0,
340
null,
341
null,
342
when);
343
344
return;
345
}
346
347
// Adjust caretPosition for supplementary char
348
for (int i=0; i< caretPosition; i++){
349
if (i < composedText.length()
350
&& Character.charCount(composedText.codePointAt(i))==2){
351
caretPosition++;
352
i++;
353
}
354
}
355
356
// Now sending the composed text to the client
357
int composedOffset;
358
AttributedString inputText;
359
360
// if there is any partially committed text, concatenate it to
361
// the composed text.
362
if (committedText != null) {
363
composedOffset = committedText.length();
364
inputText = new AttributedString(committedText + composedText);
365
committedText = null;
366
} else {
367
composedOffset = 0;
368
inputText = new AttributedString(composedText.toString());
369
}
370
371
int currentFeedback;
372
int nextFeedback;
373
int startOffset = 0;
374
int currentOffset;
375
int visiblePosition = 0;
376
TextHitInfo visiblePositionInfo = null;
377
378
rawFeedbacks.rewind();
379
currentFeedback = rawFeedbacks.getNext();
380
rawFeedbacks.unget();
381
while ((nextFeedback = rawFeedbacks.getNext()) != -1) {
382
if (visiblePosition == 0) {
383
visiblePosition = nextFeedback & XIMVisibleMask;
384
if (visiblePosition != 0) {
385
int index = rawFeedbacks.getOffset() - 1;
386
387
if (visiblePosition == XIMVisibleToBackward)
388
visiblePositionInfo = TextHitInfo.leading(index);
389
else
390
visiblePositionInfo = TextHitInfo.trailing(index);
391
}
392
}
393
nextFeedback &= ~XIMVisibleMask;
394
if (currentFeedback != nextFeedback) {
395
rawFeedbacks.unget();
396
currentOffset = rawFeedbacks.getOffset();
397
inputText.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT,
398
convertVisualFeedbackToHighlight(currentFeedback),
399
composedOffset + startOffset,
400
composedOffset + currentOffset);
401
startOffset = currentOffset;
402
currentFeedback = nextFeedback;
403
}
404
}
405
currentOffset = rawFeedbacks.getOffset();
406
if (currentOffset >= 0) {
407
inputText.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT,
408
convertVisualFeedbackToHighlight(currentFeedback),
409
composedOffset + startOffset,
410
composedOffset + currentOffset);
411
}
412
413
postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
414
inputText.getIterator(),
415
composedOffset,
416
TextHitInfo.leading(caretPosition),
417
visiblePositionInfo,
418
when);
419
}
420
421
/* Some IMs need forced Text clear */
422
void clearComposedText(long when) {
423
composedText = null;
424
postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
425
null, 0, null, null,
426
when);
427
if (committedText != null && committedText.length() > 0) {
428
dispatchCommittedText(committedText, when);
429
}
430
committedText = null;
431
rawFeedbacks = null;
432
}
433
434
void clearComposedText() {
435
if (EventQueue.isDispatchThread()) {
436
clearComposedText(EventQueue.getMostRecentEventTime());
437
}
438
}
439
440
/*
441
* Subclasses should override disposeImpl() instead of dispose(). Client
442
* code should always invoke dispose(), never disposeImpl().
443
*/
444
protected synchronized void disposeImpl() {
445
disposeXIC();
446
awtLock();
447
try {
448
clearComposedText();
449
} finally {
450
// Put awtUnlock into finally block in case an exception is thrown in clearComposedText.
451
awtUnlock();
452
}
453
awtFocussedComponent = null;
454
lastXICFocussedComponent = null;
455
needResetXIC = false;
456
savedCompositionState = false;
457
compositionEnableSupported = true;
458
}
459
460
/**
461
* @see java.awt.im.spi.InputMethod#setCompositionEnabled(boolean)
462
*/
463
public void setCompositionEnabled(boolean enable) {
464
/* If the composition state is successfully changed, set
465
the savedCompositionState to 'enable'. Otherwise, simply
466
return.
467
setCompositionEnabledNative may throw UnsupportedOperationException.
468
Don't try to catch it since the method may be called by clients.
469
Use package private mthod 'resetCompositionState' if you want the
470
exception to be caught.
471
*/
472
boolean pre, post;
473
pre=getCompositionState();
474
475
if (setCompositionEnabledNative(enable)) {
476
savedCompositionState = enable;
477
}
478
479
post=getCompositionState();
480
if (pre != post && post == enable){
481
if (enable == false) flushText();
482
if (awtFocussedComponent != null && isActive){
483
setXICFocus(getPeer(awtFocussedComponent),
484
true, haveActiveClient());
485
}
486
}
487
}
488
489
private native void setStatusAreaVisible(boolean value, long data);
490
}
491
492