Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gdkandroidsurface.c

  Sprache: C
 

/*
 * Copyright (c) 2024 Florian "sp1rit" <sp1rit@disroot.org>
 *
 * 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, see <http://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */


#include "config.h"

#include <math.h>

#include "gdkframeclockidleprivate.h"
#include "gdkframeclockprivate.h"
#include "gdkglcontextprivate.h"

#include "gdkandroidchoreographersource-private.h"

#include <android/native_window_jni.h>

#include "gdkandroidinit-private.h"
#include "gdkandroiddisplay-private.h"
#include "gdkandroidtoplevel-private.h"
#include "gdkandroidevents-private.h"
#include "gdkandroiddnd-private.h"
#include "gdkandroidutils-private.h"

#include "gdkandroidsurface-private.h"

#define gdk_android_check_surface(surface) {             \
    if (!surface)                                        \
      return;                                            \
    g_return_if_fail (GDK_IS_ANDROID_SURFACE (surface)); \
  }
#define gdk_android_check_surface_val(surface, val) {               \
    if (!surface)                                                   \
      return val;                                                   \
    g_return_val_if_fail (GDK_IS_ANDROID_SURFACE (surface), (val)); \
  }
#define gdk_android_check_surface_throw(surface, object) {                                                                                                                              \
    if (!surface)                                                                                                                                                                       \
      {                                                                                                                                                                                 \
        jthrowable exception = (*env)->NewObject (env, gdk_android_get_java_cache ()->surface_exception.klass, gdk_android_get_java_cache ()->surface_exception.constructor, (object)); \
        (*env)->Throw (env, exception);                                                                                                                                                 \
        (*env)->DeleteLocalRef (env, exception);                                                                                                                                        \
        return;                                                                                                                                                                         \
      }                                                                                                                                                                                 \
    g_return_if_fail (GDK_IS_ANDROID_SURFACE (surface));                                                                                                                                \
  }

static void
gdk_android_surface_reposition_children (GdkAndroidSurface *self)
{
  for (const GList *iter = GDK_SURFACE (self)->children;
       iter != NULL;
       iter = iter->next)
    {
      GdkAndroidSurface *child = iter->data;
      g_assert (GDK_IS_ANDROID_SURFACE (child));

      GDK_ANDROID_SURFACE_GET_CLASS (child)->reposition (child);
    }
}

static void
gdk_android_surface_drop_child_refs (GdkAndroidSurface *self)
{
  GdkSurface *surface = (GdkSurface *)self;
  JNIEnv *env = gdk_android_get_env();
  for (const GList *i = surface->children; i != NULL; i = i->next)
    {
      GdkAndroidSurface *child = (GdkAndroidSurface *)i->data;
      if (child->surface)
        {
          (*env)->CallVoidMethod (env, child->surface, gdk_android_get_java_cache ()->surface.drop);
          (*env)->DeleteGlobalRef (env, child->surface);
          child->surface = NULL;
        }
      gdk_android_surface_drop_child_refs(child);
    }
}

static void
gdk_android_surface_set_input_region (GdkSurface     *surface,
                                      cairo_region_t *shape_region);

void
_gdk_android_surface_bind_native (JNIEnv *env, jobject this, jlong identifier)
{
  GdkAndroidDisplay *display = gdk_android_display_get_display_instance ();
  GdkAndroidSurface *self = g_hash_table_lookup (display->surfaces, (gpointer) identifier);
  gdk_android_check_surface_throw (self, this);

  g_debug ("TRACE: Surface.BindNative (%p [%s])", self, G_OBJECT_TYPE_NAME (self));

  if (self->surface)
    {
      (*env)->CallVoidMethod (env, self->surface, gdk_android_get_java_cache ()->surface.drop);
      (*env)->DeleteGlobalRef (env, self->surface);
    }
  gdk_android_surface_drop_child_refs(self);
  self->surface = (*env)->NewGlobalRef (env, this);

  (*env)->CallVoidMethod(env, this, gdk_android_get_java_cache ()->surface.set_visibility, self->visible);

  gdk_android_surface_set_input_region ((GdkSurface *) self, ((GdkSurface *) self)->input_region);
}

void
_gdk_android_surface_on_attach (JNIEnv *env, jobject this)
{
  glong identifier = (*env)->GetLongField (env, this, gdk_android_get_java_cache ()->surface.surface_identifier);
  GdkAndroidDisplay *display = gdk_android_display_get_display_instance ();
  GdkAndroidSurface *self = g_hash_table_lookup (display->surfaces, (gpointer) identifier);
  gdk_android_check_surface (self);

  g_debug ("TRACE: Surface.OnAttach (%p [%s])", self, G_OBJECT_TYPE_NAME (self));
}

static void
gdk_android_surface_handle_map (GdkAndroidSurface *self);
void
_gdk_android_surface_on_layout_surface (JNIEnv *env, jobject this,
                                        jint width, jint height,
                                        jfloat scale)
{
  glong identifier = (*env)->GetLongField (env, this, gdk_android_get_java_cache ()->surface.surface_identifier);
  GdkAndroidDisplay *display = gdk_android_display_get_display_instance ();
  GdkAndroidSurface *self = g_hash_table_lookup (display->surfaces, (gpointer) identifier);
  gdk_android_check_surface (self);

  g_debug ("TRACE: Surface.OnLayoutSurface (%p [%s]): %dx%d @ %f", self, G_OBJECT_TYPE_NAME (self), width, height, scale);

  self->cfg.width = width;
  self->cfg.height = height;
  self->cfg.scale = scale;

  GdkAndroidSurfaceClass *klass = GDK_ANDROID_SURFACE_GET_CLASS (self);
  if (klass->on_layout)
    klass->on_layout (self);

  GdkSurface *surface = (GdkSurface *)self;
  surface->width = ceilf (self->cfg.width / self->cfg.scale);
  surface->height = ceilf (self->cfg.height / self->cfg.scale);
  surface->x = self->cfg.x / self->cfg.scale;
  surface->y = self->cfg.y / self->cfg.scale;

  g_debug ("New surface bounds: %dx%d at (%d|%d)", surface->width, surface->height, surface->x, surface->y);
  _gdk_surface_update_size (surface);
  gdk_android_surface_reposition_children (self);
  gdk_surface_invalidate_rect (surface, NULL);

  gdk_surface_request_layout ((GdkSurface *) self);

  /* Complete a deferred map: gdk_android_surface_eventloop_idle sets
   * delayed_map = TRUE when notifyVisibility(true) arrives before the surface
   * geometry is fully known (cfg.x == 0 || cfg.y == 0).  At this point width,
   * height, and scale are initialised, so it is safe to map the surface. */

  if (self->delayed_map)
    {
      gdk_android_surface_handle_map (self);
      self->delayed_map = FALSE;
    }
}

void
_gdk_android_surface_on_layout_position (JNIEnv *env, jobject this,
                                         jint x, jint y)
{
  glong identifier = (*env)->GetLongField (env, this, gdk_android_get_java_cache ()->surface.surface_identifier);
  GdkAndroidDisplay *display = gdk_android_display_get_display_instance ();
  GdkAndroidSurface *self = g_hash_table_lookup (display->surfaces, (gpointer) identifier);
  gdk_android_check_surface (self);

  g_debug ("TRACE: Surface.OnLayoutPosition (%p [%s]): (%d|%d)", self, G_OBJECT_TYPE_NAME (self), x, y);

  self->cfg.x = x;
  self->cfg.y = y;

  GdkAndroidSurfaceClass *klass = GDK_ANDROID_SURFACE_GET_CLASS (self);
  if (klass->on_layout)
    klass->on_layout (self);

  GdkSurface *surface = (GdkSurface *)self;
  surface->x = self->cfg.x / self->cfg.scale;
  surface->y = self->cfg.y / self->cfg.scale;

  gdk_android_surface_reposition_children (self);
}

void
_gdk_android_surface_on_detach (JNIEnv *env, jobject this)
{
  glong identifier = (*env)->GetLongField (env, this, gdk_android_get_java_cache ()->surface.surface_identifier);

  GdkAndroidDisplay *display = gdk_android_display_get_display_instance ();
  GdkAndroidSurface *self = g_hash_table_lookup (display->surfaces, (gpointer) identifier);
  gdk_android_check_surface (self);

  g_debug ("TRACE: Surface.OnDetach (%p [%s])", self, G_OBJECT_TYPE_NAME (self));
}

void
_gdk_android_surface_on_dnd_start_failed (JNIEnv *env, jobject this,
                                          jobject native_identifier)
{
  GdkAndroidDisplay *display = gdk_android_display_get_display_instance ();
  gdk_android_dnd_handle_drag_start_fail (display, native_identifier);
}

void
_gdk_android_surface_on_motion_event (JNIEnv *env, jobject this,
                                      jint event_identifier, jobject event)
{
  glong identifier = (*env)->GetLongField (env, this, gdk_android_get_java_cache ()->surface.surface_identifier);

  GdkAndroidDisplay *display = gdk_android_display_get_display_instance ();
  GdkAndroidSurface *self = g_hash_table_lookup (display->surfaces, (gpointer) identifier);
  gdk_android_check_surface (self);

  gdk_android_events_handle_motion_event (self, event, event_identifier);
}

void
_gdk_android_surface_on_key_event (JNIEnv *env, jobject this, jobject event)
{
  glong identifier = (*env)->GetLongField (env, this, gdk_android_get_java_cache ()->surface.surface_identifier);

  GdkAndroidDisplay *display = gdk_android_display_get_display_instance ();
  GdkAndroidSurface *self = g_hash_table_lookup (display->surfaces, (gpointer) identifier);
  gdk_android_check_surface (self);

  gdk_android_events_handle_key_event (self, event);
}

jboolean
_gdk_android_surface_on_drag_event (JNIEnv *env, jobject this, jobject event)
{
  glong identifier = (*env)->GetLongField (env, this, gdk_android_get_java_cache ()->surface.surface_identifier);

  GdkAndroidDisplay *display = gdk_android_display_get_display_instance ();
  GdkAndroidSurface *self = g_hash_table_lookup (display->surfaces, (gpointer) identifier);
  gdk_android_check_surface_val (self, FALSE);

  return gdk_android_dnd_surface_handle_drop_event (self, event);
}

typedef struct
{
  pthread_barrier_t event_loop_idle;
  pthread_barrier_t surface_update_complete;
  GdkAndroidSurface *self;
  gboolean visible;
} GdkAndroidSurfaceOnVisibilityData;

static void
gdk_android_surface_handle_map (GdkAndroidSurface *self)
{
  GdkSurface *surface = (GdkSurface *) self;
  GdkAndroidDisplay *display = (GdkAndroidDisplay *) gdk_surface_get_display (surface);

  // Resynchronize visibility state in case of mismatch.
  //   This can happen if there are two events queued where the first presents
  //   the popup surface while the second hides it again. As the second event
  //   triggers before the android eventloop OnVisibility synchronization happens
  //   the surface should actually be hidden.
  //   Early return, as seat_grab can also lead to popup_present calls.
  JNIEnv *env = gdk_android_get_env();
  if (!self->visible)
    {
      (*env)->CallVoidMethod (env, self->surface, gdk_android_get_java_cache ()->surface.set_visibility, FALSE);
      return;
    }

  gdk_surface_set_is_mapped (surface, TRUE);

  if (surface->autohide)
    {
      g_debug ("Grabbing surface %p [%s]", self, G_OBJECT_TYPE_NAME (self));
      gdk_seat_grab ((GdkSeat *) display->seat, surface);
      self->popup_grab = TRUE;
    }
}

static gboolean
gdk_android_surface_eventloop_idle (GdkAndroidSurfaceOnVisibilityData *data)
{
  // wait for the even loop calling this function
  pthread_barrier_wait (&data->event_loop_idle);

  // data becomes invalid after the next call, so copy what is needed
  GdkAndroidSurface *self = g_object_ref (data->self);
  gboolean visible = data->visible;

  // wait for the ui thread to have updated the native window
  pthread_barrier_wait (&data->surface_update_complete);

  GdkSurface *surface = (GdkSurface *) self;

  g_debug ("TRACE: Surface.OnVisibility (%p [%s])", self, G_OBJECT_TYPE_NAME (self));
  // GdkFrameClock *clock = gdk_surface_get_frame_clock(surface);
  if (visible)
    {
      // GDK_FRAME_CLOCK_GET_CLASS(clock)->thaw(clock); // is this legal?
      // gdk_android_surface_queue_configuration_update(self);
      if (self->cfg.x == 0 || self->cfg.y == 0)
        {
          /* Position not yet known — defer map to
           * _gdk_android_surface_on_layout_surface.  This runs before
           * notifyLayoutSurface because surfaceCreated calls
           * notifyVisibility synchronously (see ToplevelActivity.java). */

          self->delayed_map = TRUE;
        }
      else
        {
          self->delayed_map = FALSE;
          gdk_android_surface_handle_map (self);
        }

      GdkAndroidDisplay *display = GDK_ANDROID_DISPLAY (gdk_surface_get_display (surface));
      display->visible_surfaces = g_list_prepend (display->visible_surfaces, self);
      self->visible_node = display->visible_surfaces;
      if (display->visible_surfaces->next == NULL && display->choreographer_source)
        gdk_android_choreographer_source_unpause (
            (GdkAndroidChoreographerSource *) display->choreographer_source);
    }
  else
    {
      // GDK_FRAME_CLOCK_GET_CLASS(clock)->freeze(clock);

      // This is a really ugly hack to prevent the visibility getting set to
      // FALSE, after Gdk.Surface.set_is_mapped (false) triggers
      // Gdk.Surface.hide getting called. Just resetting to the previous
      // visibility state seems to mostly work and the reposition calls on
      // popups to properly push or reposition themselves on the ToplevelView.
      gboolean old_visibility = self->visible;

      self->delayed_map = FALSE;
      // There is still an issue where GdkSurface.set_is_mapped triggers
      // Gtk.Widget.hide, which inturn cause a GtkWidget.unparent -> unrealize,
      // which then calls Gdk.Surface.destroy and fully removes the popup, even
      // tho it is only shortly gone during activity recreation. As the grab
      // doesn't get removed, no further inputs gets processed due to GDK
      // complaining about inconsistent input state.
      // I don't really know how to fix this one...
      gdk_surface_set_is_mapped (surface, FALSE);

      // cont. ugly hack
      self->visible = old_visibility;

      GdkAndroidDisplay *display = GDK_ANDROID_DISPLAY (gdk_surface_get_display (surface));
      if (self->visible_node)
        {
          display->visible_surfaces = g_list_delete_link (display->visible_surfaces,
                                                          self->visible_node);
          self->visible_node = NULL;
          if (display->visible_surfaces == NULL && display->choreographer_source)
            gdk_android_choreographer_source_pause (
                (GdkAndroidChoreographerSource *) display->choreographer_source);
        }
    }

  g_object_unref (self);
  return G_SOURCE_REMOVE;
}

void
_gdk_android_surface_on_visibility_ui_thread (JNIEnv *env, jobject this,
                                              jboolean visible)
{
  glong identifier = (*env)->GetLongField (env, this, gdk_android_get_java_cache ()->surface.surface_identifier);
  GdkAndroidDisplay *display = gdk_android_display_get_display_instance ();
  GdkAndroidSurface *self = gdk_android_display_get_surface_from_identifier (display, identifier);
  if (!self)
    return;
  if (!GDK_IS_ANDROID_SURFACE (self))
    {
      g_object_unref (self);
      return;
    }

  g_debug ("TRACE: [UiThread] Surface.OnVisibility (%p [%s]): %d", self, G_OBJECT_TYPE_NAME (self), visible);

  GdkAndroidSurfaceOnVisibilityData data;
  pthread_barrier_init (&data.event_loop_idle, NULL, 2);
  pthread_barrier_init (&data.surface_update_complete, NULL, 2);
  data.self = self;
  data.visible = visible;

  g_idle_add_full (G_PRIORITY_DEFAULT - 10, G_SOURCE_FUNC (gdk_android_surface_eventloop_idle), &data, NULL);
  pthread_barrier_wait (&data.event_loop_idle); // wait for eventloop idle

  g_mutex_lock (&self->native_lock);

  g_clear_pointer (&self->native, ANativeWindow_release);
  if (visible)
    {
      (*env)->PushLocalFrame (env, 2);
      jobject holder = (*env)->CallObjectMethod (env, this, gdk_android_get_java_cache ()->surface.get_holder);
      jobject android_surface = (*env)->CallObjectMethod (env, holder, gdk_android_get_java_cache ()->a_surfaceholder.get_surface);
      self->native = ANativeWindow_fromSurface (env, android_surface);
      (*env)->PopLocalFrame (env, NULL);
    }

  GdkDrawContext *attached = gdk_surface_get_attached_context ((GdkSurface *)self);
  if (GDK_IS_GL_CONTEXT (attached))
    gdk_gl_context_set_egl_native_window ((GdkGLContext *)attached, self->native);

  g_mutex_unlock (&self->native_lock);

  pthread_barrier_wait (&data.surface_update_complete); // let the eventloop continue running
  // The bionic pthread barrier implementation behaves a bit wierd when doing calling wait multiple
  // times per instance. Because of this, we just have two barriers for the two stages instead of
  // reusing a single one.
  pthread_barrier_destroy (&data.event_loop_idle);
  pthread_barrier_destroy (&data.surface_update_complete);

  g_object_unref (self);
}

/**
 * GdkAndroidSurface:
 *
 * The Android implementation of [class@Gdk.Surface].
 *
 * On Android, each surface is backed by an Android
 * [SurfaceView](https://developer.android.com/reference/android/view/SurfaceView).
 *
 * Since: 4.18
 */

G_DEFINE_TYPE (GdkAndroidSurface, gdk_android_surface, GDK_TYPE_SURFACE)

static void
gdk_android_surface_finalize (GObject *object)
{
  GdkAndroidSurface *self = GDK_ANDROID_SURFACE (object);
  g_debug ("Finalizing surface %p [%s]", (gpointer) self, G_OBJECT_TYPE_NAME (self));
  if (self->active_drop)
    {
      g_info ("Finalizing surface %p with active drop operation", self);
      g_object_unref (self->active_drop);
    }
  JNIEnv *env = gdk_android_get_env ();
  if (self->native)
    ANativeWindow_release (self->native);
  if (self->surface)
    (*env)->DeleteGlobalRef (env, self->surface);
  g_mutex_clear (&self->native_lock);
  G_OBJECT_CLASS (gdk_android_surface_parent_class)->finalize (object);
}

static void
gdk_android_surface_frame_clock_after_paint (GdkFrameClock *clock,
                                             GdkSurface    *surface)
{
  GdkAndroidSurface *self = (GdkAndroidSurface *)surface;
  if (!self->surface)
    return;

  JNIEnv *env = gdk_android_get_env();
  (*env)->PushLocalFrame (env, 1);
  jobject view = (*env)->CallObjectMethod (env, self->surface,
                                           gdk_android_get_java_cache ()->a_view.get_display);
  if (!view)
    goto exit;
  float refresh = (*env)->CallFloatMethod (env, view,
                                           gdk_android_get_java_cache ()->a_display.get_refresh_rate);
  refresh = (float) G_NSEC_PER_SEC / refresh;

  GdkAndroidDisplay *display = GDK_ANDROID_DISPLAY (gdk_surface_get_display (surface));
  if (display->choreographer_source)
    {
      gdk_frame_clock_presented (clock,
                                 gdk_frame_clock_get_frame_counter (clock),
                                 gdk_android_choreographer_source_get_presentation_time (
                                   (GdkAndroidChoreographerSource *) display->choreographer_source),
                                 refresh);
    }
  else
    {
      gdk_frame_clock_submitted (clock,
                                 gdk_frame_clock_get_frame_counter (clock),
                                 refresh);
    }

exit:
  (*env)->PopLocalFrame (env, NULL);
}

static void
gdk_android_surface_constructed (GObject *object)
{
  GdkAndroidSurface *self = GDK_ANDROID_SURFACE (object);
  GdkSurface *surface = (GdkSurface *) self;
  GdkAndroidDisplay *display = GDK_ANDROID_DISPLAY (gdk_surface_get_display (surface));

  GdkFrameClock *frame_clock = _gdk_frame_clock_idle_new ();
  gdk_surface_set_frame_clock (surface, frame_clock);
  // GDK_FRAME_CLOCK_GET_CLASS(frame_clock)->freeze(frame_clock);
  g_signal_connect (frame_clock,
                    "after-paint",
                    G_CALLBACK (gdk_android_surface_frame_clock_after_paint),
                    self);
  g_object_unref (frame_clock);

  gdk_android_display_add_surface (display, self);

  G_OBJECT_CLASS (gdk_android_surface_parent_class)->constructed (object);
}

static void
gdk_android_surface_hide (GdkSurface *surface)
{
  GdkAndroidSurface *self = (GdkAndroidSurface *) surface;

  // Being able to call hide implies there being the possibility to unhide it again.
  // Where should that be implemented?
  g_debug ("AndroidSurface: hide called %p [%s] (%d %d)", self,
           G_OBJECT_TYPE_NAME (self), surface->is_mapped, surface->pending_is_mapped);

  self->visible = FALSE;

  if (!self->surface || surface->destroyed)
    return;

  if (surface->autohide && self->popup_grab)
    {
      GdkSeat *seat;

      seat = gdk_display_get_default_seat (surface->display);
      gdk_seat_ungrab (seat, surface);
      self->popup_grab = FALSE;
    }

  JNIEnv *env = gdk_android_get_env ();

  if (surface->is_mapped)
    (*env)->CallVoidMethod (env, self->surface, gdk_android_get_java_cache ()->surface.set_visibility, FALSE);

  _gdk_surface_clear_update_area (surface);
}

static void
gdk_android_surface_get_geometry (GdkSurface *surface,
                                  int *x, int *y,
                                  int *width, int *height)
{
  GdkSurface *parent = surface->parent;
  *x = surface->x - (parent ? parent->x : 0);
  *y = surface->y - (parent ? parent->y : 0);
  *width = surface->width;
  *height = surface->height;
}

static void
gdk_android_surface_get_root_coords (GdkSurface *surface,
                                     int x, int y,
                                     int *root_x, int *root_y)
{
  *root_x = x + surface->x;
  *root_y = y + surface->y;
}

static gboolean
gdk_android_surface_get_device_state (GdkSurface      *surface,
                                      GdkDevice       *device,
                                      double *x, double *y,
                                      GdkModifierType *mask)
{
  return gdk_device_get_surface_at_position (device, x, y) == surface;
}

static void
gdk_android_surface_set_input_region (GdkSurface     *surface,
                                      cairo_region_t *shape_region)
{
  GdkAndroidSurface *self = (GdkAndroidSurface *) surface;
  if (!self->surface)
    return;

  JNIEnv *env = gdk_android_get_env ();
  if (!shape_region)
    {
      (*env)->CallVoidMethod (env,
                              self->surface,
                              gdk_android_get_java_cache ()->surface.set_input_region,
                              NULL);
      return;
    }

  (*env)->PushLocalFrame (env, 2);

  gint n_rects = cairo_region_num_rectangles (shape_region);
  jobjectArray jrects = (*env)->NewObjectArray (env, n_rects, gdk_android_get_java_cache ()->a_rectf.klass, NULL);
  for (gint i = 0; i < n_rects; i++)
    {
      cairo_rectangle_int_t rect;
      cairo_region_get_rectangle (shape_region, i, &rect);

      jobject jrect = (*env)->NewObject (env, gdk_android_get_java_cache ()->a_rectf.klass,
                                         gdk_android_get_java_cache ()->a_rectf.constructor,
                                         (jfloat) (rect.x * self->cfg.scale),
                                         (jfloat) (rect.y * self->cfg.scale),
                                         (jfloat) ((rect.x + rect.width) * self->cfg.scale),
                                         (jfloat) ((rect.y + rect.height) * self->cfg.scale));
      (*env)->SetObjectArrayElement (env, jrects, i, jrect);
      (*env)->DeleteLocalRef (env, jrect);
    }

  (*env)->CallVoidMethod (env, self->surface, gdk_android_get_java_cache ()->surface.set_input_region, jrects);

  (*env)->PopLocalFrame (env, NULL);
}

static void
gdk_android_surface_destroy (GdkSurface *surface, gboolean foreign_destroy)
{
  GdkAndroidSurface *self = GDK_ANDROID_SURFACE (surface);
  GdkAndroidDisplay *display = GDK_ANDROID_DISPLAY (gdk_surface_get_display (surface));
  g_debug ("Destroying Surface %p (foreign: %d)", (gpointer) self, foreign_destroy);

  g_signal_handlers_disconnect_by_func (gdk_surface_get_frame_clock (surface),
                                        gdk_android_surface_frame_clock_after_paint,
                                        surface);

  if (!foreign_destroy && self->surface)
    {
      JNIEnv *env = gdk_android_get_env ();
      (*env)->CallVoidMethod (env, self->surface, gdk_android_get_java_cache ()->surface.drop);
    }
  g_hash_table_remove (display->surfaces, self);
}

static gdouble
gdk_android_surface_get_scale (GdkSurface *surface)
{
  GdkAndroidSurface *self = GDK_ANDROID_SURFACE (surface);
  return self->cfg.scale;
}

static gboolean
gdk_android_surface_compute_size (GdkSurface *surface)
{
  return FALSE;
}

static void
gdk_android_surface_reposition (GdkAndroidSurface *surface)
{
}

static void
gdk_android_surface_class_init (GdkAndroidSurfaceClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GdkSurfaceClass *surface_class = GDK_SURFACE_CLASS (klass);

  object_class->finalize = gdk_android_surface_finalize;
  object_class->constructed = gdk_android_surface_constructed;

  surface_class->hide = gdk_android_surface_hide;
  surface_class->get_geometry = gdk_android_surface_get_geometry;
  surface_class->get_root_coords = gdk_android_surface_get_root_coords;
  surface_class->get_device_state = gdk_android_surface_get_device_state;
  surface_class->set_input_region = gdk_android_surface_set_input_region;
  surface_class->destroy = gdk_android_surface_destroy;
  surface_class->drag_begin = gdk_android_dnd_surface_drag_begin;
  surface_class->get_scale = gdk_android_surface_get_scale;
  surface_class->compute_size = gdk_android_surface_compute_size;

  klass->reposition = gdk_android_surface_reposition;
}

static void
gdk_android_surface_init (GdkAndroidSurface *self)
{
  g_mutex_init (&self->native_lock);

  self->delayed_map = FALSE;
  self->cfg = (GdkAndroidSurfaceConfiguration){
    .x = 0, .y = 0, .width = 0, .height = 0, .scale = 1.f
  };
}

GdkAndroidToplevel *
gdk_android_surface_get_toplevel (GdkAndroidSurface *self)
{
  GdkSurface *surface = (GdkSurface *) self;
  if (surface->parent)
    return gdk_android_surface_get_toplevel (GDK_ANDROID_SURFACE (surface->parent));
  return GDK_ANDROID_TOPLEVEL (self);
}

Messung V0.5 in Prozent
C=98 H=97 G=97

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet am  2026-07-02) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik