I am merging my Cells fork of LTk with LTk, by which I mean using as much as possible LTk low-level stuff along with my own DEF-C-WIDGET high-level stuff. Things look OK so far, but I had a problem using ltk::read-data to get back the item ID no after creating an item.
My problem is that the ID no comes back as an unvarnished "42". But read-data is looking for (:data <data>):
(defun read-data () (let ((d (read-wish))) (if (listp d) ; paranoia check when we do not read a list eg. error messages from wish (progn (loop while (not (equal (first d) :data)) do (setf *event-queue* (append *event-queue* (list d))) (setf d (read-wish))) (second d)) (format t "read-data:~a~a~%" d (read-all *wish*)))))
How do I arrange for Tk to respond with (:data 42) when I create an item? Or does read-data need to handle un-tagged data from Tk differently?
Aside: I just noticed:
(defun read-event (&key (blocking t)) (or (pop *event-queue*) (when (or blocking (can-read *wish*)) (read-preserving-whitespace *wish* nil nil))))
Should that be checking to see if any data read from Tk is tagged (:callback ,,,,)?
kenny
Hi Kenny,
great to see you onboard :)
On 2/1/06, Kenny Tilton ktilton@nyc.rr.com wrote:
I am merging my Cells fork of LTk with LTk, by which I mean using as much as possible LTk low-level stuff along with my own DEF-C-WIDGET high-level stuff. Things look OK so far, but I had a problem using ltk::read-data to get back the item ID no after creating an item.
Thomas just talked me into doing something similiar - so if I can help, I will gladly do so :) As a general remark: if you have not got Ltk 0.88 yet, get it today!
My problem is that the ID no comes back as an unvarnished "42". But read-data is looking for (:data <data>):
(defun read-data () (let ((d (read-wish))) (if (listp d) ; paranoia check when we do not read a list eg. error messages from wish (progn (loop while (not (equal (first d) :data)) do (setf *event-queue* (append *event-queue* (list d))) (setf d (read-wish))) (second d)) (format t "read-data:~a~a~%" d (read-all *wish*)))))
Well, all the item creation functions do send the answer tagged. As I want to send data always and ever only tagged, I have created the senddata functions on the tk side (senddata, senddatastring, senddatastrings) which take care of tagging, and in the case of strings, properly escaping the characters in the strings to be lisp-readable.
How do I arrange for Tk to respond with (:data 42) when I create an item? Or does read-data need to handle un-tagged data from Tk differently?
(defun create-line (canvas coords) (format-wish "senddata [~a create line~{ ~a~}]" (widget-path canvas) coords) (read-data))
That should be the template for any of those functions.
Aside: I just noticed:
(defun read-event (&key (blocking t)) (or (pop *event-queue*) (when (or blocking (can-read *wish*)) (read-preserving-whitespace *wish* nil nil))))
Should that be checking to see if any data read from Tk is tagged (:callback ,,,,)?
read-event just reads, the tag-checking is done in process-one-event. The different event types differ on the lisp side only in the signature of the called function - command callbacks receive either zero or one arguments, the one argument is then the new value of the widget, generic events created by bind pass an event structure to the callback function, containg e.g. the mouse coordinates or key codes.
Peter
Peter Herth wrote:
Hi Kenny,
great to see you onboard :)
On 2/1/06, Kenny Tilton ktilton@nyc.rr.com wrote:
I am merging my Cells fork of LTk with LTk, by which I mean using as much as possible LTk low-level stuff along with my own DEF-C-WIDGET high-level stuff. Things look OK so far, but I had a problem using ltk::read-data to get back the item ID no after creating an item.
Thomas just talked me into doing something similiar - so if I can help, I will gladly do so :) As a general remark: if you have not got Ltk 0.88 yet, get it today!
Just got it.
My problem is that the ID no comes back as an unvarnished "42". But read-data is looking for (:data <data>):
(defun read-data () (let ((d (read-wish))) (if (listp d) ; paranoia check when we do not read a list eg. error messages from wish (progn (loop while (not (equal (first d) :data)) do (setf *event-queue* (append *event-queue* (list d))) (setf d (read-wish))) (second d)) (format t "read-data:~a~a~%" d (read-all *wish*)))))
Well, all the item creation functions do send the answer tagged. As I want to send data always and ever only tagged, I have created the senddata functions...
I figured as much, even found where you created the proc, but did not manage to assemble two and two somehow.
on the tk side (senddata, senddatastring, senddatastrings) which take care of tagging, and in the case of strings, properly escaping the characters in the strings to be lisp-readable.
Great.
kenny
This is one of my favorites ever:
To do dataflow from Tk, I settled on:
trace add variable .w42 write "mytraceproc"
And mytraceproc cloned from sendata et al.
After a fascinating learning period I got it to work. Most of the time.
When it fails (get this) it is because the sympol is in a different package (My "LTk2" package.) That is the listener package while I am running. Normally callback gets symbols in LTk, and that is how they are stored in the callback hash table.
What triggers this just some of the time? Amazing:
typing text is ok deleting text with backspace is ok selecting text and then deleting it with backspace is OK selecting text and then typing text (causing the selection first to be deleted).... ...is NOT ok.
How does LTk end up with a symbol in the same package based on what the user is doing to the field?
My guess is that Tk sends two messages, one delete, one insert, and that some different codebranch is (a) reached because of the unusual circumstances and (b) does something funny with *package*.
ken
Kenny Tilton wrote:
<snip> How does LTk end up with a symbol in the same package based on what the user is doing to the field?
My guess is that Tk sends two messages, one delete, one insert, and that some different codebranch is (a) reached because of the unusual circumstances and (b) does something funny with *package*.
This fixes the probelm (I disabled the local binding of *package* to Ltk):
(defun read-wish() (let ((*read-eval* nil) #+not (*package* (find-package :ltk))) (ukt:trc "read-wish" *package*) (read (wish-stream *wish*) nil nil)))
Why was the package being forced to LTk, and for only some of the reads?
ken
On 2/5/06, Kenny Tilton ktilton@nyc.rr.com wrote:
Why was the package being forced to LTk, and for only some of the reads?
I think that was detritus from an attempt on my part to ensure read/print consistency. Misguided because ltk doesn't send non-keyword symbols over the line, and doesn't expect to read them. Moral #1 is, don't use non-keyword symbols when talking to wish (moral #2 is comming in the next message :)
On 2/5/06, Kenny Tilton ktilton@nyc.rr.com wrote:
This is one of my favorites ever:
To do dataflow from Tk, I settled on:
Translating for Peter, this means Kenny is trying to make changes to the Tk widgets (eg, a text box) show up as changes to c-input slots on the Lisp side. That way c-formulas can react to what the user typed.
trace add variable .w42 write "mytraceproc"
And mytraceproc cloned from sendata et al.
After a fascinating learning period I got it to work. Most of the time.
When it fails (get this) it is because the sympol is in a different package (My "LTk2" package.) That is the listener package while I am running. Normally callback gets symbols in LTk, and that is how they are stored in the callback hash table.
The internal interface to callbacks is: create-name, add-callback, remove-callback, and callback. Contrary to what the lambda-list of what the last three would make you believe, callbacks are named by strings, not symbols. You should get the name for a new callback from create-name. I'll be fixing that in subversion if Peter doesn't beat me to it.
Thomas F. Burdick wrote:
On 2/5/06, Kenny Tilton ktilton@nyc.rr.com wrote:
This is one of my favorites ever:
To do dataflow from Tk, I settled on:
Translating for Peter, this means Kenny is trying to make changes to the Tk widgets (eg, a text box) show up as changes to c-input slots on the Lisp side. That way c-formulas can react to what the user typed.
trace add variable .w42 write "mytraceproc"
And mytraceproc cloned from sendata et al.
After a fascinating learning period I got it to work. Most of the time.
When it fails (get this) it is because the sympol is in a different package (My "LTk2" package.) That is the listener package while I am running. Normally callback gets symbols in LTk, and that is how they are stored in the callback hash table.
The internal interface to callbacks is: create-name, add-callback, remove-callback, and callback. Contrary to what the lambda-list of what the last three would make you believe, callbacks are named by strings, not symbols. You should get the name for a new callback from create-name. I'll be fixing that in subversion if Peter doesn't beat me to it.
Oh. Pity. Symbols are Good Things. I see no problem with symbols and wish. Why complicate things with unnecessary rules (Thou shalt use strings.)
Actually, I think LTk needs to evolve a little in regard to communication with wish. I understand the desire to make things easy for casual users, but I do not think that should extend to defining "an internal interface", with strictures on communication with wish.
I suggest refactoring to create a core that makes no assumptions about Tk output beginning with :callback/data/event, such that a power developer can work as they please. Then recreate the newby-friendly layer atop that. One trick might be to have the Dummies layer arrange for all dummy traffic to begin (:ltk-for-dummies ....) and if the engine gets a message that begins with something else it calls a generic function with the unexpected leading symbol as the first parameter. Then I can specialize EQL on :kennys-madness and control things while still being part of LTk.
Anticipating a possible alternative, the beauty of this is that one does not have to be forever tweaking LTk to make power users happy, one just stays out of their way by not bogarting the pipe to wish.
Overall, I think LTk is a great project for Common Lisp.
kt
Hi Kenny,
On 2/6/06, Kenny Tilton ktilton@nyc.rr.com wrote:
Oh. Pity. Symbols are Good Things. I see no problem with symbols and wish. Why complicate things with unnecessary rules (Thou shalt use strings.)
Oh, there are no unneccessary rules :). It is just an observation, that strings tend to work (and keywords for most things), but symbols can create problems in the communication. But if that can easily be fixed, I am all for it!
Actually, I think LTk needs to evolve a little in regard to communication with wish. I understand the desire to make things easy for casual users, but I do not think that should extend to defining "an internal interface", with strictures on communication with wish.
Well, the casual user should only use Ltk, but not poke around within it. So no especial care needs to be taken in the internals. The current interface evolved from trying to make the communication as straight forward as prossible while making it robust and flexible.
I suggest refactoring to create a core that makes no assumptions about Tk output beginning with :callback/data/event, such that a power developer can work as they please. Then recreate the newby-friendly layer atop that. One trick might be to have the Dummies layer arrange for all dummy traffic to begin (:ltk-for-dummies ....) and if the engine gets a message that begins with something else it calls a generic function with the unexpected leading symbol as the first parameter. Then I can specialize EQL on :kennys-madness and control things while still being part of LTk.
Currently, Ltk dispatches on the keyword :callback, :data, :event in the first element of the list, so I think the simplest solution would be to call a generic function for every other case.
Anticipating a possible alternative, the beauty of this is that one does not have to be forever tweaking LTk to make power users happy, one just stays out of their way by not bogarting the pipe to wish.
Overall, I think LTk is a great project for Common Lisp.
Thanks :)
Peter
So, here my change which should perform the wished feature:
;; the generic function to specialize on (defmethod handle-output (key params))
(defun process-one-event (event) (when event (when *debug-tk* (format *trace-output* "l:~s<=~%" event) (finish-output *trace-output*)) (cond ((and (not (listp event)) *trace-tk*) (princ event *trace-output*) (finish-output *trace-output*)) ((not (listp event)) nil) ((eq (first event) :callback) (let ((params (rest event))) (callback (first params) (rest params)))) ((eq (first event) :event) (let* ((params (rest event)) (callback (first params)) (evp (rest params)) (event (construct-tk-event evp))) (callback callback (list event)))) (t (handle-output (first event) (rest event))))))
Peter Herth wrote:
So, here my change which should perform the wished feature:
;; the generic function to specialize on (defmethod handle-output (key params))
(defun process-one-event (event) (when event (when *debug-tk* (format *trace-output* "l:~s<=~%" event) (finish-output *trace-output*)) (cond ((and (not (listp event)) *trace-tk*) (princ event *trace-output*) (finish-output *trace-output*)) ((not (listp event)) nil) ((eq (first event) :callback) (let ((params (rest event))) (callback (first params) (rest params)))) ((eq (first event) :event) (let* ((params (rest event)) (callback (first params)) (evp (rest params)) (event (construct-tk-event evp))) (callback callback (list event)))) (t (handle-output (first event) (rest event)))))) _______________________________________________
Thanks. I am going to soldier on for a while with LTk and continue digesting all this. To a certain extent I am starting to think the best way out for a power user is custom procs -- maybe that is my problem. It certainly helped with a Tcl TRACE I wantet to do.
kenny
On 2/6/06, Kenny Tilton ktilton@nyc.rr.com wrote:
Thomas F. Burdick wrote:
The internal interface to callbacks is: create-name, add-callback, remove-callback, and callback. Contrary to what the lambda-list of what the last three would make you believe, callbacks are named by strings, not symbols. You should get the name for a new callback from create-name. I'll be fixing that in subversion if Peter doesn't beat me to it.
Oh. Pity. Symbols are Good Things. I see no problem with symbols and wish. Why complicate things with unnecessary rules (Thou shalt use strings.)
I wasn't trying to enumerate a rule, just saying what the internal interface inside Ltk is. The reason for that is that foo::bar is Tcl syntax for its namespacing system, so if you want to send an arbitrary identifier from Lisp to Tcl and back, a string is the easiest to do right.
Actually, I think LTk needs to evolve a little in regard to communication with wish. I understand the desire to make things easy for casual users, but I do not think that should extend to defining "an internal interface", with strictures on communication with wish.
Hmm, I really meant more "conventions used within Ltk" rather than "internal interface". FWIW, the communication with wish could use an overhaul to make it a little more robust. That said, there shouldn't be anything you can't do with format-wish, read-data, senddata on the Tk side, and the new hook Peter put into the event-handling mechanism. At least, that's sufficient for everything Ltk does itself :-)
Thomas F. Burdick wrote:
On 2/6/06, Kenny Tilton ktilton@nyc.rr.com wrote:
Thomas F. Burdick wrote:
The internal interface to callbacks is: create-name, add-callback, remove-callback, and callback. Contrary to what the lambda-list of what the last three would make you believe, callbacks are named by strings, not symbols. You should get the name for a new callback from create-name. I'll be fixing that in subversion if Peter doesn't beat me to it.
Oh. Pity. Symbols are Good Things. I see no problem with symbols and wish. Why complicate things with unnecessary rules (Thou shalt use strings.)
I wasn't trying to enumerate a rule, just saying what the internal interface inside Ltk is. The reason for that is that foo::bar is Tcl syntax for its namespacing system, so if you want to send an arbitrary identifier from Lisp to Tcl and back, a string is the easiest to do right.
OK, makes sense. (Where did they get /that/ wacky namespace syntax?!)
Actually, I think LTk needs to evolve a little in regard to communication with wish. I understand the desire to make things easy for casual users, but I do not think that should extend to defining "an internal interface", with strictures on communication with wish.
Hmm, I really meant more "conventions used within Ltk" rather than "internal interface". FWIW, the communication with wish could use an overhaul to make it a little more robust. That said, there shouldn't be anything you can't do with format-wish, read-data, senddata on the Tk side, and the new hook Peter put into the event-handling mechanism.
What hook would that be? The one prompted by my whining, viz, to dispatch any unrecognized first symbol to a generic handler users can specialize?
At least, that's sufficient for everything Ltk does itself :-)
<g> Well that certainly ducks my point: any successful library will get pushed in ways the author cannot anticipate. Of course, one can always hope for failure. :) That said, it may well be that the pinhole interface (:callback or :data only) data is perfect, and that power users can in fact achieve anything just by writing a suitable proc, so I am going to shut up for a while.
kt