Page 1 of 1

PB 5.20 - Differences between callback and event loop

Posted: Wed Oct 23, 2013 4:36 pm
by c4s
Until now I thought that the window callback is the option of choice when dealing with API events. What confuses though is that using the main event loop actually works better... For example if I want to receive the mouse move and click events on the string gadget I have to use the main event loop - this was pretty unexpected! Why is it like that? Is it a bug?

Example code:

Code: Select all

Procedure WinCallback(WindowID, Message, WParam, LParam)
	Result = #PB_ProcessPureBasicEvents

	Select Message
		Case #WM_MOUSEMOVE
			Debug "move (API, callback)"
		Case #WM_LBUTTONDOWN
			Debug "down (API, callback)"
		Case #WM_LBUTTONUP
			Debug "up   (API, callback)"
	EndSelect

	ProcedureReturn Result  
EndProcedure

OpenWindow(0, 0, 0, 200, 60, "WinAPI Events", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
StringGadget(1, 5, 5, 190, 20, "")

SetWindowCallback(@WinCallback(), 0)

Repeat
	Select WaitWindowEvent()
		Case #WM_MOUSEMOVE
			Debug "move (API, event loop)"
		Case #WM_LBUTTONDOWN
			Debug "down (API, event loop)"
		Case #WM_LBUTTONUP
			Debug "up   (API, event loop)"
		Case #PB_Event_LeftClick  ; By the way, a native #WM_MOUSEMOVE is missing in my opinion
			Debug "up   (PB,  event loop)"
		Case #PB_Event_CloseWindow
			Break
	EndSelect
ForEver
Using PB 5.20 LTS (x86) on Windows 8.1 (x64).

Re: PB 5.20 - Differences between callback and event loop

Posted: Wed Oct 23, 2013 5:16 pm
by ts-soft
c4s wrote:For example if I want to receive the mouse move and click events on the string gadget I have to use the main event loop - this was pretty unexpected! Why is it like that? Is it a bug?
No, to catch this events, you have to subclass the Gadget/Child.

Re: PB 5.20 - Differences between callback and event loop

Posted: Wed Oct 23, 2013 6:22 pm
by c4s
Do you mean that I cannot receive the window mouse's move and click events if the mouse is over another gadget? The main event loop already gives me what I want, why?

Re: PB 5.20 - Differences between callback and event loop

Posted: Thu Oct 24, 2013 12:41 pm
by TI-994A
c4s wrote:...The main event loop already gives me what I want, why?
Hi c4s. You're right; PureBasic's window event loop does process almost all the windows' messages, but not all. This example will illustrate how the WM_PAINT event and the parameters of the WM_SIZE event cannot be effectively handled by PureBasic's window event loop:

Code: Select all

Procedure WinCallback(WindowID, Message, WParam, LParam)
  Select Message
    Case #WM_SIZE 
      Select WParam 
        Case #SIZE_MINIMIZED 
          Debug "Callback: Minimized"
      EndSelect
    Case #WM_PAINT
      Debug "Callback: Paint"
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure

OpenWindow(0, 0, 0, 400, 300, "Windows Callback", #PB_Window_SystemMenu |
                                                  #PB_Window_MinimizeGadget |
                                                  #PB_Window_ScreenCentered)
SetWindowCallback(@WinCallback())
MessageRequester("Windows Messages", 
                 "Move this message box over the window" + #CRLF$ +
                 "and notice that PureBasic's event loop" + #CRLF$ +
                 "does not receive the WM_PAINT events.")
MessageRequester("Windows Messages",
                 "When the window is minimized, PureBasic's event" + #CRLF$ +
                 "loop can only process the WM_SIZE message, but" + #CRLF$ +
                 "not the SIZE_MINIMIZED message parameter.")
ClearDebugOutput()

Repeat
  Select WaitWindowEvent()
    Case #WM_SIZE
      Debug "PureBasic: Size"
      ;EventwParam()?
    Case #WM_PAINT
      Debug "PureBasic: Paint"
    Case #PB_Event_CloseWindow
      Break
  EndSelect
ForEver
In addition to this, in some cases, callbacks can offer greater control over the subclassed gadgets in the way the windows' messages are processed. Although PureBasic's SetWindowCallback() function does not seem to do this, the Windows' API function SetWindowLongPtr() provides the option to either dispatch or discard the intercepted messages, which can be very useful. This functionality is demonstrated in this example, which subclasses an EditorGadget() and disables the TAB and ENTER keys:

Code: Select all

Procedure EditorProc(hWnd, uMsg, wParam, lParam)
  Shared sysProc
  Select uMsg 
    Case #WM_CHAR, #WM_KEYDOWN
      Select wParam
        Case #VK_TAB
          SetGadgetText(1, "You pressed TAB")
          uMsg = 0
        Case #VK_RETURN
          SetGadgetText(1, "You pressed ENTER")
          uMsg = 0
      EndSelect
  EndSelect
  ProcedureReturn CallWindowProc_(sysProc, hWnd, uMsg, wParam, lParam)
EndProcedure

OpenWindow(0, 0, 0, 200, 150, "Windows Callback",
           #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
EditorGadget(1, 5, 5, 190, 110, #PB_Editor_WordWrap)
ButtonGadget(2, 5, 120, 190, 20, "Activate Callback")
SetGadgetText(1, "Press the TAB & RETURN keys to test their normal behaviour...")
SetActiveGadget(1)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      appQuit = 1
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 2
          If activated
            SetWindowLongPtr_(GadgetID(1), #GWL_WNDPROC, sysProc)
            SetGadgetText(2, "Deactivated - Click to Activate")
            activated = 0
          Else
            sysProc = SetWindowLongPtr_(GadgetID(1), #GWL_WNDPROC, @EditorProc())
            SetGadgetText(2, "Activated - Click to Deactivate")
            activated = 1
          EndIf
          SetGadgetText(1, "Press the TAB & RETURN now...")
          SetActiveGadget(1)
      EndSelect
  EndSelect
Until appQuit = 1
Since PureBasic's SetWindowCallback() is now a Windows-only function, the SetWindowLong() alternative will not compromise cross-platform compatibility. However, the use of Windows-only message constants like WM_MOUSEMOVE, WM_KEYDOWN, etc., in the main event loop would require a lot of conditional compiling to keep the program cross-compatible.

My apologies if this is off-topic. :)

Re: PB 5.20 - Differences between callback and event loop

Posted: Thu Oct 24, 2013 8:24 pm
by c4s
Hm, what I don't understand is why the PB event loop gives me more opportunities with API events than the window callback. Normally it should be the other way round?!

I read somewhere that especially starting with PB5.20 API events shouldn't be accessed in the main event loop anymore. Instead the callback should be used. However in my case doing so doesn't make that much sense because it's actually more limited than before... Any suggestions on how to fix this?

Re: PB 5.20 - Differences between callback and event loop

Posted: Fri Oct 25, 2013 12:46 am
by TI-994A
c4s wrote:...the PB event loop gives me more opportunities with API events than the window callback. Normally it should be the other way round?!
Hi c4s. If I may ask, more opportunities how? :)

Re: PB 5.20 - Differences between callback and event loop

Posted: Fri Oct 25, 2013 4:07 pm
by c4s
Well, for example I can react on the mouse move and click events that happen over another gadget (see first post for an example). For some strange reason these API events are only triggered in the main event loop but not in the window callback.

Re: PB 5.20 - Differences between callback and event loop

Posted: Fri Oct 25, 2013 5:38 pm
by hallodri
The reason for this is not strange. Each window (every gadget or window) has its own event function. PureBasic collected from all the appropriate callback events, which you can then retrieve it with the help of WaitWindowEvent. If you want to get all the events, you have to individually bend each window function (subclass).

Re: PB 5.20 - Differences between callback and event loop

Posted: Sat Oct 26, 2013 8:26 am
by c4s
To get the general mouse moving and clicking behavior over a window (not interested in each gadget), I first have to collect all events for the gadgets etc. and then deduce it from that? That's pretty strange if you ask me!

Re: PB 5.20 - Differences between callback and event loop

Posted: Sat Oct 26, 2013 9:54 am
by Danilo
c4s wrote:That's pretty strange if you ask me!
Why is it strange if somebody asks you? Gadgets are independent objects on top of the window,
so on a mouse move or click the object under the cursor gets the messages. If an object does
not support a message, it usually forwards it to its parent object.
Messages supported by the object are handled by this object. For example, a button handles
mouse button down, mouse move, and mouse button up messages itself. If it detects a click with
this messages, it sends a notification message like BN_CLICK to it's parent object.

Beside that, what do you need the "general mouse moving and clicking behavior" for?
Maybe it's better to explain what you want to achieve. If you want to know mouse movement
over a specific object (like a button), you usually do this in the specific object's event handler,
so this object works independent of the other neighboring objects.

Re: PB 5.20 - Differences between callback and event loop

Posted: Sat Oct 26, 2013 1:53 pm
by c4s
Danilo wrote:
c4s wrote:That's pretty strange if you ask me!
Why is it strange if somebody asks you?
I thought it's saying, the "in my opinion" kind of...
Danilo wrote:Gadgets are independent objects on top of the window,
so on a mouse move or click the object under the cursor gets the messages. If an object does
not support a message, it usually forwards it to its parent object. [...]
OK, understood that. Thanks for the explanation.
Danilo wrote:Beside that, what do you need the "general mouse moving and clicking behavior" for?
I need to get some code running under 5.10/5.20. I'm not yet ready for BindEvent() etc. so I though I'd just start with removing all API events (mainly mouse move and click) from the main loop and putting it in a callback. But that doesn't seem to work either so for now I just have to leave it as it is...