gtkdrawingarea.c 7.96 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2 3 4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6 7 8 9 10 11
 * 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
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
Javier Jardon's avatar
Javier Jardon committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
17 18

/*
19
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20 21
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
22
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 24
 */

25
#include "config.h"
Elliot Lee's avatar
Elliot Lee committed
26
#include "gtkdrawingarea.h"
Matthias Clasen's avatar
Matthias Clasen committed
27
#include "gtkintl.h"
28
#include "gtkstylecontext.h"
Elliot Lee's avatar
Elliot Lee committed
29 30


31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
/**
 * SECTION:gtkdrawingarea
 * @Short_description: A widget for custom user interface elements
 * @Title: GtkDrawingArea
 * @See_also: #GtkImage
 *
 * The #GtkDrawingArea widget is used for creating custom user interface
 * elements. It's essentially a blank widget; you can draw on it. After
 * creating a drawing area, the application may want to connect to:
 *
 * <itemizedlist>
 *   <listitem>
 *     <para>
 *     Mouse and button press signals to respond to input from
 *     the user. (Use gtk_widget_add_events() to enable events
 *     you wish to receive.)
 *     </para>
 *   </listitem>
 *   <listitem>
 *     <para>
 *     The #GtkWidget::realize signal to take any necessary actions
 *     when the widget is instantiated on a particular display.
 *     (Create GDK resources in response to this signal.)
 *     </para>
 *   </listitem>
 *   <listitem>
 *     <para>
 *     The #GtkWidget::configure-event signal to take any necessary
 *     actions when the widget changes size.
 *     </para>
 *   </listitem>
 *   <listitem>
 *     <para>
 *     The #GtkWidget::draw signal to handle redrawing the
 *     contents of the widget.
 *     </para>
 *   </listitem>
 * </itemizedlist>
 *
 * The following code portion demonstrates using a drawing
 * area to display a circle in the normal widget foreground
 * color.
 *
 * Note that GDK automatically clears the exposed area to the
 * background color before sending the expose event, and that
 * drawing is implicitly clipped to the exposed area.
 *
 * <example>
 * <title>Simple GtkDrawingArea usage</title>
 * <programlisting>
 * gboolean
 * draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
 * {
 *   guint width, height;
 *   GdkRGBA color;
 *
 *   width = gtk_widget_get_allocated_width (widget);
 *   height = gtk_widget_get_allocated_height (widget);
 *   cairo_arc (cr,
 *              width / 2.0, height / 2.0,
 *              MIN (width, height) / 2.0,
 *              0, 2 * G_PI);
 *
 *   gtk_style_context_get_color (gtk_widget_get_style_context (widget),
 *                                0,
 *                                &amp;color);
 *   gdk_cairo_set_source_rgba (cr, &amp;color);
 *
 *   cairo_fill (cr);
 *
 *  return FALSE;
 * }
 * [...]
 *   GtkWidget &ast;drawing_area = gtk_drawing_area_new (<!-- -->);
 *   gtk_widget_set_size_request (drawing_area, 100, 100);
 *   g_signal_connect (G_OBJECT (drawing_area), "draw",
 *                     G_CALLBACK (draw_callback), NULL);
 * </programlisting>
 * </example>
 *
 * Draw signals are normally delivered when a drawing area first comes
 * onscreen, or when it's covered by another window and then uncovered.
 * You can also force an expose event by adding to the "damage region"
 * of the drawing area's window; gtk_widget_queue_draw_area() and
 * gdk_window_invalidate_rect() are equally good ways to do this.
 * You'll then get a draw signal for the invalid region.
 *
 * The available routines for drawing are documented on the <link
 * linkend="gdk3-Cairo-Interaction">GDK Drawing Primitives</link> page
 * and the cairo documentation.
 *
 * To receive mouse events on a drawing area, you will need to enable
 * them with gtk_widget_add_events(). To receive keyboard events, you
124
 * will need to set the "can-focus" property on the drawing area, and you
125
 * should probably draw some user-visible indication that the drawing
126
 * area is focused. Use gtk_widget_has_focus() in your expose event
127
 * handler to decide whether to draw the focus indicator. See
128
 * gtk_render_focus() for one way to draw focus.
129 130
 */

Elliot Lee's avatar
Elliot Lee committed
131 132
static void gtk_drawing_area_realize       (GtkWidget           *widget);
static void gtk_drawing_area_size_allocate (GtkWidget           *widget,
133
                                            GtkAllocation       *allocation);
134
static void gtk_drawing_area_send_configure (GtkDrawingArea     *darea);
Elliot Lee's avatar
Elliot Lee committed
135

Matthias Clasen's avatar
Matthias Clasen committed
136
G_DEFINE_TYPE (GtkDrawingArea, gtk_drawing_area, GTK_TYPE_WIDGET)
Elliot Lee's avatar
Elliot Lee committed
137 138 139 140

static void
gtk_drawing_area_class_init (GtkDrawingAreaClass *class)
{
141
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
Elliot Lee's avatar
Elliot Lee committed
142 143 144 145 146 147 148 149 150 151

  widget_class->realize = gtk_drawing_area_realize;
  widget_class->size_allocate = gtk_drawing_area_size_allocate;
}

static void
gtk_drawing_area_init (GtkDrawingArea *darea)
{
}

152 153 154 155 156 157 158
/**
 * gtk_drawing_area_new:
 *
 * Creates a new drawing area.
 *
 * Returns: a new #GtkDrawingArea
 */
Elliot Lee's avatar
Elliot Lee committed
159
GtkWidget*
160
gtk_drawing_area_new (void)
Elliot Lee's avatar
Elliot Lee committed
161
{
Manish Singh's avatar
Manish Singh committed
162
  return g_object_new (GTK_TYPE_DRAWING_AREA, NULL);
Elliot Lee's avatar
Elliot Lee committed
163 164 165 166 167
}

static void
gtk_drawing_area_realize (GtkWidget *widget)
{
168
  GtkDrawingArea *darea = GTK_DRAWING_AREA (widget);
169 170
  GtkAllocation allocation;
  GdkWindow *window;
Elliot Lee's avatar
Elliot Lee committed
171 172 173
  GdkWindowAttr attributes;
  gint attributes_mask;

174
  if (!gtk_widget_get_has_window (widget))
175 176 177 178 179
    {
      GTK_WIDGET_CLASS (gtk_drawing_area_parent_class)->realize (widget);
    }
  else
    {
180
      gtk_widget_set_realized (widget, TRUE);
181

182 183
      gtk_widget_get_allocation (widget, &allocation);

184
      attributes.window_type = GDK_WINDOW_CHILD;
185 186 187 188
      attributes.x = allocation.x;
      attributes.y = allocation.y;
      attributes.width = allocation.width;
      attributes.height = allocation.height;
189 190 191 192
      attributes.wclass = GDK_INPUT_OUTPUT;
      attributes.visual = gtk_widget_get_visual (widget);
      attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;

193
      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
194

195 196
      window = gdk_window_new (gtk_widget_get_parent_window (widget),
                               &attributes, attributes_mask);
197
      gtk_widget_register_window (widget, window);
198
      gtk_widget_set_window (widget, window);
199

200 201
      gtk_style_context_set_background (gtk_widget_get_style_context (widget),
                                        window);
202
    }
203 204

  gtk_drawing_area_send_configure (GTK_DRAWING_AREA (widget));
Elliot Lee's avatar
Elliot Lee committed
205 206 207 208
}

static void
gtk_drawing_area_size_allocate (GtkWidget     *widget,
209
                                GtkAllocation *allocation)
Elliot Lee's avatar
Elliot Lee committed
210 211 212 213
{
  g_return_if_fail (GTK_IS_DRAWING_AREA (widget));
  g_return_if_fail (allocation != NULL);

214
  gtk_widget_set_allocation (widget, allocation);
Elliot Lee's avatar
Elliot Lee committed
215

216
  if (gtk_widget_get_realized (widget))
Elliot Lee's avatar
Elliot Lee committed
217
    {
218
      if (gtk_widget_get_has_window (widget))
219
        gdk_window_move_resize (gtk_widget_get_window (widget),
220 221
                                allocation->x, allocation->y,
                                allocation->width, allocation->height);
Elliot Lee's avatar
Elliot Lee committed
222

223
      gtk_drawing_area_send_configure (GTK_DRAWING_AREA (widget));
Elliot Lee's avatar
Elliot Lee committed
224 225
    }
}
226 227 228 229

static void
gtk_drawing_area_send_configure (GtkDrawingArea *darea)
{
230
  GtkAllocation allocation;
231
  GtkWidget *widget;
232
  GdkEvent *event = gdk_event_new (GDK_CONFIGURE);
233 234

  widget = GTK_WIDGET (darea);
235
  gtk_widget_get_allocation (widget, &allocation);
236

237
  event->configure.window = g_object_ref (gtk_widget_get_window (widget));
238
  event->configure.send_event = TRUE;
239 240 241 242
  event->configure.x = allocation.x;
  event->configure.y = allocation.y;
  event->configure.width = allocation.width;
  event->configure.height = allocation.height;
243

244 245
  gtk_widget_event (widget, event);
  gdk_event_free (event);
246
}