Page 1 of 1

Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 1:53 pm
by moulder61
Hi all,
I'm trying to create my own logout dialog for Linux. It shows a small version of my wallpaper and 3 buttons for Logout, Restart and Shutdown.

Image

I programmed it to have no title bar, not show up in the taskbar and have no Cancel option. So, apart from pressing the ESC key I want to be able to close the window by left clicking anywhere outside of it. So far, I can't work out how to do it. Maybe it's not possible?
The closest I got was clicking inside the window then moving the mouse outside the window and it closes, because I can work out how to detect a left click and then the mouse being outside the window, but that's not the effect I'm after.
I can also get it to close if I click in the window itself but not on the buttons, but again, that's not what I'm after exactly.
The question is basically, how do I detect a mouse click outside a window?
I could just add a Cancel button, but I'm awkward and like to do things the hard way. 8)
Any ideas?

Thanks,
Moulder.

Re: Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 2:35 pm
by Axolotl
If you want close your app by that click you can wait for an

Code: Select all

case #PB_Event_DeactivateWindow 
event and leave the mainloop (End the app!).

Re: Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 4:22 pm
by moulder61
Thanks for the pointer, Axolotl.
Whether I can work out how to actually do that remains to be seen! :)
I noticed you made another post after replying to this one regarding "Return-Values of WindowMouseX() and WindowMouseY()".
Is that related to my question? If so, are you suggesting that I couldn't do it the way I wanted because of a possible bug?

Moulder.

Re: Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 4:30 pm
by moulder61
@Axolotl,

I just looked at your other post and you have included the necessary code to quit when the window is deactivated.
It never occurred to me to do it that way so thanks for that. ;)

Moulder.

Re: Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 5:02 pm
by Axolotl
Hi Moulder,

yes, that other post is because I was thinking about a solution for your problem. I know you are on linux, so I checked something out.
My first idea was to use a window with the desktop size, so mouse clicks are always inside.
But than I remembered that I have no idea how to create transparent screens on linux..... (You should know I am just started my linux adventure)
Instead of leaving the mainloop you can hide the window and by using a timer bring the window back.... (but that is not what you are after I guess)

Re: Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 7:31 pm
by moulder61
Hi Axolotl,
I did another version using a full screen and sprites which worked OK.
I wanted to experiment with buttons/gadgets to see if I could do it but it was more trouble.
Your solution worked, mostly. My problem is that I'm using a minimal environment which doesn't have a desktop as such, so clicking outside the window on the desktop doesn't take focus away from the window(deactivate it), so I had to come up with a workaround using xdotool. :) I did say I was awkward! Clicking on another window, however, did change the focus so that worked as expected.
I don't think individual transparent screens are possible unless you use some kind of compositor like Picom maybe? Not sure?
The way I did it(regarding the sprite based logout application) was to take a screenshot of my desktop using either imagemagick or scrot(scrot was slightly slower) shrink it and blow it back up and display that image in the main window in an attempt to do a kind of fake blurring behind the logout window.

Image

It works quite well. Just not as slick as BetterLockScreen though.
When I clean up both versions I'll share them on here so people can laugh or cry. Whatever. :oops:

Moulder.

Re: Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 7:43 pm
by mestnyi

Code: Select all

Global w_this, w_flag
DisableDebugger

Enumeration #PB_EventType_FirstCustomValue
  #PB_eventtype_Left2Click
  #PB_eventtype_Left3Click
EndEnumeration

Procedure SetGadgetState_(gadget, state)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_MacOS
       ; ExplorerListGadget, ListIconGadget и ListViewGadget — все три построены на одном и том же классе Cocoa (NSTableView).
       ; CocoaMessage(0, GadgetID(gadget), "scrollColumnToVisible:", state)
        If state >= 0
          CocoaMessage(0, GadgetID(gadget), "scrollRowToVisible:", state )
        EndIf
        
      CompilerCase #PB_OS_Windows
				Select GadgetType(gadget)
					Case #PB_GadgetType_ListView
						SendMessage_(GadgetID(gadget), #LB_SETTOPINDEX, CountGadgetItems(gadget) - 1, #Null)
					Case #PB_GadgetType_ListIcon
						SendMessage_(GadgetID(gadget), #LVM_ENSUREVISIBLE, CountGadgetItems(gadget) - 1, #Null)
					Case #PB_GadgetType_Editor
						SendMessage_(GadgetID(gadget), #EM_SCROLLCARET, #SB_BOTTOM, 0)
				EndSelect
				
			CompilerCase #PB_OS_Linux
				Protected *Adjustment.GtkAdjustment
				*Adjustment = gtk_scrolled_window_get_vadjustment_(gtk_widget_get_parent_(GadgetID(gadget)))
				*Adjustment\value = *Adjustment\upper
				gtk_adjustment_value_changed_(*Adjustment)
		CompilerEndSelect 
		
    SetGadgetState(gadget, state)
  EndProcedure
  
  Procedure DoEvents( EventType )
  Protected result
  
  Select EventType
    Case #PB_EventType_LeftButtonDown : result = 1 : AddGadgetItem(w_flag, -1, " leftdown")
    Case #PB_EventType_LeftButtonUp   : result = 1 : AddGadgetItem(w_flag, -1, "  leftup")
    Case #PB_EventType_LeftClick      : result = 1 : AddGadgetItem(w_flag, -1, "   click") 
    Case #PB_eventtype_Left2Click     : result = 1 : AddGadgetItem(w_flag, -1, "     2_click") 
    Case #PB_eventtype_Left3Click     : result = 1 : AddGadgetItem(w_flag, -1, "       3_click") 
  EndSelect
  
  If result
    SetGadgetState(w_flag, CountGadgetItems(w_flag) - 1)
  EndIf
EndProcedure

Procedure MouseState( )
  Static press.b, ClickTime.q, ClickCount
  Protected DoubleClickTime, ElapsedMilliseconds.q, state.b
  
  CompilerSelect #PB_Compiler_OS 
    CompilerCase #PB_OS_Linux
      Protected desktop_x, desktop_y, handle, *GdkWindow.GdkWindowObject = gdk_window_at_pointer_( @desktop_x, @desktop_y )
      
      If *GdkWindow
        gdk_window_get_pointer_(*GdkWindow, @desktop_x, @desktop_y, @mask)
      EndIf
      
      If mask & 256; #GDK_BUTTON1_MASK
        state = 1
      EndIf
      If mask & 512 ; #GDK_BUTTON3_MASK
        state = 3
      EndIf
      If mask & 1024 ; #GDK_BUTTON2_MASK
        state = 2
      EndIf
      
    CompilerCase #PB_OS_Windows
      state = GetAsyncKeyState_(#VK_LBUTTON) >> 15 & 1 + 
              GetAsyncKeyState_(#VK_RBUTTON) >> 15 & 2 + 
              GetAsyncKeyState_(#VK_MBUTTON) >> 15 & 3 
    CompilerCase #PB_OS_MacOS
       ;EnableDebugger
       state = CocoaMessage(0, 0, "NSEvent pressedMouseButtons") ; class var pressedMouseButtons: Int { get }
       ;Debug CocoaMessage(0, 0, "buttonNumber") ; var buttonNumber: Int { get }
       ;Debug CocoaMessage(0, 0, "clickCount") ; var clickCount: Int { get }
  CompilerEndSelect
  
  If press <> state
    If state
      ElapsedMilliseconds.q = ElapsedMilliseconds( ) 
      
      CompilerIf #PB_Compiler_OS = #PB_OS_Windows
        DoubleClickTime = 10
      CompilerElse
        DoubleClickTime = DoubleClickTime( )
      CompilerEndIf
      
      If DoubleClickTime > ( ElapsedMilliseconds - ClickTime )
        ClickCount + 1
      Else
        ClickCount = 1
      EndIf
      ClickTime = ElapsedMilliseconds
      
      If ClickCount = 1
        If state = 1
          Debug "LeftDown - "
          DoEvents( #PB_EventType_LeftButtonDown )
        ElseIf state = 2
          Debug "RightDown - "
        EndIf
      EndIf
      
    Else
      If ClickCount = 1
        If press = 1
          Debug "LeftUp - "
          DoEvents( #PB_EventType_LeftButtonUp )
        ElseIf press = 2
          Debug "RightUp - "
        EndIf
      EndIf
      
      ;\\ do 3click events
      If ClickCount = 3
        If press = 1
          Debug "   Left3Click - "
          DoEvents( #PB_eventtype_Left3Click )
        ElseIf press = 2
          Debug "   Right3Click - "
        EndIf
        
        ;\\ do 2click events
      ElseIf ClickCount = 2
        If press = 1
          Debug "  Left2Click - "
          DoEvents( #PB_eventtype_Left2Click )
        ElseIf press = 2
          Debug "  Right2Click - "
        EndIf
        
        
        ;\\ do 1click events
      Else
        ;         If Not PressedWidget( )\state\drag
        ;           If PressedWidget( ) = EnteredWidget( )
        If press = 1
          Debug " LeftClick - "
          DoEvents( #PB_EventType_LeftClick )
        ElseIf press = 2
          Debug " RightClick - "
        EndIf
        
        ;           EndIf
        ;         EndIf
      EndIf
      
    EndIf
    press = state
  EndIf
  
EndProcedure


OpenWindow(0, 0, 0, 170, 300, "click-events", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
w_flag = ListViewGadget(-1,10, 10, 150, 200) 
w_this = ButtonGadget(-1,10, 220, 150, 70, "Click me", #PB_Button_MultiLine )


Repeat
  Event = WaitWindowEvent(1)
  MouseState( )
  
Until Event = #PB_Event_CloseWindow

Re: Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 8:09 pm
by moulder61
Hi mestnyi,

I'm not sure what your code is for exactly but it doesn't solve the issue I had because it doesn't detect mouse clicks outside the window. At least not in Linux.

Thanks anyway.
Moulder.

Re: Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 8:12 pm
by RASHAD
Use Thread

Re: Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 10:36 pm
by moulder61
Hi RASHAD,

As one of the acknowledged experts on here, "Use Thread" might well be the answer, but I have no idea what that means?

Moulder.

Re: Detecting left mouse click outside window

Posted: Wed Jul 17, 2024 11:55 pm
by RASHAD
Hi
I am not expert with Linux :)
But I hope the next snippet will help somehow
Good luck
Remember to enable thread safe in compiler options

Code: Select all

Global Quit,active

Procedure watchdog(par)
  Repeat
    Delay(25)
    If active = 1
      active = 0
      Debug "Mouse clicked outside"
    EndIf  
  Until Quit = 1
EndProcedure

If OpenWindow(0, 0, 0, 195, 260, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget|#PB_Window_ScreenCentered)
ButtonGadget(0,10,10,80,30,"EXIT")  
  
Thread = CreateThread(@watchDOG(),30)
  Repeat
    Select WaitWindowEvent(1)
      Case #PB_Event_CloseWindow
        Quit = 1
        
      Case #PB_Event_DeactivateWindow 
        active = 1
        
      Case #PB_Event_Gadget
        Select EventGadget()
          Case 0
            Quit = 1
        EndSelect
    EndSelect
  Until Quit = 1  
EndIf
End   

Re: Detecting left mouse click outside window

Posted: Thu Jul 18, 2024 9:55 am
by moulder61
@RASHAD

I managed to get my application working using Axolotl's example by adding these lines:

Select event
Case #PB_Event_DeactivateWindow
End

One of the problems I have, as I kind of explained before somewhere, is that I am not using your average Ubuntu or Debian Linux.
I got for more obscure versions and/or chop them about because I like to mess about with stuff. :)
So, in my minimal Void based Linux with just XFWM as a window manager but no actual desktop as such because I don't need icons all over my desktop making it messy or the kind of usual desktop menu options XFCE gives you, clicking on the desktop doesn't deactivate the active window! Clicking on another window does deactivate it.
I am using something called xclickroot to detect mouse clicks on the desktop and the only thing it checks for is a right click which then launches jgmenu which is my preferred dynamic applications menu. Launching jgmenu has the desired effect of stealing focus but is not the ideal solution, so I had to add something as a left click option to get it to unfocus/deactivate the window to work properly. I managed to get it working with Axolotls example and xdotool to fake clicking elsewhere.
Your code works on more standard versions of Linux window managers/environments, but even with my workaround it doesn't work in this Void based OS that I use mostly. I'm sure I could get around it if I needed to, but as I said, Axolotl's idea fixed it simply enough.
Interestingly, or not, in your code example, dragging the window via the title bar causes a "mouse clicked outside" message in the debugger. I don't know if it's supposed to do that? Also, I'm no wiser as to what threads are. :?

Thanks again for your help, I will probably have more obscure questions/requirements in the future. ;)

Moulder.

Re: Detecting left mouse click outside window

Posted: Thu Jul 18, 2024 10:07 am
by RASHAD
It doesn't matter which way you went through
It does matter that your problems are solved
Happy sailing with PB

Re: Detecting left mouse click outside window

Posted: Thu Jul 18, 2024 10:13 am
by moulder61
RASHAD wrote: Thu Jul 18, 2024 10:07 am It doesn't matter which way you went through
It does matter that your problems are solved
Happy sailing with PB
Thanks again for your input.
My problems will never be solved. Trust me. ;)
There's a saying "If it ain't broke, don't fix it".
I say, "If it ain't broke, fix it until it is!". :lol:

Moulder.