Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/macosx/native/libawt_lwawt/awt/CGraphicsDevice.m
41152 views
1
/*
2
* Copyright (c) 2012, 2019, 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
#import "LWCToolkit.h"
27
#import "ThreadUtilities.h"
28
#include "GeomUtilities.h"
29
#include "JNIUtilities.h"
30
31
/**
32
* Some default values for invalid CoreGraphics display ID.
33
*/
34
#define DEFAULT_DEVICE_WIDTH 1024
35
#define DEFAULT_DEVICE_HEIGHT 768
36
#define DEFAULT_DEVICE_DPI 72
37
38
/*
39
* Convert the mode string to the more convinient bits per pixel value
40
*/
41
static int getBPPFromModeString(CFStringRef mode)
42
{
43
if ((CFStringCompare(mode, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
44
// This is a strange mode, where we using 10 bits per RGB component and pack it into 32 bits
45
// Java is not ready to work with this mode but we have to specify it as supported
46
return 30;
47
}
48
else if (CFStringCompare(mode, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
49
return 32;
50
}
51
else if (CFStringCompare(mode, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
52
return 16;
53
}
54
else if (CFStringCompare(mode, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
55
return 8;
56
}
57
58
return 0;
59
}
60
61
static BOOL isValidDisplayMode(CGDisplayModeRef mode){
62
return (1 < CGDisplayModeGetWidth(mode) && 1 < CGDisplayModeGetHeight(mode));
63
}
64
65
static CFMutableArrayRef getAllValidDisplayModes(jint displayID){
66
// CGDisplayCopyAllDisplayModes can return NULL if displayID is invalid
67
CFArrayRef allModes = CGDisplayCopyAllDisplayModes(displayID, NULL);
68
CFMutableArrayRef validModes = nil;
69
if (allModes) {
70
CFIndex numModes = CFArrayGetCount(allModes);
71
validModes = CFArrayCreateMutable(kCFAllocatorDefault, numModes + 1, &kCFTypeArrayCallBacks);
72
73
CFIndex n;
74
for (n=0; n < numModes; n++) {
75
CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);
76
if (cRef != NULL && isValidDisplayMode(cRef)) {
77
CFArrayAppendValue(validModes, cRef);
78
}
79
}
80
CFRelease(allModes);
81
82
// CGDisplayCopyDisplayMode can return NULL if displayID is invalid
83
CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(displayID);
84
if (currentMode) {
85
BOOL containsCurrentMode = NO;
86
numModes = CFArrayGetCount(validModes);
87
for (n=0; n < numModes; n++) {
88
if(CFArrayGetValueAtIndex(validModes, n) == currentMode){
89
containsCurrentMode = YES;
90
break;
91
}
92
}
93
if (!containsCurrentMode) {
94
CFArrayAppendValue(validModes, currentMode);
95
}
96
CGDisplayModeRelease(currentMode);
97
}
98
}
99
100
return validModes;
101
}
102
103
/*
104
* Find the best possible match in the list of display modes that we can switch to based on
105
* the provided parameters.
106
*/
107
static CGDisplayModeRef getBestModeForParameters(CFArrayRef allModes, int w, int h, int bpp, int refrate) {
108
CGDisplayModeRef bestGuess = NULL;
109
CFIndex numModes = allModes ? CFArrayGetCount(allModes) : 0, n;
110
111
for(n = 0; n < numModes; n++ ) {
112
CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);
113
if(cRef == NULL) {
114
continue;
115
}
116
CFStringRef modeString = CGDisplayModeCopyPixelEncoding(cRef);
117
int thisBpp = getBPPFromModeString(modeString);
118
CFRelease(modeString);
119
int thisH = (int)CGDisplayModeGetHeight(cRef);
120
int thisW = (int)CGDisplayModeGetWidth(cRef);
121
if (thisBpp != bpp || thisH != h || thisW != w) {
122
// One of the key parameters does not match
123
continue;
124
}
125
126
if (refrate == 0) { // REFRESH_RATE_UNKNOWN
127
return cRef;
128
}
129
130
// Refresh rate might be 0 in display mode and we ask for specific display rate
131
// but if we do not find exact match then 0 refresh rate might be just Ok
132
int thisRefrate = (int)CGDisplayModeGetRefreshRate(cRef);
133
if (thisRefrate == refrate) {
134
// Exact match
135
return cRef;
136
}
137
if (thisRefrate == 0) {
138
// Not exactly what was asked for, but may fit our needs if we don't find an exact match
139
bestGuess = cRef;
140
}
141
}
142
return bestGuess;
143
}
144
145
/*
146
* Create a new java.awt.DisplayMode instance based on provided
147
* CGDisplayModeRef, if CGDisplayModeRef is NULL, then some stub is returned.
148
*/
149
static jobject createJavaDisplayMode(CGDisplayModeRef mode, JNIEnv *env) {
150
jobject ret = NULL;
151
jint h = DEFAULT_DEVICE_HEIGHT, w = DEFAULT_DEVICE_WIDTH, bpp = 0, refrate = 0;
152
JNI_COCOA_ENTER(env);
153
if (mode) {
154
CFStringRef currentBPP = CGDisplayModeCopyPixelEncoding(mode);
155
bpp = getBPPFromModeString(currentBPP);
156
refrate = CGDisplayModeGetRefreshRate(mode);
157
h = CGDisplayModeGetHeight(mode);
158
w = CGDisplayModeGetWidth(mode);
159
CFRelease(currentBPP);
160
}
161
DECLARE_CLASS_RETURN(jc_DisplayMode, "java/awt/DisplayMode", ret);
162
DECLARE_METHOD_RETURN(jc_DisplayMode_ctor, jc_DisplayMode, "<init>", "(IIII)V", ret);
163
ret = (*env)->NewObject(env, jc_DisplayMode, jc_DisplayMode_ctor, w, h, bpp, refrate);
164
CHECK_EXCEPTION();
165
JNI_COCOA_EXIT(env);
166
return ret;
167
}
168
169
170
/*
171
* Class: sun_awt_CGraphicsDevice
172
* Method: nativeGetXResolution
173
* Signature: (I)D
174
*/
175
JNIEXPORT jdouble JNICALL
176
Java_sun_awt_CGraphicsDevice_nativeGetXResolution
177
(JNIEnv *env, jclass class, jint displayID)
178
{
179
// CGDisplayScreenSize can return 0 if displayID is invalid
180
CGSize size = CGDisplayScreenSize(displayID);
181
CGRect rect = CGDisplayBounds(displayID);
182
// 1 inch == 25.4 mm
183
jfloat inches = size.width / 25.4f;
184
return inches > 0 ? rect.size.width / inches : DEFAULT_DEVICE_DPI;
185
}
186
187
/*
188
* Class: sun_awt_CGraphicsDevice
189
* Method: nativeGetYResolution
190
* Signature: (I)D
191
*/
192
JNIEXPORT jdouble JNICALL
193
Java_sun_awt_CGraphicsDevice_nativeGetYResolution
194
(JNIEnv *env, jclass class, jint displayID)
195
{
196
// CGDisplayScreenSize can return 0 if displayID is invalid
197
CGSize size = CGDisplayScreenSize(displayID);
198
CGRect rect = CGDisplayBounds(displayID);
199
// 1 inch == 25.4 mm
200
jfloat inches = size.height / 25.4f;
201
return inches > 0 ? rect.size.height / inches : DEFAULT_DEVICE_DPI;
202
}
203
204
/*
205
* Class: sun_awt_CGraphicsDevice
206
* Method: nativeGetBounds
207
* Signature: (I)Ljava/awt/Rectangle;
208
*/
209
JNIEXPORT jobject JNICALL
210
Java_sun_awt_CGraphicsDevice_nativeGetBounds
211
(JNIEnv *env, jclass class, jint displayID)
212
{
213
CGRect rect = CGDisplayBounds(displayID);
214
if (rect.size.width == 0) {
215
rect.size.width = DEFAULT_DEVICE_WIDTH;
216
}
217
if (rect.size.height == 0) {
218
rect.size.height = DEFAULT_DEVICE_HEIGHT;
219
}
220
return CGToJavaRect(env, rect);
221
}
222
223
/*
224
* Class: sun_awt_CGraphicsDevice
225
* Method: nativeGetScreenInsets
226
* Signature: (I)D
227
*/
228
JNIEXPORT jobject JNICALL
229
Java_sun_awt_CGraphicsDevice_nativeGetScreenInsets
230
(JNIEnv *env, jclass class, jint displayID)
231
{
232
jobject ret = NULL;
233
__block NSRect frame = NSZeroRect;
234
__block NSRect visibleFrame = NSZeroRect;
235
JNI_COCOA_ENTER(env);
236
237
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
238
NSArray *screens = [NSScreen screens];
239
for (NSScreen *screen in screens) {
240
NSDictionary *screenInfo = [screen deviceDescription];
241
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
242
if ([screenID unsignedIntValue] == displayID){
243
frame = [screen frame];
244
visibleFrame = [screen visibleFrame];
245
break;
246
}
247
}
248
}];
249
// Convert between Cocoa's coordinate system and Java.
250
jint bottom = visibleFrame.origin.y - frame.origin.y;
251
jint top = frame.size.height - visibleFrame.size.height - bottom;
252
jint left = visibleFrame.origin.x - frame.origin.x;
253
jint right = frame.size.width - visibleFrame.size.width - left;
254
255
DECLARE_CLASS_RETURN(jc_Insets, "java/awt/Insets", ret);
256
DECLARE_METHOD_RETURN(jc_Insets_ctor, jc_Insets, "<init>", "(IIII)V", ret);
257
ret = (*env)->NewObject(env, jc_Insets, jc_Insets_ctor, top, left, bottom, right);
258
259
JNI_COCOA_EXIT(env);
260
261
return ret;
262
}
263
264
/*
265
* Class: sun_awt_CGraphicsDevice
266
* Method: nativeSetDisplayMode
267
* Signature: (IIIII)V
268
*/
269
JNIEXPORT void JNICALL
270
Java_sun_awt_CGraphicsDevice_nativeSetDisplayMode
271
(JNIEnv *env, jclass class, jint displayID, jint w, jint h, jint bpp, jint refrate)
272
{
273
JNI_COCOA_ENTER(env);
274
CFArrayRef allModes = getAllValidDisplayModes(displayID);
275
CGDisplayModeRef closestMatch = getBestModeForParameters(allModes, (int)w, (int)h, (int)bpp, (int)refrate);
276
277
__block CGError retCode = kCGErrorSuccess;
278
if (closestMatch != NULL) {
279
CGDisplayModeRetain(closestMatch);
280
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
281
CGDisplayConfigRef config;
282
retCode = CGBeginDisplayConfiguration(&config);
283
if (retCode == kCGErrorSuccess) {
284
CGConfigureDisplayWithDisplayMode(config, displayID, closestMatch, NULL);
285
retCode = CGCompleteDisplayConfiguration(config, kCGConfigureForAppOnly);
286
}
287
CGDisplayModeRelease(closestMatch);
288
}];
289
} else {
290
JNU_ThrowIllegalArgumentException(env, "Invalid display mode");
291
}
292
293
if (retCode != kCGErrorSuccess){
294
JNU_ThrowIllegalArgumentException(env, "Unable to set display mode!");
295
}
296
CFRelease(allModes);
297
JNI_COCOA_EXIT(env);
298
}
299
/*
300
* Class: sun_awt_CGraphicsDevice
301
* Method: nativeGetDisplayMode
302
* Signature: (I)Ljava/awt/DisplayMode
303
*/
304
JNIEXPORT jobject JNICALL
305
Java_sun_awt_CGraphicsDevice_nativeGetDisplayMode
306
(JNIEnv *env, jclass class, jint displayID)
307
{
308
jobject ret = NULL;
309
// CGDisplayCopyDisplayMode can return NULL if displayID is invalid
310
CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(displayID);
311
ret = createJavaDisplayMode(currentMode, env);
312
CGDisplayModeRelease(currentMode);
313
return ret;
314
}
315
316
/*
317
* Class: sun_awt_CGraphicsDevice
318
* Method: nativeGetDisplayMode
319
* Signature: (I)[Ljava/awt/DisplayModes
320
*/
321
JNIEXPORT jobjectArray JNICALL
322
Java_sun_awt_CGraphicsDevice_nativeGetDisplayModes
323
(JNIEnv *env, jclass class, jint displayID)
324
{
325
jobjectArray jreturnArray = NULL;
326
JNI_COCOA_ENTER(env);
327
CFArrayRef allModes = getAllValidDisplayModes(displayID);
328
329
CFIndex numModes = allModes ? CFArrayGetCount(allModes): 0;
330
DECLARE_CLASS_RETURN(jc_DisplayMode, "java/awt/DisplayMode", NULL);
331
332
jreturnArray = (*env)->NewObjectArray(env, (jsize)numModes, jc_DisplayMode, NULL);
333
if (!jreturnArray) {
334
NSLog(@"CGraphicsDevice can't create java array of DisplayMode objects");
335
return nil;
336
}
337
338
CFIndex n;
339
for (n=0; n < numModes; n++) {
340
CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);
341
if (cRef != NULL) {
342
jobject oneMode = createJavaDisplayMode(cRef, env);
343
(*env)->SetObjectArrayElement(env, jreturnArray, n, oneMode);
344
if ((*env)->ExceptionOccurred(env)) {
345
(*env)->ExceptionDescribe(env);
346
(*env)->ExceptionClear(env);
347
continue;
348
}
349
(*env)->DeleteLocalRef(env, oneMode);
350
}
351
}
352
if (allModes) {
353
CFRelease(allModes);
354
}
355
JNI_COCOA_EXIT(env);
356
357
return jreturnArray;
358
}
359
360
/*
361
* Class: sun_awt_CGraphicsDevice
362
* Method: nativeGetScaleFactor
363
* Signature: (I)D
364
*/
365
JNIEXPORT jdouble JNICALL
366
Java_sun_awt_CGraphicsDevice_nativeGetScaleFactor
367
(JNIEnv *env, jclass class, jint displayID)
368
{
369
__block jdouble ret = 1.0f;
370
371
JNI_COCOA_ENTER(env);
372
373
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
374
NSArray *screens = [NSScreen screens];
375
for (NSScreen *screen in screens) {
376
NSDictionary *screenInfo = [screen deviceDescription];
377
NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
378
if ([screenID unsignedIntValue] == displayID){
379
if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
380
ret = [screen backingScaleFactor];
381
}
382
break;
383
}
384
}
385
}];
386
387
JNI_COCOA_EXIT(env);
388
return ret;
389
}
390
391