1/*
2 * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#ifdef HEADLESS
27    #error This file should not be included in headless library
28#endif
29
30#include "awt_p.h"
31#include "java_awt_Component.h"
32
33#include "awt_Component.h"
34
35#include <jni.h>
36#include <jni_util.h>
37#include <jawt_md.h>
38
39extern struct ComponentIDs componentIDs;
40
41#include "awt_GraphicsEnv.h"
42extern jfieldID windowID;
43extern jfieldID targetID;
44extern jfieldID graphicsConfigID;
45extern jfieldID drawStateID;
46extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs;
47
48/*
49 * Lock the surface of the target component for native rendering.
50 * When finished drawing, the surface must be unlocked with
51 * Unlock().  This function returns a bitmask with one or more of the
52 * following values:
53 *
54 * JAWT_LOCK_ERROR - When an error has occurred and the surface could not
55 * be locked.
56 *
57 * JAWT_LOCK_CLIP_CHANGED - When the clip region has changed.
58 *
59 * JAWT_LOCK_BOUNDS_CHANGED - When the bounds of the surface have changed.
60 *
61 * JAWT_LOCK_SURFACE_CHANGED - When the surface itself has changed
62 */
63JNIEXPORT jint JNICALL awt_DrawingSurface_Lock(JAWT_DrawingSurface* ds)
64{
65    JNIEnv* env;
66    jobject target, peer;
67    jclass componentClass;
68    jint drawState;
69
70    if (ds == NULL) {
71#ifdef DEBUG
72        fprintf(stderr, "Drawing Surface is NULL\n");
73#endif
74        return (jint)JAWT_LOCK_ERROR;
75    }
76    env = ds->env;
77    target = ds->target;
78
79    /* Make sure the target is a java.awt.Component */
80    componentClass = (*env)->FindClass(env, "java/awt/Component");
81    CHECK_NULL_RETURN(componentClass, (jint)JAWT_LOCK_ERROR);
82
83    if (!(*env)->IsInstanceOf(env, target, componentClass)) {
84#ifdef DEBUG
85            fprintf(stderr, "Target is not a component\n");
86#endif
87        return (jint)JAWT_LOCK_ERROR;
88        }
89
90    if (!awtLockInited) {
91        return (jint)JAWT_LOCK_ERROR;
92    }
93    AWT_LOCK();
94
95    /* Get the peer of the target component */
96    peer = (*env)->GetObjectField(env, target, componentIDs.peer);
97    if (JNU_IsNull(env, peer)) {
98#ifdef DEBUG
99        fprintf(stderr, "Component peer is NULL\n");
100#endif
101                AWT_FLUSH_UNLOCK();
102        return (jint)JAWT_LOCK_ERROR;
103    }
104
105   drawState = (*env)->GetIntField(env, peer, drawStateID);
106    (*env)->SetIntField(env, peer, drawStateID, 0);
107    return drawState;
108}
109
110JNIEXPORT int32_t JNICALL
111    awt_GetColor(JAWT_DrawingSurface* ds, int32_t r, int32_t g, int32_t b)
112{
113    JNIEnv* env;
114    jobject target, peer;
115    jclass componentClass;
116    AwtGraphicsConfigDataPtr adata;
117    int32_t result;
118     jobject gc_object;
119    if (ds == NULL) {
120#ifdef DEBUG
121        fprintf(stderr, "Drawing Surface is NULL\n");
122#endif
123        return (int32_t) 0;
124    }
125
126    env = ds->env;
127    target = ds->target;
128
129    /* Make sure the target is a java.awt.Component */
130    componentClass = (*env)->FindClass(env, "java/awt/Component");
131    CHECK_NULL_RETURN(componentClass, (int32_t) 0);
132
133    if (!(*env)->IsInstanceOf(env, target, componentClass)) {
134#ifdef DEBUG
135        fprintf(stderr, "DrawingSurface target must be a component\n");
136#endif
137        return (int32_t) 0;
138    }
139
140    if (!awtLockInited) {
141        return (int32_t) 0;
142    }
143
144    AWT_LOCK();
145
146    /* Get the peer of the target component */
147    peer = (*env)->GetObjectField(env, target, componentIDs.peer);
148    if (JNU_IsNull(env, peer)) {
149#ifdef DEBUG
150        fprintf(stderr, "Component peer is NULL\n");
151#endif
152        AWT_UNLOCK();
153        return (int32_t) 0;
154    }
155     /* GraphicsConfiguration object of MComponentPeer */
156    gc_object = (*env)->GetObjectField(env, peer, graphicsConfigID);
157
158    if (gc_object != NULL) {
159        adata = (AwtGraphicsConfigDataPtr)
160            JNU_GetLongFieldAsPtr(env, gc_object,
161                                  x11GraphicsConfigIDs.aData);
162    } else {
163        adata = getDefaultConfig(DefaultScreen(awt_display));
164    }
165
166    result = adata->AwtColorMatch(r, g, b, adata);
167        AWT_UNLOCK();
168        return result;
169}
170
171/*
172 * Get the drawing surface info.
173 * The value returned may be cached, but the values may change if
174 * additional calls to Lock() or Unlock() are made.
175 * Lock() must be called before this can return a valid value.
176 * Returns NULL if an error has occurred.
177 * When finished with the returned value, FreeDrawingSurfaceInfo must be
178 * called.
179 */
180JNIEXPORT JAWT_DrawingSurfaceInfo* JNICALL
181awt_DrawingSurface_GetDrawingSurfaceInfo(JAWT_DrawingSurface* ds)
182{
183    JNIEnv* env;
184    jobject target, peer;
185    jclass componentClass;
186    JAWT_X11DrawingSurfaceInfo* px;
187    JAWT_DrawingSurfaceInfo* p;
188    XWindowAttributes attrs;
189
190    if (ds == NULL) {
191#ifdef DEBUG
192        fprintf(stderr, "Drawing Surface is NULL\n");
193#endif
194        return NULL;
195    }
196
197    env = ds->env;
198    target = ds->target;
199
200    /* Make sure the target is a java.awt.Component */
201    componentClass = (*env)->FindClass(env, "java/awt/Component");
202    CHECK_NULL_RETURN(componentClass, NULL);
203
204    if (!(*env)->IsInstanceOf(env, target, componentClass)) {
205#ifdef DEBUG
206        fprintf(stderr, "DrawingSurface target must be a component\n");
207#endif
208        return NULL;
209        }
210
211    if (!awtLockInited) {
212        return NULL;
213    }
214
215    AWT_LOCK();
216
217    /* Get the peer of the target component */
218    peer = (*env)->GetObjectField(env, target, componentIDs.peer);
219    if (JNU_IsNull(env, peer)) {
220#ifdef DEBUG
221        fprintf(stderr, "Component peer is NULL\n");
222#endif
223                AWT_UNLOCK();
224        return NULL;
225    }
226
227    AWT_UNLOCK();
228
229    /* Allocate platform-specific data */
230    px = (JAWT_X11DrawingSurfaceInfo*)
231        malloc(sizeof(JAWT_X11DrawingSurfaceInfo));
232
233    /* Set drawable and display */
234    px->drawable = (*env)->GetLongField(env, peer, windowID);
235    px->display = awt_display;
236
237    /* Get window attributes to set other values */
238    XGetWindowAttributes(awt_display, (Window)(px->drawable), &attrs);
239
240    /* Set the other values */
241    px->visualID = XVisualIDFromVisual(attrs.visual);
242    px->colormapID = attrs.colormap;
243    px->depth = attrs.depth;
244    px->GetAWTColor = awt_GetColor;
245
246    /* Allocate and initialize platform-independent data */
247    p = (JAWT_DrawingSurfaceInfo*)malloc(sizeof(JAWT_DrawingSurfaceInfo));
248    p->platformInfo = px;
249    p->ds = ds;
250    p->bounds.x = (*env)->GetIntField(env, target, componentIDs.x);
251    p->bounds.y = (*env)->GetIntField(env, target, componentIDs.y);
252    p->bounds.width = (*env)->GetIntField(env, target, componentIDs.width);
253    p->bounds.height = (*env)->GetIntField(env, target, componentIDs.height);
254    p->clipSize = 1;
255    p->clip = &(p->bounds);
256
257    /* Return our new structure */
258    return p;
259}
260
261/*
262 * Free the drawing surface info.
263 */
264JNIEXPORT void JNICALL
265awt_DrawingSurface_FreeDrawingSurfaceInfo(JAWT_DrawingSurfaceInfo* dsi)
266{
267    if (dsi == NULL ) {
268#ifdef DEBUG
269        fprintf(stderr, "Drawing Surface Info is NULL\n");
270#endif
271        return;
272    }
273    free(dsi->platformInfo);
274    free(dsi);
275}
276
277/*
278 * Unlock the drawing surface of the target component for native rendering.
279 */
280JNIEXPORT void JNICALL awt_DrawingSurface_Unlock(JAWT_DrawingSurface* ds)
281{
282    JNIEnv* env;
283    if (ds == NULL) {
284#ifdef DEBUG
285        fprintf(stderr, "Drawing Surface is NULL\n");
286#endif
287        return;
288    }
289    env = ds->env;
290    AWT_FLUSH_UNLOCK();
291}
292
293JNIEXPORT JAWT_DrawingSurface* JNICALL
294    awt_GetDrawingSurface(JNIEnv* env, jobject target)
295{
296    jclass componentClass;
297    JAWT_DrawingSurface* p;
298
299    /* Make sure the target component is a java.awt.Component */
300    componentClass = (*env)->FindClass(env, "java/awt/Component");
301    CHECK_NULL_RETURN(componentClass, NULL);
302
303    if (!(*env)->IsInstanceOf(env, target, componentClass)) {
304#ifdef DEBUG
305        fprintf(stderr,
306            "GetDrawingSurface target must be a java.awt.Component\n");
307#endif
308        return NULL;
309    }
310
311    p = (JAWT_DrawingSurface*)malloc(sizeof(JAWT_DrawingSurface));
312    p->env = env;
313    p->target = (*env)->NewGlobalRef(env, target);
314    p->Lock = awt_DrawingSurface_Lock;
315    p->GetDrawingSurfaceInfo = awt_DrawingSurface_GetDrawingSurfaceInfo;
316    p->FreeDrawingSurfaceInfo = awt_DrawingSurface_FreeDrawingSurfaceInfo;
317    p->Unlock = awt_DrawingSurface_Unlock;
318    return p;
319}
320
321JNIEXPORT void JNICALL
322    awt_FreeDrawingSurface(JAWT_DrawingSurface* ds)
323{
324    JNIEnv* env;
325
326    if (ds == NULL ) {
327#ifdef DEBUG
328        fprintf(stderr, "Drawing Surface is NULL\n");
329#endif
330        return;
331    }
332    env = ds->env;
333    (*env)->DeleteGlobalRef(env, ds->target);
334    free(ds);
335}
336
337JNIEXPORT void JNICALL
338    awt_Lock(JNIEnv* env)
339{
340    if (awtLockInited) {
341        AWT_LOCK();
342    }
343}
344
345JNIEXPORT void JNICALL
346    awt_Unlock(JNIEnv* env)
347{
348    if (awtLockInited) {
349        AWT_FLUSH_UNLOCK();
350    }
351}
352
353JNIEXPORT jobject JNICALL
354    awt_GetComponent(JNIEnv* env, void* platformInfo)
355{
356    Window window = (Window)platformInfo;
357    jobject peer = NULL;
358    jobject target = NULL;
359
360    AWT_LOCK();
361
362    if (window != None) {
363        peer = JNU_CallStaticMethodByName(env, NULL, "sun/awt/X11/XToolkit",
364            "windowToXWindow", "(J)Lsun/awt/X11/XBaseWindow;", (jlong)window).l;
365        if ((*env)->ExceptionCheck(env)) {
366            AWT_UNLOCK();
367            return (jobject)NULL;
368        }
369    }
370    if ((peer != NULL) &&
371        (JNU_IsInstanceOfByName(env, peer, "sun/awt/X11/XWindow") == 1)) {
372        target = (*env)->GetObjectField(env, peer, targetID);
373    }
374
375    if (target == NULL) {
376        (*env)->ExceptionClear(env);
377        JNU_ThrowNullPointerException(env, "NullPointerException");
378        AWT_UNLOCK();
379        return (jobject)NULL;
380    }
381
382    AWT_UNLOCK();
383
384    return target;
385}
386
387// EmbeddedFrame support
388
389static char *const embeddedClassName = "sun/awt/X11/XEmbeddedFrame";
390
391JNIEXPORT jobject JNICALL awt_CreateEmbeddedFrame
392(JNIEnv* env, void* platformInfo)
393{
394    static jmethodID mid = NULL;
395    static jclass cls;
396    if (mid == NULL) {
397        cls = (*env)->FindClass(env, embeddedClassName);
398        CHECK_NULL_RETURN(cls, NULL);
399        mid = (*env)->GetMethodID(env, cls, "<init>", "(JZ)V");
400        CHECK_NULL_RETURN(mid, NULL);
401    }
402    return (*env)->NewObject(env, cls, mid, platformInfo, JNI_TRUE);
403}
404
405
406JNIEXPORT void JNICALL awt_SetBounds
407(JNIEnv *env, jobject embeddedFrame, jint x, jint y, jint w, jint h)
408{
409    static jmethodID mid = NULL;
410    if (mid == NULL) {
411        jclass cls = (*env)->FindClass(env, embeddedClassName);
412        CHECK_NULL(cls);
413        mid = (*env)->GetMethodID(env, cls, "setBoundsPrivate", "(IIII)V");
414        CHECK_NULL(mid);
415    }
416    (*env)->CallVoidMethod(env, embeddedFrame, mid, x, y, w, h);
417}
418
419JNIEXPORT void JNICALL awt_SynthesizeWindowActivation
420(JNIEnv *env, jobject embeddedFrame, jboolean doActivate)
421{
422    static jmethodID mid = NULL;
423    if (mid == NULL) {
424        jclass cls = (*env)->FindClass(env, embeddedClassName);
425        CHECK_NULL(cls);
426        mid = (*env)->GetMethodID(env, cls, "synthesizeWindowActivation", "(Z)V");
427        CHECK_NULL(mid);
428    }
429    (*env)->CallVoidMethod(env, embeddedFrame, mid, doActivate);
430}
431