FunctionPackage: cgToCDocOverviewCGDocRelNotesFAQIndexPermutedIndex
Allegro CL version 10.0
Unrevised from 9.0 to 10.0.
9.0 version

post-funcall-in-cg-process

Arguments: function &key arguments (process multiprocessing:*current-process*) type delete-types unless-types

This function places a funcallable object to be called later onto a "funcall queue" for the specified Common Graphics process. The function call will be made only after all pending window messages in that process have been handled completely, and after all function calls that were already in the funcall queue for that process have been called and have returned.

The queued funcalls are called only by the main event-handling loop inside the function event-loop, which is normally called by any Common Graphics process. While calls to functions such as process-wait or process-pending-events will handle window messages at that time, these calls will not process queued funcalls.

This function is typically useful when message-handling code calls certain functions that block, which allows further messages to be handled while the code that is running for the current message is blocking. If further messages arrive during the blocking period, this can cause message-handling code to be re-entered or otherwise run in an order that is not expected, which may cause the application to get into a confused or hung state.

In particular, calls to process-wait, with-process-lock, sleep, or process-pending-events will cause subsequent messages to be handled immediately (or when they occur during the function's waiting period). Note that various Common Graphics or other Allegro CL functions may call these functions internally, and therefore will have the same potential problem; for example, the AllegroStore macro with-transaction calls with-process-lock, and so Common Graphics message-handling code that calls with-transaction may want to queue this call if it might cause confusion when intervening messages all wait on the lock while the same process is already using it.

The arguments to post-funcall-in-cg-process are:

Note that the queued functions are always called asynchronously, and so the caller of post-funcall-in-cg-process cannot wait for a returned value or an indication that the code has run. So it is probably most useful to call post-funcall-in-cg-process at the very top of a message-handling method or function, so that everything that would have been done by the event-handler is done instead by the queued function call. (eval-in-listener-thread, on the other hand, can wait for completion, though it may be used only in the IDE and not in a standalone application.)

About design considerations for event-driven applications in cgide.htm for more information.

An Example

Below is an example that causes each mouse-in event of a window to print a string to the Debug Window (when the example is run in the IDE) and then to wait two seconds. Because this action is queued by calling post-funcall-in-cg-process each time, the messages will not print more often then every two seconds, even if you rapidly move the mouse into and out of the window, because each queued function will be called only after the preceding one has returned. (Without the call to post-funcall-in-cg-process, the call to sleep would cause further messages to be handled, and each string would be printed almost immediately when the event occurs.)

Notice that the mouse-moved method continues to print coordinates immediately to the IDE status-bar, even as the printing done by the mouse-in method is delayed by the calls to sleep. (In real application code, the delay would more likely be done by a call to process-wait or with-process-lock rather than a call to sleep like the one in this simple example.)

(in-package :cg-user)

(defclass my-win (frame-window)())

(defmethod mouse-moved ((window my-win) buttons pos)
  (declare (ignore buttons))
  (setq pos (copy-position pos))
  (ide:lisp-message "Mouse now at ~a   ~a"
    (position-x pos)(position-y pos)))

(defmethod mouse-in ((window my-win) buttons mouse-out-object)
  (declare (ignore buttons))
  
  (post-funcall-in-cg-process 
      (lambda ()
        (format t "~&Moved out of ~a into ~a~%"
          (name-string mouse-out-object)
          (name-string window))
        (sleep 2))
    :type :mouse-in-message)
  
  #|
  ;; This alternative uses an :arguments argument
  ;; rather than closing over variable bindings.  Note that this
  ;; causes the format arguments to be evaluated when this code
  ;; is posted rather than when it is run later.
  (post-funcall-in-cg-process
      (lambda (format-string &rest format-args)
        (apply #'format t format-string format-args)
        (sleep 2))
    :arguments (list "~&Moved out of ~a into ~a~%"
                     (name-string mouse-out-object)
                     (name-string window))
    :type :mouse-in-message
    
    ;; Adding this would prune out mouse-in messages that are
    ;; still queued when this later event is handled, so that only
    ;; one mouse-in message will print after the last mouse-in event.
    :delete-types '(:mouse-in-message))
  |#
  )

(make-window :my-win :class 'my-win)

Copyright (c) 1998-2019, Franz Inc. Oakland, CA., USA. All rights reserved.
This page was not revised from the 9.0 page.
Created 2015.5.21.

ToCDocOverviewCGDocRelNotesFAQIndexPermutedIndex
Allegro CL version 10.0
Unrevised from 9.0 to 10.0.
9.0 version