Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c
+++ new/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c
1 1 /*
2 2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 #include "jni_util.h"
27 27 #include "awt_p.h"
28 28 #include "awt.h"
29 29 #include "color.h"
30 30 #include <java_awt_DisplayMode.h>
31 31 #include <sun_awt_X11GraphicsEnvironment.h>
32 32 #include <sun_awt_X11GraphicsDevice.h>
33 33 #include <sun_awt_X11GraphicsConfig.h>
34 34 #ifndef HEADLESS
35 35 #include <X11/extensions/Xdbe.h>
36 36 #include <X11/XKBlib.h>
37 37 #include "Xrandr.h"
38 38 #include "GLXGraphicsConfig.h"
39 39 #endif /* !HEADLESS */
40 40
41 41 #include <jni.h>
42 42 #include <jni_util.h>
43 43 #include <jvm.h>
44 44 #include <jvm_md.h>
45 45 #include <jlong.h>
46 46 #include "systemScale.h"
47 47 #include <stdlib.h>
48 48
49 49 #include "awt_GraphicsEnv.h"
50 50 #include "awt_util.h"
51 51 #include "gdefs.h"
52 52 #include <dlfcn.h>
53 53 #include "Trace.h"
54 54
55 55 #ifdef NETSCAPE
56 56 #include <signal.h>
57 57 extern int awt_init_xt;
58 58 #endif
59 59
60 60 #ifndef HEADLESS
61 61
62 62 int awt_numScreens; /* Xinerama-aware number of screens */
63 63
64 64 AwtScreenDataPtr x11Screens;
65 65
66 66 /*
67 67 * Set in initDisplay() to indicate whether we should attempt to initialize
68 68 * GLX for the default configuration.
69 69 */
70 70 static jboolean glxRequested = JNI_FALSE;
71 71
72 72 #endif /* !HEADLESS */
73 73
74 74 #ifdef HEADLESS
75 75 #define Display void
76 76 #endif /* HEADLESS */
77 77
78 78 Display *awt_display;
79 79
80 80 jclass tkClass = NULL;
81 81 jmethodID awtLockMID = NULL;
82 82 jmethodID awtUnlockMID = NULL;
83 83 jmethodID awtWaitMID = NULL;
84 84 jmethodID awtNotifyMID = NULL;
85 85 jmethodID awtNotifyAllMID = NULL;
86 86 jboolean awtLockInited = JNI_FALSE;
87 87
88 88 /** Convenience macro for loading the lock-related method IDs. */
89 89 #define GET_STATIC_METHOD(klass, method_id, method_name, method_sig) \
90 90 do { \
91 91 method_id = (*env)->GetStaticMethodID(env, klass, \
92 92 method_name, method_sig); \
93 93 if (method_id == NULL) return NULL; \
94 94 } while (0)
95 95
96 96 struct X11GraphicsConfigIDs x11GraphicsConfigIDs;
97 97 struct X11GraphicsDeviceIDs x11GraphicsDeviceIDs;
98 98
99 99 #ifndef HEADLESS
100 100 int awtCreateX11Colormap(AwtGraphicsConfigDataPtr adata);
101 101 #endif /* HEADLESS */
102 102
103 103 static char *x11GraphicsConfigClassName = "sun/awt/X11GraphicsConfig";
104 104
105 105 /* AWT and Xinerama
106 106 *
107 107 * As of fix 4356756, AWT is Xinerama-aware. X11GraphicsDevices are created for
108 108 * each screen of a Xinerama setup, though X11 itself still only sees a single
109 109 * display.
110 110 * In many places where we talk to X11, a xinawareScreen variable is used to
111 111 * pass the correct Display value, depending on the circumstances (a single
112 112 * X display, multiple X displays, or a single X display with multiple
113 113 * Xinerama screens).
114 114 *
115 115 * Solaris and Linux differ in the functions used to access Xinerama-related
116 116 * data. This is in part because at this time, the X consortium has not
117 117 * finalized the "official" Xinerama API. Once this spec is available, and
118 118 * both OSes are conformant, one code base should be sufficient for Xinerama
119 119 * operation on both OSes. Until then, some of the Xinerama-related code
120 120 * is ifdef'd appropriately. -bchristi, 7/12/01
121 121 */
122 122
123 123 #define MAXFRAMEBUFFERS 16
124 124 #if defined(__linux__) || defined(MACOSX)
125 125 typedef struct {
126 126 int screen_number;
127 127 short x_org;
128 128 short y_org;
129 129 short width;
130 130 short height;
131 131 } XineramaScreenInfo;
132 132
133 133 typedef XineramaScreenInfo* XineramaQueryScreensFunc(Display*, int*);
134 134
135 135 #else /* SOLARIS */
136 136 typedef Status XineramaGetInfoFunc(Display* display, int screen_number,
137 137 XRectangle* framebuffer_rects, unsigned char* framebuffer_hints,
138 138 int* num_framebuffers);
139 139 typedef Status XineramaGetCenterHintFunc(Display* display, int screen_number,
140 140 int* x, int* y);
141 141
142 142 XineramaGetCenterHintFunc* XineramaSolarisCenterFunc = NULL;
143 143 #endif
144 144
145 145 Bool usingXinerama = False;
146 146 XRectangle fbrects[MAXFRAMEBUFFERS];
147 147
148 148 JNIEXPORT void JNICALL
149 149 Java_sun_awt_X11GraphicsConfig_initIDs (JNIEnv *env, jclass cls)
150 150 {
151 151 x11GraphicsConfigIDs.aData = NULL;
152 152 x11GraphicsConfigIDs.bitsPerPixel = NULL;
153 153 x11GraphicsConfigIDs.screen = NULL;
154 154
155 155 x11GraphicsConfigIDs.aData = (*env)->GetFieldID (env, cls, "aData", "J");
156 156 CHECK_NULL(x11GraphicsConfigIDs.aData);
157 157 x11GraphicsConfigIDs.bitsPerPixel = (*env)->GetFieldID (env, cls, "bitsPerPixel", "I");
158 158 CHECK_NULL(x11GraphicsConfigIDs.bitsPerPixel);
159 159 x11GraphicsConfigIDs.screen = (*env)->GetFieldID (env, cls, "screen", "Lsun/awt/X11GraphicsDevice;");
160 160 CHECK_NULL(x11GraphicsConfigIDs.screen);
161 161
162 162 if (x11GraphicsConfigIDs.aData == NULL ||
163 163 x11GraphicsConfigIDs.bitsPerPixel == NULL ||
164 164 x11GraphicsConfigIDs.screen == NULL) {
165 165
166 166 JNU_ThrowNoSuchFieldError(env, "Can't find a field");
167 167 return;
168 168 }
169 169 }
170 170
171 171 JNIEXPORT void JNICALL
172 172 Java_sun_awt_X11GraphicsDevice_initIDs (JNIEnv *env, jclass cls)
173 173 {
174 174 x11GraphicsDeviceIDs.screen = NULL;
175 175 x11GraphicsDeviceIDs.screen = (*env)->GetFieldID (env, cls, "screen", "I");
176 176 DASSERT(x11GraphicsDeviceIDs.screen);
177 177 }
178 178
179 179 #ifndef HEADLESS
180 180
181 181 /*
182 182 * XIOErrorHandler
183 183 */
184 184 static int xioerror_handler(Display *disp)
185 185 {
186 186 if (awtLockInited) {
187 187 if (errno == EPIPE) {
188 188 jio_fprintf(stderr, "X connection to %s host broken (explicit kill or server shutdown)\n", XDisplayName(NULL));
189 189 }
190 190 /*SignalError(lockedee->lastpc, lockedee, "fp/ade/gui/GUIException", "I/O error"); */
191 191 }
192 192 return 0;
193 193 }
194 194
195 195 static AwtGraphicsConfigDataPtr
196 196 findWithTemplate(XVisualInfo *vinfo,
197 197 long mask)
198 198 {
199 199
200 200 XVisualInfo *visualList;
201 201 XColor color;
202 202 AwtGraphicsConfigDataPtr defaultConfig;
203 203 int visualsMatched, i;
204 204
205 205 visualList = XGetVisualInfo(awt_display,
206 206 mask, vinfo, &visualsMatched);
207 207 if (visualList) {
208 208 defaultConfig = ZALLOC(_AwtGraphicsConfigData);
209 209 for (i = 0; i < visualsMatched; i++) {
210 210 memcpy(&defaultConfig->awt_visInfo, &visualList[i], sizeof(XVisualInfo));
211 211 defaultConfig->awt_depth = visualList[i].depth;
212 212
213 213 /* we can't use awtJNI_CreateColorData here, because it'll pull,
214 214 SystemColor, which in turn will cause toolkit to be reinitialized */
215 215 if (awtCreateX11Colormap(defaultConfig)) {
216 216 /* Allocate white and black pixels for this visual */
217 217 color.flags = DoRed | DoGreen | DoBlue;
218 218 color.red = color.green = color.blue = 0x0000;
219 219 XAllocColor(awt_display, defaultConfig->awt_cmap, &color);
220 220 x11Screens[visualList[i].screen].blackpixel = color.pixel;
221 221 color.flags = DoRed | DoGreen | DoBlue;
222 222 color.red = color.green = color.blue = 0xffff;
223 223 XAllocColor(awt_display, defaultConfig->awt_cmap, &color);
224 224 x11Screens[visualList[i].screen].whitepixel = color.pixel;
225 225
226 226 XFree(visualList);
227 227 return defaultConfig;
228 228 }
229 229 }
230 230 XFree(visualList);
231 231 free((void *)defaultConfig);
232 232 }
233 233 return NULL;
234 234 }
235 235
236 236 /* default config is based on X11 screen. All Xinerama screens of that X11
237 237 screen will have the same default config */
238 238 /* Need more notes about which fields of the structure are based on the X
239 239 screen, and which are based on the Xinerama screen */
240 240 static AwtGraphicsConfigDataPtr
241 241 makeDefaultConfig(JNIEnv *env, int screen) {
242 242
243 243 AwtGraphicsConfigDataPtr defaultConfig;
244 244 int xinawareScreen = 0;
245 245 VisualID forcedVisualID = 0, defaultVisualID;
246 246 char *forcedVisualStr;
247 247 XVisualInfo vinfo;
248 248 long mask;
249 249
250 250 xinawareScreen = usingXinerama ? 0 : screen;
251 251 defaultVisualID =
252 252 XVisualIDFromVisual(DefaultVisual(awt_display, xinawareScreen));
253 253
254 254 memset(&vinfo, 0, sizeof(XVisualInfo));
255 255 vinfo.screen = xinawareScreen;
256 256
257 257 if ((forcedVisualStr = getenv("FORCEDEFVIS"))) {
258 258 mask = VisualIDMask | VisualScreenMask;
259 259 if (sscanf(forcedVisualStr, "%lx", &forcedVisualID) > 0 &&
260 260 forcedVisualID > 0)
261 261 {
262 262 vinfo.visualid = forcedVisualID;
263 263 } else {
264 264 vinfo.visualid = defaultVisualID;
265 265 }
266 266 } else {
267 267 VisualID bestGLXVisualID;
268 268 if (glxRequested &&
269 269 (bestGLXVisualID = GLXGC_FindBestVisual(env, xinawareScreen)) > 0)
270 270 {
271 271 /* we've found the best visual for use with GLX, so use it */
272 272 vinfo.visualid = bestGLXVisualID;
273 273 mask = VisualIDMask | VisualScreenMask;
274 274 } else {
275 275 /* otherwise, continue looking for the best X11 visual */
276 276 vinfo.depth = 24;
277 277 vinfo.class = TrueColor;
278 278 mask = VisualDepthMask | VisualScreenMask | VisualClassMask;
279 279 }
280 280 }
281 281
282 282 /* try the best, or forced visual */
283 283 defaultConfig = findWithTemplate(&vinfo, mask);
284 284 if (defaultConfig) {
285 285 return defaultConfig;
286 286 }
287 287
288 288 /* try the default visual */
289 289 vinfo.visualid = defaultVisualID;
290 290 mask = VisualIDMask | VisualScreenMask;
291 291 defaultConfig = findWithTemplate(&vinfo, mask);
292 292 if (defaultConfig) {
293 293 return defaultConfig;
294 294 }
295 295
296 296 /* try any TrueColor */
297 297 vinfo.class = TrueColor;
298 298 mask = VisualScreenMask | VisualClassMask;
299 299 defaultConfig = findWithTemplate(&vinfo, mask);
300 300 if (defaultConfig) {
301 301 return defaultConfig;
302 302 }
303 303
304 304 /* try 8-bit PseudoColor */
305 305 vinfo.depth = 8;
306 306 vinfo.class = PseudoColor;
307 307 mask = VisualDepthMask | VisualScreenMask | VisualClassMask;
308 308 defaultConfig = findWithTemplate(&vinfo, mask);
309 309 if (defaultConfig) {
310 310 return defaultConfig;
311 311 }
312 312
313 313 /* try any 8-bit */
314 314 vinfo.depth = 8;
315 315 mask = VisualDepthMask | VisualScreenMask;
316 316 defaultConfig = findWithTemplate(&vinfo, mask);
317 317 if (defaultConfig) {
318 318 return defaultConfig;
319 319 }
320 320
321 321 /* we tried everything, give up */
322 322 JNU_ThrowInternalError(env, "Can't find supported visual");
323 323 XCloseDisplay(awt_display);
324 324 awt_display = NULL;
325 325 return NULL;
326 326 }
327 327
328 328 static void
329 329 getAllConfigs (JNIEnv *env, int screen, AwtScreenDataPtr screenDataPtr) {
330 330
331 331 int i;
332 332 int n8p=0, n12p=0, n8s=0, n8gs=0, n8sg=0, n1sg=0, nTrue=0;
333 333 int nConfig;
334 334 XVisualInfo *pVI8p, *pVI12p, *pVI8s, *pVITrue, *pVI8gs,
335 335 *pVI8sg, *pVI1sg = NULL, viTmp;
336 336 AwtGraphicsConfigDataPtr *graphicsConfigs;
337 337 AwtGraphicsConfigDataPtr defaultConfig;
338 338 int ind;
339 339 char errmsg[128];
340 340 int xinawareScreen;
341 341 void* xrenderLibHandle = NULL;
342 342 XRenderFindVisualFormatFunc* xrenderFindVisualFormat = NULL;
343 343 int major_opcode, first_event, first_error;
344 344
345 345 if (usingXinerama) {
346 346 xinawareScreen = 0;
347 347 }
348 348 else {
349 349 xinawareScreen = screen;
350 350 }
351 351
352 352 AWT_LOCK ();
353 353
354 354 viTmp.screen = xinawareScreen;
355 355
356 356 viTmp.depth = 8;
357 357 viTmp.class = PseudoColor;
358 358 viTmp.colormap_size = 256;
359 359 pVI8p = XGetVisualInfo (awt_display,
360 360 VisualDepthMask | VisualClassMask |
361 361 VisualColormapSizeMask | VisualScreenMask,
362 362 &viTmp, &n8p);
363 363
364 364 viTmp.depth = 12;
365 365 viTmp.class = PseudoColor;
366 366 viTmp.colormap_size = 4096;
367 367 pVI12p = XGetVisualInfo (awt_display,
368 368 VisualDepthMask | VisualClassMask |
369 369 VisualColormapSizeMask | VisualScreenMask,
370 370 &viTmp, &n12p);
371 371
372 372 viTmp.class = TrueColor;
373 373 pVITrue = XGetVisualInfo (awt_display,
374 374 VisualClassMask |
375 375 VisualScreenMask,
376 376 &viTmp, &nTrue);
377 377
378 378 viTmp.depth = 8;
379 379 viTmp.class = StaticColor;
380 380 pVI8s = XGetVisualInfo (awt_display, VisualDepthMask | VisualClassMask |
381 381 VisualScreenMask, &viTmp, &n8s);
382 382
383 383 viTmp.depth = 8;
384 384 viTmp.class = GrayScale;
385 385 viTmp.colormap_size = 256;
386 386 pVI8gs = XGetVisualInfo (awt_display,
387 387 VisualDepthMask | VisualClassMask |
388 388 VisualColormapSizeMask | VisualScreenMask,
389 389 &viTmp, &n8gs);
390 390 viTmp.depth = 8;
391 391 viTmp.class = StaticGray;
392 392 viTmp.colormap_size = 256;
393 393 pVI8sg = XGetVisualInfo (awt_display,
394 394 VisualDepthMask | VisualClassMask |
395 395 VisualColormapSizeMask | VisualScreenMask,
396 396 &viTmp, &n8sg);
397 397
398 398 /* REMIND.. remove when we have support for the color classes below */
399 399 /* viTmp.depth = 1; */
400 400 /* viTmp.class = StaticGray; */
401 401 /* pVI1sg = XGetVisualInfo (awt_display, VisualDepthMask | VisualClassMask, */
402 402 /* viTmp, &n1sg); */
403 403
404 404 nConfig = n8p + n12p + n8s + n8gs + n8sg + n1sg + nTrue + 1;
405 405 graphicsConfigs = (AwtGraphicsConfigDataPtr *)
406 406 calloc(nConfig, sizeof(AwtGraphicsConfigDataPtr));
407 407 if (graphicsConfigs == NULL) {
408 408 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2),
409 409 NULL);
410 410 AWT_UNLOCK();
411 411 return;
412 412 }
413 413
414 414 if (screenDataPtr->defaultConfig == NULL) {
415 415 /*
416 416 * After a display change event, the default config field will have
417 417 * been reset, so we need to recreate the default config here.
418 418 */
419 419 screenDataPtr->defaultConfig = makeDefaultConfig(env, screen);
420 420 }
421 421
422 422 defaultConfig = screenDataPtr->defaultConfig;
423 423 graphicsConfigs[0] = defaultConfig;
424 424 nConfig = 1; /* reserve index 0 for default config */
425 425
426 426 // Only use the RENDER extension if it is available on the X server
427 427 if (XQueryExtension(awt_display, "RENDER",
428 428 &major_opcode, &first_event, &first_error))
429 429 {
430 430 xrenderLibHandle = dlopen("libXrender.so.1", RTLD_LAZY | RTLD_GLOBAL);
431 431
432 432 #ifdef MACOSX
433 433 #define XRENDER_LIB "/usr/X11/lib/libXrender.dylib"
434 434 #else
↓ open down ↓ |
434 lines elided |
↑ open up ↑ |
435 435 #define XRENDER_LIB "libXrender.so"
436 436 #endif
437 437
438 438 if (xrenderLibHandle == NULL) {
439 439 xrenderLibHandle = dlopen(XRENDER_LIB,
440 440 RTLD_LAZY | RTLD_GLOBAL);
441 441 }
442 442
443 443 #ifndef __linux__ /* SOLARIS */
444 444 if (xrenderLibHandle == NULL) {
445 - xrenderLibHandle = dlopen("/usr/sfw/lib/libXrender.so.1",
445 + xrenderLibHandle = dlopen("/usr/lib/libXrender.so.1",
446 446 RTLD_LAZY | RTLD_GLOBAL);
447 447 }
448 448 #endif
449 449
450 450 if (xrenderLibHandle != NULL) {
451 451 xrenderFindVisualFormat =
452 452 (XRenderFindVisualFormatFunc*)dlsym(xrenderLibHandle,
453 453 "XRenderFindVisualFormat");
454 454 }
455 455 }
456 456
457 457 for (i = 0; i < nTrue; i++) {
458 458 if (XVisualIDFromVisual(pVITrue[i].visual) ==
459 459 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual) ||
460 460 pVITrue[i].depth == 12) {
461 461 /* Skip the non-supported 12-bit TrueColor visual */
462 462 continue;
463 463 } else {
464 464 ind = nConfig++;
465 465 }
466 466 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
467 467 graphicsConfigs [ind]->awt_depth = pVITrue [i].depth;
468 468 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVITrue [i],
469 469 sizeof (XVisualInfo));
470 470 if (xrenderFindVisualFormat != NULL) {
471 471 XRenderPictFormat *format = xrenderFindVisualFormat (awt_display,
472 472 pVITrue [i].visual);
473 473 if (format &&
474 474 format->type == PictTypeDirect &&
475 475 format->direct.alphaMask)
476 476 {
477 477 graphicsConfigs [ind]->isTranslucencySupported = 1;
478 478 memcpy(&graphicsConfigs [ind]->renderPictFormat, format,
479 479 sizeof(*format));
480 480 }
481 481 }
482 482 }
483 483
484 484 if (xrenderLibHandle != NULL) {
485 485 dlclose(xrenderLibHandle);
486 486 xrenderLibHandle = NULL;
487 487 }
488 488
489 489 for (i = 0; i < n8p; i++) {
490 490 if (XVisualIDFromVisual(pVI8p[i].visual) ==
491 491 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
492 492 continue;
493 493 } else {
494 494 ind = nConfig++;
495 495 }
496 496 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
497 497 graphicsConfigs [ind]->awt_depth = pVI8p [i].depth;
498 498 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI8p [i],
499 499 sizeof (XVisualInfo));
500 500 }
501 501
502 502 for (i = 0; i < n12p; i++) {
503 503 if (XVisualIDFromVisual(pVI12p[i].visual) ==
504 504 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
505 505 continue;
506 506 } else {
507 507 ind = nConfig++;
508 508 }
509 509 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
510 510 graphicsConfigs [ind]->awt_depth = pVI12p [i].depth;
511 511 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI12p [i],
512 512 sizeof (XVisualInfo));
513 513 }
514 514
515 515 for (i = 0; i < n8s; i++) {
516 516 if (XVisualIDFromVisual(pVI8s[i].visual) ==
517 517 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
518 518 continue;
519 519 } else {
520 520 ind = nConfig++;
521 521 }
522 522 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
523 523 graphicsConfigs [ind]->awt_depth = pVI8s [i].depth;
524 524 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI8s [i],
525 525 sizeof (XVisualInfo));
526 526 }
527 527
528 528 for (i = 0; i < n8gs; i++) {
529 529 if (XVisualIDFromVisual(pVI8gs[i].visual) ==
530 530 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
531 531 continue;
532 532 } else {
533 533 ind = nConfig++;
534 534 }
535 535 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
536 536 graphicsConfigs [ind]->awt_depth = pVI8gs [i].depth;
537 537 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI8gs [i],
538 538 sizeof (XVisualInfo));
539 539 }
540 540
541 541 for (i = 0; i < n8sg; i++) {
542 542 if (XVisualIDFromVisual(pVI8sg[i].visual) ==
543 543 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
544 544 continue;
545 545 } else {
546 546 ind = nConfig++;
547 547 }
548 548 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
549 549 graphicsConfigs [ind]->awt_depth = pVI8sg [i].depth;
550 550 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI8sg [i],
551 551 sizeof (XVisualInfo));
552 552 }
553 553
554 554 for (i = 0; i < n1sg; i++) {
555 555 if (XVisualIDFromVisual(pVI1sg[i].visual) ==
556 556 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
557 557 continue;
558 558 } else {
559 559 ind = nConfig++;
560 560 }
561 561 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
562 562 graphicsConfigs [ind]->awt_depth = pVI1sg [i].depth;
563 563 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI1sg [i],
564 564 sizeof (XVisualInfo));
565 565 }
566 566
567 567 if (n8p != 0)
568 568 XFree (pVI8p);
569 569 if (n12p != 0)
570 570 XFree (pVI12p);
571 571 if (n8s != 0)
572 572 XFree (pVI8s);
573 573 if (n8gs != 0)
574 574 XFree (pVI8gs);
575 575 if (n8sg != 0)
576 576 XFree (pVI8sg);
577 577 if (n1sg != 0)
578 578 XFree (pVI1sg);
579 579
580 580 screenDataPtr->numConfigs = nConfig;
581 581 screenDataPtr->configs = graphicsConfigs;
582 582
583 583 AWT_UNLOCK ();
584 584 }
585 585
586 586 #ifndef HEADLESS
587 587 #if defined(__linux__) || defined(MACOSX)
588 588 static void xinerama_init_linux()
589 589 {
590 590 void* libHandle = NULL;
591 591 int32_t locNumScr = 0;
592 592 XineramaScreenInfo *xinInfo;
593 593 char* XineramaQueryScreensName = "XineramaQueryScreens";
594 594 XineramaQueryScreensFunc* XineramaQueryScreens = NULL;
595 595
596 596 /* load library */
597 597 libHandle = dlopen(VERSIONED_JNI_LIB_NAME("Xinerama", "1"),
598 598 RTLD_LAZY | RTLD_GLOBAL);
599 599 if (libHandle == NULL) {
600 600 libHandle = dlopen(JNI_LIB_NAME("Xinerama"), RTLD_LAZY | RTLD_GLOBAL);
601 601 }
602 602 if (libHandle != NULL) {
603 603 XineramaQueryScreens = (XineramaQueryScreensFunc*)
604 604 dlsym(libHandle, XineramaQueryScreensName);
605 605
606 606 if (XineramaQueryScreens != NULL) {
607 607 DTRACE_PRINTLN("calling XineramaQueryScreens func on Linux");
608 608 xinInfo = (*XineramaQueryScreens)(awt_display, &locNumScr);
609 609 if (xinInfo != NULL && locNumScr > XScreenCount(awt_display)) {
610 610 int32_t idx;
611 611 DTRACE_PRINTLN("Enabling Xinerama support");
612 612 usingXinerama = True;
613 613 /* set global number of screens */
614 614 DTRACE_PRINTLN1(" num screens = %i\n", locNumScr);
615 615 awt_numScreens = locNumScr;
616 616
617 617 /* stuff values into fbrects */
618 618 for (idx = 0; idx < awt_numScreens; idx++) {
619 619 DASSERT(xinInfo[idx].screen_number == idx);
620 620
621 621 fbrects[idx].width = xinInfo[idx].width;
622 622 fbrects[idx].height = xinInfo[idx].height;
623 623 fbrects[idx].x = xinInfo[idx].x_org;
624 624 fbrects[idx].y = xinInfo[idx].y_org;
625 625 }
626 626 } else {
627 627 DTRACE_PRINTLN("calling XineramaQueryScreens didn't work");
628 628 }
629 629 } else {
630 630 DTRACE_PRINTLN("couldn't load XineramaQueryScreens symbol");
631 631 }
632 632 dlclose(libHandle);
633 633 } else {
634 634 DTRACE_PRINTLN1("\ncouldn't open shared library: %s\n", dlerror());
635 635 }
636 636 }
637 637 #endif
638 638 #if !defined(__linux__) && !defined(MACOSX) /* Solaris */
639 639 static void xinerama_init_solaris()
640 640 {
641 641 void* libHandle = NULL;
642 642 unsigned char fbhints[MAXFRAMEBUFFERS];
643 643 int32_t locNumScr = 0;
644 644 /* load and run XineramaGetInfo */
645 645 char* XineramaGetInfoName = "XineramaGetInfo";
646 646 char* XineramaGetCenterHintName = "XineramaGetCenterHint";
647 647 XineramaGetInfoFunc* XineramaSolarisFunc = NULL;
648 648
649 649 /* load library */
650 650 libHandle = dlopen(JNI_LIB_NAME("Xext"), RTLD_LAZY | RTLD_GLOBAL);
651 651 if (libHandle != NULL) {
652 652 XineramaSolarisFunc = (XineramaGetInfoFunc*)dlsym(libHandle, XineramaGetInfoName);
653 653 XineramaSolarisCenterFunc =
654 654 (XineramaGetCenterHintFunc*)dlsym(libHandle, XineramaGetCenterHintName);
655 655
656 656 if (XineramaSolarisFunc != NULL) {
657 657 DTRACE_PRINTLN("calling XineramaGetInfo func on Solaris");
658 658 if ((*XineramaSolarisFunc)(awt_display, 0, &fbrects[0],
659 659 &fbhints[0], &locNumScr) != 0 &&
660 660 locNumScr > XScreenCount(awt_display))
661 661 {
662 662 DTRACE_PRINTLN("Enabling Xinerama support");
663 663 usingXinerama = True;
664 664 /* set global number of screens */
665 665 DTRACE_PRINTLN1(" num screens = %i\n", locNumScr);
666 666 awt_numScreens = locNumScr;
667 667 } else {
668 668 DTRACE_PRINTLN("calling XineramaGetInfo didn't work");
669 669 }
670 670 } else {
671 671 DTRACE_PRINTLN("couldn't load XineramaGetInfo symbol");
672 672 }
673 673 dlclose(libHandle);
674 674 } else {
675 675 DTRACE_PRINTLN1("\ncouldn't open shared library: %s\n", dlerror());
676 676 }
677 677 }
678 678 #endif
679 679
680 680 /*
681 681 * Checks if Xinerama is running and perform Xinerama-related
682 682 * platform dependent initialization.
683 683 */
684 684 static void xineramaInit(void) {
685 685 char* XinExtName = "XINERAMA";
686 686 int32_t major_opcode, first_event, first_error;
687 687 Bool gotXinExt = False;
688 688
689 689 gotXinExt = XQueryExtension(awt_display, XinExtName, &major_opcode,
690 690 &first_event, &first_error);
691 691
692 692 if (!gotXinExt) {
693 693 DTRACE_PRINTLN("Xinerama extension is not available");
694 694 return;
695 695 }
696 696
697 697 DTRACE_PRINTLN("Xinerama extension is available");
698 698 #if defined(__linux__) || defined(MACOSX)
699 699 xinerama_init_linux();
700 700 #else /* Solaris */
701 701 xinerama_init_solaris();
702 702 #endif /* __linux__ || MACOSX */
703 703 }
704 704 #endif /* HEADLESS */
705 705
706 706 Display *
707 707 awt_init_Display(JNIEnv *env, jobject this)
708 708 {
709 709 jclass klass;
710 710 Display *dpy;
711 711 char errmsg[128];
712 712 int i;
713 713 #ifdef NETSCAPE
714 714 sigset_t alarm_set, oldset;
715 715 #endif
716 716
717 717 if (awt_display) {
718 718 return awt_display;
719 719 }
720 720
721 721 #ifdef NETSCAPE
722 722 /* Disable interrupts during XtOpenDisplay to avoid bugs in unix os select
723 723 code: some unix systems don't implement SA_RESTART properly and
724 724 because of this, select returns with EINTR. Most implementations of
725 725 gethostbyname don't cope with EINTR properly and as a result we get
726 726 stuck (forever) in the gethostbyname code
727 727 */
728 728 sigemptyset(&alarm_set);
729 729 sigaddset(&alarm_set, SIGALRM);
730 730 sigprocmask(SIG_BLOCK, &alarm_set, &oldset);
731 731 #endif
732 732
733 733 /* Load AWT lock-related methods in SunToolkit */
734 734 klass = (*env)->FindClass(env, "sun/awt/SunToolkit");
735 735 if (klass == NULL) return NULL;
736 736 GET_STATIC_METHOD(klass, awtLockMID, "awtLock", "()V");
737 737 GET_STATIC_METHOD(klass, awtUnlockMID, "awtUnlock", "()V");
738 738 GET_STATIC_METHOD(klass, awtWaitMID, "awtLockWait", "(J)V");
739 739 GET_STATIC_METHOD(klass, awtNotifyMID, "awtLockNotify", "()V");
740 740 GET_STATIC_METHOD(klass, awtNotifyAllMID, "awtLockNotifyAll", "()V");
741 741 tkClass = (*env)->NewGlobalRef(env, klass);
742 742 awtLockInited = JNI_TRUE;
743 743
744 744 if (getenv("_AWT_IGNORE_XKB") != NULL &&
745 745 strlen(getenv("_AWT_IGNORE_XKB")) > 0) {
746 746 if (XkbIgnoreExtension(True)) {
747 747 printf("Ignoring XKB.\n");
748 748 }
749 749 }
750 750
751 751 dpy = awt_display = XOpenDisplay(NULL);
752 752 #ifdef NETSCAPE
753 753 sigprocmask(SIG_SETMASK, &oldset, NULL);
754 754 #endif
755 755 if (!dpy) {
756 756 jio_snprintf(errmsg,
757 757 sizeof(errmsg),
758 758 "Can't connect to X11 window server using '%s' as the value of the DISPLAY variable.",
759 759 (getenv("DISPLAY") == NULL) ? ":0.0" : getenv("DISPLAY"));
760 760 JNU_ThrowByName(env, "java/awt/AWTError", errmsg);
761 761 return NULL;
762 762 }
763 763
764 764 XSetIOErrorHandler(xioerror_handler);
765 765 JNU_CallStaticMethodByName(env, NULL, "sun/awt/X11/XErrorHandlerUtil", "init", "(J)V",
766 766 ptr_to_jlong(awt_display));
767 767 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
768 768
769 769 /* set awt_numScreens, and whether or not we're using Xinerama */
770 770 xineramaInit();
771 771
772 772 if (!usingXinerama) {
773 773 awt_numScreens = XScreenCount(awt_display);
774 774 }
775 775
776 776 DTRACE_PRINTLN1("allocating %i screens\n", awt_numScreens);
777 777 /* Allocate screen data structure array */
778 778 x11Screens = calloc(awt_numScreens, sizeof(AwtScreenData));
779 779 if (x11Screens == NULL) {
780 780 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2),
781 781 NULL);
782 782 return NULL;
783 783 }
784 784
785 785 for (i = 0; i < awt_numScreens; i++) {
786 786 if (usingXinerama) {
787 787 /* All Xinerama screens use the same X11 root for now */
788 788 x11Screens[i].root = RootWindow(awt_display, 0);
789 789 }
790 790 else {
791 791 x11Screens[i].root = RootWindow(awt_display, i);
792 792 }
793 793 x11Screens[i].defaultConfig = makeDefaultConfig(env, i);
794 794 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
795 795 }
796 796
797 797 return dpy;
798 798 }
799 799 #endif /* !HEADLESS */
800 800
801 801 /*
802 802 * Class: sun_awt_X11GraphicsEnvironment
803 803 * Method: getDefaultScreenNum
804 804 * Signature: ()I
805 805 */
806 806 JNIEXPORT jint JNICALL
807 807 Java_sun_awt_X11GraphicsEnvironment_getDefaultScreenNum(
808 808 JNIEnv *env, jobject this)
809 809 {
810 810 #ifdef HEADLESS
811 811 return (jint)0;
812 812 #else
813 813 return DefaultScreen(awt_display);
814 814 #endif /* !HEADLESS */
815 815 }
816 816
817 817 #ifndef HEADLESS
818 818 static void ensureConfigsInited(JNIEnv* env, int screen) {
819 819 if (x11Screens[screen].numConfigs == 0) {
820 820 if (env == NULL) {
821 821 env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
822 822 }
823 823 getAllConfigs (env, screen, &(x11Screens[screen]));
824 824 }
825 825 }
826 826 #endif
827 827
828 828 #ifdef HEADLESS
829 829 void* getDefaultConfig(int screen) {
830 830 return NULL;
831 831 }
832 832 #else
833 833 AwtGraphicsConfigDataPtr
834 834 getDefaultConfig(int screen) {
835 835 ensureConfigsInited(NULL, screen);
836 836 return x11Screens[screen].defaultConfig;
837 837 }
838 838
839 839 AwtScreenDataPtr
840 840 getScreenData(int screen) {
841 841 return &(x11Screens[screen]);
842 842 }
843 843 #endif /* !HEADLESS */
844 844
845 845 /*
846 846 * Class: sun_awt_X11GraphicsEnvironment
847 847 * Method: initDisplay
848 848 * Signature: (Z)V
849 849 */
850 850 JNIEXPORT void JNICALL
851 851 Java_sun_awt_X11GraphicsEnvironment_initDisplay(JNIEnv *env, jobject this,
852 852 jboolean glxReq)
853 853 {
854 854 #ifndef HEADLESS
855 855 glxRequested = glxReq;
856 856 (void) awt_init_Display(env, this);
857 857 #endif /* !HEADLESS */
858 858 }
859 859
860 860 /*
861 861 * Class: sun_awt_X11GraphicsEnvironment
862 862 * Method: initGLX
863 863 * Signature: ()Z
864 864 */
865 865 JNIEXPORT jboolean JNICALL
866 866 Java_sun_awt_X11GraphicsEnvironment_initGLX(JNIEnv *env, jclass x11ge)
867 867 {
868 868 #ifndef HEADLESS
869 869 jboolean glxAvailable;
870 870
871 871 AWT_LOCK();
872 872 glxAvailable = GLXGC_IsGLXAvailable();
873 873 AWT_UNLOCK();
874 874
875 875 return glxAvailable;
876 876 #else
877 877 return JNI_FALSE;
878 878 #endif /* !HEADLESS */
879 879 }
880 880
881 881 /*
882 882 * Class: sun_awt_X11GraphicsEnvironment
883 883 * Method: getNumScreens
884 884 * Signature: ()I
885 885 */
886 886 JNIEXPORT jint JNICALL
887 887 Java_sun_awt_X11GraphicsEnvironment_getNumScreens(JNIEnv *env, jobject this)
888 888 {
889 889 #ifdef HEADLESS
890 890 return (jint)0;
891 891 #else
892 892 return awt_numScreens;
893 893 #endif /* !HEADLESS */
894 894 }
895 895
896 896 /*
897 897 * Class: sun_awt_X11GraphicsDevice
898 898 * Method: getDisplay
899 899 * Signature: ()J
900 900 */
901 901 JNIEXPORT jlong JNICALL
902 902 Java_sun_awt_X11GraphicsDevice_getDisplay(JNIEnv *env, jobject this)
903 903 {
904 904 #ifdef HEADLESS
905 905 return NULL;
906 906 #else
907 907 return ptr_to_jlong(awt_display);
908 908 #endif /* !HEADLESS */
909 909 }
910 910
911 911 #ifdef MITSHM
912 912
913 913 static jint canUseShmExt = UNSET_MITSHM;
914 914 static jint canUseShmExtPixmaps = UNSET_MITSHM;
915 915 static jboolean xshmAttachFailed = JNI_FALSE;
916 916
917 917 int XShmAttachXErrHandler(Display *display, XErrorEvent *xerr) {
918 918 if (xerr->minor_code == X_ShmAttach) {
919 919 xshmAttachFailed = JNI_TRUE;
920 920 }
921 921 return 0;
922 922 }
923 923 jboolean isXShmAttachFailed() {
924 924 return xshmAttachFailed;
925 925 }
926 926 void resetXShmAttachFailed() {
927 927 xshmAttachFailed = JNI_FALSE;
928 928 }
929 929
930 930 extern int mitShmPermissionMask;
931 931
932 932 void TryInitMITShm(JNIEnv *env, jint *shmExt, jint *shmPixmaps) {
933 933 XShmSegmentInfo shminfo;
934 934 int XShmMajor, XShmMinor;
935 935 int a, b, c;
936 936
937 937 AWT_LOCK();
938 938 if (canUseShmExt != UNSET_MITSHM) {
939 939 *shmExt = canUseShmExt;
940 940 *shmPixmaps = canUseShmExtPixmaps;
941 941 AWT_UNLOCK();
942 942 return;
943 943 }
944 944
945 945 *shmExt = canUseShmExt = CANT_USE_MITSHM;
946 946 *shmPixmaps = canUseShmExtPixmaps = CANT_USE_MITSHM;
947 947
948 948 if (awt_display == (Display *)NULL) {
949 949 AWT_NOFLUSH_UNLOCK();
950 950 return;
951 951 }
952 952
953 953 /**
954 954 * XShmQueryExtension returns False in remote server case.
955 955 * Unfortunately it also returns True in ssh case, so
956 956 * we need to test that we can actually do XShmAttach.
957 957 */
958 958 if (XShmQueryExtension(awt_display)) {
959 959 shminfo.shmid = shmget(IPC_PRIVATE, 0x10000,
960 960 IPC_CREAT|mitShmPermissionMask);
961 961 if (shminfo.shmid < 0) {
962 962 AWT_UNLOCK();
963 963 J2dRlsTraceLn1(J2D_TRACE_ERROR,
964 964 "TryInitMITShm: shmget has failed: %s",
965 965 strerror(errno));
966 966 return;
967 967 }
968 968 shminfo.shmaddr = (char *) shmat(shminfo.shmid, 0, 0);
969 969 if (shminfo.shmaddr == ((char *) -1)) {
970 970 shmctl(shminfo.shmid, IPC_RMID, 0);
971 971 AWT_UNLOCK();
972 972 J2dRlsTraceLn1(J2D_TRACE_ERROR,
973 973 "TryInitMITShm: shmat has failed: %s",
974 974 strerror(errno));
975 975 return;
976 976 }
977 977 shminfo.readOnly = True;
978 978
979 979 resetXShmAttachFailed();
980 980 /**
981 981 * The J2DXErrHandler handler will set xshmAttachFailed
982 982 * to JNI_TRUE if any Shm error has occured.
983 983 */
984 984 EXEC_WITH_XERROR_HANDLER(XShmAttachXErrHandler,
985 985 XShmAttach(awt_display, &shminfo));
986 986
987 987 /**
988 988 * Get rid of the id now to reduce chances of leaking
989 989 * system resources.
990 990 */
991 991 shmctl(shminfo.shmid, IPC_RMID, 0);
992 992
993 993 if (isXShmAttachFailed() == JNI_FALSE) {
994 994 canUseShmExt = CAN_USE_MITSHM;
995 995 /* check if we can use shared pixmaps */
996 996 XShmQueryVersion(awt_display, &XShmMajor, &XShmMinor,
997 997 (Bool*)&canUseShmExtPixmaps);
998 998 canUseShmExtPixmaps = canUseShmExtPixmaps &&
999 999 (XShmPixmapFormat(awt_display) == ZPixmap);
1000 1000 XShmDetach(awt_display, &shminfo);
1001 1001 }
1002 1002 shmdt(shminfo.shmaddr);
1003 1003 *shmExt = canUseShmExt;
1004 1004 *shmPixmaps = canUseShmExtPixmaps;
1005 1005 }
1006 1006 AWT_UNLOCK();
1007 1007 }
1008 1008 #endif /* MITSHM */
1009 1009
1010 1010 /*
1011 1011 * Class: sun_awt_X11GraphicsEnvironment
1012 1012 * Method: checkShmExt
1013 1013 * Signature: ()I
1014 1014 */
1015 1015 JNIEXPORT jint JNICALL
1016 1016 Java_sun_awt_X11GraphicsEnvironment_checkShmExt(JNIEnv *env, jobject this)
1017 1017 {
1018 1018
1019 1019 int shmExt = NOEXT_MITSHM, shmPixmaps;
1020 1020 #ifdef MITSHM
1021 1021 TryInitMITShm(env, &shmExt, &shmPixmaps);
1022 1022 #endif
1023 1023 return shmExt;
1024 1024 }
1025 1025
1026 1026 /*
1027 1027 * Class: sun_awt_X11GraphicsEnvironment
1028 1028 * Method: getDisplayString
1029 1029 * Signature: ()Ljava/lang/String
1030 1030 */
1031 1031 JNIEXPORT jstring JNICALL
1032 1032 Java_sun_awt_X11GraphicsEnvironment_getDisplayString
1033 1033 (JNIEnv *env, jobject this)
1034 1034 {
1035 1035 #ifdef HEADLESS
1036 1036 return (jstring)NULL;
1037 1037 #else
1038 1038 return (*env)->NewStringUTF(env, DisplayString(awt_display));
1039 1039 #endif /* HEADLESS */
1040 1040 }
1041 1041
1042 1042
1043 1043 /*
1044 1044 * Class: sun_awt_X11GraphicsDevice
1045 1045 * Method: getNumConfigs
1046 1046 * Signature: ()I
1047 1047 */
1048 1048 JNIEXPORT jint JNICALL
1049 1049 Java_sun_awt_X11GraphicsDevice_getNumConfigs(
1050 1050 JNIEnv *env, jobject this, jint screen)
1051 1051 {
1052 1052 #ifdef HEADLESS
1053 1053 return (jint)0;
1054 1054 #else
1055 1055 ensureConfigsInited(env, screen);
1056 1056 return x11Screens[screen].numConfigs;
1057 1057 #endif /* !HEADLESS */
1058 1058 }
1059 1059
1060 1060 /*
1061 1061 * Class: sun_awt_X11GraphicsDevice
1062 1062 * Method: getConfigVisualId
1063 1063 * Signature: (I)I
1064 1064 */
1065 1065 JNIEXPORT jint JNICALL
1066 1066 Java_sun_awt_X11GraphicsDevice_getConfigVisualId(
1067 1067 JNIEnv *env, jobject this, jint index, jint screen)
1068 1068 {
1069 1069 #ifdef HEADLESS
1070 1070 return (jint)0;
1071 1071 #else
1072 1072 int visNum;
1073 1073
1074 1074 ensureConfigsInited(env, screen);
1075 1075 if (index == 0) {
1076 1076 return ((jint)x11Screens[screen].defaultConfig->awt_visInfo.visualid);
1077 1077 } else {
1078 1078 return ((jint)x11Screens[screen].configs[index]->awt_visInfo.visualid);
1079 1079 }
1080 1080 #endif /* !HEADLESS */
1081 1081 }
1082 1082
1083 1083 /*
1084 1084 * Class: sun_awt_X11GraphicsDevice
1085 1085 * Method: getConfigDepth
1086 1086 * Signature: (I)I
1087 1087 */
1088 1088 JNIEXPORT jint JNICALL
1089 1089 Java_sun_awt_X11GraphicsDevice_getConfigDepth(
1090 1090 JNIEnv *env, jobject this, jint index, jint screen)
1091 1091 {
1092 1092 #ifdef HEADLESS
1093 1093 return (jint)0;
1094 1094 #else
1095 1095 int visNum;
1096 1096
1097 1097 ensureConfigsInited(env, screen);
1098 1098 if (index == 0) {
1099 1099 return ((jint)x11Screens[screen].defaultConfig->awt_visInfo.depth);
1100 1100 } else {
1101 1101 return ((jint)x11Screens[screen].configs[index]->awt_visInfo.depth);
1102 1102 }
1103 1103 #endif /* !HEADLESS */
1104 1104 }
1105 1105
1106 1106 /*
1107 1107 * Class: sun_awt_X11GraphicsDevice
1108 1108 * Method: getConfigColormap
1109 1109 * Signature: (I)I
1110 1110 */
1111 1111 JNIEXPORT jint JNICALL
1112 1112 Java_sun_awt_X11GraphicsDevice_getConfigColormap(
1113 1113 JNIEnv *env, jobject this, jint index, jint screen)
1114 1114 {
1115 1115 #ifdef HEADLESS
1116 1116 return (jint)0;
1117 1117 #else
1118 1118 int visNum;
1119 1119
1120 1120 ensureConfigsInited(env, screen);
1121 1121 if (index == 0) {
1122 1122 return ((jint)x11Screens[screen].defaultConfig->awt_cmap);
1123 1123 } else {
1124 1124 return ((jint)x11Screens[screen].configs[index]->awt_cmap);
1125 1125 }
1126 1126 #endif /* !HEADLESS */
1127 1127 }
1128 1128
1129 1129 /*
1130 1130 * Class: sun_awt_X11GraphicsDevice
1131 1131 * Method: resetNativeData
1132 1132 * Signature: (I)V
1133 1133 */
1134 1134 JNIEXPORT void JNICALL
1135 1135 Java_sun_awt_X11GraphicsDevice_resetNativeData
1136 1136 (JNIEnv *env, jclass x11gd, jint screen)
1137 1137 {
1138 1138 #ifndef HEADLESS
1139 1139 /*
1140 1140 * Reset references to the various configs; the actual native config data
1141 1141 * will be free'd later by the Disposer mechanism when the Java-level
1142 1142 * X11GraphicsConfig objects go away. By setting these values to NULL,
1143 1143 * we ensure that they will be reinitialized as necessary (for example,
1144 1144 * see the getNumConfigs() method).
1145 1145 */
1146 1146 if (x11Screens[screen].configs) {
1147 1147 free(x11Screens[screen].configs);
1148 1148 x11Screens[screen].configs = NULL;
1149 1149 }
1150 1150 x11Screens[screen].defaultConfig = NULL;
1151 1151 x11Screens[screen].numConfigs = 0;
1152 1152 #endif /* !HEADLESS */
1153 1153 }
1154 1154
1155 1155 /*
1156 1156 * Class: sun_awt_X11GraphicsConfig
1157 1157 * Method: dispose
1158 1158 * Signature: (J)V
1159 1159 */
1160 1160 JNIEXPORT void JNICALL
1161 1161 Java_sun_awt_X11GraphicsConfig_dispose
1162 1162 (JNIEnv *env, jclass x11gc, jlong configData)
1163 1163 {
1164 1164 #ifndef HEADLESS
1165 1165 AwtGraphicsConfigDataPtr aData = (AwtGraphicsConfigDataPtr)
1166 1166 jlong_to_ptr(configData);
1167 1167
1168 1168 if (aData == NULL) {
1169 1169 return;
1170 1170 }
1171 1171
1172 1172 AWT_LOCK();
1173 1173 if (aData->awt_cmap) {
1174 1174 XFreeColormap(awt_display, aData->awt_cmap);
1175 1175 }
1176 1176 if (aData->awtImage) {
1177 1177 free(aData->awtImage);
1178 1178 }
1179 1179 if (aData->monoImage) {
1180 1180 XFree(aData->monoImage);
1181 1181 }
1182 1182 if (aData->monoPixmap) {
1183 1183 XFreePixmap(awt_display, aData->monoPixmap);
1184 1184 }
1185 1185 if (aData->monoPixmapGC) {
1186 1186 XFreeGC(awt_display, aData->monoPixmapGC);
1187 1187 }
1188 1188 if (aData->color_data) {
1189 1189 free(aData->color_data);
1190 1190 }
1191 1191 AWT_UNLOCK();
1192 1192
1193 1193 if (aData->glxInfo) {
1194 1194 /*
1195 1195 * The native GLXGraphicsConfig data needs to be disposed separately
1196 1196 * on the OGL queue flushing thread (should not be called while
1197 1197 * the AWT lock is held).
1198 1198 */
1199 1199 JNU_CallStaticMethodByName(env, NULL,
1200 1200 "sun/java2d/opengl/OGLRenderQueue",
1201 1201 "disposeGraphicsConfig", "(J)V",
1202 1202 ptr_to_jlong(aData->glxInfo));
1203 1203 }
1204 1204
1205 1205 free(aData);
1206 1206 #endif /* !HEADLESS */
1207 1207 }
1208 1208
1209 1209 /*
1210 1210 * Class: sun_awt_X11GraphicsConfig
1211 1211 * Method: getXResolution
1212 1212 * Signature: ()I
1213 1213 */
1214 1214 JNIEXPORT jdouble JNICALL
1215 1215 Java_sun_awt_X11GraphicsConfig_getXResolution(
1216 1216 JNIEnv *env, jobject this, jint screen)
1217 1217 {
1218 1218 #ifdef HEADLESS
1219 1219 return (jdouble)0;
1220 1220 #else
1221 1221 return ((DisplayWidth(awt_display, screen) * 25.4) /
1222 1222 DisplayWidthMM(awt_display, screen));
1223 1223 #endif /* !HEADLESS */
1224 1224 }
1225 1225
1226 1226 /*
1227 1227 * Class: sun_awt_X11GraphicsConfig
1228 1228 * Method: getYResolution
1229 1229 * Signature: ()I
1230 1230 */
1231 1231 JNIEXPORT jdouble JNICALL
1232 1232 Java_sun_awt_X11GraphicsConfig_getYResolution(
1233 1233 JNIEnv *env, jobject this, jint screen)
1234 1234 {
1235 1235 #ifdef HEADLESS
1236 1236 return (jdouble)0;
1237 1237 #else
1238 1238 return ((DisplayHeight(awt_display, screen) * 25.4) /
1239 1239 DisplayHeightMM(awt_display, screen));
1240 1240 #endif /* !HEADLESS */
1241 1241 }
1242 1242
1243 1243
1244 1244 /*
1245 1245 * Class: sun_awt_X11GraphicsConfig
1246 1246 * Method: getNumColors
1247 1247 * Signature: ()I
1248 1248 */
1249 1249 JNIEXPORT jint JNICALL
1250 1250 Java_sun_awt_X11GraphicsConfig_getNumColors(
1251 1251 JNIEnv *env, jobject this)
1252 1252 {
1253 1253 #ifdef HEADLESS
1254 1254 return (jint)0;
1255 1255 #else
1256 1256 AwtGraphicsConfigData *adata;
1257 1257
1258 1258 adata = (AwtGraphicsConfigData *) JNU_GetLongFieldAsPtr(env, this,
1259 1259 x11GraphicsConfigIDs.aData);
1260 1260
1261 1261 return adata->awt_num_colors;
1262 1262 #endif /* !HEADLESS */
1263 1263 }
1264 1264
1265 1265 /*
1266 1266 * Class: sun_awt_X11GraphicsConfig
1267 1267 * Method: init
1268 1268 * Signature: (I)V
1269 1269 */
1270 1270 JNIEXPORT void JNICALL
1271 1271 Java_sun_awt_X11GraphicsConfig_init(
1272 1272 JNIEnv *env, jobject this, jint visualNum, jint screen)
1273 1273 {
1274 1274 #ifndef HEADLESS
1275 1275 AwtGraphicsConfigData *adata = NULL;
1276 1276 AwtScreenData asd = x11Screens[screen];
1277 1277 int i, n;
1278 1278 int depth;
1279 1279 XImage * tempImage;
1280 1280
1281 1281 /* If haven't gotten all of the configs yet, do it now. */
1282 1282 if (asd.numConfigs == 0) {
1283 1283 getAllConfigs (env, screen, &asd);
1284 1284 }
1285 1285
1286 1286 /* Check the graphicsConfig for this visual */
1287 1287 for (i = 0; i < asd.numConfigs; i++) {
1288 1288 AwtGraphicsConfigDataPtr agcPtr = asd.configs[i];
1289 1289 if ((jint)agcPtr->awt_visInfo.visualid == visualNum) {
1290 1290 adata = agcPtr;
1291 1291 break;
1292 1292 }
1293 1293 }
1294 1294
1295 1295 /* If didn't find the visual, throw an exception... */
1296 1296 if (adata == (AwtGraphicsConfigData *) NULL) {
1297 1297 JNU_ThrowIllegalArgumentException(env, "Unknown Visual Specified");
1298 1298 return;
1299 1299 }
1300 1300
1301 1301 /* adata->awt_cmap initialization has been deferred to
1302 1302 * makeColorModel call
1303 1303 */
1304 1304
1305 1305 JNU_SetLongFieldFromPtr(env, this, x11GraphicsConfigIDs.aData, adata);
1306 1306
1307 1307 depth = adata->awt_visInfo.depth;
1308 1308 tempImage = XCreateImage(awt_display,
1309 1309 adata->awt_visInfo.visual,
1310 1310 depth, ZPixmap, 0, NULL, 1, 1, 32, 0);
1311 1311 adata->pixelStride = (tempImage->bits_per_pixel + 7) / 8;
1312 1312 (*env)->SetIntField(env, this, x11GraphicsConfigIDs.bitsPerPixel,
1313 1313 (jint)tempImage->bits_per_pixel);
1314 1314 XDestroyImage(tempImage);
1315 1315 #endif /* !HEADLESS */
1316 1316 }
1317 1317
1318 1318
1319 1319
1320 1320 /*
1321 1321 * Class: sun_awt_X11GraphicsConfig
1322 1322 * Method: makeColorModel
1323 1323 * Signature: ()Ljava/awt/image/ColorModel
1324 1324 */
1325 1325 JNIEXPORT jobject JNICALL
1326 1326 Java_sun_awt_X11GraphicsConfig_makeColorModel(
1327 1327 JNIEnv *env, jobject this)
1328 1328 {
1329 1329 #ifdef HEADLESS
1330 1330 return NULL;
1331 1331 #else
1332 1332 AwtGraphicsConfigData *adata;
1333 1333 jobject colorModel;
1334 1334
1335 1335 /*
1336 1336 * If awt is not locked yet, return null since the toolkit is not
1337 1337 * initialized yet.
1338 1338 */
1339 1339 if (!awtLockInited) {
1340 1340 return NULL;
1341 1341 }
1342 1342
1343 1343 AWT_LOCK ();
1344 1344
1345 1345 adata = (AwtGraphicsConfigData *) JNU_GetLongFieldAsPtr(env, this,
1346 1346 x11GraphicsConfigIDs.aData);
1347 1347
1348 1348 /* If colormap entry of adata is NULL, need to create it now */
1349 1349 if (adata->awt_cmap == (Colormap) NULL) {
1350 1350 awtJNI_CreateColorData (env, adata, 1);
1351 1351 }
1352 1352
1353 1353 /* Make Color Model object for this GraphicsConfiguration */
1354 1354 colorModel = (*env)->ExceptionCheck(env)
1355 1355 ? NULL : awtJNI_GetColorModel (env, adata);
1356 1356
1357 1357 AWT_UNLOCK ();
1358 1358
1359 1359 return colorModel;
1360 1360 #endif /* !HEADLESS */
1361 1361 }
1362 1362
1363 1363
1364 1364 /*
1365 1365 * Class: sun_awt_X11GraphicsConfig
1366 1366 * Method: getBounds
1367 1367 * Signature: ()Ljava/awt/Rectangle
1368 1368 */
1369 1369 JNIEXPORT jobject JNICALL
1370 1370 Java_sun_awt_X11GraphicsConfig_pGetBounds(JNIEnv *env, jobject this, jint screen)
1371 1371 {
1372 1372 #ifdef HEADLESS
1373 1373 return NULL;
1374 1374 #else
1375 1375 jclass clazz;
1376 1376 jmethodID mid;
1377 1377 jobject bounds = NULL;
1378 1378 AwtGraphicsConfigDataPtr adata;
1379 1379
1380 1380 adata = (AwtGraphicsConfigDataPtr)
1381 1381 JNU_GetLongFieldAsPtr(env, this, x11GraphicsConfigIDs.aData);
1382 1382
1383 1383 clazz = (*env)->FindClass(env, "java/awt/Rectangle");
1384 1384 CHECK_NULL_RETURN(clazz, NULL);
1385 1385 mid = (*env)->GetMethodID(env, clazz, "<init>", "(IIII)V");
1386 1386 if (mid != NULL) {
1387 1387 if (usingXinerama) {
1388 1388 if (0 <= screen && screen < awt_numScreens) {
1389 1389 bounds = (*env)->NewObject(env, clazz, mid, fbrects[screen].x,
1390 1390 fbrects[screen].y,
1391 1391 fbrects[screen].width,
1392 1392 fbrects[screen].height);
1393 1393 } else {
1394 1394 jclass exceptionClass = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
1395 1395 if (exceptionClass != NULL) {
1396 1396 (*env)->ThrowNew(env, exceptionClass, "Illegal screen index");
1397 1397 }
1398 1398 }
1399 1399 } else {
1400 1400 XWindowAttributes xwa;
1401 1401 memset(&xwa, 0, sizeof(xwa));
1402 1402
1403 1403 AWT_LOCK ();
1404 1404 XGetWindowAttributes(awt_display,
1405 1405 RootWindow(awt_display, adata->awt_visInfo.screen),
1406 1406 &xwa);
1407 1407 AWT_UNLOCK ();
1408 1408
1409 1409 bounds = (*env)->NewObject(env, clazz, mid, 0, 0,
1410 1410 xwa.width, xwa.height);
1411 1411 }
1412 1412
1413 1413 if ((*env)->ExceptionOccurred(env)) {
1414 1414 return NULL;
1415 1415 }
1416 1416 }
1417 1417 return bounds;
1418 1418 #endif /* !HEADLESS */
1419 1419 }
1420 1420
1421 1421 /*
1422 1422 * Class: sun_awt_X11GraphicsConfig
1423 1423 * Method: createBackBuffer
1424 1424 * Signature: (JI)J
1425 1425 */
1426 1426 JNIEXPORT jlong JNICALL
1427 1427 Java_sun_awt_X11GraphicsConfig_createBackBuffer
1428 1428 (JNIEnv *env, jobject this, jlong window, jint swapAction)
1429 1429 {
1430 1430 int32_t v1, v2;
1431 1431 XdbeBackBuffer ret = (unsigned long) 0;
1432 1432 Window w = (Window)window;
1433 1433 AWT_LOCK();
1434 1434 if (!XdbeQueryExtension(awt_display, &v1, &v2)) {
1435 1435 JNU_ThrowByName(env, "java/lang/Exception",
1436 1436 "Could not query double-buffer extension");
1437 1437 AWT_UNLOCK();
1438 1438 return (jlong)0;
1439 1439 }
1440 1440 ret = XdbeAllocateBackBufferName(awt_display, w,
1441 1441 (XdbeSwapAction)swapAction);
1442 1442 AWT_FLUSH_UNLOCK();
1443 1443 return (jlong)ret;
1444 1444 }
1445 1445
1446 1446 /*
1447 1447 * Class: sun_awt_X11GraphicsConfig
1448 1448 * Method: destroyBackBuffer
1449 1449 * Signature: (J)V
1450 1450 */
1451 1451 JNIEXPORT void JNICALL
1452 1452 Java_sun_awt_X11GraphicsConfig_destroyBackBuffer
1453 1453 (JNIEnv *env, jobject this, jlong backBuffer)
1454 1454 {
1455 1455 AWT_LOCK();
1456 1456 XdbeDeallocateBackBufferName(awt_display, (XdbeBackBuffer)backBuffer);
1457 1457 AWT_FLUSH_UNLOCK();
1458 1458 }
1459 1459
1460 1460 /*
1461 1461 * Class: sun_awt_X11GraphicsConfig
1462 1462 * Method: swapBuffers
1463 1463 * Signature: (JI)V
1464 1464 */
1465 1465 JNIEXPORT void JNICALL
1466 1466 Java_sun_awt_X11GraphicsConfig_swapBuffers
1467 1467 (JNIEnv *env, jobject this,
1468 1468 jlong window, jint swapAction)
1469 1469 {
1470 1470 XdbeSwapInfo swapInfo;
1471 1471
1472 1472 AWT_LOCK();
1473 1473
1474 1474 XdbeBeginIdiom(awt_display);
1475 1475 swapInfo.swap_window = (Window)window;
1476 1476 swapInfo.swap_action = (XdbeSwapAction)swapAction;
1477 1477 if (!XdbeSwapBuffers(awt_display, &swapInfo, 1)) {
1478 1478 JNU_ThrowInternalError(env, "Could not swap buffers");
1479 1479 }
1480 1480 XdbeEndIdiom(awt_display);
1481 1481
1482 1482 AWT_FLUSH_UNLOCK();
1483 1483 }
1484 1484
1485 1485 /*
1486 1486 * Class: sun_awt_X11GraphicsConfig
1487 1487 * Method: isTranslucencyCapable
1488 1488 * Signature: (J)V
1489 1489 */
1490 1490 JNIEXPORT jboolean JNICALL
1491 1491 Java_sun_awt_X11GraphicsConfig_isTranslucencyCapable
1492 1492 (JNIEnv *env, jobject this, jlong configData)
1493 1493 {
1494 1494 #ifdef HEADLESS
1495 1495 return JNI_FALSE;
1496 1496 #else
1497 1497 AwtGraphicsConfigDataPtr aData = (AwtGraphicsConfigDataPtr)jlong_to_ptr(configData);
1498 1498 if (aData == NULL) {
1499 1499 return JNI_FALSE;
1500 1500 }
1501 1501 return aData->isTranslucencySupported ? JNI_TRUE : JNI_FALSE;
1502 1502 #endif
1503 1503 }
1504 1504
1505 1505 /*
1506 1506 * Class: sun_awt_X11GraphicsDevice
1507 1507 * Method: isDBESupported
1508 1508 * Signature: ()Z
1509 1509 */
1510 1510 JNIEXPORT jboolean JNICALL
1511 1511 Java_sun_awt_X11GraphicsDevice_isDBESupported(JNIEnv *env, jobject this)
1512 1512 {
1513 1513 #ifdef HEADLESS
1514 1514 return JNI_FALSE;
1515 1515 #else
1516 1516 int opcode = 0, firstEvent = 0, firstError = 0;
1517 1517 jboolean ret;
1518 1518
1519 1519 AWT_LOCK();
1520 1520 ret = (jboolean)XQueryExtension(awt_display, "DOUBLE-BUFFER",
1521 1521 &opcode, &firstEvent, &firstError);
1522 1522 AWT_FLUSH_UNLOCK();
1523 1523 return ret;
1524 1524 #endif /* !HEADLESS */
1525 1525 }
1526 1526
1527 1527 /*
1528 1528 * Class: sun_awt_X11GraphicsDevice
1529 1529 * Method: getDoubleBufferVisuals
1530 1530 * Signature: (I)V
1531 1531 */
1532 1532 JNIEXPORT void JNICALL
1533 1533 Java_sun_awt_X11GraphicsDevice_getDoubleBufferVisuals(JNIEnv *env,
1534 1534 jobject this, jint screen)
1535 1535 {
1536 1536 #ifndef HEADLESS
1537 1537 jclass clazz;
1538 1538 jmethodID midAddVisual;
1539 1539 Window rootWindow;
1540 1540 int i, n = 1;
1541 1541 XdbeScreenVisualInfo* visScreenInfo;
1542 1542 int xinawareScreen;
1543 1543
1544 1544 if (usingXinerama) {
1545 1545 xinawareScreen = 0;
1546 1546 }
1547 1547 else {
1548 1548 xinawareScreen = screen;
1549 1549 }
1550 1550
1551 1551 clazz = (*env)->GetObjectClass(env, this);
1552 1552 midAddVisual = (*env)->GetMethodID(env, clazz, "addDoubleBufferVisual",
1553 1553 "(I)V");
1554 1554 CHECK_NULL(midAddVisual);
1555 1555 AWT_LOCK();
1556 1556 rootWindow = RootWindow(awt_display, xinawareScreen);
1557 1557 visScreenInfo = XdbeGetVisualInfo(awt_display, &rootWindow, &n);
1558 1558 if (visScreenInfo == NULL) {
1559 1559 JNU_ThrowInternalError(env, "Could not get visual info");
1560 1560 AWT_UNLOCK();
1561 1561 return;
1562 1562 }
1563 1563 AWT_FLUSH_UNLOCK();
1564 1564 for (i = 0; i < visScreenInfo->count; i++) {
1565 1565 XdbeVisualInfo* visInfo = visScreenInfo->visinfo;
1566 1566 (*env)->CallVoidMethod(env, this, midAddVisual, (visInfo[i]).visual);
1567 1567 if ((*env)->ExceptionCheck(env)) {
1568 1568 break;
1569 1569 }
1570 1570 }
1571 1571 #endif /* !HEADLESS */
1572 1572 }
1573 1573
1574 1574 /*
1575 1575 * Class: sun_awt_X11GraphicsEnvironment
1576 1576 * Method: pRunningXinerama
1577 1577 * Signature: ()Z
1578 1578 */
1579 1579 JNIEXPORT jboolean JNICALL
1580 1580 Java_sun_awt_X11GraphicsEnvironment_pRunningXinerama(JNIEnv *env,
1581 1581 jobject this)
1582 1582 {
1583 1583 #ifdef HEADLESS
1584 1584 return JNI_FALSE;
1585 1585 #else
1586 1586 return usingXinerama ? JNI_TRUE : JNI_FALSE;
1587 1587 #endif /* HEADLESS */
1588 1588 }
1589 1589
1590 1590 /*
1591 1591 * Can return NULL.
1592 1592 *
1593 1593 * Class: sun_awt_X11GraphicsEnvironment
1594 1594 * Method: getXineramaCenterPoint
1595 1595 * Signature: ()Ljava/awt/Point
1596 1596 */
1597 1597 JNIEXPORT jobject JNICALL
1598 1598 Java_sun_awt_X11GraphicsEnvironment_getXineramaCenterPoint(JNIEnv *env,
1599 1599 jobject this)
1600 1600 {
1601 1601 jobject point = NULL;
1602 1602 #ifndef HEADLESS /* return NULL in HEADLESS, Linux */
1603 1603 #if !defined(__linux__) && !defined(MACOSX)
1604 1604 int x,y;
1605 1605
1606 1606 AWT_LOCK();
1607 1607 DASSERT(usingXinerama);
1608 1608 if (XineramaSolarisCenterFunc != NULL) {
1609 1609 (XineramaSolarisCenterFunc)(awt_display, 0, &x, &y);
1610 1610 point = JNU_NewObjectByName(env, "java/awt/Point","(II)V", x, y);
1611 1611 DASSERT(point);
1612 1612 } else {
1613 1613 DTRACE_PRINTLN("unable to call XineramaSolarisCenterFunc: symbol is null");
1614 1614 }
1615 1615 AWT_FLUSH_UNLOCK();
1616 1616 #endif /* __linux __ || MACOSX */
1617 1617 #endif /* HEADLESS */
1618 1618 return point;
1619 1619 }
1620 1620
1621 1621
1622 1622 /**
1623 1623 * Begin DisplayMode/FullScreen support
1624 1624 */
1625 1625
1626 1626 #ifndef HEADLESS
1627 1627
1628 1628 #define BIT_DEPTH_MULTI java_awt_DisplayMode_BIT_DEPTH_MULTI
1629 1629 #define REFRESH_RATE_UNKNOWN java_awt_DisplayMode_REFRESH_RATE_UNKNOWN
1630 1630
1631 1631 typedef Status
1632 1632 (*XRRQueryVersionType) (Display *dpy, int *major_versionp, int *minor_versionp);
1633 1633 typedef XRRScreenConfiguration*
1634 1634 (*XRRGetScreenInfoType)(Display *dpy, Drawable root);
1635 1635 typedef void
1636 1636 (*XRRFreeScreenConfigInfoType)(XRRScreenConfiguration *config);
1637 1637 typedef short*
1638 1638 (*XRRConfigRatesType)(XRRScreenConfiguration *config,
1639 1639 int sizeID, int *nrates);
1640 1640 typedef short
1641 1641 (*XRRConfigCurrentRateType)(XRRScreenConfiguration *config);
1642 1642 typedef XRRScreenSize*
1643 1643 (*XRRConfigSizesType)(XRRScreenConfiguration *config,
1644 1644 int *nsizes);
1645 1645 typedef SizeID
1646 1646 (*XRRConfigCurrentConfigurationType)(XRRScreenConfiguration *config,
1647 1647 Rotation *rotation);
1648 1648 typedef Status
1649 1649 (*XRRSetScreenConfigAndRateType)(Display *dpy,
1650 1650 XRRScreenConfiguration *config,
1651 1651 Drawable draw,
1652 1652 int size_index,
1653 1653 Rotation rotation,
1654 1654 short rate,
1655 1655 Time timestamp);
1656 1656 typedef Rotation
1657 1657 (*XRRConfigRotationsType)(XRRScreenConfiguration *config,
1658 1658 Rotation *current_rotation);
1659 1659
1660 1660 typedef XRRScreenResources* (*XRRGetScreenResourcesType)(Display *dpy,
1661 1661 Window window);
1662 1662
1663 1663 typedef void (*XRRFreeScreenResourcesType)(XRRScreenResources *resources);
1664 1664
1665 1665 typedef XRROutputInfo * (*XRRGetOutputInfoType)(Display *dpy,
1666 1666 XRRScreenResources *resources, RROutput output);
1667 1667
1668 1668 typedef void (*XRRFreeOutputInfoType)(XRROutputInfo *outputInfo);
1669 1669
1670 1670 static XRRQueryVersionType awt_XRRQueryVersion;
1671 1671 static XRRGetScreenInfoType awt_XRRGetScreenInfo;
1672 1672 static XRRFreeScreenConfigInfoType awt_XRRFreeScreenConfigInfo;
1673 1673 static XRRConfigRatesType awt_XRRConfigRates;
1674 1674 static XRRConfigCurrentRateType awt_XRRConfigCurrentRate;
1675 1675 static XRRConfigSizesType awt_XRRConfigSizes;
1676 1676 static XRRConfigCurrentConfigurationType awt_XRRConfigCurrentConfiguration;
1677 1677 static XRRSetScreenConfigAndRateType awt_XRRSetScreenConfigAndRate;
1678 1678 static XRRConfigRotationsType awt_XRRConfigRotations;
1679 1679 static XRRGetScreenResourcesType awt_XRRGetScreenResources;
1680 1680 static XRRFreeScreenResourcesType awt_XRRFreeScreenResources;
1681 1681 static XRRGetOutputInfoType awt_XRRGetOutputInfo;
1682 1682 static XRRFreeOutputInfoType awt_XRRFreeOutputInfo;
1683 1683
1684 1684 #define LOAD_XRANDR_FUNC(f) \
1685 1685 do { \
1686 1686 awt_##f = (f##Type)dlsym(pLibRandR, #f); \
1687 1687 if (awt_##f == NULL) { \
1688 1688 J2dRlsTraceLn1(J2D_TRACE_ERROR, \
1689 1689 "X11GD_InitXrandrFuncs: Could not load %s", #f); \
1690 1690 dlclose(pLibRandR); \
1691 1691 return JNI_FALSE; \
1692 1692 } \
1693 1693 } while (0)
1694 1694
1695 1695 static jboolean
1696 1696 X11GD_InitXrandrFuncs(JNIEnv *env)
1697 1697 {
1698 1698 int rr_maj_ver = 0, rr_min_ver = 0;
1699 1699
1700 1700 void *pLibRandR = dlopen(VERSIONED_JNI_LIB_NAME("Xrandr", "2"),
1701 1701 RTLD_LAZY | RTLD_LOCAL);
1702 1702 if (pLibRandR == NULL) {
1703 1703 pLibRandR = dlopen(JNI_LIB_NAME("Xrandr"), RTLD_LAZY | RTLD_LOCAL);
1704 1704 }
1705 1705 if (pLibRandR == NULL) {
1706 1706 J2dRlsTraceLn(J2D_TRACE_ERROR,
1707 1707 "X11GD_InitXrandrFuncs: Could not open libXrandr.so.2");
1708 1708 return JNI_FALSE;
1709 1709 }
1710 1710
1711 1711 LOAD_XRANDR_FUNC(XRRQueryVersion);
1712 1712
1713 1713 if (!(*awt_XRRQueryVersion)(awt_display, &rr_maj_ver, &rr_min_ver)) {
1714 1714 J2dRlsTraceLn(J2D_TRACE_ERROR,
1715 1715 "X11GD_InitXrandrFuncs: XRRQueryVersion returned an error status");
1716 1716 dlclose(pLibRandR);
1717 1717 return JNI_FALSE;
1718 1718 }
1719 1719
1720 1720 if (usingXinerama) {
1721 1721 /*
1722 1722 * We can proceed as long as this is RANDR 1.2 or above.
1723 1723 * As of Xorg server 1.3 onwards the Xinerama backend may actually be
1724 1724 * a fake one provided by RANDR itself. See Java bug 6636469 for info.
1725 1725 */
1726 1726 if (!(rr_maj_ver > 1 || (rr_maj_ver == 1 && rr_min_ver >= 2))) {
1727 1727 J2dRlsTraceLn2(J2D_TRACE_INFO, "X11GD_InitXrandrFuncs: Can't use Xrandr. "
1728 1728 "Xinerama is active and Xrandr version is %d.%d",
1729 1729 rr_maj_ver, rr_min_ver);
1730 1730 dlclose(pLibRandR);
1731 1731 return JNI_FALSE;
1732 1732 }
1733 1733
1734 1734 /*
1735 1735 * REMIND: Fullscreen mode doesn't work quite right with multi-monitor
1736 1736 * setups and RANDR 1.2.
1737 1737 */
1738 1738 if ((rr_maj_ver == 1 && rr_min_ver <= 2) && awt_numScreens > 1) {
1739 1739 J2dRlsTraceLn(J2D_TRACE_INFO, "X11GD_InitXrandrFuncs: Can't use Xrandr. "
1740 1740 "Multiple screens in use");
1741 1741 dlclose(pLibRandR);
1742 1742 return JNI_FALSE;
1743 1743 }
1744 1744 }
1745 1745
1746 1746 LOAD_XRANDR_FUNC(XRRGetScreenInfo);
1747 1747 LOAD_XRANDR_FUNC(XRRFreeScreenConfigInfo);
1748 1748 LOAD_XRANDR_FUNC(XRRConfigRates);
1749 1749 LOAD_XRANDR_FUNC(XRRConfigCurrentRate);
1750 1750 LOAD_XRANDR_FUNC(XRRConfigSizes);
1751 1751 LOAD_XRANDR_FUNC(XRRConfigCurrentConfiguration);
1752 1752 LOAD_XRANDR_FUNC(XRRSetScreenConfigAndRate);
1753 1753 LOAD_XRANDR_FUNC(XRRConfigRotations);
1754 1754 LOAD_XRANDR_FUNC(XRRGetScreenResources);
1755 1755 LOAD_XRANDR_FUNC(XRRFreeScreenResources);
1756 1756 LOAD_XRANDR_FUNC(XRRGetOutputInfo);
1757 1757 LOAD_XRANDR_FUNC(XRRFreeOutputInfo);
1758 1758
1759 1759 return JNI_TRUE;
1760 1760 }
1761 1761
1762 1762 static jobject
1763 1763 X11GD_CreateDisplayMode(JNIEnv *env, jint width, jint height,
1764 1764 jint bitDepth, jint refreshRate)
1765 1765 {
1766 1766 jclass displayModeClass;
1767 1767 jmethodID cid;
1768 1768 jint validRefreshRate = refreshRate;
1769 1769
1770 1770 displayModeClass = (*env)->FindClass(env, "java/awt/DisplayMode");
1771 1771 CHECK_NULL_RETURN(displayModeClass, NULL);
1772 1772 if (JNU_IsNull(env, displayModeClass)) {
1773 1773 JNU_ThrowInternalError(env,
1774 1774 "Could not get display mode class");
1775 1775 return NULL;
1776 1776 }
1777 1777
1778 1778 cid = (*env)->GetMethodID(env, displayModeClass, "<init>", "(IIII)V");
1779 1779 CHECK_NULL_RETURN(cid, NULL);
1780 1780 if (cid == NULL) {
1781 1781 JNU_ThrowInternalError(env,
1782 1782 "Could not get display mode constructor");
1783 1783 return NULL;
1784 1784 }
1785 1785
1786 1786 // early versions of xrandr may report "empty" rates (6880694)
1787 1787 if (validRefreshRate <= 0) {
1788 1788 validRefreshRate = REFRESH_RATE_UNKNOWN;
1789 1789 }
1790 1790
1791 1791 return (*env)->NewObject(env, displayModeClass, cid,
1792 1792 width, height, bitDepth, validRefreshRate);
1793 1793 }
1794 1794
1795 1795 static void
1796 1796 X11GD_AddDisplayMode(JNIEnv *env, jobject arrayList,
1797 1797 jint width, jint height,
1798 1798 jint bitDepth, jint refreshRate)
1799 1799 {
1800 1800 jobject displayMode = X11GD_CreateDisplayMode(env, width, height,
1801 1801 bitDepth, refreshRate);
1802 1802 if (!JNU_IsNull(env, displayMode)) {
1803 1803 jclass arrayListClass;
1804 1804 jmethodID mid;
1805 1805 arrayListClass = (*env)->GetObjectClass(env, arrayList);
1806 1806 if (JNU_IsNull(env, arrayListClass)) {
1807 1807 JNU_ThrowInternalError(env,
1808 1808 "Could not get class java.util.ArrayList");
1809 1809 return;
1810 1810 }
1811 1811 mid = (*env)->GetMethodID(env, arrayListClass, "add",
1812 1812 "(Ljava/lang/Object;)Z");
1813 1813 CHECK_NULL(mid);
1814 1814 if (mid == NULL) {
1815 1815 JNU_ThrowInternalError(env,
1816 1816 "Could not get method java.util.ArrayList.add()");
1817 1817 return;
1818 1818 }
1819 1819 (*env)->CallObjectMethod(env, arrayList, mid, displayMode);
1820 1820 (*env)->DeleteLocalRef(env, displayMode);
1821 1821 }
1822 1822 }
1823 1823
1824 1824 static void
1825 1825 X11GD_SetFullscreenMode(Window win, jboolean enabled)
1826 1826 {
1827 1827 Atom wmState = XInternAtom(awt_display, "_NET_WM_STATE", False);
1828 1828 Atom wmStateFs = XInternAtom(awt_display,
1829 1829 "_NET_WM_STATE_FULLSCREEN", False);
1830 1830 XWindowAttributes attr;
1831 1831 XEvent event;
1832 1832
1833 1833 if (wmState == None || wmStateFs == None
1834 1834 || !XGetWindowAttributes(awt_display, win, &attr)) {
1835 1835 return;
1836 1836 }
1837 1837
1838 1838 memset(&event, 0, sizeof(event));
1839 1839 event.xclient.type = ClientMessage;
1840 1840 event.xclient.message_type = wmState;
1841 1841 event.xclient.display = awt_display;
1842 1842 event.xclient.window = win;
1843 1843 event.xclient.format = 32;
1844 1844 event.xclient.data.l[0] = enabled ? 1 : 0; // 1==add, 0==remove
1845 1845 event.xclient.data.l[1] = wmStateFs;
1846 1846
1847 1847 XSendEvent(awt_display, attr.root, False,
1848 1848 SubstructureRedirectMask | SubstructureNotifyMask,
1849 1849 &event);
1850 1850 XSync(awt_display, False);
1851 1851 }
1852 1852 #endif /* !HEADLESS */
1853 1853
1854 1854 /*
1855 1855 * Class: sun_awt_X11GraphicsDevice
1856 1856 * Method: initXrandrExtension
1857 1857 * Signature: ()Z
1858 1858 */
1859 1859 JNIEXPORT jboolean JNICALL
1860 1860 Java_sun_awt_X11GraphicsDevice_initXrandrExtension
1861 1861 (JNIEnv *env, jclass x11gd)
1862 1862 {
1863 1863 #ifdef HEADLESS
1864 1864 return JNI_FALSE;
1865 1865 #else
1866 1866 int opcode = 0, firstEvent = 0, firstError = 0;
1867 1867 jboolean ret;
1868 1868
1869 1869 AWT_LOCK();
1870 1870 ret = (jboolean)XQueryExtension(awt_display, "RANDR",
1871 1871 &opcode, &firstEvent, &firstError);
1872 1872 if (ret) {
1873 1873 ret = X11GD_InitXrandrFuncs(env);
1874 1874 }
1875 1875 AWT_FLUSH_UNLOCK();
1876 1876
1877 1877 return ret;
1878 1878 #endif /* HEADLESS */
1879 1879 }
1880 1880
1881 1881 /*
1882 1882 * Class: sun_awt_X11GraphicsDevice
1883 1883 * Method: getCurrentDisplayMode
1884 1884 * Signature: (I)Ljava/awt/DisplayMode;
1885 1885 */
1886 1886 JNIEXPORT jobject JNICALL
1887 1887 Java_sun_awt_X11GraphicsDevice_getCurrentDisplayMode
1888 1888 (JNIEnv* env, jclass x11gd, jint screen)
1889 1889 {
1890 1890 #ifdef HEADLESS
1891 1891 return NULL;
1892 1892 #else
1893 1893 XRRScreenConfiguration *config;
1894 1894 jobject displayMode = NULL;
1895 1895
1896 1896 AWT_LOCK();
1897 1897
1898 1898 if (screen < ScreenCount(awt_display)) {
1899 1899
1900 1900 config = awt_XRRGetScreenInfo(awt_display,
1901 1901 RootWindow(awt_display, screen));
1902 1902 if (config != NULL) {
1903 1903 Rotation rotation;
1904 1904 short curRate;
1905 1905 SizeID curSizeIndex;
1906 1906 XRRScreenSize *sizes;
1907 1907 int nsizes;
1908 1908
1909 1909 curSizeIndex = awt_XRRConfigCurrentConfiguration(config, &rotation);
1910 1910 sizes = awt_XRRConfigSizes(config, &nsizes);
1911 1911 curRate = awt_XRRConfigCurrentRate(config);
1912 1912
1913 1913 if ((sizes != NULL) &&
1914 1914 (curSizeIndex < nsizes))
1915 1915 {
1916 1916 XRRScreenSize curSize = sizes[curSizeIndex];
1917 1917 displayMode = X11GD_CreateDisplayMode(env,
1918 1918 curSize.width,
1919 1919 curSize.height,
1920 1920 BIT_DEPTH_MULTI,
1921 1921 curRate);
1922 1922 }
1923 1923
1924 1924 awt_XRRFreeScreenConfigInfo(config);
1925 1925 }
1926 1926 }
1927 1927
1928 1928 AWT_FLUSH_UNLOCK();
1929 1929
1930 1930 return displayMode;
1931 1931 #endif /* HEADLESS */
1932 1932 }
1933 1933
1934 1934 /*
1935 1935 * Class: sun_awt_X11GraphicsDevice
1936 1936 * Method: enumDisplayModes
1937 1937 * Signature: (ILjava/util/ArrayList;)V
1938 1938 */
1939 1939 JNIEXPORT void JNICALL
1940 1940 Java_sun_awt_X11GraphicsDevice_enumDisplayModes
1941 1941 (JNIEnv* env, jclass x11gd,
1942 1942 jint screen, jobject arrayList)
1943 1943 {
1944 1944 #ifndef HEADLESS
1945 1945
1946 1946 AWT_LOCK();
1947 1947
1948 1948 if (usingXinerama && XScreenCount(awt_display) > 0) {
1949 1949 XRRScreenResources *res = awt_XRRGetScreenResources(awt_display,
1950 1950 RootWindow(awt_display, 0));
1951 1951 if (res) {
1952 1952 if (res->noutput > screen) {
1953 1953 XRROutputInfo *output_info = awt_XRRGetOutputInfo(awt_display,
1954 1954 res, res->outputs[screen]);
1955 1955 if (output_info) {
1956 1956 int i;
1957 1957 for (i = 0; i < res->nmode; i++) {
1958 1958 RRMode m = output_info->modes[i];
1959 1959 int j;
1960 1960 XRRModeInfo *mode;
1961 1961 for (j = 0; j < res->nmode; j++) {
1962 1962 mode = &res->modes[j];
1963 1963 if (mode->id == m) {
1964 1964 float rate = 0;
1965 1965 if (mode->hTotal && mode->vTotal) {
1966 1966 rate = ((float)mode->dotClock /
1967 1967 ((float)mode->hTotal *
1968 1968 (float)mode->vTotal));
1969 1969 }
1970 1970 X11GD_AddDisplayMode(env, arrayList,
1971 1971 mode->width, mode->height,
1972 1972 BIT_DEPTH_MULTI, (int)(rate +.2));
1973 1973 break;
1974 1974 }
1975 1975 }
1976 1976 }
1977 1977 awt_XRRFreeOutputInfo(output_info);
1978 1978 }
1979 1979 }
1980 1980 awt_XRRFreeScreenResources(res);
1981 1981 }
1982 1982 } else {
1983 1983 XRRScreenConfiguration *config;
1984 1984
1985 1985 config = awt_XRRGetScreenInfo(awt_display,
1986 1986 RootWindow(awt_display, screen));
1987 1987 if (config != NULL) {
1988 1988 int nsizes, i, j;
1989 1989 XRRScreenSize *sizes = awt_XRRConfigSizes(config, &nsizes);
1990 1990
1991 1991 if (sizes != NULL) {
1992 1992 for (i = 0; i < nsizes; i++) {
1993 1993 int nrates;
1994 1994 XRRScreenSize size = sizes[i];
1995 1995 short *rates = awt_XRRConfigRates(config, i, &nrates);
1996 1996
1997 1997 for (j = 0; j < nrates; j++) {
1998 1998 X11GD_AddDisplayMode(env, arrayList,
1999 1999 size.width,
2000 2000 size.height,
2001 2001 BIT_DEPTH_MULTI,
2002 2002 rates[j]);
2003 2003 if ((*env)->ExceptionCheck(env)) {
2004 2004 break;
2005 2005 }
2006 2006 }
2007 2007 }
2008 2008 }
2009 2009
2010 2010 awt_XRRFreeScreenConfigInfo(config);
2011 2011 }
2012 2012 }
2013 2013
2014 2014 AWT_FLUSH_UNLOCK();
2015 2015 #endif /* !HEADLESS */
2016 2016 }
2017 2017
2018 2018 /*
2019 2019 * Class: sun_awt_X11GraphicsDevice
2020 2020 * Method: configDisplayMode
2021 2021 * Signature: (IIII)V
2022 2022 */
2023 2023 JNIEXPORT void JNICALL
2024 2024 Java_sun_awt_X11GraphicsDevice_configDisplayMode
2025 2025 (JNIEnv* env, jclass x11gd,
2026 2026 jint screen, jint width, jint height, jint refreshRate)
2027 2027 {
2028 2028 #ifndef HEADLESS
2029 2029 jboolean success = JNI_FALSE;
2030 2030 XRRScreenConfiguration *config;
2031 2031 Drawable root;
2032 2032 Rotation currentRotation = RR_Rotate_0;
2033 2033
2034 2034 AWT_LOCK();
2035 2035
2036 2036 root = RootWindow(awt_display, screen);
2037 2037 config = awt_XRRGetScreenInfo(awt_display, root);
2038 2038 if (config != NULL) {
2039 2039 jboolean foundConfig = JNI_FALSE;
2040 2040 int chosenSizeIndex = -1;
2041 2041 short chosenRate = -1;
2042 2042 int nsizes;
2043 2043 XRRScreenSize *sizes = awt_XRRConfigSizes(config, &nsizes);
2044 2044 awt_XRRConfigRotations(config, ¤tRotation);
2045 2045
2046 2046 if (sizes != NULL) {
2047 2047 int i, j;
2048 2048
2049 2049 /* find the size index that matches the requested dimensions */
2050 2050 for (i = 0; i < nsizes; i++) {
2051 2051 XRRScreenSize size = sizes[i];
2052 2052
2053 2053 if ((size.width == width) && (size.height == height)) {
2054 2054 /* we've found our size index... */
2055 2055 int nrates;
2056 2056 short *rates = awt_XRRConfigRates(config, i, &nrates);
2057 2057
2058 2058 /* now find rate that matches requested refresh rate */
2059 2059 for (j = 0; j < nrates; j++) {
2060 2060 if (rates[j] == refreshRate) {
2061 2061 /* we've found our rate; break out of the loop */
2062 2062 chosenSizeIndex = i;
2063 2063 chosenRate = rates[j];
2064 2064 foundConfig = JNI_TRUE;
2065 2065 break;
2066 2066 }
2067 2067 }
2068 2068
2069 2069 break;
2070 2070 }
2071 2071 }
2072 2072 }
2073 2073
2074 2074 if (foundConfig) {
2075 2075 Status status =
2076 2076 awt_XRRSetScreenConfigAndRate(awt_display, config, root,
2077 2077 chosenSizeIndex,
2078 2078 currentRotation,
2079 2079 chosenRate,
2080 2080 CurrentTime);
2081 2081
2082 2082 /* issue XSync to ensure immediate mode change */
2083 2083 XSync(awt_display, False);
2084 2084
2085 2085 if (status == RRSetConfigSuccess) {
2086 2086 success = JNI_TRUE;
2087 2087 }
2088 2088 }
2089 2089
2090 2090 awt_XRRFreeScreenConfigInfo(config);
2091 2091 }
2092 2092
2093 2093 AWT_FLUSH_UNLOCK();
2094 2094
2095 2095 if (!success && !(*env)->ExceptionCheck(env)) {
2096 2096 JNU_ThrowInternalError(env, "Could not set display mode");
2097 2097 }
2098 2098 #endif /* !HEADLESS */
2099 2099 }
2100 2100
2101 2101 /*
2102 2102 * Class: sun_awt_X11GraphicsDevice
2103 2103 * Method: enterFullScreenExclusive
2104 2104 * Signature: (J)V
2105 2105 */
2106 2106 JNIEXPORT void JNICALL
2107 2107 Java_sun_awt_X11GraphicsDevice_enterFullScreenExclusive
2108 2108 (JNIEnv* env, jclass x11gd,
2109 2109 jlong window)
2110 2110 {
2111 2111 #ifndef HEADLESS
2112 2112 Window win = (Window)window;
2113 2113
2114 2114 AWT_LOCK();
2115 2115 XSync(awt_display, False); /* ensures window is visible first */
2116 2116 X11GD_SetFullscreenMode(win, JNI_TRUE);
2117 2117 AWT_UNLOCK();
2118 2118 #endif /* !HEADLESS */
2119 2119 }
2120 2120
2121 2121 /*
2122 2122 * Class: sun_awt_X11GraphicsDevice
2123 2123 * Method: exitFullScreenExclusive
2124 2124 * Signature: (J)V
2125 2125 */
2126 2126 JNIEXPORT void JNICALL
2127 2127 Java_sun_awt_X11GraphicsDevice_exitFullScreenExclusive
2128 2128 (JNIEnv* env, jclass x11gd,
2129 2129 jlong window)
2130 2130 {
2131 2131 #ifndef HEADLESS
2132 2132 Window win = (Window)window;
2133 2133
2134 2134 AWT_LOCK();
2135 2135 X11GD_SetFullscreenMode(win, JNI_FALSE);
2136 2136 AWT_UNLOCK();
2137 2137 #endif /* !HEADLESS */
2138 2138 }
2139 2139
2140 2140 /**
2141 2141 * End DisplayMode/FullScreen support
2142 2142 */
2143 2143
2144 2144 static char *get_output_screen_name(JNIEnv *env, int screen) {
2145 2145 if (!awt_XRRGetScreenResources || !awt_XRRGetOutputInfo) {
2146 2146 return NULL;
2147 2147 }
2148 2148 char *name = NULL;
2149 2149 AWT_LOCK();
2150 2150 int scr = 0, out = 0;
2151 2151 if (usingXinerama && XScreenCount(awt_display) > 0) {
2152 2152 out = screen;
2153 2153 } else {
2154 2154 scr = screen;
2155 2155 }
2156 2156
2157 2157 XRRScreenResources *res = awt_XRRGetScreenResources(awt_display,
2158 2158 RootWindow(awt_display, scr));
2159 2159 if (res) {
2160 2160 if (res->noutput > out) {
2161 2161 XRROutputInfo *output_info = awt_XRRGetOutputInfo(awt_display,
2162 2162 res, res->outputs[out]);
2163 2163 if (output_info) {
2164 2164 if (output_info->name) {
2165 2165 name = strdup(output_info->name);
2166 2166 }
2167 2167 awt_XRRFreeOutputInfo(output_info);
2168 2168 }
2169 2169 }
2170 2170 awt_XRRFreeScreenResources(res);
2171 2171 }
2172 2172 AWT_UNLOCK();
2173 2173 return name;
2174 2174 }
2175 2175
2176 2176 /*
2177 2177 * Class: sun_awt_X11GraphicsDevice
2178 2178 * Method: getNativeScaleFactor
2179 2179 * Signature: (I)D
2180 2180 */
2181 2181 JNIEXPORT jdouble JNICALL
2182 2182 Java_sun_awt_X11GraphicsDevice_getNativeScaleFactor
2183 2183 (JNIEnv *env, jobject this, jint screen) {
2184 2184 char *name = get_output_screen_name(env, screen);
2185 2185 double scale = getNativeScaleFactor(name);
2186 2186 if (name) {
2187 2187 free(name);
2188 2188 }
2189 2189 return scale;
2190 2190 }
↓ open down ↓ |
1735 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX