1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module gtk.GLArea;
26 
27 private import gdk.GLContext;
28 private import glib.ConstructionException;
29 private import glib.ErrorG;
30 private import gobject.ObjectG;
31 private import gobject.Signals;
32 private import gtk.Widget;
33 public  import gtkc.gdktypes;
34 private import gtkc.gtk;
35 public  import gtkc.gtktypes;
36 
37 
38 /**
39  * #GtkGLArea is a widget that allows drawing with OpenGL.
40  * 
41  * #GtkGLArea sets up its own #GdkGLContext for the window it creates, and
42  * creates a custom GL framebuffer that the widget will do GL rendering onto.
43  * It also ensures that this framebuffer is the default GL rendering target
44  * when rendering.
45  * 
46  * In order to draw, you have to connect to the #GtkGLArea::render signal,
47  * or subclass #GtkGLArea and override the @GtkGLAreaClass.render() virtual
48  * function.
49  * 
50  * The #GtkGLArea widget ensures that the #GdkGLContext is associated with
51  * the widget's drawing area, and it is kept updated when the size and
52  * position of the drawing area changes.
53  * 
54  * ## Drawing with GtkGLArea ##
55  * 
56  * The simplest way to draw using OpenGL commands in a #GtkGLArea is to
57  * create a widget instance and connect to the #GtkGLArea::render signal:
58  * 
59  * |[<!-- language="C" -->
60  * // create a GtkGLArea instance
61  * GtkWidget *gl_area = gtk_gl_area_new ();
62  * 
63  * // connect to the "render" signal
64  * g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);
65  * ]|
66  * 
67  * The `render()` function will be called when the #GtkGLArea is ready
68  * for you to draw its content:
69  * 
70  * |[<!-- language="C" -->
71  * static gboolean
72  * render (GtkGLArea *area, GdkGLContext *context)
73  * {
74  * // inside this function it's safe to use GL; the given
75  * // #GdkGLContext has been made current to the drawable
76  * // surface used by the #GtkGLArea and the viewport has
77  * // already been set to be the size of the allocation
78  * 
79  * // we can start by clearing the buffer
80  * glClearColor (0, 0, 0, 0);
81  * glClear (GL_COLOR_BUFFER_BIT);
82  * 
83  * // draw your object
84  * draw_an_object ();
85  * 
86  * // we completed our drawing; the draw commands will be
87  * // flushed at the end of the signal emission chain, and
88  * // the buffers will be drawn on the window
89  * return TRUE;
90  * }
91  * ]|
92  * 
93  * If you need to initialize OpenGL state, e.g. buffer objects or
94  * shaders, you should use the #GtkWidget::realize signal; you
95  * can use the #GtkWidget::unrealize signal to clean up. Since the
96  * #GdkGLContext creation and initialization may fail, you will
97  * need to check for errors, using gtk_gl_area_get_error(). An example
98  * of how to safely initialize the GL state is:
99  * 
100  * |[<!-- language="C" -->
101  * static void
102  * on_realize (GtkGLarea *area)
103  * {
104  * // We need to make the context current if we want to
105  * // call GL API
106  * gtk_gl_area_make_current (area);
107  * 
108  * // If there were errors during the initialization or
109  * // when trying to make the context current, this
110  * // function will return a #GError for you to catch
111  * if (gtk_gl_area_get_error (area) != NULL)
112  * return;
113  * 
114  * // You can also use gtk_gl_area_set_error() in order
115  * // to show eventual initialization errors on the
116  * // GtkGLArea widget itself
117  * GError *internal_error = NULL;
118  * init_buffer_objects (&error);
119  * if (error != NULL)
120  * {
121  * gtk_gl_area_set_error (area, error);
122  * g_error_free (error);
123  * return;
124  * }
125  * 
126  * init_shaders (&error);
127  * if (error != NULL)
128  * {
129  * gtk_gl_area_set_error (area, error);
130  * g_error_free (error);
131  * return;
132  * }
133  * }
134  * ]|
135  * 
136  * If you need to change the options for creating the #GdkGLContext
137  * you should use the #GtkGLArea::create-context signal.
138  *
139  * Since: 3.16
140  */
141 public class GLArea : Widget
142 {
143 	/** the main Gtk struct */
144 	protected GtkGLArea* gtkGLArea;
145 
146 	/** Get the main Gtk struct */
147 	public GtkGLArea* getGLAreaStruct()
148 	{
149 		return gtkGLArea;
150 	}
151 
152 	/** the main Gtk struct as a void* */
153 	protected override void* getStruct()
154 	{
155 		return cast(void*)gtkGLArea;
156 	}
157 
158 	protected override void setStruct(GObject* obj)
159 	{
160 		gtkGLArea = cast(GtkGLArea*)obj;
161 		super.setStruct(obj);
162 	}
163 
164 	/**
165 	 * Sets our main struct and passes it to the parent class.
166 	 */
167 	public this (GtkGLArea* gtkGLArea, bool ownedRef = false)
168 	{
169 		this.gtkGLArea = gtkGLArea;
170 		super(cast(GtkWidget*)gtkGLArea, ownedRef);
171 	}
172 
173 	/**
174 	 */
175 
176 	public static GType getType()
177 	{
178 		return gtk_gl_area_get_type();
179 	}
180 
181 	/**
182 	 * Creates a new #GtkGLArea widget.
183 	 *
184 	 * Return: the newly created #GtkGLArea
185 	 *
186 	 * Since: 3.16
187 	 *
188 	 * Throws: ConstructionException GTK+ fails to create the object.
189 	 */
190 	public this()
191 	{
192 		auto p = gtk_gl_area_new();
193 		
194 		if(p is null)
195 		{
196 			throw new ConstructionException("null returned by new");
197 		}
198 		
199 		this(cast(GtkGLArea*) p, true);
200 	}
201 
202 	/**
203 	 * Ensures that the @area framebuffer object is made the current draw
204 	 * and read target, and that all the required buffers for the @area
205 	 * are created and bound to the frambuffer.
206 	 *
207 	 * This function is automatically called before emitting the
208 	 * #GtkGLArea::render signal, and doesn't normally need to be called
209 	 * by application code.
210 	 *
211 	 * Since: 3.16
212 	 */
213 	public void attachBuffers()
214 	{
215 		gtk_gl_area_attach_buffers(gtkGLArea);
216 	}
217 
218 	/**
219 	 * Returns whether the area is in auto render mode or not.
220 	 *
221 	 * Return: %TRUE if the @area is auto rendering, %FALSE otherwise
222 	 *
223 	 * Since: 3.16
224 	 */
225 	public bool getAutoRender()
226 	{
227 		return gtk_gl_area_get_auto_render(gtkGLArea) != 0;
228 	}
229 
230 	/**
231 	 * Retrieves the #GdkGLContext used by @area.
232 	 *
233 	 * Return: the #GdkGLContext
234 	 *
235 	 * Since: 3.16
236 	 */
237 	public GLContext getContext()
238 	{
239 		auto p = gtk_gl_area_get_context(gtkGLArea);
240 		
241 		if(p is null)
242 		{
243 			return null;
244 		}
245 		
246 		return ObjectG.getDObject!(GLContext)(cast(GdkGLContext*) p);
247 	}
248 
249 	/**
250 	 * Gets the current error set on the @area.
251 	 *
252 	 * Return: the #GError or %NULL
253 	 *
254 	 * Since: 3.16
255 	 */
256 	public ErrorG getError()
257 	{
258 		auto p = gtk_gl_area_get_error(gtkGLArea);
259 		
260 		if(p is null)
261 		{
262 			return null;
263 		}
264 		
265 		return new ErrorG(cast(GError*) p);
266 	}
267 
268 	/**
269 	 * Returns whether the area has an alpha component.
270 	 *
271 	 * Return: %TRUE if the @area has an alpha component, %FALSE otherwise
272 	 *
273 	 * Since: 3.16
274 	 */
275 	public bool getHasAlpha()
276 	{
277 		return gtk_gl_area_get_has_alpha(gtkGLArea) != 0;
278 	}
279 
280 	/**
281 	 * Returns whether the area has a depth buffer.
282 	 *
283 	 * Return: %TRUE if the @area has a depth buffer, %FALSE otherwise
284 	 *
285 	 * Since: 3.16
286 	 */
287 	public bool getHasDepthBuffer()
288 	{
289 		return gtk_gl_area_get_has_depth_buffer(gtkGLArea) != 0;
290 	}
291 
292 	/**
293 	 * Returns whether the area has a stencil buffer.
294 	 *
295 	 * Return: %TRUE if the @area has a stencil buffer, %FALSE otherwise
296 	 *
297 	 * Since: 3.16
298 	 */
299 	public bool getHasStencilBuffer()
300 	{
301 		return gtk_gl_area_get_has_stencil_buffer(gtkGLArea) != 0;
302 	}
303 
304 	/**
305 	 * Retrieves the required version of OpenGL set
306 	 * using gtk_gl_area_set_required_version().
307 	 *
308 	 * Params:
309 	 *     major = return location for the required major version
310 	 *     minor = return location for the required minor version
311 	 *
312 	 * Since: 3.16
313 	 */
314 	public void getRequiredVersion(out int major, out int minor)
315 	{
316 		gtk_gl_area_get_required_version(gtkGLArea, &major, &minor);
317 	}
318 
319 	/**
320 	 * Ensures that the #GdkGLContext used by @area is associated with
321 	 * the #GtkGLArea.
322 	 *
323 	 * This function is automatically called before emitting the
324 	 * #GtkGLArea::render signal, and doesn't normally need to be called
325 	 * by application code.
326 	 *
327 	 * Since: 3.16
328 	 */
329 	public void makeCurrent()
330 	{
331 		gtk_gl_area_make_current(gtkGLArea);
332 	}
333 
334 	/**
335 	 * Marks the currently rendered data (if any) as invalid, and queues
336 	 * a redraw of the widget, ensuring that the #GtkGLArea::render signal
337 	 * is emitted during the draw.
338 	 *
339 	 * This is only needed when the gtk_gl_area_set_auto_render() has
340 	 * been called with a %FALSE value. The default behaviour is to
341 	 * emit #GtkGLArea::render on each draw.
342 	 *
343 	 * Since: 3.16
344 	 */
345 	public void queueRender()
346 	{
347 		gtk_gl_area_queue_render(gtkGLArea);
348 	}
349 
350 	/**
351 	 * If @auto_render is %TRUE the #GtkGLArea::render signal will be
352 	 * emitted every time the widget draws. This is the default and is
353 	 * useful if drawing the widget is faster.
354 	 *
355 	 * If @auto_render is %FALSE the data from previous rendering is kept
356 	 * around and will be used for drawing the widget the next time,
357 	 * unless the window is resized. In order to force a rendering
358 	 * gtk_gl_area_queue_render() must be called. This mode is useful when
359 	 * the scene changes seldomly, but takes a long time to redraw.
360 	 *
361 	 * Params:
362 	 *     autoRender = a boolean
363 	 *
364 	 * Since: 3.16
365 	 */
366 	public void setAutoRender(bool autoRender)
367 	{
368 		gtk_gl_area_set_auto_render(gtkGLArea, autoRender);
369 	}
370 
371 	/**
372 	 * Sets an error on the area which will be shown instead of the
373 	 * GL rendering. This is useful in the #GtkGLArea::create-context
374 	 * signal if GL context creation fails.
375 	 *
376 	 * Params:
377 	 *     error = a new #GError, or %NULL to unset the error
378 	 *
379 	 * Since: 3.16
380 	 */
381 	public void setError(ErrorG error)
382 	{
383 		gtk_gl_area_set_error(gtkGLArea, (error is null) ? null : error.getErrorGStruct());
384 	}
385 
386 	/**
387 	 * If @has_alpha is %TRUE the buffer allocated by the widget will have
388 	 * an alpha channel component, and when rendering to the window the
389 	 * result will be composited over whatever is below the widget.
390 	 *
391 	 * If @has_alpha is %FALSE there will be no alpha channel, and the
392 	 * buffer will fully replace anything below the widget.
393 	 *
394 	 * Params:
395 	 *     hasAlpha = %TRUE to add an alpha component
396 	 *
397 	 * Since: 3.16
398 	 */
399 	public void setHasAlpha(bool hasAlpha)
400 	{
401 		gtk_gl_area_set_has_alpha(gtkGLArea, hasAlpha);
402 	}
403 
404 	/**
405 	 * If @has_depth_buffer is %TRUE the widget will allocate and
406 	 * enable a depth buffer for the target framebuffer. Otherwise
407 	 * there will be none.
408 	 *
409 	 * Params:
410 	 *     hasDepthBuffer = %TRUE to add a depth buffer
411 	 *
412 	 * Since: 3.16
413 	 */
414 	public void setHasDepthBuffer(bool hasDepthBuffer)
415 	{
416 		gtk_gl_area_set_has_depth_buffer(gtkGLArea, hasDepthBuffer);
417 	}
418 
419 	/**
420 	 * If @has_stencil_buffer is %TRUE the widget will allocate and
421 	 * enable a stencil buffer for the target framebuffer. Otherwise
422 	 * there will be none.
423 	 *
424 	 * Params:
425 	 *     hasStencilBuffer = %TRUE to add a stencil buffer
426 	 *
427 	 * Since: 3.16
428 	 */
429 	public void setHasStencilBuffer(bool hasStencilBuffer)
430 	{
431 		gtk_gl_area_set_has_stencil_buffer(gtkGLArea, hasStencilBuffer);
432 	}
433 
434 	/**
435 	 * Sets the required version of OpenGL to be used when creating the context
436 	 * for the widget.
437 	 *
438 	 * This function must be called before the area has been realized.
439 	 *
440 	 * Params:
441 	 *     major = the major version
442 	 *     minor = the minor version
443 	 *
444 	 * Since: 3.16
445 	 */
446 	public void setRequiredVersion(int major, int minor)
447 	{
448 		gtk_gl_area_set_required_version(gtkGLArea, major, minor);
449 	}
450 
451 	int[string] connectedSignals;
452 
453 	GLContext delegate(GLArea)[] onCreateContextListeners;
454 	/**
455 	 * The ::create-context signal is emitted when the widget is being
456 	 * realized, and allows you to override how the GL context is
457 	 * created. This is useful when you want to reuse an existing GL
458 	 * context, or if you want to try creating different kinds of GL
459 	 * options.
460 	 *
461 	 * If context creation fails then the signal handler can use
462 	 * gtk_gl_area_set_error() to register a more detailed error
463 	 * of how the construction failed.
464 	 *
465 	 * Return: a newly created #GdkGLContext;
466 	 *     the #GtkGLArea widget will take ownership of the returned value.
467 	 *
468 	 * Since: 3.16
469 	 */
470 	void addOnCreateContext(GLContext delegate(GLArea) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
471 	{
472 		if ( "create-context" !in connectedSignals )
473 		{
474 			Signals.connectData(
475 				this,
476 				"create-context",
477 				cast(GCallback)&callBackCreateContext,
478 				cast(void*)this,
479 				null,
480 				connectFlags);
481 			connectedSignals["create-context"] = 1;
482 		}
483 		onCreateContextListeners ~= dlg;
484 	}
485 	extern(C) static GdkGLContext* callBackCreateContext(GtkGLArea* glareaStruct, GLArea _glarea)
486 	{
487 		foreach ( GLContext delegate(GLArea) dlg; _glarea.onCreateContextListeners )
488 		{
489 			if ( auto r = dlg(_glarea) )
490 				return r.getGLContextStruct();
491 		}
492 		
493 		return null;
494 	}
495 
496 	bool delegate(GLContext, GLArea)[] onRenderListeners;
497 	/**
498 	 * The ::render signal is emitted every time the contents
499 	 * of the #GtkGLArea should be redrawn.
500 	 *
501 	 * The @context is bound to the @area prior to emitting this function,
502 	 * and the buffers are painted to the window once the emission terminates.
503 	 *
504 	 * Params:
505 	 *     context = the #GdkGLContext used by @area
506 	 *
507 	 * Return: %TRUE to stop other handlers from being invoked for the event.
508 	 *     %FALSE to propagate the event further.
509 	 *
510 	 * Since: 3.16
511 	 */
512 	void addOnRender(bool delegate(GLContext, GLArea) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
513 	{
514 		if ( "render" !in connectedSignals )
515 		{
516 			Signals.connectData(
517 				this,
518 				"render",
519 				cast(GCallback)&callBackRender,
520 				cast(void*)this,
521 				null,
522 				connectFlags);
523 			connectedSignals["render"] = 1;
524 		}
525 		onRenderListeners ~= dlg;
526 	}
527 	extern(C) static int callBackRender(GtkGLArea* glareaStruct, GdkGLContext* context, GLArea _glarea)
528 	{
529 		foreach ( bool delegate(GLContext, GLArea) dlg; _glarea.onRenderListeners )
530 		{
531 			if ( dlg(ObjectG.getDObject!(GLContext)(context), _glarea) )
532 			{
533 				return 1;
534 			}
535 		}
536 		
537 		return 0;
538 	}
539 
540 	void delegate(int, int, GLArea)[] onResizeListeners;
541 	void addOnResize(void delegate(int, int, GLArea) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
542 	{
543 		if ( "resize" !in connectedSignals )
544 		{
545 			Signals.connectData(
546 				this,
547 				"resize",
548 				cast(GCallback)&callBackResize,
549 				cast(void*)this,
550 				null,
551 				connectFlags);
552 			connectedSignals["resize"] = 1;
553 		}
554 		onResizeListeners ~= dlg;
555 	}
556 	extern(C) static void callBackResize(GtkGLArea* glareaStruct, int object, int p0, GLArea _glarea)
557 	{
558 		foreach ( void delegate(int, int, GLArea) dlg; _glarea.onResizeListeners )
559 		{
560 			dlg(object, p0, _glarea);
561 		}
562 	}
563 }