This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Messages and Message Loops
Message loops
A thread with windows takes their messages from its queue and hands them to their window procedures. cl-win32 has two ways:
(win32:run-message-loop) ; waits, until POST-QUIT-MESSAGE; => its code
(win32:process-messages) ; hands over what is waiting, and returns
run-message-loop waits for messages and hands each over, until the
thread calls post-quit-message; it returns the code given to
post-quit-message. It wakes for messages sent from other threads too.
Handing a message over allocates nothing, so the loop can run for the
life of a program.
process-messages hands over the messages waiting and returns without
waiting for more. It returns nil, or t and the code if it came across
the quit message. Use it in a loop that does other work, such as a game
loop that renders a frame after each round.
Both translate key messages: after a key press that types a character,
Windows posts +wm-char+ with it, after dead keys. See
Keyboard and Pointer.
An error in a window procedure is signalled from run-message-loop or
process-messages, right after the message it happened in. The loop may
be called again to go on:
(loop
(handler-case (return (win32:run-message-loop))
(error (condition)
(log-error condition))))
Posting and sending
(win32:post-message window win32:+wm-close+) ; returns at once
(win32:send-message window (+ win32:+wm-app+ 1) 7 0) ; => the procedure's result
post-message puts a message on the queue of the window's thread and
returns. It may be called from any thread.
send-message calls the window's procedure with the message and returns
its result. From another thread than the window's, it waits until the
window's thread takes the message, which it does while it waits for
messages. So the window's thread must not be waiting for the sender, or
neither goes on: don't hold a lock the window procedure needs while you
send.
wparam is an unsigned integer and lparam a signed one, both 0 if left
out.
Messages of your own
Numbers from +wm-app+ (#x8000) up are free for a program's own messages,
and from +wm-user+ (#x400) up for a window class's. A message-only
window with a message of your own is the usual way to give work to a
thread with a message loop. See Recipes.
Looking ahead
(win32:peek-message) ; => the next message, its wparam, lparam and time
(win32:peek-message :window window) ; only that window's
(win32:peek-message :first win32:+wm-keydown+ :last win32:+wm-keyup+)
peek-message returns the next message waiting for the calling thread, its
wparam and lparam, and its time, without taking it; or nil if none
is. :window and :first and :last narrow which messages count.
message-time is the time of the message being handled, in milliseconds
since Windows started. Two messages Windows made for one action, such as
the two key messages of AltGr, have the same time. message-position is
where the pointer was on the screen then, which a message without a
position of its own, such as +wm-capturechanged+, needs.
Taking parameters apart
Many messages pack two 16-bit numbers into one parameter.
| Function | Like | Gives |
|---|---|---|
low-word |
LOWORD |
bits 0–15, unsigned |
high-word |
HIWORD |
bits 16–31, unsigned |
signed-low-word |
GET_X_LPARAM |
bits 0–15, signed: pointer x |
signed-high-word |
GET_Y_LPARAM, GET_WHEEL_DELTA_WPARAM |
bits 16–31, signed: pointer y, wheel turns |
make-lparam |
MAKELPARAM |
two words put together |
;; In a window procedure:
((= message win32:+wm-size+)
(resize (win32:low-word lparam) (win32:high-word lparam))
0)
((= message win32:+wm-mousemove+)
(move-to (win32:signed-low-word lparam) (win32:signed-high-word lparam))
0)
Pointer positions are signed: a drag that leaves the window, or a window on a display left of the main one, gives negative ones.
read-rect reads a RECT a parameter points to, as +wm-dpichanged+'s
lparam does, and returns its left, top, right and bottom.
The messages
cl-win32 names the messages its users need most as constants:
- Lifetime:
+wm-nccreate+,+wm-create+,+wm-destroy+,+wm-ncdestroy+,+wm-close+,+wm-quit+. - Size and place:
+wm-size+with+size-restored+,+size-minimized+and+size-maximized+;+wm-move+,+wm-windowposchanging+,+wm-windowposchanged+,+wm-getminmaxinfo+,+wm-entersizemove+,+wm-exitsizemove+,+wm-dpichanged+. - State:
+wm-activate+,+wm-setfocus+,+wm-killfocus+,+wm-showwindow+,+wm-settext+,+wm-gettext+. - Painting:
+wm-paint+,+wm-erasebkgnd+,+wm-setcursor+. - Keyboard:
+wm-keydown+,+wm-keyup+,+wm-syskeydown+,+wm-syskeyup+,+wm-char+,+wm-syschar+,+wm-deadchar+,+wm-sysdeadchar+,+wm-syscommand+. - Pointer:
+wm-mousemove+,+wm-mouseleave+,+wm-lbuttondown+,+wm-lbuttonup+,+wm-lbuttondblclk+,+wm-rbuttondown+,+wm-rbuttonup+,+wm-mbuttondown+,+wm-mbuttonup+,+wm-xbuttondown+and+wm-xbuttonup+with+xbutton1+and+xbutton2+;+wm-mousewheel+and+wm-mousehwheel+with+wheel-delta+;+wm-capturechanged+. - Others:
+wm-null+,+wm-user+,+wm-app+.
Each constant's docstring says what its parameters hold. Messages without a constant are numbers like any other: compare with the number from Windows' documentation.