gtkdrawingarea.c 8 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
15 16 17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18
 */
19 20

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

27
#include "config.h"
Elliot Lee's avatar
Elliot Lee committed
28
#include "gtkdrawingarea.h"
29
#include "gtkintl.h"
Elliot Lee's avatar
Elliot Lee committed
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 124
/**
 * 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
125
 * will need to set the "can-focus" property on the drawing area, and you
126
 * should probably draw some user-visible indication that the drawing
127
 * area is focused. Use gtk_widget_has_focus() in your expose event
128
 * handler to decide whether to draw the focus indicator. See
129
 * gtk_render_focus() for one way to draw focus.
130 131
 */

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

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

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

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

static void
gtk_drawing_area_init (GtkDrawingArea *darea)
{
}

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

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

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

183 184
      gtk_widget_get_allocation (widget, &allocation);

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

194
      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
195

196 197 198 199
      window = gdk_window_new (gtk_widget_get_parent_window (widget),
                               &attributes, attributes_mask);
      gdk_window_set_user_data (window, darea);
      gtk_widget_set_window (widget, window);
200

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

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

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

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

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

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

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

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

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

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