## 7 Hello World

This node includes the C declarations and Scheme code required to implement Havoc Pennington’s Hello World example from GGAD. For an extra, Schemely treat, its `delete_event` callback is a Scheme procedure closed over a binding of `counter` that is used to implement some impertinent behavior.

    #| -*-Scheme-*-

    This is Havoc Pennington's Hello World example from GGAD, in the raw
    FFI.  Note that no arrangements have been made to de-register the
    callbacks. |#

    (declare (usual-integrations))

    (C-include "prhello")

    (define (hello)
      (C-call "gtk_init" 0 null-alien)
      (let ((window (let ((alien (make-alien '|GtkWidget|)))
    		  (C-call "gtk_window_new" alien
    			  (C-enum "GTK_WINDOW_TOPLEVEL"))
    		  (if (alien-null? alien) (error "Could not create window."))
    		  alien))
    	(button (let ((alien (make-alien '|GtkWidget|)))
    		  (C-call "gtk_button_new" alien)
    		  (if (alien-null? alien) (error "Could not create button."))
    		  alien))
    	(label (let ((alien (make-alien '|GtkWidget|)))
    		 (C-call "gtk_label_new" alien "Hello, World!")
    		 (if (alien-null? alien) (error "Could not create label."))
    		 alien)))
        (C-call "gtk_container_add" button label)
        (C-call "gtk_container_add" window button)
        (C-call "gtk_window_set_title" window "Hello")
        (C-call "gtk_container_set_border_width" button 10)
        (let ((counter 0))
          (C-call "g_signal_connect" window "delete_event"
    	      (C-callback "delete_event")	;trampoline
    	      (C-callback			;callback ID
    	       (lambda (w e)
    		 (outf-console ";Delete me "(- 2 counter)" times.\n")
    		 (set! counter (1+ counter))
    		 ;; Three or more is the charm.
    		 (if (> counter 2)
    		     (begin
    		       (C-call "gtk_main_quit")
    		       0)
    		     1))))
          (C-call "g_signal_connect" button "clicked"
    	      (C-callback "clicked")	;trampoline
    	      (C-callback			;callback ID
    	       (lambda (w)
    		 (let ((gstring (make-alien '(* |gchar|))))
    		   (C-call "gtk_label_get_text" gstring label)
    		   (let ((text (c-peek-cstring gstring)))
    		     (C-call "gtk_label_set_text" label
    			     (list->string (reverse! (string->list text))))))
    		 unspecific))))
        (C-call "gtk_widget_show_all" window)
        (C-call "gtk_main")
        window))

Here are the C declarations.

    #| -*-Scheme-*-

    C declarations for prhello.scm. |#

    (typedef gint int)
    (typedef guint uint)
    (typedef gchar char)
    (typedef gboolean gint)
    (typedef gpointer (* mumble))

    (extern void
    	gtk_init
    	(argc (* int))
    	(argv (* (* (* char)))))

    (extern (* GtkWidget)
    	gtk_window_new
    	(type GtkWindowType))

    (typedef GtkWindowType
    	 (enum
    	  (GTK_WINDOW_TOPLEVEL)
    	  (GTK_WINDOW_POPUP)))

    (extern (* GtkWidget)
    	gtk_button_new)

    (extern (* GtkWidget)
    	gtk_label_new
    	(str (* (const char))))

    (extern void
    	gtk_container_add
    	(container (* GtkContainer))
    	(widget    (* GtkWidget)))

    (extern void
    	gtk_window_set_title
    	(window (* GtkWindow))
    	(title  (* (const gchar))))

    (extern void
    	gtk_container_set_border_width
    	(container (* GtkContainer))
    	(border_width guint))

    (extern void
    	gtk_widget_show_all
    	(widget (* GtkWidget)))

    (extern void
    	g_signal_connect
    	(object (* GtkObject))
    	(name (* gchar))
    	(CALLBACK GtkSignalFunc)
    	(ID gpointer))

    (typedef GtkSignalFunc (* mumble))

    (callback gboolean
    	  delete_event
    	  (window (* GtkWidget))
    	  (event (* GdkEventAny))
    	  (ID gpointer))

    (callback void
    	  clicked
    	  (widget (* GtkWidget))
    	  (ID gpointer))

    (extern void
    	gtk_widget_destroy
    	(widget (* GtkWidget)))

    (extern (* (const gchar))
    	gtk_label_get_text
    	(label (* GtkLabel)))

    (extern void
    	gtk_label_set_text
    	(label (* GtkLabel))
    	(str (* (const char))))

    (extern void gtk_main)
    (extern void gtk_main_quit)