Blob Blame History Raw
/*
 * Java ATK Wrapper for GNOME
 * Copyright (C) 2009 Sun Microsystems Inc.
 * Copyright (C) 2015 Magdalen Berns <m.berns@thismagpie.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <atk/atk.h>
#include <glib.h>
#include <glib-object.h>
#include "jawimpl.h"
#include "jawutil.h"

extern void jaw_component_interface_init(AtkComponentIface*);
extern gpointer jaw_component_data_init(jobject);
extern void jaw_component_data_finalize(gpointer);

static gboolean jaw_component_contains(AtkComponent *component,
                                       gint         x,
                                       gint         y,
                                       AtkCoordType coord_type);

static AtkObject* jaw_component_ref_accessible_at_point(AtkComponent *component,
                                                        gint         x,
                                                        gint         y,
                                                        AtkCoordType coord_type);

static void jaw_component_get_extents(AtkComponent *component,
                                      gint         *x,
                                      gint         *y,
                                      gint         *width,
                                      gint         *height,
                                      AtkCoordType coord_type);

static gboolean jaw_component_set_extents(AtkComponent *component,
                                          gint         x,
                                          gint         y,
                                          gint         width,
                                          gint         height,
                                          AtkCoordType coord_type);

static gboolean jaw_component_grab_focus(AtkComponent *component);
static AtkLayer jaw_component_get_layer(AtkComponent *component);
/*static gint		jaw_component_get_mdi_zorder		(AtkComponent		*component);
static gdouble		jaw_component_get_alpha			(AtkComponent		*component);*/

typedef struct _ComponentData {
  jobject atk_component;
} ComponentData;

void
jaw_component_interface_init (AtkComponentIface *iface)
{
  iface->contains = jaw_component_contains;
  iface->ref_accessible_at_point = jaw_component_ref_accessible_at_point;
  iface->get_extents = jaw_component_get_extents;
  iface->grab_focus = jaw_component_grab_focus;
  iface->add_focus_handler = NULL;
  iface->remove_focus_handler = NULL;
  iface->get_layer = jaw_component_get_layer;
  iface->get_mdi_zorder = NULL; /*jaw_component_get_mdi_zorder;*/
  iface->get_alpha = NULL; /*jaw_component_get_alpha;*/
  iface->set_extents = jaw_component_set_extents;
  iface->set_position = NULL;
  iface->set_size = NULL;
  iface->bounds_changed = NULL;
}

gpointer
jaw_component_data_init (jobject ac)
{
  ComponentData *data = g_new0(ComponentData, 1);

  JNIEnv *jniEnv = jaw_util_get_jni_env();
  jclass classComponent = (*jniEnv)->FindClass(jniEnv,
                                               "org/GNOME/Accessibility/AtkComponent");
  jmethodID jmid = (*jniEnv)->GetMethodID(jniEnv,
                                          classComponent,
                                          "<init>",
                                          "(Ljavax/accessibility/AccessibleContext;)V");

  jobject jatk_component = (*jniEnv)->NewObject(jniEnv, classComponent, jmid, ac);
  data->atk_component = (*jniEnv)->NewGlobalRef(jniEnv, jatk_component);

  return data;
}

void
jaw_component_data_finalize (gpointer p)
{
  ComponentData *data = (ComponentData*)p;
  JNIEnv *jniEnv = jaw_util_get_jni_env();

  if (data && data->atk_component)
  {
    (*jniEnv)->DeleteGlobalRef(jniEnv, data->atk_component);
    data->atk_component = NULL;
  }
}

static void
coord_screen_to_local (JNIEnv *jniEnv, jobject jobj, gint *x, gint *y)
{
  jclass classAccessibleComponent = (*jniEnv)->FindClass(jniEnv,
                                                         "javax/accessibility/AccessibleComponent");
  jmethodID jmid = (*jniEnv)->GetMethodID(jniEnv,
                                          classAccessibleComponent,
                                          "getLocationOnScreen",
                                          "()Ljava/awt/Point;");

  jobject jpoint = (*jniEnv)->CallObjectMethod(jniEnv, jobj, jmid);

  jclass classPoint = (*jniEnv)->FindClass(jniEnv, "java/awt/Point");
  jfieldID jfidX = (*jniEnv)->GetFieldID(jniEnv, classPoint, "x", "I");
  jfieldID jfidY = (*jniEnv)->GetFieldID(jniEnv, classPoint, "y", "I");
  jint jx = (*jniEnv)->GetIntField(jniEnv, jpoint, jfidX);
  jint jy = (*jniEnv)->GetIntField(jniEnv, jpoint, jfidY);

  (*x) = (*x) - (gint)jx;
  (*y) = (*y) - (gint)jy;
}

static gboolean
jaw_component_contains (AtkComponent *component, gint x, gint y, AtkCoordType coord_type)
{
  JawObject *jaw_obj = JAW_OBJECT(component);
  ComponentData *data = jaw_object_get_interface_data(jaw_obj, INTERFACE_COMPONENT);
  jobject atk_component = data->atk_component;

  JNIEnv *jniEnv = jaw_util_get_jni_env();
  jclass classAtkComponent = (*jniEnv)->FindClass(jniEnv,
                                                  "org/GNOME/Accessibility/AtkComponent");

  jmethodID jmid = (*jniEnv)->GetMethodID(jniEnv,
                                          classAtkComponent,
                                          "contains",
                                          "(III)Z");

  jboolean jcontains = (*jniEnv)->CallBooleanMethod(jniEnv,
                                                    atk_component,
                                                    jmid,
                                                    (jint)x,
                                                    (jint)y,
                                                    (jint)coord_type);

  if (jcontains == JNI_TRUE)
  {
    return TRUE;
  } else {
    return FALSE;
  }
}

static AtkObject*
jaw_component_ref_accessible_at_point (AtkComponent *component, gint x, gint y, AtkCoordType coord_type)
{
  JawObject *jaw_obj = JAW_OBJECT(component);
  ComponentData *data = jaw_object_get_interface_data(jaw_obj, INTERFACE_COMPONENT);
  jobject atk_component = data->atk_component;

  JNIEnv *jniEnv = jaw_util_get_jni_env();
  jclass classAtkComponent = (*jniEnv)->FindClass(jniEnv,
                                                  "org/GNOME/Accessibility/AtkComponent");
  jmethodID jmid = (*jniEnv)->GetMethodID(jniEnv,
                                          classAtkComponent,
                                          "get_accessible_at_point",
                                          "(III)Ljavax/accessibility/AccessibleContext;");
  jobject child_ac = (*jniEnv)->CallObjectMethod(jniEnv,
                                                 atk_component,
                                                 jmid,
                                                 (jint)x,
                                                 (jint)y,
                                                 (jint)coord_type);

  JawImpl* jaw_impl = jaw_impl_get_instance( jniEnv, child_ac );

  g_object_ref( G_OBJECT(jaw_impl) );

  return ATK_OBJECT(jaw_impl);
}

static void
jaw_component_get_extents (AtkComponent *component,
                           gint         *x,
                           gint         *y,
                           gint         *width,
                           gint         *height,
                           AtkCoordType coord_type)
{
  if (x == NULL || y == NULL || width == NULL || height == NULL)
    return;

  if (component == NULL)
    return;

  JawObject *jaw_obj = JAW_OBJECT(component);
  ComponentData *data = jaw_object_get_interface_data(jaw_obj,
                                                      INTERFACE_COMPONENT);
  jobject atk_component = data->atk_component;

  JNIEnv *jniEnv = jaw_util_get_jni_env();
  jclass classAtkComponent = (*jniEnv)->FindClass(jniEnv,
                                                  "org/GNOME/Accessibility/AtkComponent");
  jmethodID jmid = (*jniEnv)->GetMethodID(jniEnv,
                                          classAtkComponent,
                                          "get_extents",
                                          "()Ljava/awt/Rectangle;");

  jobject jrectangle = (*jniEnv)->CallObjectMethod(jniEnv, atk_component, jmid);

  if (jrectangle == NULL)
  {
    (*x) = 0;
    (*y) = 0;
    (*width) = 0;
    (*height) = 0;
    return;
  }

  jclass classRectangle = (*jniEnv)->FindClass(jniEnv, "java/awt/Rectangle");
  jfieldID jfidX = (*jniEnv)->GetFieldID(jniEnv, classRectangle, "x", "I");
  jfieldID jfidY = (*jniEnv)->GetFieldID(jniEnv, classRectangle, "y", "I");
  jfieldID jfidW = (*jniEnv)->GetFieldID(jniEnv, classRectangle, "width", "I");
  jfieldID jfidH = (*jniEnv)->GetFieldID(jniEnv, classRectangle, "height", "I");
  (*x)      = (gint)(*jniEnv)->GetIntField(jniEnv, jrectangle, jfidX);
  (*y)      = (gint)(*jniEnv)->GetIntField(jniEnv, jrectangle, jfidY);
  (*width)  = (gint)(*jniEnv)->GetIntField(jniEnv, jrectangle, jfidW);
  (*height) = (gint)(*jniEnv)->GetIntField(jniEnv, jrectangle, jfidH);
}

static gboolean
jaw_component_set_extents (AtkComponent *component,
                           gint         x,
                           gint         y,
                           gint         width,
                           gint         height,
                           AtkCoordType coord_type)
{

  JawObject *jaw_obj = JAW_OBJECT(component);
  ComponentData *data = jaw_object_get_interface_data(jaw_obj, INTERFACE_COMPONENT);
  jobject atk_component = data->atk_component;

  JNIEnv *jniEnv = jaw_util_get_jni_env();
  jclass classAtkComponent = (*jniEnv)->FindClass(jniEnv,
                                                  "org/GNOME/Accessibility/AtkComponent");

  jmethodID jmid = (*jniEnv)->GetMethodID(jniEnv,
                                          classAtkComponent,
                                          "set_extents",
                                          "(IIIII)Ljava/awt/Rectangle;");

  jobject jcomponent = (*jniEnv)->CallObjectMethod(jniEnv,
                                                   atk_component,
                                                   jmid,
                                                   (jint)x,
                                                   (jint)y,
                                                   (jint)width,
                                                   (jint)height,
                                                   (jint)coord_type);

  if (jcomponent == NULL)
  {
    width = 0;
    height = 0;
    x = 0;
    y = 0;
    return FALSE;
  }

  jclass classRectangle = (*jniEnv)->FindClass(jniEnv, "java/awt/Rectangle");

  // Get Field IDs
  jfieldID jfidX       = (*jniEnv)->GetFieldID(jniEnv,
                                               atk_component,
                                               "x",
                                               "I");
  jfieldID jfidY       = (*jniEnv)->GetFieldID(jniEnv,
                                               atk_component,
                                               "y",
                                               "I");
  jfieldID jfidWidth   = (*jniEnv)->GetFieldID(jniEnv,
                                               atk_component,
                                               "width",
                                               "I");
  jfieldID jfidHeight  = (*jniEnv)->GetFieldID(jniEnv,
                                               atk_component,
                                               "height",
                                               "I");

  jint jwidth = (*jniEnv)->GetIntField(jniEnv, classRectangle, jfidWidth);
  jint jheight = (*jniEnv)->GetIntField(jniEnv, classRectangle, jfidHeight);
  jint jx = (*jniEnv)->GetIntField(jniEnv, classRectangle, jfidX);
  jint jy = (*jniEnv)->GetIntField(jniEnv, classRectangle, jfidY);

  width = (gint)jwidth;
  height = (gint)jheight;
  x = (gint)jx;
  y = (gint)jy;

  return TRUE;
}

static gboolean
jaw_component_grab_focus (AtkComponent *component)
{
  JawObject *jaw_obj = JAW_OBJECT(component);
  ComponentData *data = jaw_object_get_interface_data(jaw_obj, INTERFACE_COMPONENT);
  jobject atk_component = data->atk_component;

  JNIEnv *jniEnv = jaw_util_get_jni_env();
  jclass classAtkComponent = (*jniEnv)->FindClass(jniEnv,
                                                  "org/GNOME/Accessibility/AtkComponent");
  jmethodID jmid = (*jniEnv)->GetMethodID(jniEnv,
                                          classAtkComponent,
                                          "grab_focus",
                                          "()Z");
  jboolean jresult = (*jniEnv)->CallBooleanMethod(jniEnv, atk_component, jmid);

  if (jresult == JNI_TRUE)
  {
    return TRUE;
  }

  return FALSE;
}

static AtkLayer
jaw_component_get_layer (AtkComponent *component)
{
  JawObject *jaw_obj = JAW_OBJECT(component);
  ComponentData *data = jaw_object_get_interface_data(jaw_obj,
                                                      INTERFACE_COMPONENT);
  jobject atk_component = data->atk_component;

  JNIEnv *jniEnv = jaw_util_get_jni_env();
  jclass classAtkComponent = (*jniEnv)->FindClass(jniEnv,
                                                  "org/GNOME/Accessibility/AtkComponent");
  jmethodID jmid = (*jniEnv)->GetMethodID(jniEnv,
                                          classAtkComponent,
                                          "get_layer",
                                          "()I");

  jint jlayer = (*jniEnv)->CallIntMethod(jniEnv, atk_component, jmid);

  return (AtkLayer)jlayer;
}