Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  gtklayoutmanager.c

  Sprache: C
 

/* gtklayoutmanager.c: Layout manager base class
 * Copyright 2018  The GNOME Foundation
 *
 * 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/>.
 *
 * Author: Emmanuele Bassi
 */


/**
 * GtkLayoutManager:
 *
 * Handles the preferred size and allocation for children of a widget.
 *
 * You typically subclass `GtkLayoutManager` if you want to implement a
 * layout policy for the children of a widget, or if you want to determine
 * the size of a widget depending on its contents.
 *
 * Each `GtkWidget` can only have a `GtkLayoutManager` instance associated
 * to it at any given time; it is possible, though, to replace the layout
 * manager instance using [method@Gtk.Widget.set_layout_manager].
 *
 * ## Layout properties
 *
 * A layout manager can expose properties for controlling the layout of
 * each child, by creating an object type derived from [class@Gtk.LayoutChild]
 * and installing the properties on it as normal `GObject` properties.
 *
 * Each `GtkLayoutChild` instance storing the layout properties for a
 * specific child is created through the [method@Gtk.LayoutManager.get_layout_child]
 * method; a `GtkLayoutManager` controls the creation of its `GtkLayoutChild`
 * instances by overriding the GtkLayoutManagerClass.create_layout_child()
 * virtual function. The typical implementation should look like:
 *
 * ```c
 * static GtkLayoutChild *
 * create_layout_child (GtkLayoutManager *manager,
 *                      GtkWidget        *container,
 *                      GtkWidget        *child)
 * {
 *   return g_object_new (your_layout_child_get_type (),
 *                        "layout-manager", manager,
 *                        "child-widget", child,
 *                        NULL);
 * }
 * ```
 *
 * The [property@Gtk.LayoutChild:layout-manager] and
 * [property@Gtk.LayoutChild:child-widget] properties
 * on the newly created `GtkLayoutChild` instance are mandatory. The
 * `GtkLayoutManager` will cache the newly created `GtkLayoutChild` instance
 * until the widget is removed from its parent, or the parent removes the
 * layout manager.
 *
 * Each `GtkLayoutManager` instance creating a `GtkLayoutChild` should use
 * [method@Gtk.LayoutManager.get_layout_child] every time it needs to query
 * the layout properties; each `GtkLayoutChild` instance should call
 * [method@Gtk.LayoutManager.layout_changed] every time a property is
 * updated, in order to queue a new size measuring and allocation.
 */


#include "config.h"

#include "gtklayoutmanagerprivate.h"
#include "gtklayoutchild.h"
#include "gtkwidgetprivate.h"
#include "gtknative.h"
#include "gtkpopover.h"
#include "gtktexthandleprivate.h"
#include "gtktooltipwindowprivate.h"

#ifdef G_ENABLE_DEBUG
#define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method)   G_STMT_START {  \
        GObject *_obj = G_OBJECT (m);                                   \
        g_warning ("Layout managers of type %s do not implement "       \
                   "the GtkLayoutManager::%s method",                   \
                   G_OBJECT_TYPE_NAME (_obj),                           \
                   #method);                           } G_STMT_END
#else
#define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method)
#endif

typedef struct {
  GtkWidget *widget;
  GtkRoot *root;

  /* HashTable<Widget, LayoutChild> */
  GHashTable *layout_children;
} GtkLayoutManagerPrivate;

G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkLayoutManager, gtk_layout_manager, G_TYPE_OBJECT)

static void
gtk_layout_manager_real_root (GtkLayoutManager *manager)
{
}

static void
gtk_layout_manager_real_unroot (GtkLayoutManager *manager)
{
}

static GtkSizeRequestMode
gtk_layout_manager_real_get_request_mode (GtkLayoutManager *manager,
                                          GtkWidget        *widget)
{
  int hfw = 0, wfh = 0;
  GtkWidget *child;

  for (child = _gtk_widget_get_first_child (widget);
       child != NULL;
       child = _gtk_widget_get_next_sibling (child))
    {
      GtkSizeRequestMode res;

      if (!gtk_widget_should_layout (child))
        continue;

      res = gtk_widget_get_request_mode (child);

      switch (res)
        {
        case GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH:
          hfw += 1;
          break;

        case GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT:
          wfh += 1;
          break;

        case GTK_SIZE_REQUEST_CONSTANT_SIZE:
        default:
          break;
        }
    }

 if (hfw == 0 && wfh == 0)
   return GTK_SIZE_REQUEST_CONSTANT_SIZE;

 return hfw >= wfh ? GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH
                   : GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
}

static void
gtk_layout_manager_real_measure (GtkLayoutManager *manager,
                                 GtkWidget        *widget,
                                 GtkOrientation    orientation,
                                 int               for_size,
                                 int              *minimum,
                                 int              *natural,
                                 int              *baseline_minimum,
                                 int              *baseline_natural)
{
  LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, measure);

  if (minimum != NULL)
    *minimum = 0;

  if (natural != NULL)
    *natural = 0;

  if (baseline_minimum != NULL)
    *baseline_minimum = 0;

  if (baseline_natural != NULL)
    *baseline_natural = 0;
}

static void
gtk_layout_manager_real_allocate (GtkLayoutManager *manager,
                                  GtkWidget        *widget,
                                  int               width,
                                  int               height,
                                  int               baseline)
{
  LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, allocate);
}

static GtkLayoutChild *
gtk_layout_manager_real_create_layout_child (GtkLayoutManager *manager,
                                             GtkWidget        *widget,
                                             GtkWidget        *child)
{
  GtkLayoutManagerClass *manager_class = GTK_LAYOUT_MANAGER_GET_CLASS (manager);

  if (manager_class->layout_child_type == G_TYPE_INVALID)
    {
      LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, create_layout_child);
      return NULL;
    }

  return g_object_new (manager_class->layout_child_type,
                       "layout-manager", manager,
                       "child-widget", child,
                       NULL);
}

static void
gtk_layout_manager_finalize (GObject *gobject)
{
  GtkLayoutManager *self = GTK_LAYOUT_MANAGER (gobject);
  GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (self);

  g_clear_pointer (&priv->layout_children, g_hash_table_unref);

  G_OBJECT_CLASS (gtk_layout_manager_parent_class)->finalize (gobject);
}

static void
gtk_layout_manager_class_init (GtkLayoutManagerClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->finalize = gtk_layout_manager_finalize;

  klass->get_request_mode = gtk_layout_manager_real_get_request_mode;
  klass->measure = gtk_layout_manager_real_measure;
  klass->allocate = gtk_layout_manager_real_allocate;
  klass->create_layout_child = gtk_layout_manager_real_create_layout_child;
  klass->root = gtk_layout_manager_real_root;
  klass->unroot = gtk_layout_manager_real_unroot;
}

static void
gtk_layout_manager_init (GtkLayoutManager *self)
{
}

/*< private >
 * gtk_layout_manager_set_widget:
 * @layout_manager: a `GtkLayoutManager`
 * @widget: (nullable): a `GtkWidget`
 *
 * Sets a back pointer from @widget to @layout_manager.
 */

void
gtk_layout_manager_set_widget (GtkLayoutManager *layout_manager,
                               GtkWidget        *widget)
{
  GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (layout_manager);

  if (widget != NULL && priv->widget != NULL)
    {
      g_critical ("The layout manager %p of type %s is already in use "
                  "by widget %p '%s', and cannot be used by widget %p '%s'",
                  layout_manager, G_OBJECT_TYPE_NAME (layout_manager),
                  priv->widget, gtk_widget_get_name (priv->widget),
                  widget, gtk_widget_get_name (widget));
      return;
    }

  priv->widget = widget;

  if (widget != NULL)
    gtk_layout_manager_set_root (layout_manager, gtk_widget_get_root (widget));
}

/*< private >
 * gtk_layout_manager_set_root:
 * @layout_manager: a i`GtkLayoutManager`
 * @root: (nullable): a `GtkWidget` implementing `GtkRoot`
 *
 * Sets a back pointer from @root to @layout_manager.
 *
 * This function is called by `GtkWidget` when getting rooted and unrooted,
 * and will call `GtkLayoutManagerClass.root()` or `GtkLayoutManagerClass.unroot()`
 * depending on whether @root is a `GtkWidget` or %NULL.
 */

void
gtk_layout_manager_set_root (GtkLayoutManager *layout_manager,
                             GtkRoot          *root)
{
  GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (layout_manager);
  GtkRoot *old_root = priv->root;

  priv->root = root;

  if (old_root != root)
    {
      if (priv->root != NULL)
        GTK_LAYOUT_MANAGER_GET_CLASS (layout_manager)->root (layout_manager);
      else
        GTK_LAYOUT_MANAGER_GET_CLASS (layout_manager)->unroot (layout_manager);
    }
}

/**
 * gtk_layout_manager_measure:
 * @manager: a `GtkLayoutManager`
 * @widget: the `GtkWidget` using @manager
 * @orientation: the orientation to measure
 * @for_size: Size for the opposite of @orientation; for instance, if
 *   the @orientation is %GTK_ORIENTATION_HORIZONTAL, this is the height
 *   of the widget; if the @orientation is %GTK_ORIENTATION_VERTICAL, this
 *   is the width of the widget. This allows to measure the height for the
 *   given width, and the width for the given height. Use -1 if the size
 *   is not known
 * @minimum: (out) (optional): the minimum size for the given size and
 *   orientation
 * @natural: (out) (optional): the natural, or preferred size for the
 *   given size and orientation
 * @minimum_baseline: (out) (optional): the baseline position for the
 *   minimum size
 * @natural_baseline: (out) (optional): the baseline position for the
 *   natural size
 *
 * Measures the size of the @widget using @manager, for the
 * given @orientation and size.
 *
 * See the [class@Gtk.Widget] documentation on layout management for
 * more details.
 */

void
gtk_layout_manager_measure (GtkLayoutManager *manager,
                            GtkWidget        *widget,
                            GtkOrientation    orientation,
                            int               for_size,
                            int              *minimum,
                            int              *natural,
                            int              *minimum_baseline,
                            int              *natural_baseline)
{
  GtkLayoutManagerClass *klass;
  int min_size = 0;
  int nat_size = 0;
  int min_baseline = -1;
  int nat_baseline = -1;


  g_return_if_fail (GTK_IS_LAYOUT_MANAGER (manager));
  g_return_if_fail (GTK_IS_WIDGET (widget));

  klass = GTK_LAYOUT_MANAGER_GET_CLASS (manager);

  klass->measure (manager, widget, orientation,
                  for_size,
                  &min_size, &nat_size,
                  &min_baseline, &nat_baseline);

  if (minimum)
    *minimum = min_size;

  if (natural)
    *natural = nat_size;

  if (minimum_baseline)
    *minimum_baseline = min_baseline;

  if (natural_baseline)
    *natural_baseline = nat_baseline;
}

static void
allocate_native_children (GtkWidget *widget)
{
  GtkWidget *child;

  for (child = _gtk_widget_get_first_child (widget);
       child != NULL;
       child = _gtk_widget_get_next_sibling (child))
    {
      if (GTK_IS_POPOVER (child))
        gtk_popover_present (GTK_POPOVER (child));
      else if (GTK_IS_TEXT_HANDLE (child))
        gtk_text_handle_present (GTK_TEXT_HANDLE (child));
      else if (GTK_IS_TOOLTIP_WINDOW (child))
        gtk_tooltip_window_present (GTK_TOOLTIP_WINDOW (child));
      else if (GTK_IS_NATIVE (child))
        g_warning ("Unable to present a to the layout manager unknown auxiliary child surface widget type %s",
                   G_OBJECT_TYPE_NAME (child));
    }
}

/**
 * gtk_layout_manager_allocate:
 * @manager: a `GtkLayoutManager`
 * @widget: the `GtkWidget` using @manager
 * @width: the new width of the @widget
 * @height: the new height of the @widget
 * @baseline: the baseline position of the @widget, or -1
 *
 * Assigns the given @width, @height, and @baseline to
 * a @widget, and computes the position and sizes of the children of
 * the @widget using the layout management policy of @manager.
 */

void
gtk_layout_manager_allocate (GtkLayoutManager *manager,
                             GtkWidget        *widget,
                             int               width,
                             int               height,
                             int               baseline)
{
  GtkLayoutManagerClass *klass;

  g_return_if_fail (GTK_IS_LAYOUT_MANAGER (manager));
  g_return_if_fail (GTK_IS_WIDGET (widget));
  g_return_if_fail (baseline >= -1);

  allocate_native_children (widget);

  klass = GTK_LAYOUT_MANAGER_GET_CLASS (manager);

  klass->allocate (manager, widget, width, height, baseline);
}

/**
 * gtk_layout_manager_get_request_mode:
 * @manager: a `GtkLayoutManager`
 *
 * Retrieves the request mode of @manager.
 *
 * Returns: a `GtkSizeRequestMode`
 */

GtkSizeRequestMode
gtk_layout_manager_get_request_mode (GtkLayoutManager *manager)
{
  GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager);
  GtkLayoutManagerClass *klass;

  g_return_val_if_fail (GTK_IS_LAYOUT_MANAGER (manager), GTK_SIZE_REQUEST_CONSTANT_SIZE);
  g_return_val_if_fail (priv->widget != NULL, GTK_SIZE_REQUEST_CONSTANT_SIZE);

  klass = GTK_LAYOUT_MANAGER_GET_CLASS (manager);

  return klass->get_request_mode (manager, priv->widget);
}

/**
 * gtk_layout_manager_get_widget:
 * @manager: a `GtkLayoutManager`
 *
 * Retrieves the `GtkWidget` using the given `GtkLayoutManager`.
 *
 * Returns: (transfer none) (nullable): a `GtkWidget`
 */

GtkWidget *
gtk_layout_manager_get_widget (GtkLayoutManager *manager)
{
  GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager);

  g_return_val_if_fail (GTK_IS_LAYOUT_MANAGER (manager), NULL);

  return priv->widget;
}

/**
 * gtk_layout_manager_layout_changed:
 * @manager: a `GtkLayoutManager`
 *
 * Queues a resize on the `GtkWidget` using @manager, if any.
 *
 * This function should be called by subclasses of `GtkLayoutManager`
 * in response to changes to their layout management policies.
 */

void
gtk_layout_manager_layout_changed (GtkLayoutManager *manager)
{
  GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager);

  g_return_if_fail (GTK_IS_LAYOUT_MANAGER (manager));

  if (priv->widget != NULL)
    gtk_widget_queue_resize (priv->widget);
}

/*< private >
 * gtk_layout_manager_remove_layout_child:
 * @manager: a `GtkLayoutManager`
 * @widget: a `GtkWidget`
 *
 * Removes the `GtkLayoutChild` associated with @widget from the
 * given `GtkLayoutManager`, if any is set.
 */

void
gtk_layout_manager_remove_layout_child (GtkLayoutManager *manager,
                                        GtkWidget        *widget)
{
  GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager);

  if (priv->layout_children != NULL)
    {
      g_hash_table_remove (priv->layout_children, widget);
      if (g_hash_table_size (priv->layout_children) == 0)
        g_clear_pointer (&priv->layout_children, g_hash_table_unref);
    }
}

/**
 * gtk_layout_manager_get_layout_child:
 * @manager: a `GtkLayoutManager`
 * @child: a `GtkWidget`
 *
 * Retrieves a `GtkLayoutChild` instance for the `GtkLayoutManager`,
 * creating one if necessary.
 *
 * The @child widget must be a child of the widget using @manager.
 *
 * The `GtkLayoutChild` instance is owned by the `GtkLayoutManager`,
 * and is guaranteed to exist as long as @child is a child of the
 * `GtkWidget` using the given `GtkLayoutManager`.
 *
 * Returns: (transfer none): a `GtkLayoutChild`
 */

GtkLayoutChild *
gtk_layout_manager_get_layout_child (GtkLayoutManager *manager,
                                     GtkWidget        *child)
{
  GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager);
  GtkLayoutChild *res;
  GtkWidget *parent;

  g_return_val_if_fail (GTK_IS_LAYOUT_MANAGER (manager), NULL);
  g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);

  parent = _gtk_widget_get_parent (child);
  g_return_val_if_fail (parent != NULL, NULL);

  if (priv->widget != parent)
    {
      g_critical ("The parent %s %p of the widget %s %p does not "
                  "use the given layout manager of type %s %p",
                  gtk_widget_get_name (parent), parent,
                  gtk_widget_get_name (child), child,
                  G_OBJECT_TYPE_NAME (manager), manager);
      return NULL;
    }

  if (priv->layout_children == NULL)
    {
      priv->layout_children = g_hash_table_new_full (NULL, NULL,
                                                     NULL,
                                                     (GDestroyNotify) g_object_unref);
    }

  res = g_hash_table_lookup (priv->layout_children, child);
  if (res != NULL)
    {
      /* If the LayoutChild instance is stale, and refers to another
       * layout manager, then we simply ask the LayoutManager to
       * replace it, as it means the layout manager for the parent
       * widget was replaced
       */

      if (gtk_layout_child_get_layout_manager (res) == manager)
        return res;
    }

  res = GTK_LAYOUT_MANAGER_GET_CLASS (manager)->create_layout_child (manager, parent, child);
  if (res == NULL)
    {
      g_critical ("The layout manager of type %s %p does not create "
                  "GtkLayoutChild instances",
                  G_OBJECT_TYPE_NAME (manager), manager);
      return NULL;
    }

  g_assert (g_type_is_a (G_OBJECT_TYPE (res), GTK_TYPE_LAYOUT_CHILD));
  g_hash_table_insert (priv->layout_children, child, res);

  return res;
}

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

¤ Dauer der Verarbeitung: 0.19 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