[SOLVED] Events in system tray

Just starting out? Need help? Post your questions and find answers here.
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

[SOLVED] Events in system tray

Post by ZX80 »

Hi, all.

Sorry if this is a dumb question and if I missed this, but I can't seem to find a solution. My question sound as:
How can I forcefully clear the event queue ? I'm getting a lot of mouse click events in the main loop when I click on an icon multiple times. That's ok, but I need only one. Only the first event. Here is minimal code that demonstrates the problem:

Code: Select all

win_nr = OpenWindow(#PB_Any, 0, 0, 400, 200, "test-window", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
If win_nr = 0 : End : EndIf

hIcon = ExtractIcon_(0, "imageres.dll", 100)
AddSysTrayIcon(1, WindowID(win_nr), hIcon)

msgbox_title.s = "Attention !"
msgbox_body.s  = "blah-blah-blah..."

Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #PB_Event_SysTray
      Select EventType()
        Case #PB_EventType_LeftClick, #PB_EventType_LeftDoubleClick
          Debug "LeftClick or LeftDoubleClick was detected on SysTray"
          If FindWindow_(0, msgbox_title) = 0
            MessageRequester(msgbox_title, msgbox_body, #MB_SYSTEMMODAL)
          Else ; do nothing !
            Debug "msgbox already opened"
          EndIf
      EndSelect
      
    Case #PB_Event_CloseWindow
      DestroyIcon_(hIcon)
      Break
  EndSelect
ForEver
Try clicking the taskbar icon several times and you will see a lot of repeated pop-up messages (one by one). Yes, I know that MessageRequester() function slows down the entire program until it is closed. but then why do the events accumulate if it's already open and the clicks continue ? :shock:

So...
How to clear the event queue from mouse clicks :?:

Thank you in advance !
Last edited by ZX80 on Thu Sep 05, 2024 2:13 pm, edited 1 time in total.
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

Re: Events in system tray

Post by Axolotl »

Hi ZX80,

I am pretty sure that you can solve your problem by separating the events like this code below.
If I remember correctly than a Double Click always fires an Single Click as well, so in your code you react on all events....

Code: Select all

Procedure Trace(Message$) 
  Static s_index = 0 

  AddGadgetItem(0, s_index, RSet(Str(s_index), 4, "0") + ": " + Message$) 
  SetGadgetState(0, s_index) 
  s_index + 1 
EndProcedure 

win_nr = OpenWindow(#PB_Any, 0, 0, 400, 200, "test-window", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
If win_nr = 0 : End : EndIf
  ListViewGadget(0, 0, 0, 400, 200, $4000) 

hIcon = ExtractIcon_(0, "imageres.dll", 100)
AddSysTrayIcon(1, WindowID(win_nr), hIcon)

msgbox_title.s = "Attention !"
msgbox_body.s  = "blah-blah-blah..."

Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #PB_Event_SysTray
      Select EventType()
        Case #PB_EventType_LeftClick
          Trace("LeftClick on SysTray") 
        Case #PB_EventType_LeftDoubleClick
          Trace("LeftDoubleClick on SysTray") 

;         Case #PB_EventType_LeftClick, #PB_EventType_LeftDoubleClick
; ;         Debug "LeftClick or LeftDoubleClick was detected on SysTray"
;           Trace("LeftClick or LeftDoubleClick was detected on SysTray") 
;           If FindWindow_(0, msgbox_title) = 0
;             MessageRequester(msgbox_title, msgbox_body, #MB_SYSTEMMODAL)
;           Else ; do nothing !
; ;           Debug "msgbox already opened"
;             Trace("msgbox already opened") 
;           EndIf
      EndSelect
      
    Case #PB_Event_CloseWindow
      DestroyIcon_(hIcon)
      Break
  EndSelect
ForEver
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
User avatar
TI-994A
Addict
Addict
Posts: 2698
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Events in system tray

Post by TI-994A »

ZX80 wrote: Wed Sep 04, 2024 11:41 am...I'm getting a lot of mouse click events in the main loop when I click on an icon multiple times. That's ok, but I need only one.
The message requester is blocking the subsequent clicks from being processed, and those clicks are being processed only after the message requester is dismissed. If a message requester is required, perhaps implement a custom one, otherwise, other code logic should not block the clicks from being processed and cleared from the queue.

Here's an example:

Code: Select all

Global msgBoxWindow, msgBoxButton
Procedure msgBox(msg.s)
  Shared win_nr
  msgBoxWindow = OpenWindow(#PB_Any, 0, 0, 200, 100, "MsgBox", 
                            #PB_Window_Tool | #PB_Window_WindowCentered, 
                            WindowID(win_nr))
  text = TextGadget(#PB_Any, 0, 20, 200, 30, msg, #PB_Text_Center)
  msgBoxButton = ButtonGadget(#PB_Any, 50, 50, 100, 30, "OK")
EndProcedure

win_nr = OpenWindow(#PB_Any, 0, 0, 400, 200, "test-window", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
If win_nr = 0 : End : EndIf

hIcon = ExtractIcon_(0, "imageres.dll", 100)
AddSysTrayIcon(1, WindowID(win_nr), hIcon)

msgbox_title.s = "Attention !"
msgbox_body.s  = "blah-blah-blah..."

Repeat
  Event = WaitWindowEvent()
  Select Event
      
    Case #PB_Event_SysTray
      Select EventType()
        Case #PB_EventType_LeftClick, #PB_EventType_LeftDoubleClick
          If Not systrayActivated            
            systrayActivated = #True
            Debug "LeftClick or LeftDoubleClick was detected on SysTray"
            msgBox("blah-blah-blah...")            
          EndIf
      EndSelect
      
    Case #PB_Event_Gadget
      If EventGadget() = msgBoxButton
        CloseWindow(msgBoxWindow)
        systrayActivated = #False
      EndIf
      
    Case #PB_Event_CloseWindow
      DestroyIcon_(hIcon)
      Break
      
  EndSelect
ForEver
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: Events in system tray

Post by ZX80 »

Axolotl, good time ! Thanks for your answer.
I am pretty sure that you can solve your problem by separating the events like this code below.
I don't think that's the issue here. I think I've found a solution. Is this normal practice ?

Code: Select all

Global thread

Procedure PopupMsg(*x)
  MessageRequester("Attention !", "blah-blah-blah...", #MB_SYSTEMMODAL)
  thread = 0
EndProcedure

win_nr = OpenWindow(#PB_Any, 0, 0, 400, 200, "test-window", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
If win_nr = 0 : End : EndIf

hIcon = ExtractIcon_(0, "imageres.dll", 100)
AddSysTrayIcon(1, WindowID(win_nr), hIcon)


Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #PB_Event_SysTray
      Select EventType()
        Case #PB_EventType_LeftClick, #PB_EventType_LeftDoubleClick
          Debug "LeftClick or LeftDoubleClick was detected on SysTray"
          If thread = 0
            thread = CreateThread(@PopupMsg(), 0)
          Else
            Debug "Close the previous Msgbox first."
          EndIf
      EndSelect
      
    Case #PB_Event_CloseWindow
      DestroyIcon_(hIcon)
      Break
  EndSelect
ForEver
By the way, the middle key is not processed on my system. In my case, it is combined with a wheel. Has anyone caught the events '#PB_EventType_MouseEnter' and '#PB_EventType_MouseLeave' in the system tray ?
I was looking at this old thread.
Last edited by ZX80 on Wed Sep 04, 2024 12:54 pm, edited 1 time in total.
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: Events in system tray

Post by ZX80 »

Hello, TI-994A.

Thanks for the clarification. Your code works too.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: Events in system tray

Post by RASHAD »

Hi ZX80
You may need non blocking message

Code: Select all

Prototype SplashMessageSetup(hWnd,lpText$,lpCaption$,uType,wLanguageID.w,dwMilliseconds)
Procedure SplashMessage(title$,text$,ms=1000,icon=#MB_ICONINFORMATION)
  lib=OpenLibrary(#PB_Any,"user32.dll")
  If lib
    SplashMessageSetup.SplashMessageSetup=GetFunction(lib,"MessageBoxTimeoutW")
    SplashMessageSetup(GetForegroundWindow_(),text$,title$,#MB_SETFOREGROUND|#MB_TOPMOST|#MB_TASKMODAL|icon,0,ms)
    CloseLibrary(lib)
  EndIf
EndProcedure


win_nr = OpenWindow(#PB_Any, 0, 0, 400, 200, "test-window", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
If win_nr = 0 : End : EndIf

hIcon = ExtractIcon_(0, "imageres.dll", 100)
AddSysTrayIcon(1, WindowID(win_nr), hIcon)

msgbox_title.s = "Attention !"
msgbox_body.s  = "blah-blah-blah..."

Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #PB_Event_SysTray
      Select EventType()
        Case #PB_EventType_LeftClick, #PB_EventType_LeftDoubleClick
          Debug "LeftClick or LeftDoubleClick was detected on SysTray"
          If FindWindow_(0, msgbox_title) = 0
            SplashMessage(msgbox_title,msgbox_body,1000)
          Else ; do nothing !
            Debug "msgbox already opened"
          EndIf
      EndSelect
      
    Case #PB_Event_CloseWindow
      DestroyIcon_(hIcon)
      Break
  EndSelect
ForEver
Egypt my love
User avatar
mk-soft
Always Here
Always Here
Posts: 6202
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Events in system tray

Post by mk-soft »

Works only under Windows with Thread, but not allways
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: Events in system tray

Post by ZX80 »

RASHAD, mk-soft, thank you for your attention to my question.

RASHAD, yes, I know about the SplashMessage. You already published this, if my memory serves me correctly. Thanks for this. But in this case it is not entirely appropriate here. In addition, this does not prevent multiple messages from appearing, since there is a timeout and the message is automatically closed. One follows another. I understand that this sounds stupid, and it's unlikely that anyone will click on the icon many times, but this should also be provided, right ? I don’t know if you’ve heard of such a term as “foolproofing” ? This is it. I was surprised that MessageRequester() in this case turned out to be non-blocking at all. And here I want to carefully ask: Is this a bug or not ?

Thank you all again !
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: Events in system tray

Post by ZX80 »

@TI-994A
TI-994A wrote: Wed Sep 04, 2024 12:39 pm The message requester is blocking the subsequent clicks from being processed, and those clicks are being processed only after the message requester is dismissed...
I'm very sorry, but why in my second code these clicks are not processed when the message is closed ? After all, in your opinion, they should accumulate somewhere in the message queue, right ? How is it that it magically clears itself ? In my second code we still see the response to clicks. You can see this in the debug window. I don't understand anything. :shock:
User avatar
TI-994A
Addict
Addict
Posts: 2698
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Events in system tray

Post by TI-994A »

ZX80 wrote: Thu Sep 05, 2024 9:13 am... in my second code these clicks are not processed when the message is closed ? After all, in your opinion, they should accumulate somewhere in the message queue, right ? How is it that it magically clears itself ?
Hello again, @ZX80. The clicks are queued in your first example, because the conventional message requester blocks all event processing until it is closed. But now, in your second example, the message requester is being called from a thread, so it no longer blocks the processing of subsequent clicks, and they are all processed instantly, one after another, thereby clearing the queue. Nothing blocked or queued.

I've commented your second example to explain this. My apologies, but I'm just trying to be clear, and in no way am I trying to be condescending with the simplistic explanations. :D

Code: Select all

Global thread

Procedure PopupMsg(*x)
  MessageRequester("Attention !", "blah-blah-blah...", #MB_SYSTEMMODAL)
  thread = 0
EndProcedure

win_nr = OpenWindow(#PB_Any, 0, 0, 400, 200, "test-window", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
If win_nr = 0 : End : EndIf

hIcon = ExtractIcon_(0, "imageres.dll", 100)
AddSysTrayIcon(1, WindowID(win_nr), hIcon)


Repeat
  Event = WaitWindowEvent()
  Select Event
      
    ; example: left-click or left-double-click sysTray item 10 TIMES  
      
    ; 1. all 10 sysTray click events will trigger this CASE  
    Case #PB_Event_SysTray
      
      ; 2. check each sysTray event type
      Select EventType()
          
        ; 3. all 10 systTray event types are either left-click or 
         ;   left-double-click, so they will all trigger this CASE                        
        Case #PB_EventType_LeftClick, #PB_EventType_LeftDoubleClick
          
          ; 4. all 10 left-click or left-double-click events
          ;    will reach HERE and print this debug statement
          Debug "LeftClick or LeftDoubleClick was detected on SysTray"
          
          ; 5. all 10 left-click or left-double-click events
          ;    will also reach HERE...
          
          ; 6. but only the FIRST left-click or left-double-click
          ;    event will satisfy the condition [If thread = 0]
          If thread = 0
            
            ; 7. the FIRST left-click or left-double-click event
            ;    enters this block and creates the msgBox thread
            
            thread = CreateThread(@PopupMsg(), 0)
            
            ; 8. now the thread has been created so [thread != 0] anymore
            ;    so the other 9 left-click or left-double-click events
            ;    cannot enter this IF block and gets thrown to the ELSE block
            
          Else
            
            ; 9. all the other 9 left-click or left-double-click events
            ;    reach HERE instead and print this debug statement 
            Debug "Close the previous Msgbox first."
            
          EndIf
          
      ; 10. all 10 systTray events have now been processed and cleared from the queue!
      ;     when the thread terminates and [thread = 0] again the thread block can be
      ;     reached and a new msgBox thread can be created again by subsequent events.
      EndSelect      
      
      
    Case #PB_Event_CloseWindow
      DestroyIcon_(hIcon)
      Break
  EndSelect
ForEver
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
ZX80
Enthusiast
Enthusiast
Posts: 361
Joined: Mon Dec 12, 2016 1:37 pm

Re: Events in system tray

Post by ZX80 »

TI-994A, thanks a lot !

Yes, everything is much clearer now. Sorry for not being attentive enough. :oops:
You're absolutely right about the thread. Thanks for your detailed comments.
Post Reply