Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  gimppopup.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * gimppopup.c
 * Copyright (C) 2003-2014 Michael Natterer <mitch@gimp.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */


#include "config.h"

#include <gegl.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

#include "libgimpwidgets/gimpwidgets.h"

#include "widgets-types.h"

#include "gimppopup.h"


enum
{
  CANCEL,
  CONFIRM,
  LAST_SIGNAL
};

typedef struct _GimpPopupPrivate
{
  GtkWidget *parent;
} GimpPopupPrivate;


static gboolean gimp_popup_map_event    (GtkWidget      *widget,
                                         GdkEventAny    *event);
static gboolean gimp_popup_button_press (GtkWidget      *widget,
                                         GdkEventButton *bevent);
static gboolean gimp_popup_key_press    (GtkWidget      *widget,
                                         GdkEventKey    *kevent);

static void     gimp_popup_real_cancel  (GimpPopup      *popup);
static void     gimp_popup_real_confirm (GimpPopup      *popup);


G_DEFINE_TYPE_WITH_PRIVATE (GimpPopup, gimp_popup, GTK_TYPE_WINDOW)

#define parent_class gimp_popup_parent_class

static guint popup_signals[LAST_SIGNAL];


static void
gimp_popup_class_init (GimpPopupClass *klass)
{
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  GtkBindingSet  *binding_set;

  popup_signals[CANCEL] =
    g_signal_new ("cancel",
                  G_OBJECT_CLASS_TYPE (klass),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GimpPopupClass, cancel),
                  NULL, NULL, NULL,
                  G_TYPE_NONE, 0);

  popup_signals[CONFIRM] =
    g_signal_new ("confirm",
                  G_OBJECT_CLASS_TYPE (klass),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GimpPopupClass, confirm),
                  NULL, NULL, NULL,
                  G_TYPE_NONE, 0);

  widget_class->map_event          = gimp_popup_map_event;
  widget_class->button_press_event = gimp_popup_button_press;
  widget_class->key_press_event    = gimp_popup_key_press;

  klass->cancel                    = gimp_popup_real_cancel;
  klass->confirm                   = gimp_popup_real_confirm;

  binding_set = gtk_binding_set_by_class (klass);

  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0,
                                "cancel", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0,
                                "confirm", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0,
                                "confirm", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0,
                                "confirm", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0,
                                "confirm", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0,
                                "confirm", 0);
}

static void
gimp_popup_init (GimpPopup *popup)
{
}

static void
gimp_popup_grab_notify (GtkWidget *widget,
                        gboolean   was_grabbed)
{
  GtkWidget *grab_widget;
  GtkWidget *iter;

  if (was_grabbed)
    return;

  grab_widget = gtk_grab_get_current ();

  /* ignore grabs on one of our children, like a scrollbar */
  if (gtk_widget_is_ancestor (grab_widget, widget))
    return;

  /* ignore grabs from windows / menus shown by
   * internal widgets */

  iter = gtk_widget_get_toplevel (grab_widget);
  while (iter)
    {
      if (iter == widget)
        return;

      if (GTK_IS_WINDOW (iter))
        iter = (GtkWidget*) gtk_window_get_transient_for ((GtkWindow*) iter);
      else
        break;
    }

  g_signal_emit (widget, popup_signals[CANCEL], 0);
}

static gboolean
gimp_popup_grab_broken_event (GtkWidget          *widget,
                              GdkEventGrabBroken *event)
{
  gimp_popup_grab_notify (widget, FALSE);

  return FALSE;
}

static gboolean
gimp_popup_map_event (GtkWidget   *widget,
                      GdkEventAny *event)
{
  GdkDisplay *display = gtk_widget_get_display (widget);

  GTK_WIDGET_CLASS (parent_class)->map_event (widget, event);

  /*  grab with owner_events == TRUE so the popup's widgets can
   *  receive events. we filter away events outside this toplevel
   *  away in button_press()
   */

  if (gdk_seat_grab (gdk_display_get_default_seat (display),
                     gtk_widget_get_window (widget),
                     GDK_SEAT_CAPABILITY_ALL,
                     TRUE,
                     NULL,
                     (GdkEvent *) event,
                     NULL, NULL) == GDK_GRAB_SUCCESS)
    {
      gtk_grab_add (widget);

      g_signal_connect (widget, "grab-notify",
                        G_CALLBACK (gimp_popup_grab_notify),
                        widget);
      g_signal_connect (widget, "grab-broken-event",
                        G_CALLBACK (gimp_popup_grab_broken_event),
                        widget);

      return FALSE;
    }

  /*  if we could not grab, destroy the popup instead of leaving it
   *  around uncloseable.
   */

  g_signal_emit (widget, popup_signals[CANCEL], 0);

  return FALSE;
}

static gboolean
gimp_popup_button_press (GtkWidget      *widget,
                         GdkEventButton *bevent)
{
  GtkWidget *event_widget;
  gboolean   cancel  = FALSE;
  gboolean   confirm = FALSE;

  event_widget = gtk_get_event_widget ((GdkEvent *) bevent);

  if (event_widget == widget)
    {
      GtkAllocation allocation;

      gtk_widget_get_allocation (widget, &allocation);

      /*  the event was on the popup, which can either be really on the
       *  popup or outside gimp (owner_events == TRUE, see map())
       */

      if (bevent->x < 0                ||
          bevent->y < 0                ||
          bevent->x > allocation.width ||
          bevent->y > allocation.height)
        {
          /*  the event was outsde gimp  */

          cancel = TRUE;
        }
    }
  else if (gtk_widget_get_toplevel (event_widget) != widget)
    {
      GimpPopupPrivate *priv;
      /*  the event was on a gimp widget, but not inside the popup  */

      priv = gimp_popup_get_instance_private (GIMP_POPUP (widget));
      if (event_widget == priv->parent || gtk_widget_is_ancestor (event_widget, priv->parent))
        confirm = TRUE;
      else
        cancel = TRUE;
    }

  if (cancel)
    g_signal_emit (widget, popup_signals[CANCEL], 0);
  else if (confirm)
    g_signal_emit (widget, popup_signals[CONFIRM], 0);

  return (cancel || confirm);
}

static gboolean
gimp_popup_key_press (GtkWidget   *widget,
                      GdkEventKey *kevent)
{
  GtkWidget *focus            = gtk_window_get_focus (GTK_WINDOW (widget));
  gboolean   activate_binding = TRUE;

  if (focus &&
      (GTK_IS_EDITABLE (focus) ||
       GTK_IS_TEXT_VIEW (focus)) &&
      (kevent->keyval == GDK_KEY_space ||
       kevent->keyval == GDK_KEY_KP_Space))
    {
      /*  if a text widget has the focus, and the key was space,
       *  don't manually activate the binding to allow entering the
       *  space in the focus widget.
       */

      activate_binding = FALSE;
    }

  if (activate_binding)
    {
      GtkBindingSet *binding_set;

      binding_set = gtk_binding_set_by_class (g_type_class_peek (GIMP_TYPE_POPUP));

      /*  invoke the popup's binding entries manually, because
       *  otherwise the focus widget (GtkTreeView e.g.) would consume
       *  it
       */

      if (gtk_binding_set_activate (binding_set,
                                    kevent->keyval,
                                    kevent->state,
                                    G_OBJECT (widget)))
        {
          return TRUE;
        }
    }

  return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, kevent);
}

static void
gimp_popup_real_cancel (GimpPopup *popup)
{
  GtkWidget *widget = GTK_WIDGET (popup);

  if (gtk_grab_get_current () == widget)
    gtk_grab_remove (widget);

  gtk_widget_destroy (widget);
}

static void
gimp_popup_real_confirm (GimpPopup *popup)
{
  GtkWidget *widget = GTK_WIDGET (popup);

  if (gtk_grab_get_current () == widget)
    gtk_grab_remove (widget);

  gtk_widget_destroy (widget);
}

/**
 * gimp_popup_show:
 * @popup:
 * @widget: the parent widget which will determine @popup location.
 *
 * Shows @popup above @widget. Its placement will be determined relatively to
 * @widget.
 * Moreover clicking outside @popup but within @widget will be considered a
 * "confirm" signal. Typically @widget would be a button. A typical UX could be:
 * clicking it once would show the popup; clicking it again would confirm the
 * choice within the popup.
 */

void
gimp_popup_show (GimpPopup *popup,
                 GtkWidget *widget)
{
  GimpPopupPrivate *priv;
  GdkDisplay       *display;
  GdkMonitor       *monitor;
  GtkRequisition    requisition;
  GtkAllocation     allocation;
  GdkRectangle      rect;
  gint              orig_x;
  gint              orig_y;
  gint              x;
  gint              y;

  g_return_if_fail (GIMP_IS_POPUP (popup));
  g_return_if_fail (GTK_IS_WIDGET (widget));

  priv = gimp_popup_get_instance_private (popup);
  priv->parent = widget;

  gtk_widget_get_preferred_size (GTK_WIDGET (popup), &requisition, NULL);

  gtk_widget_get_allocation (widget, &allocation);
  gdk_window_get_origin (gtk_widget_get_window (widget), &orig_x, &orig_y);

  if (! gtk_widget_get_has_window (widget))
    {
      orig_x += allocation.x;
      orig_y += allocation.y;
    }

  display = gtk_widget_get_display (widget);

  monitor = gdk_display_get_monitor_at_point (display, orig_x, orig_y);
  gdk_monitor_get_workarea (monitor, &rect);

  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
    {
      x = orig_x + allocation.width - requisition.width;

      if (x < rect.x)
        x -= allocation.width - requisition.width;
    }
  else
    {
      x = orig_x;

      if (x + requisition.width > rect.x + rect.width)
        x += allocation.width - requisition.width;
    }

  y = orig_y + allocation.height;

  if (y + requisition.height > rect.y + rect.height)
    y = orig_y - requisition.height;

  gtk_window_set_screen (GTK_WINDOW (popup), gtk_widget_get_screen (widget));
  gtk_window_set_transient_for (GTK_WINDOW (popup),
                                GTK_WINDOW (gtk_widget_get_toplevel (widget)));

  gtk_window_move (GTK_WINDOW (popup), x, y);
  gtk_widget_show (GTK_WIDGET (popup));
}

Messung
CHZG
82999391

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


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

letze Version des Elbe Quellennavigators


Jenseits des Üblichen ....
    

Besucher

Besucher

Statistik
#Sources=1104856
#Domains=417319