This is the mail archive of the guile-gtk@sourceware.cygnus.com mailing list for the Guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: select+read on socket in guile,guile-gtk



While mulling over the comments from Chris C. and Gary H. (thanks!), and
poking about the source code preparing to write some guile port
extensions, I found a couple of read-made ways to accomplish what I need
for now.

On Wed, 21 Jun 2000, I wrote:

> if guile's cooperative threads play nice with guile-gtk -
> Can I create and maniuplate Gtk+ GUIs from any thread?

Turns out that with a little fiddling, this works after a fashion;
example program attached.

> On Mon, 19 Jun 2000, I wrote:
> > Does guile-gtk provide a way to hook (file descriptors from) guile ports
> > into the Gtk+ select loop?   Glib's GIOChannel's perhaps?

Turns out that Gtk+ has such a facility, and guile-gtk already exposes it:  
gtk-input-add

> > What I'm ultimately trying to do is arrange for a procedure to get called
> > with complete lines read from a connected TCP socket, so that information
> > recieved from the server at the other end can be used to update
> > items in a guile-gtk interface.

Two short example programs in this direction are attached, tested with a
freshly-compiled guile-1.4 and guile-gtk-0.18 (with Greg Badros' patch for
smob creation)

The first one coaxes guile cooperative threads and guile-gtk into running
together.  It ends up burning a lot of CPU time; probably both gtk and
guile are doing nonblocking reads and yielding back and forth.  
The second uses gtk-input-add.
Along the way, both illustrate creating a simple TCP client.

Steve


#!/tmp/ggtest/bin/guile-gtk -s
!#
;
; Test 3 using guile to write a simple network client
; that displays results in a Gtk+ window.
; This one uses guile cooperative threads.
;
(use-modules (ice-9 threads))
(use-modules (gtk gtk))

(read-set! keywords 'prefix)

(define (print-to-port port . l)
    (for-each (lambda (elem) (display elem port)) l))
(define (print . l)
    (apply print-to-port (cons (current-output-port) l)))

; Use any TCP server that periodicly spits back lines of text.
(define IRMP3_PORT 9232)
(define IRMP3_HOST "localhost")

(define mysock (socket AF_INET SOCK_STREAM 0))
(connect mysock AF_INET (car (hostent:addr-list 
			      (gethostbyname IRMP3_HOST)))
	 IRMP3_PORT)

(define (process-lines p lab) ; loop forever reading and processing lines
  (do ((line (read-line mysock) (read-line mysock)))
      (#f)
    (print "line=\"" line "\"\n")
    (gtk-label-set-text lab line)))

(define (make-button parent txt func) 
  (let* ((btn (gtk-button-new-with-label txt)))
    (gtk-container-add parent btn)
    (gtk-widget-show btn)
    (gtk-signal-connect btn "clicked" func)))

(define (make-label parent txt) 
  (let* ((lab (gtk-label-new txt)))
    (gtk-container-add parent lab)
    (gtk-widget-show lab)
    lab))

(let* ((window (gtk-widget-new 'GtkWindow
			       :type         'toplevel
			       :title        "hello world"
			       :GtkContainer::border_width 10))
       (vbox (gtk-vbox-new #f 10))
       (statlabel (make-label vbox "(no status yet)")))

  (make-button vbox "test me" (lambda () (display "tested.") (newline)))
  (make-button vbox "quit" (lambda () (gtk-widget-destroy window)))
  (gtk-container-add window vbox)
  (gtk-widget-show vbox)
  (gtk-widget-show window)

  (call-with-new-thread (lambda ()
			  (print "thread started\n")
			  (process-lines mysock statlabel)
			  (print "process-lines returns\n")
			  (close-port mysock))
			(lambda (e) (print "thread error " e "\n")))

; Unless we call guile's thread-yield in the gtk idle loop,
; our thread doesn't run.    And unless we call (gtk-update) inside the
; idle procedure, the gtk stuff never gets drawn properly.
; Somthing tells me this isn't the way things are supposed to work...
  (gtk-idle-add (lambda ()
		  (yield)
		  (gtk-update)
		  ))
  (gtk-standalone-main window))

; end of net3g.scm


#!/tmp/ggtest/bin/guile-gtk -s
!#
;
; Test 4 using guile to write a simple network client
; that displays results in a Gtk+ window
; This one uses gtk-input-add
;

(use-modules (gtk gtk))
(use-modules (gtk gdk))
(read-set! keywords 'prefix)

; Use any TCP server that periodicly spits back lines of text.
(define IRMP3_PORT 9232)
(define IRMP3_HOST "localhost")

(define mysock (socket AF_INET SOCK_STREAM 0))

(connect mysock AF_INET (car (hostent:addr-list 
			      (gethostbyname IRMP3_HOST)))
	 IRMP3_PORT)

(define (read-process-line p lab) ; process single line recieved over socket
  (let ((line (read-line p)))
    (gtk-label-set-text lab line)
    ))

(define (make-button parent txt func) 	; gtk helpers
  (let* ((btn (gtk-button-new-with-label txt)))
    (gtk-container-add parent btn)
    (gtk-widget-show btn)
    (gtk-signal-connect btn "clicked" func)))

(define (make-label parent txt) 
  (let* ((lab (gtk-label-new txt)))
    (gtk-container-add parent lab)
    (gtk-widget-show lab)
    lab))

(let* ((window (gtk-widget-new 'GtkWindow
			       :type         'toplevel
			       :title        "hello world"
			       :GtkContainer::border_width 10))
       (vbox (gtk-vbox-new #f 10))
       (statlabel (make-label vbox "(no status yet)")))

  (make-button vbox "test me" (lambda () (display "tested.") (newline)))
  (make-button vbox "quit" (lambda () (gtk-widget-destroy window)))
  (gtk-container-add window vbox)
  (gtk-widget-show vbox)
  (gtk-widget-show window)
  
  (gtk-input-add mysock
		 1	; should be 'read  (for GDK_INPUT_READ)
			; but that causes errors  
		 (lambda (source condition)
		   (read-process-line mysock statlabel)
		   ))

  (gtk-standalone-main window))

; end of net4g.scm



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]