~ubuntu-branches/ubuntu/quantal/gclcvs/quantal

« back to all changes in this revision

Viewing changes to gcl-tk/tkl.lisp

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-06-24 15:13:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040624151346-xh0xaaktyyp7aorc
Tags: 2.7.0-26
C_GC_OFFSET is 2 on m68k-linux

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;; Copyright (C) 1994 W. Schelter
 
2
 
 
3
;; This file is part of GNU Common Lisp, herein referred to as GCL
 
4
;;
 
5
;; GCL is free software; you can redistribute it and/or modify it under
 
6
;;  the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE as published by
 
7
;; the Free Software Foundation; either version 2, or (at your option)
 
8
;; any later version.
 
9
;; 
 
10
;; GCL is distributed in the hope that it will be useful, but WITHOUT
 
11
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
12
;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public 
 
13
;; License for more details.
 
14
;; 
 
15
 
 
16
 
 
17
 
 
18
(eval-when (load eval compile)
 
19
(in-package "TK")
 
20
)
 
21
 
 
22
(eval-when (compile) 
 
23
(proclaim '(ftype (function (t fixnum fixnum) fixnum) set-message-header
 
24
                  get-number-string))
 
25
(proclaim '(ftype (function (t t fixnum) t) store-circle))
 
26
(proclaim '(ftype (function (t fixnum) t) get-circle))
 
27
(proclaim '(ftype (function (t fixnum fixnum fixnum) fixnum)
 
28
                  push-number-string))
 
29
)
 
30
 
 
31
(defvar *tk-package* (find-package "TK"))
 
32
 
 
33
(eval-when (compile eval load)
 
34
 
 
35
(defconstant *header* '(magic1 magic2 type flag body-length nil nil msg-index nil nil))
 
36
 
 
37
;;enum print_arglist_codes {..};
 
38
(defvar *print-arglist-codes*
 
39
  '(
 
40
    normal
 
41
    no_leading_space
 
42
    join_follows
 
43
    end_join
 
44
    begin_join
 
45
    begin_join_no_leading_space
 
46
    no_quote
 
47
    no_quote_no_leading_space
 
48
    no_quote_downcase
 
49
    no_quotes_and_no_leading_space
 
50
 
 
51
    ))
 
52
 
 
53
(defconstant *mtypes*
 
54
  '( m_not_used
 
55
     m_create_command
 
56
     m_reply
 
57
     m_call
 
58
     m_tcl_command
 
59
     m_tcl_command_wait_response
 
60
     m_tcl_clear_connection  
 
61
     m_tcl_link_text_variable
 
62
     m_set_lisp_loc
 
63
     m_tcl_set_text_variable
 
64
     m_tcl_unlink_text_variable
 
65
     m_lisp_eval
 
66
     m_lisp_eval_wait_response
 
67
     ))
 
68
 
 
69
(defconstant *magic1* #\)
 
70
(defconstant *magic2* #\A)
 
71
 
 
72
 
 
73
(defvar *some-fixnums* (make-array 3 :element-type 'fixnum))
 
74
(defmacro msg-index () `(the fixnum
 
75
                            (aref (the (array fixnum) *some-fixnums*) 0)))
 
76
;;; (defmacro safe-car (x)
 
77
;;;   (cond ((symbolp x) `(if (consp ,x) (car ,x) (if (null ,x) nil
 
78
;;;                                             (not-a-cons ,x))))
 
79
;;;     (t (let ((sym (gensym)))
 
80
;;;          `(let ((,sym ,x))
 
81
;;;             (safe-car ,sym))))))
 
82
;;; (defmacro safe-cdr (x)
 
83
;;;   (cond ((symbolp x) `(if (consp ,x) (cdr ,x) (if (null ,x) nil
 
84
;;;                                             (not-a-cons ,x))))
 
85
;;;     (t (let ((sym (gensym)))
 
86
;;;          `(let ((,sym ,x))
 
87
;;;             (safe-cdr ,sym))))))
 
88
 
 
89
 
 
90
(defun desetq-consp-check (val)
 
91
  (or (consp val) (error "~a is not a cons" val)))
 
92
 
 
93
(defun desetq1 (form val)
 
94
  (cond ((symbolp form)
 
95
         (cond (form                    ;(push form *desetq-binds*)
 
96
                `(setf ,form ,val))))
 
97
        ((consp form)
 
98
         `(progn
 
99
            (desetq-consp-check ,val)
 
100
            ,(desetq1 (car form) `(car ,val))
 
101
            ,@ (if (consp (cdr form))
 
102
                   (list(desetq1 (cdr form) `(cdr ,val)))
 
103
                 (and (cdr form) `((setf ,(cdr form) (cdr ,val)))))))
 
104
        (t (error ""))))
 
105
 
 
106
(defmacro desetq (form val)
 
107
  (cond ((atom val) (desetq1 form val))
 
108
        (t (let ((value (gensym)))
 
109
             `(let ((,value ,val)) , (desetq1 form value))))))
 
110
(defmacro while (test &body body)
 
111
  `(sloop while ,test do ,@ body))
 
112
 
 
113
)
 
114
 
 
115
(defmacro nth-value (n form)
 
116
  `(multiple-value-bind ,(make-list (+ n 1) :initial-element 'a) ,form  a))
 
117
 
 
118
(defvar *tk-command* nil)
 
119
 
 
120
(defvar *debugging* nil)
 
121
(defvar *break-on-errors* nil)
 
122
 
 
123
(defvar *tk-connection* nil )
 
124
 
 
125
;; array of functions to be invoked from lisp.
 
126
(defvar *call-backs* (make-array 20 :fill-pointer 0 :adjustable t ))
 
127
 
 
128
;;array of message half read. Ie read header but not body.
 
129
(defvar *pending* nil)
 
130
 
 
131
;;circular array for replies,requests esp for debugging
 
132
;; replies is used for getting replies.
 
133
(defvar *replies* (make-array (expt 2 7)) "circle of replies to requests in *requests*")
 
134
 
 
135
;; these are strings
 
136
(defvar *requests* (make-array (expt 2 7)))
 
137
 
 
138
;; these are lisp forms
 
139
(defvar *request-forms* (make-array 40))
 
140
 
 
141
 
 
142
(defvar *read-buffer* (make-array 400 :element-type 'standard-char
 
143
                                  :fill-pointer 0 :static t))
 
144
 
 
145
(defvar *text-variable-locations*
 
146
  (make-array 10 :fill-pointer 0 :adjustable t))
 
147
 
 
148
 
 
149
 
 
150
 
 
151
(defmacro pos (flag lis)
 
152
  (or
 
153
   (member flag (symbol-value lis))
 
154
   (error "~a is not in ~a" flag lis))
 
155
  (position flag (symbol-value lis)))
 
156
 
 
157
  
 
158
 
 
159
 
 
160
 
 
161
;;; (defun p1 (a &aux tem)
 
162
;;;   ;;Used for putting  A into a string for sending a command to TK
 
163
;;;   (cond
 
164
;;;     ((and (symbolp a) (setq tem (get a 'tk-print)))
 
165
;;;      (format *tk-command* tem))
 
166
;;;     ((keywordp a)
 
167
;;;      (format *tk-command* "-~(~a~)" a))
 
168
;;;     ((numberp a)
 
169
;;;      (format *tk-command* "~a" a))
 
170
;;;     ((stringp a)
 
171
;;;      (format *tk-command* "\"~a\"" a))
 
172
;;;     ((and (consp a)(eq (car a) 'a))
 
173
;;;      (format *tk-command* "~a" (cdr a)))
 
174
;;;     ((and (consp a)(eq (car a) 'd))
 
175
;;;      (format *tk-command* "~(~a~)" (cdr a)))
 
176
;;;     ((and (symbolp a)
 
177
;;;       (eql (aref (symbol-name a) 0)
 
178
;;;            #\.))
 
179
;;;      (format *tk-command* "~(~a~)" a))
 
180
;;;    (t (error "unrecognized term ~s" a))))
 
181
 
 
182
 
 
183
(defvar *command-strings*
 
184
  (sloop for i below 2 collect
 
185
       (make-array 200 :element-type 'standard-char :fill-pointer 0 :adjustable t)))
 
186
 
 
187
(defvar *string-streams* (list (make-string-input-stream "") (make-string-input-stream "")))
 
188
 
 
189
(defmacro with-tk-command (&body body)
 
190
  `(let (tk-command (*command-strings* *command-strings*))
 
191
     (declare (type string tk-command))
 
192
     (setq tk-command (grab-tk-command))
 
193
     ,@ body))
 
194
 
 
195
(defun grab-tk-command( &aux x)
 
196
  ;; keep a list of available *command-strings* and grab one
 
197
  (cond
 
198
   ((cdr *command-strings*))
 
199
   (t 
 
200
    (setq x (list (make-array 70
 
201
                              :element-type 'standard-char
 
202
                              :fill-pointer 0 :adjustable t))
 
203
          )
 
204
    (or *command-strings* (error "how??"))
 
205
  
 
206
    (setq *command-strings* (nconc *command-strings* x))))
 
207
  (let ((x (car *command-strings*)))
 
208
    (setq  *command-strings* (cdr *command-strings*))
 
209
    (setf (fill-pointer x ) #.(length *header*))
 
210
    x
 
211
    ))
 
212
 
 
213
(defun print-to-string (str x code)
 
214
  (cond ((consp x)
 
215
         (cond ((eq (car x) 'a)
 
216
                (setq x (cdr x)
 
217
                      code (pos no_quote *print-arglist-codes*)))
 
218
               ((eq (car x) 'd)
 
219
                (setq x (cdr x)
 
220
                      code (pos no_quote_downcase *print-arglist-codes*)))
 
221
               (t (error "bad arg ~a" x)))))
 
222
  (while (null (si::print-to-string1 str x code))
 
223
    (cond ((typep x 'bignum)
 
224
           (setq x (format nil "~a" x)))
 
225
          (t (setq str (adjust-array str
 
226
                                     (the fixnum
 
227
                                          (+ (the fixnum
 
228
                                                  (array-total-size str))
 
229
                                             (the fixnum
 
230
                                                  (+ 
 
231
                                                   (if (stringp x)
 
232
                                                       (length (the string x))
 
233
                                                     0)
 
234
                                              70))))
 
235
                                     :fill-pointer (fill-pointer str)
 
236
                                     :element-type 'string-char)))))
 
237
  str)
 
238
 
 
239
(defmacro pp (x code)
 
240
  (let ((u `(pos ,code *print-arglist-codes*)))
 
241
  `(print-to-string tk-command ,x ,u)))
 
242
 
 
243
(defun print-arglist (to-string l &aux v in-join x)
 
244
;;      (sloop for v in l do (p :| | v))
 
245
  (while l
 
246
    (setq v (cdr l))
 
247
    (setq x (car l))
 
248
    (cond
 
249
     ((eql (car v) ': )
 
250
      (print-to-string to-string x
 
251
                       (if in-join
 
252
                           (pos join_follows *print-arglist-codes*)
 
253
                         (pos begin_join *print-arglist-codes*)))
 
254
      (setq in-join t)
 
255
      (setq v (cdr v)))
 
256
     (in-join
 
257
      (print-to-string to-string x (pos end_join *print-arglist-codes*))
 
258
      (setq in-join nil))
 
259
     (t;; code == (pos normal *print-arglist-codes*)
 
260
      (print-to-string to-string x (pos normal *print-arglist-codes*))))
 
261
 
 
262
    (setq l v)
 
263
    ))
 
264
     
 
265
(defmacro p (&rest l)
 
266
  `(progn ,@ (sloop for v in l collect `(p1 ,v))))
 
267
 
 
268
(defvar *send-and-wait* nil "If not nil, then wait for answer and check result")
 
269
 
 
270
(defun tk-call (fun &rest l &aux result-type)
 
271
  (with-tk-command
 
272
   (pp fun no_leading_space)
 
273
   (setq result-type (prescan-arglist l nil nil))
 
274
   (print-arglist tk-command l)
 
275
   (cond (result-type
 
276
          (call-with-result-type tk-command result-type))
 
277
         (t  (send-tcl-cmd *tk-connection* tk-command nil)
 
278
             (values)))))
 
279
 
 
280
(defun tk-do (str &rest l &aux )
 
281
  (with-tk-command
 
282
       (pp str no_quotes_and_no_leading_space)
 
283
       ;; leading keyword printed without '-' at beginning.
 
284
       (while l
 
285
         (pp (car l) no_quotes_and_no_leading_space)
 
286
         (setq l (cdr l)))
 
287
       (call-with-result-type tk-command 'string)))
 
288
 
 
289
(defun tk-do-no-wait (str &aux (n (length str)))
 
290
  (with-tk-command
 
291
   (si::copy-array-portion str  tk-command 0  #.(length *header*) n)
 
292
   (setf (fill-pointer tk-command) (the fixnum (+ n  #.(length *header*))))
 
293
   (let ()
 
294
     (send-tcl-cmd *tk-connection* tk-command nil))))
 
295
 
 
296
(defun send-tcl-cmd (c str send-and-wait )
 
297
  ;(notice-text-variables)
 
298
  (or send-and-wait (setq send-and-wait *send-and-wait*))
 
299
 ; (setq send-and-wait t)
 
300
  (vector-push-extend (code-char 0) str)
 
301
  (let ((msg-id (set-message-header str
 
302
                                    (if send-and-wait
 
303
                                        (pos m_tcl_command_wait_response *mtypes*)
 
304
                                      (pos m_tcl_command *mtypes*))
 
305
                                    (the fixnum
 
306
                                         (- (length str)
 
307
                                            #.(length *header*))))))
 
308
    
 
309
    (cond (send-and-wait
 
310
           (if *debugging*
 
311
               (store-circle *requests* (subseq str #.(length *header*))
 
312
                             msg-id))
 
313
           (store-circle *replies* nil  msg-id)
 
314
           (execute-tcl-cmd c str))
 
315
          (t (store-circle *requests* nil msg-id)
 
316
           (write-to-connection c str)))))
 
317
 
 
318
  
 
319
(defun send-tcl-create-command (c str)
 
320
  (vector-push-extend (code-char 0) str)
 
321
  (set-message-header str (pos m_create_command *mtypes*)
 
322
                      (- (length str) #.(length *header*)))
 
323
  (write-to-connection c str))
 
324
 
 
325
(defun write-to-connection (con string &aux tem)
 
326
  (let* ((*sigusr1* t)
 
327
         ;; dont let us get interrupted while writing!!
 
328
         (n (length string))
 
329
         (fd (caar con))
 
330
         (m 0))
 
331
    (declare (Fixnum n m))
 
332
    (or con (error "Trying to write to non open connection "))
 
333
    (if *debugging* (describe-message string))
 
334
    (or (typep fd 'string)
 
335
        (error "~a is not a connection" con))
 
336
    (setq m (si::our-write fd string n))
 
337
    (or (eql m n) (error "Failed to write ~a bytes to file descriptor ~a" n fd))
 
338
    (setq tem *sigusr1*)
 
339
    ;; a signal at this instruction would not be noticed...since it
 
340
    ;; would set *sigusr1* to :received but that would be too late for tem
 
341
    ;; since the old value will be popped off the binding stack at the next 'paren'
 
342
    )
 
343
  (cond ((eq tem :received)
 
344
         (read-and-act nil)))
 
345
  t)
 
346
 
 
347
 
 
348
(defun coerce-string (a)
 
349
  (cond ((stringp a) a)
 
350
        ((fixnump a) (format nil "~a" a))
 
351
        ((numberp a) (format nil "~,2f" (float a)))
 
352
        ((keywordp a)
 
353
         (format nil "-~(~a~)" a))
 
354
        ((symbolp a)
 
355
         (format nil "~(~a~)" a))
 
356
        (t (error "bad type"))))
 
357
;;2 decimals
 
358
 
 
359
(defun my-conc (a b)
 
360
  (setq a (coerce-string a))
 
361
  (setq b (coerce-string b))
 
362
  (concatenate 'string a b ))
 
363
 
 
364
;; In an arglist   'a : b' <==> (tk-conc a b)
 
365
;; eg:   1  : "b" <==> "1b"
 
366
;        "c" : "b" <==> "cb"
 
367
;        'a  : "b" <==> "ab"
 
368
;       '.a  : '.b  <==> ".a.b"
 
369
;       ':ab : "b"  <==> "abb"
 
370
 
 
371
;;Convenience for concatenating symbols, strings, numbers
 
372
;;  (tk-conc '.joe.bill ".frame.list yview " 3) ==> ".joe.bill.frame.list yview 3"
 
373
(defun tk-conc (&rest l)
 
374
  (declare (:dynamic-extent l))
 
375
  (let ((tk-command
 
376
         (make-array 30 :element-type 'standard-char
 
377
                     :fill-pointer 0 :adjustable t)))
 
378
    (cond ((null l))
 
379
          (t (pp (car l) no_quote_no_leading_space)))
 
380
    (setq l (cdr l))
 
381
    (while (cdr l)
 
382
      (pp (car l) join_follows) (setq l (cdr l)))
 
383
    (and l (pp (car l) no_quote_no_leading_space))
 
384
    tk-command
 
385
    ))
 
386
 
 
387
 
 
388
;;; (defun verify-list (l)
 
389
;;;   (loop
 
390
;;;    (cond ((null l)(return t))
 
391
;;;      ((consp l) (setq l (cdr l)))
 
392
;;;      (t (error "not a true list ~s"l)))))
 
393
 
 
394
;;; (defun prescan-arglist (l pathname name-caller &aux result-type)
 
395
;;;   (let ((v l) tem prev a b  c)
 
396
;;;     (verify-list l)
 
397
;;;     (sloop while v
 
398
;;;        do
 
399
;;;        (cond
 
400
;;;     ((keywordp (car v))
 
401
;;;      (setq a (car v))
 
402
;;;      (setq c (cdr v))
 
403
;;;      (setq b (car c) c (cadr c))
 
404
;;;      (cond ((eq a :bind)
 
405
;;;             (cond ((setq tem (cdddr v))
 
406
;;;                    (or (eq (cadr tem) ': )
 
407
;;;                        (setf (car tem)
 
408
;;;                              (tcl-create-command (car tem)
 
409
;;;                                                  nil 
 
410
;;;                                                  t))))))
 
411
;;;            ((eq c ': ))
 
412
;;;            ((member a'(:yscroll :command
 
413
;;;                                 :xscroll
 
414
;;;                                 :yscrollcommand
 
415
;;;                                 :xscrollcommand
 
416
;;;                                 :scrollcommand
 
417
;;;                                 ))
 
418
;;;             (cond ((setq tem (cdr v))
 
419
;;;                    (setf (car tem)
 
420
;;;                          (tcl-create-command (car tem)
 
421
;;;                                              (or (get a 'command-arg)
 
422
                                                     
 
423
;;;                                                  (get name-caller
 
424
;;;                                                       'command-arg))
 
425
;;;                                              nil)))))
 
426
;;;            ((eq (car v) :return)
 
427
;;;             (setf result-type (cadr v))
 
428
;;;             (cond (prev
 
429
;;;                    (setf (cdr prev) (cddr v)))
 
430
;;;                   (t (setf (car v) '(a . ""))
 
431
;;;                      (setf (cdr v) (cddr v)))))
 
432
;;;            ((eq (car v) :textvariable)
 
433
;;;             (setf (second v) (link-variable b 'string)))
 
434
;;;            ((member (car v) '(:value :onvalue :offvalue))
 
435
;;;             (let* ((va (get pathname 'variable))
 
436
;;;                    (type (get va 'linked-variable-type))
 
437
;;;                    (fun (cdr (get type
 
438
;;;                              'coercion-functions))))
 
439
;;;               (or va
 
440
;;;                   (error
 
441
;;;                    "Must specify :variable before :value so that we know the type"))
 
442
;;;               (or fun (error "No coercion-functions for type ~s" type))
 
443
;;;               (setf (cadr v) (funcall fun b))))
 
444
;;;            ((eq (car v) :variable)
 
445
;;;             (let ((va (second v))
 
446
;;;                   (type (cond ((eql name-caller 'checkbutton) 'boolean)
 
447
;;;                          (t 'string))))
 
448
;;;               (cond ((consp va)
 
449
;;;                      (desetq (type va) va)
 
450
;;;                      (or (symbolp va)
 
451
;;;                          (error "should be :variable (type symbol)"))))
 
452
;;;               (setf (get pathname 'variable) va)
 
453
;;;               (setf (second v)
 
454
;;;                   (link-variable   va type))))
 
455
;;;             )))
 
456
;;;        (setq prev v)      
 
457
;;;        (setq v (cdr v))
 
458
;;;        ))
 
459
;;;   result-type
 
460
;;;   )
 
461
 
 
462
 
 
463
(defun prescan-arglist (l pathname name-caller &aux result-type)
 
464
  (let ((v l) tem prev a )
 
465
;    (verify-list l) ; unnecessary all are from &rest args.
 
466
; If pathname supplied, then this should be an alternating list
 
467
;; of keywords and values.....
 
468
    (sloop while v
 
469
       do        (setq a (car v))
 
470
       (cond
 
471
        ((keywordp a)
 
472
         (cond
 
473
          ((eq (car v) :return)
 
474
           (setf result-type (cadr v))
 
475
           (cond (prev
 
476
                  (setf (cdr prev) (cddr v)))
 
477
                 (t (setf (car v) '(a . ""))
 
478
                    (setf (cdr v) (cddr v)))))
 
479
          ((setq tem (get a 'prescan-function))
 
480
           (funcall tem a v pathname name-caller)))))
 
481
       (setq prev v)
 
482
       (setq v (cdr v)))
 
483
    result-type))
 
484
 
 
485
(eval-when (compile eval load)
 
486
(defun set-prescan-function (fun &rest l)
 
487
  (dolist (v l) (setf (get v 'prescan-function) fun)))
 
488
)
 
489
         
 
490
          
 
491
(set-prescan-function 'prescan-bind :bind)
 
492
(defun prescan-bind
 
493
       (x  v pathname name-caller &aux tem)
 
494
      name-caller pathname x
 
495
      (cond ((setq tem (cdddr v))
 
496
             (or
 
497
              (keywordp (car tem))
 
498
              (eq (cadr tem) ': )
 
499
                 (setf (car tem)
 
500
                       (tcl-create-command (car tem)
 
501
                                           nil 
 
502
                                           t))))))
 
503
 
 
504
(set-prescan-function 'prescan-command :yscroll :command
 
505
                      :postcommand
 
506
                      :xscroll
 
507
                      :yscrollcommand
 
508
                      :xscrollcommand
 
509
                      :scrollcommand)
 
510
 
 
511
(defun prescan-command (x v pathname name-caller &aux tem arg)
 
512
  x pathname
 
513
  (setq arg (cond (( member v     '(:xscroll
 
514
                                    :yscrollcommand
 
515
                                    :xscrollcommand
 
516
                                    :scrollcommand))
 
517
                   
 
518
                   'aaaa)
 
519
                  ((get name-caller 'command-arg))))
 
520
  (cond ((setq tem (cdr v))
 
521
         (cond ((eq (car tem) :return ) :return)
 
522
               (t
 
523
                (setf (car tem)
 
524
                      (tcl-create-command (car tem) arg nil)))))))
 
525
  
 
526
(defun prescan-value (a v pathname name-caller)
 
527
  a name-caller
 
528
  (let* ((va (get pathname ':variable))
 
529
         (type (get va 'linked-variable-type))
 
530
         (fun (cdr (get type
 
531
                        'coercion-functions))))
 
532
    (or va
 
533
        (error
 
534
         "Must specify :variable before :value so that we know the type"))
 
535
    (or fun (error "No coercion-functions for type ~s" type))
 
536
    (setq v (cdr v))
 
537
    (if v
 
538
        (setf (car v) (funcall fun (car v))))))
 
539
 
 
540
(set-prescan-function 'prescan-value :value :onvalue :offvalue)
 
541
 
 
542
(set-prescan-function
 
543
 #'(lambda (a v pathname name-caller)
 
544
     a
 
545
     (let ((va (second v))
 
546
           (type (cond ((eql name-caller 'checkbutton) 'boolean)
 
547
                       (t 'string))))
 
548
       (cond ((consp va)
 
549
              (desetq (type va) va)
 
550
              (or (symbolp va)
 
551
                  (error "should be :variable (type symbol)"))))
 
552
       (cond (va
 
553
              (setf (get pathname a) va)
 
554
              (setf (second v)
 
555
                    (link-variable   va type))))))
 
556
 :variable :textvariable)
 
557
 
 
558
(defun make-widget-instance (pathname widget)
 
559
  ;; ??make these not wait for response unless user is doing debugging..
 
560
  (or (symbolp pathname) (error "must give a symbol"))
 
561
  #'(lambda ( &rest l &aux result-type (option (car l)))
 
562
      (declare (:dynamic-extent l))
 
563
      (setq result-type (prescan-arglist l pathname  widget))
 
564
      (if (and *break-on-errors* (not result-type))
 
565
          (store-circle *request-forms*
 
566
                        (cons pathname (copy-list l))
 
567
                        (msg-index)))
 
568
      (with-tk-command
 
569
       (pp pathname no_leading_space)
 
570
       ;; the leading keyword gets printed with no leading -
 
571
       (or (keywordp option)
 
572
           (error "First arg to ~s must be an option keyword not ~s"
 
573
                  pathname option ))
 
574
       (pp option no_quote)
 
575
       (setq l (cdr l))
 
576
       ;(print (car l))
 
577
       (cond ((and (keywordp (car l))
 
578
                   (not (eq option :configure))
 
579
                   (not (eq option :config))
 
580
                   (not (eq option :itemconfig))
 
581
                   (not (eq option :cget))
 
582
                   (not (eq option :postscript))
 
583
                        )
 
584
              (pp (car l) no_quote)
 
585
              (setq l (cdr l))))
 
586
       (print-arglist tk-command l)
 
587
       (cond (result-type
 
588
              (call-with-result-type tk-command result-type))
 
589
            (t  (send-tcl-cmd *tk-connection* tk-command nil)
 
590
                (values))))))
 
591
 
 
592
(defmacro def-widget (widget &key (command-arg 'sssss))
 
593
  `(eval-when (compile eval load)
 
594
    (setf (get ',widget 'command-arg) ',command-arg)
 
595
    (defun ,widget (pathname &rest l)(declare (:dynamic-extent l))
 
596
      (widget-function ',widget pathname l))))
 
597
 
 
598
     
 
599
;; comand-arg "asaa" means pass second arg back as string, and others not quoted
 
600
  ;; ??make these always wait for response
 
601
  ;; since creating a window failure is likely to cause many failures.
 
602
(defun widget-function (widget pathname l )
 
603
  (or (symbolp pathname)
 
604
      (error "First arg to ~s must be a symbol not ~s" widget pathname))
 
605
  (if *break-on-errors*
 
606
      (store-circle *request-forms* (cons pathname (copy-list l))
 
607
                    (msg-index)))
 
608
  (prescan-arglist l pathname widget)
 
609
  (with-tk-command
 
610
   (pp widget no_leading_space)
 
611
   (pp pathname normal)
 
612
   (print-arglist tk-command l )
 
613
   (multiple-value-bind (res success)
 
614
                        (send-tcl-cmd *tk-connection* tk-command t)
 
615
                        (if success
 
616
                            (setf (symbol-function pathname)
 
617
                                  (make-widget-instance pathname widget))
 
618
                          (error
 
619
                           "Cant define ~(~a~) pathnamed ~(~a~): ~a"
 
620
                           widget pathname res)))
 
621
   pathname))
 
622
(def-widget button)
 
623
(def-widget listbox)
 
624
(def-widget scale :command-arg a)
 
625
(def-widget canvas)
 
626
(def-widget menu)
 
627
(def-widget scrollbar)
 
628
(def-widget checkbutton)
 
629
(def-widget menubutton)
 
630
(def-widget text)
 
631
(def-widget entry)
 
632
(def-widget message)
 
633
(def-widget frame)
 
634
(def-widget label)
 
635
(def-widget radiobutton)
 
636
(def-widget toplevel)
 
637
 
 
638
(defmacro def-control (name &key print-name before)
 
639
  (cond ((null print-name )(setq print-name name))
 
640
        (t  (setq print-name (cons 'a print-name))))
 
641
  `(defun ,name (&rest l)
 
642
     ,@ (if before `((,before ',print-name l)))
 
643
     (control-function ',print-name l)))
 
644
 
 
645
(defun call-with-result-type (tk-command result-type)
 
646
  (multiple-value-bind
 
647
   (res suc)
 
648
   (send-tcl-cmd *tk-connection* tk-command t)
 
649
   (values (if result-type (coerce-result res result-type) res)
 
650
           suc)))
 
651
 
 
652
(defun control-function (name l &aux result-type)
 
653
      ;(store-circle *request-forms* (cons name l) (msg-index))
 
654
      (setq result-type (prescan-arglist l nil name))
 
655
      (with-tk-command
 
656
       (pp name normal)
 
657
       ;; leading keyword printed without '-' at beginning. 
 
658
       (cond ((keywordp (car l))
 
659
              (pp (car l) no_quote)
 
660
              (setq l (cdr l))))
 
661
       (print-arglist tk-command l)
 
662
       (call-with-result-type tk-command result-type)))
 
663
 
 
664
 
 
665
(dolist (v
 
666
  '( |%%| |%#| |%a| |%b| |%c| |%d| |%f| |%h| |%k| |%m| |%o| |%p| |%s| |%t|
 
667
     |%v| |%w| |%x| |%y| |%A| |%B| |%D| |%E| |%K| |%N| |%R| |%S| |%T| |%W| |%X| |%Y|))
 
668
  (progn   (setf (get v 'event-symbol)
 
669
                 (symbol-name v))
 
670
           (or (member v '(|%d| |%m| |%p| |%K| ;|%W|
 
671
                           |%A|))
 
672
               (setf (get v 'event-symbol)
 
673
                     (cons (get v 'event-symbol) 'fixnum )))))
 
674
 
 
675
(defvar *percent-symbols-used* nil)
 
676
(defun get-per-cent-symbols (expr)
 
677
  (cond ((atom expr)
 
678
         (and (symbolp expr) (get expr 'event-symbol)
 
679
              (pushnew expr *percent-symbols-used*)))
 
680
        (t (get-per-cent-symbols (car expr))
 
681
           (setq expr (cdr expr))
 
682
           (get-per-cent-symbols expr))))
 
683
 
 
684
 
 
685
(defun reserve-call-back ( &aux ind)
 
686
  (setq ind (fill-pointer *call-backs*))
 
687
  (vector-push-extend nil *call-backs* )
 
688
  ind)
 
689
 
 
690
;; The command arg:
 
691
;; For bind windowSpec SEQUENCE COMMAND
 
692
;;  COMMAND is called when the event SEQUENCE occurs to windowSpec.
 
693
;;    If COMMAND is a symbol or satisfies (functionp COMMAND), then
 
694
;;  it will be funcalled.   The number of args supplied in this
 
695
;;  case is determined by the widget... for example a COMMAND for the
 
696
;;  scale widget will be supplied exactly 1 argument.
 
697
;;    If COMMAND is a string then this will be passed to the graphics
 
698
;;  interpreter with no change, 
 
699
;;  This allows invoking of builtin functionality, without bothering the lisp process.
 
700
;;    If COMMAND is a lisp expression to eval, and it may reference
 
701
;;  details of the event via the % constructs eg:  %K refers to the keysym
 
702
;;  of the key pressed (case of BIND only).   A function whose body is the
 
703
;;  form, will actually be  constructed which takes as args all the % variables
 
704
;;  actually appearing in the form.  The body of the function will be the form.
 
705
;;  Thus (print (list |%w| %W) would turn into #'(lambda(|%w| %W) (print (list |%w| %W)))
 
706
;;  and when invoked it would be supplied with the correct args.  
 
707
 
 
708
(defvar *arglist* nil)
 
709
(defun tcl-create-command (command  arg-data allow-percent-data)
 
710
  (with-tk-command
 
711
   (cond ((or (null command) (equal command ""))
 
712
          (return-from tcl-create-command ""))
 
713
         ((stringp command)
 
714
          (return-from tcl-create-command command)))
 
715
   (let (*percent-symbols-used* tem ans  name ind)
 
716
     (setq ind  (reserve-call-back))
 
717
     (setq name (format nil "callback_~d" ind))
 
718
     ;; install in tk the knowledge that callback_ind will call back to here.
 
719
     ;; and tell it arg types expected.
 
720
     ;; the percent commands are handled differently
 
721
     (push-number-string tk-command ind #.(length *header*) 3)
 
722
     (setf (fill-pointer tk-command) #.(+ (length *header*) 3))
 
723
     (if arg-data (pp arg-data no_leading_space))
 
724
     (send-tcl-create-command *tk-connection* tk-command)
 
725
     (if (and arg-data allow-percent-data) (error "arg data and percent data not allowed"))
 
726
     (cond ((or (symbolp command)
 
727
                (functionp command)))
 
728
           (allow-percent-data
 
729
            (get-per-cent-symbols command)
 
730
            (and *percent-symbols-used* (setq ans ""))
 
731
            (sloop for v in *percent-symbols-used* 
 
732
               do (setq tem (get v 'event-symbol))
 
733
               (cond ((stringp tem)
 
734
                      (setq ans (format nil "~a \"~a\"" ans tem)))
 
735
                     ((eql (cdr tem) 'fixnum)
 
736
                      (setq ans (format nil "~a ~a" ans (car tem))))
 
737
                     (t (error "bad arg"))))
 
738
            (if ans (setq ans (concatenate 'string "{(" ans ")}")))
 
739
            (setq command `(lambda ,*percent-symbols-used*
 
740
                             ,command))
 
741
            (if ans (setq name (concatenate 'string "{"name " " ans"}"))))
 
742
           (t (setq command `(lambda (&rest *arglist*) ,command))))
 
743
     (setf (aref *call-backs* ind)  command)
 
744
     ;; the command must NOT appear as "{[...]}" or it will be eval'd. 
 
745
     (cons 'a name)
 
746
     )))
 
747
   
 
748
(defun bind (window-spec &optional sequence command type)
 
749
  "command may be a function name, or an expression which
 
750
 may involve occurrences of elements of *percent-symbols*
 
751
 The expression will be evaluated in an enviroment in which
 
752
 each of the % symbols is bound to the value of the corresponding
 
753
 event value obtained from TK."
 
754
  (cond ((equal sequence :return)
 
755
         (setq sequence nil)
 
756
         (setq command nil)))
 
757
  (cond ((equal command :return)
 
758
         (or (eq type 'string)
 
759
             (tkerror "bind only returns type string"))
 
760
         (setq command nil))
 
761
        (command
 
762
         (setq command  (tcl-create-command command nil t))))
 
763
  (with-tk-command
 
764
   (pp 'bind no_leading_space)
 
765
   (pp window-spec normal)
 
766
   (and sequence (pp sequence normal))
 
767
   (and command (pp command normal))
 
768
   (send-tcl-cmd *tk-connection* tk-command (or (null sequence)(null command)))))
 
769
 
 
770
(defmacro tk-connection-fd (x) `(caar ,x))
 
771
 
 
772
(def-control after)
 
773
(def-control exit)
 
774
(def-control lower)
 
775
(def-control place)
 
776
(def-control send)
 
777
(def-control tkvars)
 
778
(def-control winfo)
 
779
(def-control focus)
 
780
(def-control option)
 
781
(def-control raise)
 
782
(def-control tk)
 
783
;; problem on waiting.  Waiting for dialog to kill self
 
784
;; wont work because the wait blocks even messages which go
 
785
;; to say to kill...
 
786
;; must use
 
787
;; (grab :set :global .fo)
 
788
;; and sometimes the gcltkaux gets blocked and cant accept input when
 
789
;; in grabbed state...
 
790
(def-control tkwait)
 
791
(def-control wm)
 
792
(def-control destroy :before destroy-aux)
 
793
(def-control grab)
 
794
(def-control pack)
 
795
(def-control selection)
 
796
(def-control tkerror)
 
797
(def-control update)
 
798
(def-control tk-listbox-single-select :print-name "tk_listboxSingleSelect")
 
799
(def-control tk-menu-bar :print-name "tk_menuBar")
 
800
(def-control tk-dialog :print-name "tk_dialog")
 
801
(def-control get_tag_range)
 
802
 
 
803
(def-control lsearch)
 
804
(def-control lindex)
 
805
 
 
806
 
 
807
(defun tk-wait-til-exists (win)
 
808
  (tk-do (tk-conc "if ([winfo exists " win " ]) { } else {tkwait visibility " win "}")))
 
809
 
 
810
(defun destroy-aux (name  l)
 
811
  name
 
812
  (dolist (v l)
 
813
          (cond ((stringp v))
 
814
                ((symbolp v) 
 
815
                 (dolist (prop '(:variable :textvariable))
 
816
                         (remprop v prop))
 
817
                 (fmakunbound v)
 
818
                 )
 
819
                (t (error "not a pathname : ~s" v))))
 
820
          
 
821
  )
 
822
 
 
823
(defvar *default-timeout* (* 100 internal-time-units-per-second))
 
824
 
 
825
(defun execute-tcl-cmd (connection cmd)
 
826
  (let  (id tem (time *default-timeout*))
 
827
    (declare (fixnum  time))
 
828
    (setq id (get-number-string cmd  (pos msg-index *header*) 3))
 
829
    (store-circle *replies* nil  id)
 
830
    (write-to-connection connection cmd)
 
831
    (loop
 
832
     (cond ((setq tem (get-circle *replies* id))
 
833
            (cond ((or (car tem) (null *break-on-errors*))
 
834
                   (return-from execute-tcl-cmd  (values (cdr tem) (car tem))))
 
835
                  (t (cerror "Type :r to continue" "Cmd failed: ~a : ~a "
 
836
                             (subseq cmd (length *header*)
 
837
                                    (- (length cmd) 1)
 
838
                                    )
 
839
                            (cdr tem))
 
840
                     (return (cdr tem))
 
841
                     ))))
 
842
     (cond ((> (si::check-state-input
 
843
                (tk-connection-fd connection) 10) 0)
 
844
            (read-and-act id)
 
845
            ))
 
846
     (setq time (- time 10))
 
847
     (cond ((< time 0)
 
848
            (cerror ":r resumes waiting for *default-timeout*"
 
849
                    "Did not get a reply for cmd ~a" cmd)
 
850
            (setq time *default-timeout*)
 
851
            )))))
 
852
 
 
853
(defun push-number-string (string number ind  bytes )
 
854
  (declare (fixnum ind number bytes))
 
855
  ;; a number #xabcdef is stored "<ef><cd><ab>" where <ef> is (code-char #xef)
 
856
  (declare (string string))
 
857
  (declare (fixnum  number bytes ))
 
858
  (sloop while (>= bytes 1) do
 
859
     (setf (aref string ind)
 
860
           (the character (code-char
 
861
                                  (the fixnum(logand number 255)))))
 
862
     (setq ind (+ ind 1))
 
863
     (setq bytes (- bytes 1))
 
864
;     (setq number (* number 256))
 
865
     (setq number (ash number -8))
 
866
     nil))
 
867
 
 
868
(defun get-number-string (string  start  bytes &aux (number 0))
 
869
  ;; a number #xabcdef is stored "<ef><cd><ab>" where <ef> is (code-char #xef)
 
870
  (declare (string string))
 
871
  (declare (fixnum  number bytes start))
 
872
  (setq start (+ start (the fixnum (- bytes 1))))
 
873
  (sloop while (>= bytes 1) do
 
874
     (setq number (+ number (char-code (aref string start))))
 
875
     (setq start (- start 1) bytes (- bytes 1))
 
876
     (cond ((> bytes 0) (setq number (ash number 8)))
 
877
           (t (return number)))))
 
878
 
 
879
 
 
880
(defun quit () (tkdisconnect) (bye))
 
881
 
 
882
(defun debugging (x)
 
883
  (setq *debugging* x))
 
884
        
 
885
(defmacro dformat (&rest l)
 
886
  `(if *debugging* (dformat1 ,@l)))
 
887
(defun dformat1 (&rest l)
 
888
  (declare (:dynamic-extent l))
 
889
  (format *debug-io* "~%Lisp:")
 
890
  (apply 'format *debug-io* l))
 
891
 
 
892
(defvar *sigusr1* nil)
 
893
;;??NOTE NOTE we need to make it so that if doing code inside an interrupt,
 
894
;;then we do NOT do a gc for relocatable.   This will kill US.
 
895
;;One hack would be that if relocatable is low or cant be grown.. then
 
896
;;we just set a flag which says run our sigusr1 code at the next cons...
 
897
;;and dont do anything here.  Actually we can always grow relocatable via sbrk,
 
898
;;so i think it is ok.....??......
 
899
 
 
900
(defun system::sigusr1-interrupt (x)
 
901
  x
 
902
  (cond (*sigusr1*
 
903
         (setq *sigusr1* :received))
 
904
        (*tk-connection*
 
905
         (let ((*sigusr1* t))
 
906
           (dformat "Received SIGUSR1. ~a"
 
907
                    (if (> (si::check-state-input 
 
908
                            (tk-connection-fd *tk-connection*) 0) 0) ""
 
909
                      "No Data left there."))
 
910
           ;; we put 4 here to wait for a bit just in case
 
911
           ;; data comes
 
912
           (si::check-state-input 
 
913
                            (tk-connection-fd *tk-connection*) 4 )
 
914
           (read-and-act nil)))))
 
915
(setf (symbol-function 'si::SIGIO-INTERRUPT) (symbol-function 'si::sigusr1-interrupt))
 
916
 
 
917
 
 
918
(defun store-circle (ar reply id)
 
919
  (declare (type (array t) ar)
 
920
           (fixnum id))
 
921
  (setf (aref ar (the fixnum (mod id (length ar)))) reply))
 
922
 
 
923
(defun get-circle (ar  id)
 
924
  (declare (type (array t) ar)
 
925
           (fixnum id))
 
926
  (aref ar (the fixnum (mod id (length ar)))))
 
927
 
 
928
(defun decode-response (str &aux reply-from )
 
929
  (setq reply-from (get-number-string str
 
930
                              #.(+ 1 (length *header*))
 
931
                              3))
 
932
  (values
 
933
   (subseq str #.(+ 4 (length *header*)))
 
934
   (eql (aref str #.(+ 1 (length *header*))) #\0)
 
935
   reply-from
 
936
   (get-circle *requests* reply-from)))
 
937
 
 
938
(defun describe-message (vec)
 
939
 
 
940
  (let ((body-length (get-number-string vec  (pos body-length *header*) 3))
 
941
        (msg-index (get-number-string vec  (pos msg-index *header*) 3))
 
942
        (mtype (nth (char-code (aref vec (pos type *header*))) *mtypes*))
 
943
        success from-id requ
 
944
        )
 
945
    (format t "~%Msg-id=~a, type=~a, leng=~a, " msg-index mtype body-length)
 
946
    (case mtype
 
947
      (m_reply
 
948
       (setq from-id (get-number-string vec #.(+ 1  (length *header*))
 
949
                                        3))
 
950
       (setq success (eql (aref vec #.(+ 0  (length *header*)))
 
951
                          #\0))
 
952
       (setq requ (get-circle *requests* from-id))
 
953
       (format t "result-code=~a[bod:~s](form msg ~a)[hdr:~s]"
 
954
               success
 
955
               (subseq vec #.(+ 4 (length *header*)))
 
956
               from-id
 
957
                       (subseq vec 0 (length *header*))
 
958
               )
 
959
       )
 
960
      ((m_create_command m_call
 
961
         m_lisp_eval
 
962
        m_lisp_eval_wait_response)
 
963
       (let ((islot (get-number-string vec #.(+ 0 (length *header*)) 3)))
 
964
         (format t "islot=~a(callback_~a), arglist=~s" islot  islot
 
965
                 (subseq vec #.(+ 3 (length *header*))))))
 
966
      ((m_tcl_command m_tcl_command_wait_response 
 
967
                      M_TCL_CLEAR_CONNECTION
 
968
                      )
 
969
       (format t "body=[~a]"  (subseq vec (length *header*)) ))
 
970
      ((m_tcl_set_text_variable)
 
971
       (let* ((bod (subseq vec (length *header*)))
 
972
              (end (position (code-char 0) bod))
 
973
              (var (subseq bod 0 end)))
 
974
         (format t "name=~s,val=[~a],body=" var (subseq bod (+ 1 end)
 
975
                                                        (- (length bod) 1))
 
976
                 bod)))
 
977
      ((m_tcl_link_text_variable
 
978
        m_tcl_unlink_text_variable
 
979
        m_set_lisp_loc)
 
980
 
 
981
       (let (var (islot (get-number-string vec #.(+ 0 (length *header*)) 3)))
 
982
         (format t "array_slot=~a,name=~s,type=~s body=[~a]" islot
 
983
                 (setq var (aref *text-variable-locations* islot))
 
984
                 (get var 'linked-variable-type)
 
985
                 (subseq vec #.(+ 3 (length *header*))))))
 
986
      
 
987
      (otherwise (error "unknown message type ~a [~s]" mtype vec )))))
 
988
 
 
989
(defun clear-tk-connection ()
 
990
  ;; flush both sides of connection and discard any partial command.
 
991
  (cond
 
992
   (*tk-connection*
 
993
    (si::clear-connection-state (car (car *tk-connection*)))
 
994
    (setq *pending* nil)
 
995
    (with-tk-command
 
996
     (set-message-header tk-command (pos m_tcl_clear_connection *mtypes*) 0)
 
997
     (write-to-connection *tk-connection* tk-command))
 
998
    )))
 
999
 
 
1000
(defun read-tk-message (ar connection timeout &aux 
 
1001
                           (n-read 0))
 
1002
  (declare (fixnum timeout n-read)
 
1003
           (string ar))
 
1004
  (cond (*pending*
 
1005
         (read-message-body *pending* connection timeout)))
 
1006
         
 
1007
  (setq n-read(si::our-read-with-offset (tk-connection-fd  connection)
 
1008
                                        ar 0 #.(length *header*) timeout))
 
1009
  (setq *pending* ar)
 
1010
  (cond ((not  (eql n-read #.(length *header*)))
 
1011
         (cond ((< n-read 0)
 
1012
                (tkdisconnect)
 
1013
                (cerror ":r to resume "
 
1014
                        "Read got an error, have closed connection"))
 
1015
               (t              (error "Bad tk message"))))
 
1016
        (t
 
1017
         (or (and 
 
1018
              (eql (aref ar (pos magic1 *header*)) *magic1*)
 
1019
              (eql (aref ar (pos magic2 *header*)) *magic2*))
 
1020
             (error "Bad magic"))
 
1021
         (read-message-body ar connection timeout))))
 
1022
 
 
1023
(defun read-message-body (ar connection timeout &aux (m 0) (n-read 0))
 
1024
  (declare (fixnum m n-read))
 
1025
  (setq m (get-number-string ar (pos body-length *header*) 3))
 
1026
  (or (>= (array-total-size ar) (the fixnum (+ m #.(length *header*))))
 
1027
      (setq ar (adjust-array ar (the fixnum (+ m 40)))))
 
1028
  (cond (*pending*
 
1029
         (setq n-read (si::our-read-with-offset (tk-connection-fd connection)
 
1030
                                                ar
 
1031
                                     #.(length *header*) m  timeout))
 
1032
         (setq *pending* nil)
 
1033
         (or (eql n-read m)
 
1034
             (error "Failed to read ~a bytes" m))
 
1035
         (setf (fill-pointer ar) (the fixnum (+ m #.(length *header*))))))
 
1036
  (if *debugging* (describe-message ar))
 
1037
  ar)
 
1038
 
 
1039
(defun tkdisconnect ()
 
1040
  (cond (*tk-connection*
 
1041
         (si::close-sd (caar *tk-connection*))
 
1042
         (si::close-fd (cadr *tk-connection*))))
 
1043
  (setq *sigusr1* t);; disable it...
 
1044
  (setq *pending* nil)
 
1045
  (setf *tk-connection* nil)
 
1046
  
 
1047
  )
 
1048
 
 
1049
(defun read-and-act (id)
 
1050
  id
 
1051
  (when
 
1052
   *tk-connection*
 
1053
   (let* ((*sigusr1* t) tem fun string)
 
1054
     (with-tk-command
 
1055
      (tagbody
 
1056
       TOP
 
1057
       (or (> (si::check-state-input 
 
1058
               (tk-connection-fd *tk-connection*) 0) 0)
 
1059
           (return-from read-and-act))
 
1060
       (setq string (read-tk-message tk-command *tk-connection* *default-timeout*))
 
1061
 
 
1062
       (let ((type (char-code (aref string (pos type *header*))))
 
1063
             from-id success)
 
1064
         (case
 
1065
          type
 
1066
          (#.(pos m_reply *mtypes*)
 
1067
             (setq from-id (get-number-string tk-command #.(+ 1  (length *header*))
 
1068
                                              3))
 
1069
             (setq success (eql (aref tk-command  #.(+ 0  (length *header*)))
 
1070
                                #\0))
 
1071
             (cond ((and (not success)
 
1072
                         *break-on-errors*
 
1073
                         (not (get-circle *requests* from-id)))
 
1074
                    (cerror
 
1075
                     ":r to resume ignoring"
 
1076
                     "request ~s failed: ~s"
 
1077
                     (or (get-circle *request-forms* from-id) "")
 
1078
                     (subseq tk-command #.(+ 4 (length *header*))))))
 
1079
                                
 
1080
             (store-circle *replies*
 
1081
                           (cons success
 
1082
                                 (if (eql (length tk-command) #.(+ 4 (length *header*))) ""
 
1083
                                   (subseq tk-command #.(+ 4 (length *header*)))))
 
1084
                           from-id))
 
1085
          (#.(pos m_call *mtypes*)
 
1086
             ;; Can play a game of if read-and-act called with request-id:
 
1087
             ;; When we send a request which waits for an m_reply, we note
 
1088
             ;; at SEND time, the last message id received from tk.   We
 
1089
             ;; dont process any funcall's with lower id than this id,
 
1090
             ;; until after we get the m_reply back from tk.
 
1091
             (let ((islot
 
1092
                    (get-number-string tk-command #.(+ 0 (length *header*))3))
 
1093
                   (n (length tk-command)))
 
1094
               (declare (fixnum islot n))
 
1095
               (setq tem (our-read-from-string tk-command
 
1096
                                                #.(+ 0 (length *header*)3)))
 
1097
               (or (< islot (length *call-backs*))
 
1098
                   (error "out of bounds call back??"))
 
1099
               (setq fun (aref (the (array t) *call-backs*) islot))
 
1100
               (cond ((equal n #.(+ 3 (length *header*)))
 
1101
                      (funcall fun))
 
1102
                     (t
 
1103
                      (setq tem (our-read-from-string
 
1104
                                 tk-command
 
1105
                                 #.(+ 3(length *header*))))
 
1106
                      (cond ((null tem) (funcall fun))
 
1107
                            ((consp tem) (apply fun tem))
 
1108
                            (t (error "bad m_call message ")))))))
 
1109
          (#.(pos m_set_lisp_loc *mtypes*)
 
1110
             (let* ((lisp-var-id (get-number-string tk-command #.(+ 0  (length *header*))
 
1111
                                                    3))
 
1112
                    (var (aref *text-variable-locations* lisp-var-id))
 
1113
                    (type (get var 'linked-variable-type))
 
1114
                    val)
 
1115
               (setq val (coerce-result (subseq tk-command  #.(+ 3 (length *header*))) type))
 
1116
               (setf (aref *text-variable-locations* (the fixnum
 
1117
                                                          ( + lisp-var-id 1)))
 
1118
                     val)
 
1119
               (set var val)))
 
1120
          (otherwise (format t "Unknown response back ~a" tk-command)))
 
1121
               
 
1122
         (if (eql *sigusr1* :received)
 
1123
             (dformat  "<<received signal while reading>>"))
 
1124
         (go TOP)
 
1125
         ))))))
 
1126
 
 
1127
(defun our-read-from-string (string start)
 
1128
  (let* ((s (car *string-streams*))
 
1129
         (*string-streams* (cdr *string-streams*)))
 
1130
    (or s (setq s (make-string-input-stream "")))
 
1131
    (si::reset-string-input-stream s string start (length string))
 
1132
    (read s nil nil)))
 
1133
 
 
1134
 
 
1135
(defun atoi (string)
 
1136
  (if (numberp string) string
 
1137
    (our-read-from-string string 0)))
 
1138
 
 
1139
 
 
1140
(defun conc (a b &rest l &aux tem)
 
1141
  (declare (:dynamic-extent l))
 
1142
  (sloop
 
1143
     do
 
1144
     (or (symbolp a) (error "not a symbol ~s" a))
 
1145
;     (or (symbolp b) (error "not a symbol ~s" b))
 
1146
     (cond ((setq tem (get a b)))
 
1147
           (t (setf (get a b)
 
1148
                    (setq tem (intern (format nil "~a~a" a b)
 
1149
                                      *tk-package*
 
1150
                                      )))))
 
1151
     while l
 
1152
     do
 
1153
     (setq a  tem b (car l) l (cdr l)))
 
1154
  tem)
 
1155
 
 
1156
     
 
1157
 
 
1158
 
 
1159
(defun dpos (x)  (wm :geometry x "+60+25"))
 
1160
 
 
1161
(defun string-list (x)
 
1162
  (let ((tk-command
 
1163
         (make-array 30 :element-type 'standard-char :fill-pointer 0 :adjustable t)))
 
1164
    (string-list1 tk-command x)
 
1165
    tk-command))
 
1166
 
 
1167
(defun string-list1 (tk-command l &aux x)
 
1168
  ;; turn a list into a tk list
 
1169
    (desetq (x . l) l)
 
1170
    (pp x no_leading_space)
 
1171
    (while l
 
1172
      (desetq (x . l) l)
 
1173
      (cond ((atom x)
 
1174
             (pp x normal))
 
1175
            ((consp x)
 
1176
             (pp "{" no_quote)
 
1177
             (string-list1 tk-command x)
 
1178
             (pp '} no_leading_space)))))
 
1179
 
 
1180
(defun list-string (x &aux
 
1181
                      (brace-level 0)
 
1182
                      skipping (ch #\space)
 
1183
                      (n (length x))
 
1184
                      )
 
1185
  (declare (Fixnum brace-level n)
 
1186
           (string x)
 
1187
           (character ch))
 
1188
  (if (eql n 0) (return-from list-string nil)) 
 
1189
  (sloop for i below n
 
1190
     with beg = 0 and ans
 
1191
     do (setq ch (aref x i))
 
1192
     (cond
 
1193
      ((eql ch #\space)
 
1194
       (cond (skipping nil)
 
1195
             ((eql brace-level 0)
 
1196
              (if (> i beg)
 
1197
                  (setq ans (cons (subseq x beg i) ans)))
 
1198
              
 
1199
              (setq beg (+ i 1))
 
1200
                       )))
 
1201
      (t (cond (skipping (setq skipping nil)
 
1202
                         (setq beg i)))
 
1203
       (case ch
 
1204
       (#\{ (cond ((eql brace-level 0)
 
1205
                   (setq beg (+ i 1))))
 
1206
            (incf brace-level))
 
1207
       (#\} (cond ((eql brace-level 1)
 
1208
                   (setq ans (cons (subseq x beg i) ans))
 
1209
                   (setq skipping t)))
 
1210
            (incf brace-level -1)))))
 
1211
     finally
 
1212
     (unless skipping
 
1213
             (setq ans (cons (subseq x beg i) ans)))
 
1214
     (return (nreverse ans))
 
1215
     ))
 
1216
 
 
1217
;; unless keyword :integer-value, :string-value, :list-strings, :list-forms
 
1218
;; (foo :return 'list)  "ab 2 3" --> (ab 2 3)
 
1219
;; (foo :return 'list-strings)  "ab 2 3" --> ("ab" "2" "3")  ;;ie 
 
1220
;; (foo :return 'string)  "ab 2 3" --> "ab 2 3"
 
1221
;; (foo :return 't)  "ab 2 3" --> AB
 
1222
;; (foo :return 'boolean)  "1" --> t
 
1223
 
 
1224
  
 
1225
(defun coerce-result (string key)
 
1226
  (case key
 
1227
    (list (our-read-from-string (tk-conc "("string ")") 0))
 
1228
    (string string)
 
1229
    (number (our-read-from-string string 0))
 
1230
    ((t) (our-read-from-string string 0))
 
1231
    (t (let ((funs (get key 'coercion-functions)))
 
1232
         (cond ((null funs)
 
1233
                (error "Undefined coercion for type ~s" key)))
 
1234
         (funcall (car funs) string)))))
 
1235
 
 
1236
;;convert "2c" into screen units or points or something...
 
1237
    ))
 
1238
 
 
1239
;; If loc is suitable for handing to setf,  then
 
1240
;; (setf loc (coerce-result val type)
 
1241
;; (radio-button
 
1242
 
 
1243
(defvar *unbound-var* "<unbound>")
 
1244
 
 
1245
(defun link-variable (var type)
 
1246
  (let* ((i 0)
 
1247
         (ar  *text-variable-locations*)
 
1248
         (n (length ar))
 
1249
           tem
 
1250
         )
 
1251
    (declare (fixnum i n)
 
1252
             (type (array (t)) ar))
 
1253
    (cond ((stringp var)
 
1254
           (return-from link-variable var))
 
1255
          ((symbolp var))
 
1256
          ((and (consp var)
 
1257
                (consp (cdr var)))
 
1258
           (setq type (car var))
 
1259
           (setq var (cadr var))))
 
1260
    (or (and (symbolp type)
 
1261
             (get type 'coercion-functions))
 
1262
        (error "Need coercion functions for type ~s" type))
 
1263
    (or (symbolp var) (error "illegal text variable ~s" var))
 
1264
    (setq tem (get var 'linked-variable-type))
 
1265
    (unless (if (and tem (not (eq tem type)))
 
1266
                (format t "~%;;Warning: ~s had type ~s, is being changed to type ~s"
 
1267
                        var tem type
 
1268
                        )))
 
1269
    (setf (get var 'linked-variable-type) type)
 
1270
    (while (< i n)
 
1271
      (cond ((eq (aref ar i) var)
 
1272
             (return-from link-variable var))
 
1273
            ((null (aref ar i))
 
1274
             (return nil))
 
1275
            (t   (setq i (+ i 2)))))
 
1276
;; i is positioned at the write place
 
1277
    (cond ((= i n)
 
1278
           (vector-push-extend nil ar)
 
1279
           (vector-push-extend nil ar)))
 
1280
    (setf (aref ar i) var)
 
1281
    (setf (aref ar (the fixnum (+ i 1)))
 
1282
                (if (boundp var)
 
1283
                    (symbol-value var)
 
1284
                  *unbound-var*))
 
1285
    (with-tk-command
 
1286
     (push-number-string tk-command i #.(length *header*) 3)
 
1287
     (setf (fill-pointer tk-command) #. (+ 3  (length *header*)))
 
1288
     (pp var no_quotes_and_no_leading_space)
 
1289
     (vector-push-extend (code-char 0) tk-command)
 
1290
     (set-message-header tk-command (pos m_tcl_link_text_variable *mtypes*)
 
1291
                         (- (length tk-command) #.(length *header*)))
 
1292
     (write-to-connection *tk-connection* tk-command)))
 
1293
  (notice-text-variables)
 
1294
  var)
 
1295
 
 
1296
(defun unlink-variable (var )
 
1297
  (let* ((i 0)
 
1298
         (ar  *text-variable-locations*)
 
1299
         (n (length ar))
 
1300
 
 
1301
         )
 
1302
    (declare (fixnum i n)
 
1303
             (type (array (t)) ar))
 
1304
    (while (< i n)
 
1305
      (cond ((eq (aref ar i) var)
 
1306
             (setf (aref ar i) nil)
 
1307
             (setf (aref ar (+ i 1)) nil)
 
1308
             (return nil)
 
1309
             )
 
1310
            (t   (setq i (+ i 2)))))
 
1311
    
 
1312
    (cond ((< i n)
 
1313
           (with-tk-command
 
1314
            (push-number-string tk-command i #.(length *header*) 3)
 
1315
            (setf (fill-pointer tk-command) #. (+ 3  (length *header*)))
 
1316
            (pp var no_quotes_and_no_leading_space)
 
1317
            (vector-push-extend (code-char 0) tk-command)
 
1318
            (set-message-header tk-command (pos m_tcl_unlink_text_variable *mtypes*)
 
1319
                                (- (length tk-command) #.(length *header*)))
 
1320
            (write-to-connection *tk-connection* tk-command))
 
1321
           var))))
 
1322
  
 
1323
(defun notice-text-variables ()
 
1324
  (let* ((i 0)
 
1325
         (ar  *text-variable-locations*)
 
1326
         (n (length ar))
 
1327
          tem var type
 
1328
         )
 
1329
    (declare (fixnum i n)
 
1330
             (type (array (t)) ar))
 
1331
    (tagbody
 
1332
     (while (< i n)
 
1333
       (unless (or (not (boundp (setq var  (aref ar i))))
 
1334
                   (eq (setq tem (symbol-value var))
 
1335
                       (aref ar (the fixnum (+ i 1)))))
 
1336
               (setf (aref ar (the fixnum (+ i 1))) tem)
 
1337
               (setq type (get var 'linked-variable-type))
 
1338
               (with-tk-command
 
1339
                ;(push-number-string tk-command i #.(length *header*) 3)
 
1340
                ;(setf (fill-pointer tk-command) #. (+ 3  (length *header*)))
 
1341
                (pp var no_quote_no_leading_space)
 
1342
                (vector-push (code-char 0) tk-command )
 
1343
                (case type
 
1344
                  (string (or (stringp tem) (go error)))
 
1345
                  (number (or (numberp tem) (go error)))
 
1346
                  ((t) (setq tem (format nil "~s" tem )))
 
1347
                  (t 
 
1348
                   (let ((funs (get type 'coercion-functions)))
 
1349
                     (or funs (error "no writer for type ~a" type))
 
1350
                     (setq tem (funcall (cdr funs) tem)))))
 
1351
                (pp tem no_quotes_and_no_leading_space)
 
1352
                (vector-push (code-char 0) tk-command )
 
1353
                (set-message-header tk-command (pos m_tcl_set_text_variable *mtypes*)
 
1354
                                    (- (length tk-command) #.(length *header*)))
 
1355
                (write-to-connection *tk-connection* tk-command)))
 
1356
       (setq i (+ i 2)))
 
1357
     (return-from notice-text-variables)
 
1358
     error
 
1359
     (error "~s has value ~s which is not of type ~s" (aref ar i)
 
1360
            tem type)
 
1361
     )))
 
1362
(defmacro setk (&rest l)
 
1363
  `(prog1 (setf ,@ l)
 
1364
    (notice-text-variables)))
 
1365
 
 
1366
(setf (get 'boolean 'coercion-functions)
 
1367
      (cons #'(lambda (x &aux (ch (aref x 0)))
 
1368
                (cond ((eql ch #\0) nil)
 
1369
                      ((eql ch #\1) t)
 
1370
                      (t (error "non boolean value ~s" x))))
 
1371
            #'(lambda (x) (if x "1" "0"))))
 
1372
 
 
1373
(setf (get 't 'coercion-functions)
 
1374
      (cons #'(lambda (x) (our-read-from-string x 0))
 
1375
            #'(lambda (x) (format nil "~s" x))))
 
1376
 
 
1377
(setf (get 'string 'coercion-functions)
 
1378
      (cons #'(lambda (x)
 
1379
                (cond ((stringp x) x)
 
1380
                      (t (format nil "~s" x))))
 
1381
            'identity))
 
1382
 
 
1383
 
 
1384
(setf (get 'list-strings 'coercion-functions)
 
1385
      (cons 'list-string 'list-to-string))
 
1386
(defun list-to-string  (l &aux (x l) v (start t))
 
1387
  (with-tk-command
 
1388
   (while x
 
1389
     (cond ((consp x)
 
1390
            (setq v (car  x)))
 
1391
           (t (error "Not a true list ~s" l)))
 
1392
     (cond (start (pp v no_leading_space) (setq start nil))
 
1393
           (t (pp v normal)))
 
1394
     (setf x (cdr x)))
 
1395
   (subseq tk-command #.(length *header*))))
 
1396
 
 
1397
 
 
1398
 
 
1399
(defvar *tk-library* nil)
 
1400
(defun tkconnect (&key host can-rsh gcltksrv (display (si::getenv "DISPLAY"))
 
1401
                       (args  "")
 
1402
                            &aux hostid  (loopback "127.0.0.1"))
 
1403
  (if *tk-connection*  (tkdisconnect))
 
1404
  (or display (error "DISPLAY not set"))
 
1405
  (or *tk-library* (setq *tk-library* (si::getenv "TK_LIBRARY")))
 
1406
  (or gcltksrv
 
1407
      (setq     gcltksrv
 
1408
         (cond (host "gcltksrv")
 
1409
               ((si::getenv "GCL_TK_SERVER"))
 
1410
               ((probe-file (tk-conc si::*lib-directory* "/gcl-tk/gcltksrv")))
 
1411
               ((probe-file (tk-conc si::*lib-directory* "gcl-tk/gcltksrv")))
 
1412
               (t (error "Must setenv GCL_TK_SERVER ")))))
 
1413
  (let ((pid (if host  -1 (si::getpid)))
 
1414
        (tk-socket  (si::open-named-socket 0))
 
1415
        )
 
1416
    (cond ((not host) (setq hostid loopback))
 
1417
          (host (setq hostid (si::hostname-to-hostid (si::gethostname)))))
 
1418
    (or hostid (error "Can't find my address"))
 
1419
    (setq tk-socket (si::open-named-socket 0))
 
1420
    (if (pathnamep gcltksrv) (setq gcltksrv (namestring gcltksrv)))
 
1421
    (let ((command 
 
1422
           (tk-conc   gcltksrv " " hostid " "
 
1423
                       (cdr tk-socket) " "
 
1424
                        pid " " display " "
 
1425
                        args
 
1426
                        )))
 
1427
      (print command)
 
1428
      (cond ((not host) (system command))
 
1429
            (can-rsh
 
1430
              (system (tk-conc "rsh " host " "   command
 
1431
                                " < /dev/null &")))
 
1432
            (t (format t "Waiting for you to invoke GCL_TK_SERVER,
 
1433
on ~a as in: ~s~%" host command )))
 
1434
      (let ((ar *text-variable-locations*))
 
1435
        (declare (type (array (t)) ar)) 
 
1436
        (sloop for i below (length ar) by 2
 
1437
               do (remprop (aref ar i) 'linked-variable-type)))
 
1438
      (setf (fill-pointer *text-variable-locations*) 0)
 
1439
      (setf (fill-pointer *call-backs*) 0)
 
1440
 
 
1441
      (setq *tk-connection* (si::accept-socket-connection tk-socket ))
 
1442
      (if (eql pid -1)
 
1443
          (si::SET-SIGIO-FOR-FD  (car (car *tk-connection*))))
 
1444
      (setf *sigusr1* nil)
 
1445
      (tk-do (tk-conc "source "  si::*lib-directory* "gcl-tk/gcl.tcl"))
 
1446
      )))
 
1447
 
 
1448
 
 
1449
  
 
1450
(defun children (win)
 
1451
  (let ((ans (list-string (winfo :children win))))
 
1452
    (cond ((null ans) win)
 
1453
          (t (cons win (mapcar 'children ans))))))
 
1454
 
 
1455
 
 
1456
;; read nth item from a string in
 
1457
 
 
1458
 
 
1459
 
 
1460
(defun nth-a (n string &optional (separator #\space) &aux (j 0) (i 0)
 
1461
                (lim (length string)) ans)
 
1462
  (declare (fixnum j n i lim))
 
1463
  (while (< i lim)
 
1464
    (cond ((eql j n)
 
1465
           (setq ans (our-read-from-string string i))
 
1466
           (setq i lim))
 
1467
          ((eql (aref string i) separator)
 
1468
           (setq j (+ j 1))))
 
1469
    (setq i (+ i 1)))
 
1470
  ans)
 
1471
 
 
1472
 
 
1473
 
 
1474
(defun set-message-header(vec mtype body-length &aux (m (msg-index)) )
 
1475
  (declare (fixnum mtype body-length m)
 
1476
           (string vec) )
 
1477
  (setf (aref vec (pos magic1 *header*)) *magic1*)
 
1478
  (setf (aref vec (pos magic2 *header*)) *magic2*)
 
1479
;  (setf (aref vec (pos flag *header*)) (code-char (make-flag flags)))
 
1480
  (setf (aref vec (pos type *header*)) (code-char mtype))
 
1481
  (push-number-string vec body-length (pos body-length *header*) 3)
 
1482
  (push-number-string vec  m (pos msg-index *header*) 3)
 
1483
  (setf (msg-index) (the fixnum (+ m 1)))
 
1484
  m)
 
1485
 
 
1486
(defun get-autoloads (&optional (lis (directory "*.lisp")) ( out "index.lsp")
 
1487
                                &aux *paths*
 
1488
                                )
 
1489
  (declare (special *paths*))
 
1490
  (with-open-file
 
1491
   (st out :direction :output)
 
1492
   (format st "~%(in-package ~s)" (package-name *package*))
 
1493
   (dolist (v lis) (get-file-autoloads v st))
 
1494
   (format st "~%(in-package ~s)" (package-name *package*))
 
1495
   (format st "~2%~s" `(setq si::*load-path* (append ',*paths* si::*load-path*)))
 
1496
 
 
1497
   ))
 
1498
 
 
1499
 
 
1500
                  
 
1501
(defun get-file-autoloads (file &optional (out t)
 
1502
                                &aux (eof '(nil))
 
1503
                                (*package* *package*)
 
1504
                                saw-package
 
1505
                                name  )
 
1506
  (declare (special *paths*))
 
1507
  (setq name (pathname-name (pathname file)))
 
1508
  (with-open-file
 
1509
   (st file)
 
1510
   (if (boundp '*paths*)
 
1511
       (pushnew (namestring (make-pathname :directory
 
1512
                                           (pathname-directory
 
1513
                                            (truename st))))
 
1514
                *paths* :test 'equal))
 
1515
   (sloop for tem = (read st nil eof)
 
1516
          while (not (eq tem eof))
 
1517
          do (cond ((and (consp tem) (eq (car tem) 'defun))
 
1518
                    (or saw-package
 
1519
                        (format t "~%;;Warning:(in ~a) a defun not preceded by package declaration" file))
 
1520
                    (format out "~%(~s '~s '|~a|)"
 
1521
                            'si::autoload
 
1522
                            (second tem) name))
 
1523
                   ((and (consp tem) (eq (car tem) 'in-package))
 
1524
                    (setq saw-package t)
 
1525
                    (or (equal (find-package (second tem)) *package*)
 
1526
                        (format out "~%~s" tem))
 
1527
                    (eval tem))
 
1528
                   ))))
 
1529
 
 
1530
;; execute form return values as usual unless error
 
1531
;; occurs in which case if symbol set-var is supplied, set it
 
1532
;; to the tag, returning the tag.
 
1533
(defmacro myerrorset (form &optional set-var)
 
1534
 `(let ((*break-enable* nil)(*debug-io* si::*null-io*)
 
1535
        (*error-output* si::*null-io*))
 
1536
    (multiple-value-call 'error-set-help ',set-var
 
1537
     (si::error-set ,form))))
 
1538
 
 
1539
(defun error-set-help (var tag &rest l)
 
1540
  (cond (tag (if var (set var tag))) ;; got an error
 
1541
        (t (apply 'values l))))
 
1542
 
 
1543
;;; Local Variables: ***
 
1544
;;; mode:lisp ***
 
1545
;;; version-control:t ***
 
1546
;;; comment-column:0 ***
 
1547
;;; comment-start: ";;; "  ***
 
1548
;;; End: ***
 
1549
 
 
1550
 
 
1551
       
 
1552
       
 
1553