Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gnome/gtk/   (Gnome Linux Desktop Version 4.23.2©)  Datei vom 30.5.2026 mit Größe 23 kB image not shown  

Quelle  gtktexthandle.c

  Sprache: C
 

/* GTK - The GIMP Toolkit
 * Copyright © 2012 Carlos Garnacho <carlosg@gnome.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 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/>.
 */


#include "config.h"

#include "gtktexthandleprivate.h"

#include "gtkbinlayout.h"
#include "gtkcssboxesimplprivate.h"
#include "gtkcssnodeprivate.h"
#include "gtkeventcontrollermotion.h"
#include "gtkgesturedrag.h"
#include "gtkgizmoprivate.h"
#include "gtkmarshalers.h"
#include "gdk/gdkmarshalers.h"
#include "gtknativeprivate.h"
#include "gtkprivatetypebuiltins.h"
#include "gtkrendericonprivate.h"
#include "gtksnapshot.h"
#include "gtkwidgetprivate.h"
#include "gtkwindowprivate.h"
#include "gtkprivate.h"

#include "gdk/gdksurfaceprivate.h"
#include "gsk/gskrendererprivate.h"

#define DEBUG_TEXTHANDLE_LOGIC 0

enum {
  DRAG_STARTED,
  HANDLE_DRAGGED,
  DRAG_FINISHED,
  LAST_SIGNAL
};

struct _GtkTextHandle
{
  GtkWidget parent_instance;

  GdkSurface *surface;
  GskRenderer *renderer;
  GtkEventController *controller;
  GtkWidget *controller_widget;
  GtkWidget *contents;

#if DEBUG_TEXTHANDLE_LOGIC
  GtkEventController *motion;
  graphene_point_t mpos;
  const GdkRGBA *mpos_color;
#endif

  GdkRectangle pointing_to;
  GtkBorder border;
  graphene_matrix_t surface_transform;
  guint surface_transform_changed_cb;

  guint role : 2;
  guint dragged : 1;
  guint mode_visible : 1;
  guint user_visible : 1;
  guint has_point : 1;
};

static void gtk_text_handle_native_interface_init (GtkNativeInterface *iface);

static void handle_drag_begin (GtkGestureDrag *gesture,
                               double          x,
                               double          y,
                               GtkTextHandle  *handle);
static void handle_drag_update (GtkGestureDrag *gesture,
                                double          offset_x,
                                double          offset_y,
                                GtkWidget      *widget);
static void handle_drag_end (GtkGestureDrag *gesture,
                             double          offset_x,
                             double          offset_y,
                             GtkTextHandle  *handle);

G_DEFINE_TYPE_WITH_CODE (GtkTextHandle, gtk_text_handle, GTK_TYPE_WIDGET,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_NATIVE,
                                                gtk_text_handle_native_interface_init))

static guint signals[LAST_SIGNAL] = { 0 };

#if DEBUG_TEXTHANDLE_LOGIC

static const GdkRGBA gdk_texthandle_debug_color_red = { .red = 1., .green = 0., .blue = 0., .alpha = 1. };
static const GdkRGBA gdk_texthandle_debug_color_blue = { .red = 0., .green = 0., .blue = 1., .alpha = 1. };

static void
handle_get_input_extents (GtkTextHandle *handle,
                          GtkBorder     *border);

static void
handle_do_toplevel_transform (GtkTextHandle *handle, gfloat *tx, gfloat *ty);

static void
handle_motion (GtkEventController *motion, gdouble x, gdouble y, GtkTextHandle *handle)
{
  GtkBorder input_extents;
  graphene_point_t p;

  handle_get_input_extents (handle, &input_extents);

  graphene_point_init (&p, x, y);
  handle_do_toplevel_transform (handle, &p.x, &p.y);

  graphene_point_init_from_point(&handle->mpos, &p);

  if (p.x < input_extents.left || p.x >= input_extents.right ||
      p.y < input_extents.top || p.y >= input_extents.bottom)
    handle->mpos_color = &gdk_texthandle_debug_color_red;
  else
    handle->mpos_color = &gdk_texthandle_debug_color_blue;

  gtk_widget_queue_draw (GTK_WIDGET (handle));
}

static void
handle_motion_leave (GtkEventController *motion, GtkTextHandle *handle)
{
  handle->mpos_color = NULL;
}

/* transform tip-space to widget-space - only needed for visualization */
static void
handle_do_tip_transform (GtkTextHandle *handle, gfloat *tx, gfloat *ty)
{
  GtkWidget *widget = GTK_WIDGET (handle);

  if (handle->role == GTK_TEXT_HANDLE_ROLE_CURSOR)
    {
      *tx += gtk_widget_get_width (widget) / 2.f;
    }
  else if ((handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_END &&
            gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ||
           (handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_START &&
            gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL))
    {
      *tx += gtk_widget_get_width (widget);
    }
  else
    {
      *tx += 0.;
    }
}
#endif

static GdkSurface *
gtk_text_handle_native_get_surface (GtkNative *native)
{
  return GTK_TEXT_HANDLE (native)->surface;
}

static GskRenderer *
gtk_text_handle_native_get_renderer (GtkNative *native)
{
  return GTK_TEXT_HANDLE (native)->renderer;
}

static void
gtk_text_handle_native_get_surface_transform (GtkNative *native,
                                              double    *x,
                                              double    *y)
{
  GtkCssBoxes css_boxes;
  const graphene_rect_t *margin_rect;

  gtk_css_boxes_init (&css_boxes, GTK_WIDGET (native));
  margin_rect = gtk_css_boxes_get_margin_rect (&css_boxes);

  *x = - margin_rect->origin.x;
  *y = - margin_rect->origin.y;
}

static void
gtk_text_handle_get_padding (GtkTextHandle *handle,
                             GtkBorder     *padding)
{
  GtkWidget *widget = GTK_WIDGET (handle);
  GtkCssStyle *style = gtk_css_node_get_style (gtk_widget_get_css_node (widget));

  padding->left = gtk_css_number_value_get (style->size->padding_left, 100);
  padding->right = gtk_css_number_value_get (style->size->padding_right, 100);
  padding->top = gtk_css_number_value_get (style->size->padding_top, 100);
  padding->bottom = gtk_css_number_value_get (style->size->padding_bottom, 100);
}

static void
gtk_text_handle_present_surface (GtkTextHandle *handle)
{
  GtkWidget *widget = GTK_WIDGET (handle);
  GdkPopupLayout *layout;
  GdkRectangle rect;
  GtkRequisition req;
  GtkWidget *parent;
  GtkNative *native;
  graphene_point_t point = GRAPHENE_POINT_INIT (handle->pointing_to.x, handle->pointing_to.y);
  graphene_point_t transformed;
  double nx, ny;

  gtk_widget_get_preferred_size (widget, NULL, &req);
  gtk_text_handle_get_padding (handle, &handle->border);

  parent = gtk_widget_get_parent (widget);

  native = gtk_widget_get_native (parent);
  gtk_native_get_surface_transform (native, &nx, &ny);

  if (!gtk_widget_compute_transform (GTK_WIDGET (native), parent, &handle->surface_transform))
    graphene_matrix_init_identity (&handle->surface_transform);

  if (!gtk_widget_compute_point (parent, GTK_WIDGET (native),
                                 &point, &transformed))
    transformed = point;

  rect.x = (int)(transformed.x + nx);
  rect.y = (int)(transformed.y + ny) + handle->pointing_to.height - handle->border.top;

  rect.width = req.width - handle->border.left - handle->border.right;
  rect.height = 1;

  if (handle->role == GTK_TEXT_HANDLE_ROLE_CURSOR)
    rect.x -= rect.width / 2;
  else if ((handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_END &&
            gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ||
           (handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_START &&
            gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL))
    rect.x -= rect.width;

  layout = gdk_popup_layout_new (&rect,
                                 GDK_GRAVITY_SOUTH,
                                 GDK_GRAVITY_NORTH);

  gdk_popup_present (GDK_POPUP (handle->surface),
                     MAX (req.width, 1),
                     MAX (req.height, 1),
                     layout);
  gdk_popup_layout_unref (layout);
}

void
gtk_text_handle_present (GtkTextHandle *handle)
{
  GtkWidget *widget = GTK_WIDGET (handle);

  if (!_gtk_widget_get_alloc_needed (widget))
    gtk_widget_ensure_allocate (widget);
  else if (gtk_widget_get_visible (widget))
    gtk_text_handle_present_surface (handle);
}

static void
gtk_text_handle_native_layout (GtkNative *native,
                               int        width,
                               int        height)
{
  GtkWidget *widget = GTK_WIDGET (native);

  if (_gtk_widget_get_alloc_needed (widget))
    gtk_widget_allocate (widget, width, height, -1, NULL);
  else
    gtk_widget_ensure_allocate (widget);
}

static void
gtk_text_handle_native_interface_init (GtkNativeInterface *iface)
{
  iface->get_surface = gtk_text_handle_native_get_surface;
  iface->get_renderer = gtk_text_handle_native_get_renderer;
  iface->get_surface_transform = gtk_text_handle_native_get_surface_transform;
  iface->layout = gtk_text_handle_native_layout;
}

static void
surface_mapped_changed (GtkWidget *widget)
{
  GtkTextHandle *handle = GTK_TEXT_HANDLE (widget);

  gtk_widget_set_visible (widget, gdk_surface_get_mapped (handle->surface));
}

static void
gtk_text_handle_snapshot (GtkWidget   *widget,
                          GtkSnapshot *snapshot)
{
  GtkCssStyle *style = gtk_css_node_get_style (gtk_widget_get_css_node (widget));

#if DEBUG_TEXTHANDLE_LOGIC
  GtkTextHandle *handle = (GtkTextHandle*)widget;
  GtkBorder border;

  handle_get_input_extents (GTK_TEXT_HANDLE (widget), &border);

  gtk_snapshot_save (snapshot);

  /* transform to tip-space */
  graphene_point_t tr = GRAPHENE_POINT_INIT_ZERO;
  handle_do_tip_transform (handle, &tr.x, &tr.y);
  gtk_snapshot_translate(snapshot, &tr);

  /* draw extents (happens to work as popup surface allocated is big enough to include them) */
  GskRoundedRect rect = GSK_ROUNDED_RECT_INIT(border.left, border.top, border.right - border.left, border.bottom - border.top);
  float rl[4] = { 2., 2., 2., 2. };
  GdkRGBA clrl[4] = { gdk_texthandle_debug_color_blue, gdk_texthandle_debug_color_blue, gdk_texthandle_debug_color_blue, gdk_texthandle_debug_color_blue };
  gtk_snapshot_append_border (snapshot, &rect, rl, clrl);

  /* draw current pointer */
  if (handle->mpos_color)
    {
      GskPathBuilder *pb = gsk_path_builder_new ();
      gsk_path_builder_add_circle (pb, &handle->mpos, 4.);
      GskPath *p = gsk_path_builder_free_to_path (pb);
      gtk_snapshot_append_fill (snapshot, p, GSK_FILL_RULE_WINDING, handle->mpos_color);
      gsk_path_unref (p);
    }

  gtk_snapshot_restore (snapshot);

  /* draw widget bounds */
  GskRoundedRect irect = GSK_ROUNDED_RECT_INIT(00, gtk_widget_get_width (widget), gtk_widget_get_height (widget));
  float irl[4] = { 2., 2., 2., 2. };
  GdkRGBA iclrl[4] = { gdk_texthandle_debug_color_red, gdk_texthandle_debug_color_red, gdk_texthandle_debug_color_red, gdk_texthandle_debug_color_red };
  gtk_snapshot_append_border (snapshot, &irect, irl, iclrl);
#endif

  gtk_css_style_snapshot_icon (style,
                               snapshot,
                               gtk_widget_get_width (widget),
                               gtk_widget_get_height (widget));

  GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->snapshot (widget, snapshot);
}

static void
gtk_text_handle_realize (GtkWidget *widget)
{
  GtkTextHandle *handle = GTK_TEXT_HANDLE (widget);
  GdkSurface *parent_surface;
  GtkWidget *parent;
  cairo_region_t *region;

  parent = gtk_widget_get_parent (widget);
  parent_surface = gtk_native_get_surface (gtk_widget_get_native (parent));

  handle->surface = gdk_surface_new_popup (parent_surface, FALSE);
  gdk_surface_set_widget (handle->surface, widget);

  region = cairo_region_create ();
  gdk_surface_set_input_region (handle->surface, region);
  cairo_region_destroy (region);

  g_signal_connect_swapped (handle->surface, "notify::mapped",
                            G_CALLBACK (surface_mapped_changed), widget);

  GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->realize (widget);

  handle->renderer = gsk_renderer_new_for_surface_full (handle->surface, TRUE);

  gtk_native_realize (GTK_NATIVE (handle));
}

static void
gtk_text_handle_unrealize (GtkWidget *widget)
{
  GtkTextHandle *handle = GTK_TEXT_HANDLE (widget);

  gtk_native_unrealize (GTK_NATIVE (handle));

  GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->unrealize (widget);

  gsk_renderer_unrealize (handle->renderer);
  g_clear_object (&handle->renderer);

  g_signal_handlers_disconnect_by_func (handle->surface, surface_mapped_changed, widget);

  gdk_surface_set_widget (handle->surface, NULL);
  g_clear_pointer (&handle->surface, gdk_surface_destroy);
}

static void
text_handle_set_up_gesture (GtkTextHandle *handle)
{
  GtkNative *native;

  /* The drag gesture is hooked on the parent native */
  native = gtk_widget_get_native (gtk_widget_get_parent (GTK_WIDGET (handle)));
  handle->controller_widget = GTK_WIDGET (native);

  handle->controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
  gtk_event_controller_set_propagation_phase (handle->controller,
                                              GTK_PHASE_CAPTURE);
  g_signal_connect (handle->controller, "drag-begin",
                    G_CALLBACK (handle_drag_begin), handle);
  g_signal_connect (handle->controller, "drag-update",
                    G_CALLBACK (handle_drag_update), handle);
  g_signal_connect (handle->controller, "drag-end",
                    G_CALLBACK (handle_drag_end), handle);


#if DEBUG_TEXTHANDLE_LOGIC
  handle->motion = gtk_event_controller_motion_new ();
  gtk_event_controller_set_propagation_phase (handle->motion, GTK_PHASE_CAPTURE);
  g_signal_connect (handle->motion, "motion", G_CALLBACK (handle_motion), handle);
  g_signal_connect (handle->motion, "leave", G_CALLBACK (handle_motion_leave), handle);
  gtk_widget_add_controller (handle->controller_widget, handle->motion);
#endif

  gtk_widget_add_controller (handle->controller_widget, handle->controller);
}

static void
unset_surface_transform_changed_cb (gpointer user_data)
{
  GtkTextHandle *handle = GTK_TEXT_HANDLE (user_data);

  graphene_matrix_init_identity (&handle->surface_transform);
  handle->surface_transform_changed_cb = 0;
}

static gboolean
surface_transform_changed_cb (GtkWidget               *widget,
                              const graphene_matrix_t *transform,
                              gpointer                 user_data)
{
  GtkTextHandle *handle = GTK_TEXT_HANDLE (user_data);

  gtk_text_handle_present_surface (handle);

  return G_SOURCE_CONTINUE;
}

static void
gtk_text_handle_map (GtkWidget *widget)
{
  GtkTextHandle *handle = GTK_TEXT_HANDLE (widget);

  handle->surface_transform_changed_cb =
    gtk_widget_add_surface_transform_changed_callback (gtk_widget_get_parent (widget),
                                                       surface_transform_changed_cb,
                                                       widget,
                                                       unset_surface_transform_changed_cb);

  GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->map (widget);

  if (handle->has_point)
    {
      gtk_text_handle_present_surface (handle);
      text_handle_set_up_gesture (handle);
    }
}

static void
gtk_text_handle_unmap (GtkWidget *widget)
{
  GtkTextHandle *handle = GTK_TEXT_HANDLE (widget);

  gtk_widget_remove_surface_transform_changed_callback (gtk_widget_get_parent (widget),
                                                        handle->surface_transform_changed_cb);
  handle->surface_transform_changed_cb = 0;

  GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->unmap (widget);
  gdk_surface_hide (handle->surface);

  if (handle->controller_widget)
    {
#if DEBUG_TEXTHANDLE_LOGIC
      gtk_widget_remove_controller (handle->controller_widget,
                                    handle->motion);
      handle->motion = NULL;
#endif

      gtk_widget_remove_controller (handle->controller_widget,
                                    handle->controller);
      handle->controller_widget = NULL;
      handle->controller = NULL;
    }
}

static void
gtk_text_handle_dispose (GObject *object)
{
  GtkTextHandle *handle = GTK_TEXT_HANDLE (object);

  g_clear_pointer (&handle->contents, gtk_widget_unparent);

  G_OBJECT_CLASS (gtk_text_handle_parent_class)->dispose (object);
}

static void
gtk_text_handle_class_init (GtkTextHandleClass *klass)
{
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->dispose = gtk_text_handle_dispose;

  widget_class->snapshot = gtk_text_handle_snapshot;
  widget_class->realize = gtk_text_handle_realize;
  widget_class->unrealize = gtk_text_handle_unrealize;
  widget_class->map = gtk_text_handle_map;
  widget_class->unmap = gtk_text_handle_unmap;

  signals[HANDLE_DRAGGED] =
    g_signal_new (I_("handle-dragged"),
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST, 0,
                  NULL, NULL,
                  _gdk_marshal_VOID__INT_INT,
                  G_TYPE_NONE, 2,
                  G_TYPE_INT, G_TYPE_INT);
  g_signal_set_va_marshaller (signals[HANDLE_DRAGGED],
                              G_OBJECT_CLASS_TYPE (object_class),
                              _gdk_marshal_VOID__INT_INTv);

  signals[DRAG_STARTED] =
    g_signal_new (I_("drag-started"),
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST, 0,
                  NULL, NULL,
                  NULL,
                  G_TYPE_NONE, 0, G_TYPE_NONE);

  signals[DRAG_FINISHED] =
    g_signal_new (I_("drag-finished"),
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST, 0,
                  NULL, NULL,
                  NULL,
                  G_TYPE_NONE, 0, G_TYPE_NONE);

  gtk_widget_class_set_css_name (widget_class, I_("cursor-handle"));
  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
}

/* Relative to pointing_to x/y */
static void
handle_get_input_extents (GtkTextHandle *handle,
                          GtkBorder     *border)
{
  GtkWidget *widget = GTK_WIDGET (handle);

  if (handle->role == GTK_TEXT_HANDLE_ROLE_CURSOR)
    {
      border->left = (-gtk_widget_get_width (widget) / 2) - handle->border.left;
      border->right = (gtk_widget_get_width (widget) / 2) + handle->border.right;
    }
  else if ((handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_END &&
            gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ||
           (handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_START &&
            gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL))
    {
      border->left = -gtk_widget_get_width (widget) - handle->border.left;
      border->right = handle->border.right;
    }
  else
    {
      border->left = -handle->border.left;
      border->right = gtk_widget_get_width (widget) + handle->border.right;
    }

  border->top = - handle->border.top;
  border->bottom = gtk_widget_get_height (widget) + handle->border.bottom;
}

/* transform controller-space to tip-space */
static void
handle_do_toplevel_transform (GtkTextHandle *handle, gfloat *tx, gfloat *ty)
{
  graphene_point_t p;

  /* controller-space to parent-space */
  graphene_matrix_transform_point (&handle->surface_transform,
                                   &GRAPHENE_POINT_INIT (*tx, *ty),
                                   &p);

  /* parent-space to tip-space */
  p.x -= handle->pointing_to.x;
  p.y -= handle->pointing_to.y + handle->pointing_to.height;

  *tx = p.x;
  *ty = p.y;
}

static void
handle_drag_begin (GtkGestureDrag *gesture,
                   double          x,
                   double          y,
                   GtkTextHandle  *handle)
{
  GtkBorder input_extents;
  graphene_point_t p;

  handle_get_input_extents (handle, &input_extents);

  graphene_point_init (&p, x, y);
  handle_do_toplevel_transform (handle, &p.x, &p.y);

  if (p.x < input_extents.left || p.x >= input_extents.right ||
      p.y < input_extents.top || p.y >= input_extents.bottom)
    {
      gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
      return;
    }

  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
  handle->dragged = TRUE;
  g_signal_emit (handle, signals[DRAG_STARTED], 0);
}

static void
handle_drag_update (GtkGestureDrag *gesture,
                    double          offset_x,
                    double          offset_y,
                    GtkWidget      *widget)
{
  GtkTextHandle *handle = GTK_TEXT_HANDLE (widget);
  double start_x, start_y;

  gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);

  graphene_point_t p;
  graphene_matrix_transform_point (&handle->surface_transform,
                                   &GRAPHENE_POINT_INIT (start_x + offset_x, start_y + offset_y),
                                   &p);
  p.y -= handle->pointing_to.height / 2.f;

  g_signal_emit (widget, signals[HANDLE_DRAGGED], 0, (int)p.x, (int)p.y);
}

static void
handle_drag_end (GtkGestureDrag *gesture,
                 double          offset_x,
                 double          offset_y,
                 GtkTextHandle  *handle)
{
  GdkEventSequence *sequence;
  GtkEventSequenceState state;

  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
  state = gtk_gesture_get_sequence_state (GTK_GESTURE (gesture), sequence);

  if (state == GTK_EVENT_SEQUENCE_CLAIMED)
    g_signal_emit (handle, signals[DRAG_FINISHED], 0);

  handle->dragged = FALSE;
}

static void
gtk_text_handle_update_for_role (GtkTextHandle *handle)
{
  GtkWidget *widget = GTK_WIDGET (handle);

  if (handle->role == GTK_TEXT_HANDLE_ROLE_CURSOR)
    {
      gtk_widget_remove_css_class (widget, "top");
      gtk_widget_add_css_class (widget, "bottom");
      gtk_widget_add_css_class (widget, "insertion-cursor");
    }
  else if (handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_END)
    {
      gtk_widget_remove_css_class (widget, "top");
      gtk_widget_add_css_class (widget, "bottom");
      gtk_widget_remove_css_class (widget, "insertion-cursor");
    }
  else if (handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_START)
    {
      gtk_widget_add_css_class (widget, "top");
      gtk_widget_remove_css_class (widget, "bottom");
      gtk_widget_remove_css_class (widget, "insertion-cursor");
    }

  gtk_widget_queue_draw (widget);
}

static void
gtk_text_handle_init (GtkTextHandle *handle)
{
  graphene_matrix_init_identity (&handle->surface_transform);

  handle->contents = gtk_gizmo_new ("contents", NULL, NULL, NULL, NULL, NULL, NULL);
  gtk_widget_set_can_target (handle->contents, FALSE);
  gtk_widget_set_parent (handle->contents, GTK_WIDGET (handle));

  gtk_text_handle_update_for_role (handle);
}

GtkTextHandle *
gtk_text_handle_new (GtkWidget *parent)
{
  GtkTextHandle *handle;

  handle = g_object_new (GTK_TYPE_TEXT_HANDLE, NULL);
  gtk_widget_set_parent (GTK_WIDGET (handle), parent);

  return handle;
}

void
gtk_text_handle_set_role (GtkTextHandle     *handle,
                          GtkTextHandleRole  role)
{
  g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));

  if (handle->role == role)
    return;

  handle->role = role;
  gtk_text_handle_update_for_role (handle);

  if (gtk_widget_get_visible (GTK_WIDGET (handle)))
    {
      if (handle->has_point)
        gtk_text_handle_present_surface (handle);
    }
}

GtkTextHandleRole
gtk_text_handle_get_role (GtkTextHandle *handle)
{
  g_return_val_if_fail (GTK_IS_TEXT_HANDLE (handle), GTK_TEXT_HANDLE_ROLE_CURSOR);

  return handle->role;
}

void
gtk_text_handle_set_position (GtkTextHandle      *handle,
                              const GdkRectangle *rect)
{
  g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));

  if (handle->pointing_to.x == rect->x &&
      handle->pointing_to.y == rect->y &&
      handle->pointing_to.width == rect->width &&
      handle->pointing_to.height == rect->height)
    return;

  handle->pointing_to = *rect;
  handle->has_point = TRUE;

  if (gtk_widget_is_visible (GTK_WIDGET (handle)))
    gtk_text_handle_present_surface (handle);
}

gboolean
gtk_text_handle_get_is_dragged (GtkTextHandle *handle)
{
  g_return_val_if_fail (GTK_IS_TEXT_HANDLE (handle), FALSE);

  return handle->dragged;
}

Messung V0.5 in Prozent
C=98 H=94 G=95

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet am  2026-07-03) ¤

*© 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.