cursor from datasection

Just starting out? Need help? Post your questions and find answers here.
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: cursor from datasection

Post by mestnyi »

Shardik wrote: Fri Apr 08, 2022 9:38 pm On MacOS the custom cursor is displayed on the whole desktop and doesn't change when leaving the inner window.
It's not quite right. Try with this.

Code: Select all

If EventGadget() = 0 And EventType() = #PB_EventType_LeftClick
        ChangeCursorToPNGImage(0, 0)
        DisableGadget(0, #True)
        SetWindowTitle( 0, "change cursor")
      EndIf
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: cursor from datasection

Post by Shardik »

mestnyi wrote: Sun Apr 10, 2022 8:28 pm
Shardik wrote: Fri Apr 08, 2022 9:38 pm On MacOS the custom cursor is displayed on the whole desktop and doesn't change when leaving the inner window.
It's not quite right. Try with this.

Code: Select all

If EventGadget() = 0 And EventType() = #PB_EventType_LeftClick
        ChangeCursorToPNGImage(0, 0)
        DisableGadget(0, #True)
        SetWindowTitle( 0, "change cursor")
      EndIf
mestnyi, thank you for your reply. I have tested your proposed addition of SetWindowTitle( 0, "change cursor"), but after its insertion the changing of the cursor to the PNG image doesn't work anymore.

I have just tested your modification with MacOS 10.13.6 and PB 6.00 Beta 6 with Asm backend. If your modification works on your MacOS version, please tell me your MacOS and PB version.
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: cursor from datasection

Post by mestnyi »

The thing is, I wanted to say that it stops working and it doesn't have to be SetWindowTitle( ).
It turns out that we must either set the cursor all the time or apply the cursor setting at the end of all events.
I've looked for the event sent by the system after changing the cursor, but haven't found it yet.
This is what I think is what I need, but I can’t apply it in cocoa.
https://spec-zone.ru/RU/OSX/documentati ... 0060i-CH11
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: cursor from datasection

Post by Shardik »

mestnyi wrote: Thu Apr 14, 2022 8:22 am The thing is, I wanted to say that it stops working and it doesn't have to be SetWindowTitle( ).
It turns out that we must either set the cursor all the time or apply the cursor setting at the end of all events.
You are right. I am working on this problem but it may take some time.
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: cursor from datasection

Post by mestnyi »

Shardik wrote: Thu Apr 14, 2022 9:34 pm
mestnyi wrote: Thu Apr 14, 2022 8:22 am The thing is, I wanted to say that it stops working and it doesn't have to be SetWindowTitle( ).
It turns out that we must either set the cursor all the time or apply the cursor setting at the end of all events.
You are right. I am working on this problem but it may take some time.
I will be very happy if you find a solution on your own, I can't handle it.

Here is what I did to make the cursor behavior the same for all three OS.
There is just something here that I don't understand.
Why is the "enter" event fired when the mouse leaves the window and the "leave" event when the mouse is inside?

Code: Select all

EnableExplicit

UsePNGImageDecoder()

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  ImportC ""
    gtk_widget_get_window(*Widget.GtkWidget)
  EndImport
CompilerEndIf

Procedure ChangeCursorToPNGImage(WindowID.I, ImageID.I)
  Protected CustomCursor.I
  
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Linux
      CustomCursor = gdk_cursor_new_from_pixbuf_(gdk_display_get_default_(),
                                                 ImageID(ImageID), 0, 0)
      gdk_window_set_cursor_(gtk_widget_get_window(WindowID(WindowID)),
                             CustomCursor)
    CompilerCase #PB_OS_MacOS
      Protected Hotspot.NSPoint
      
      Hotspot\x = 1
      Hotspot\y = 1
      CustomCursor = CocoaMessage(0, 0, "NSCursor alloc")
      CocoaMessage(0, CustomCursor,
                   "initWithImage:", ImageID(ImageID),
                   "hotSpot:@", @Hotspot)
      CocoaMessage(0, CustomCursor, "set")
      SetWindowData(0, CustomCursor)
      
    CompilerCase #PB_OS_Windows
      Protected Cursor.ICONINFO
      
      Cursor\fIcon = #False
      Cursor\xHotspot = 1
      Cursor\yHotspot = 1
      Cursor\hbmColor = ImageID(ImageID)
      Cursor\hbmMask = ImageID(ImageID)
      CustomCursor = CreateIconIndirect_(Cursor)
      SetClassLongPtr_(WindowID(WindowID), #GCL_HCURSOR, CustomCursor)
  CompilerEndSelect
  
  ProcedureReturn CustomCursor
EndProcedure

If LoadImage(0, #PB_Compiler_Home + "examples/sources/Data/world.png") = 0
  MessageRequester("Error",
                   "Loading of image World.png failed!",
                   #PB_MessageRequester_Error)
  End
EndIf


CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
;   #NSLeftMouseDown      = 1
;   #NSLeftMouseUp        = 2
;   #NSRightMouseDown     = 3
;   #NSRightMouseUp       = 4
;   #NSMouseMoved         = 5
;   #NSLeftMouseDragged   = 6
;   #NSRightMouseDragged  = 7
;   #NSMouseEntered       = 8
;   #NSMouseExited        = 9
;   #NSKeyDown            = 10
;   #NSKeyUp              = 11
;   #NSFlagsChanged       = 12
;   #NSAppKitDefined      = 13
;   #NSSystemDefined      = 14
;   #NSApplicationDefined = 15
;   #NSPeriodic           = 16
;   #NSCursorUpdate       = 17
;   #NSScrollWheel        = 22
;   #NSTabletPoint        = 23
;   #NSTabletProximity    = 24
;   #NSOtherMouseDown     = 25
;   #NSOtherMouseUp       = 26
;   #NSOtherMouseDragged  = 27
;   #NSEventTypeGesture   = 29
;   #NSEventTypeMagnify   = 30
;   #NSEventTypeSwipe     = 31
;   #NSEventTypeRotate    = 18
;   #NSEventTypeBeginGesture = 19
;   #NSEventTypeEndGesture   = 20
;   #NSEventTypeSmartMagnify = 32
;   #NSEventTypeQuickLook   = 33
  
  ;
  #MaskLeftMouseDown      = 1<<1
  #MaskLeftMouseUp        = 1<<2
  #MaskRightMouseDown     = 1<<3
  #MaskRightMouseUp       = 1<<4
  #MaskMouseMoved         = 1<<5
  #MaskLeftMouseDragged   = 1<<6
  #MaskRightMouseDragged  = 1<<7
  #MaskMouseEntered       = 1<<9
  #MaskMouseExited        = 1<<8
  #MaskKeyDown            = 1<<10
  #MaskKeyUp              = 1<<11
  #MaskFlagsChanged       = 1<<12
  #MaskAppKitDefined      = 1<<13
  #MaskSystemDefined      = 1<<14
  #MaskApplicationDefined = 1<<15
  #MaskPeriodic           = 1<<16
  #MaskCursorUpdate       = 1<<17
  #MaskScrollWheel        = 1<<22
  #MaskTabletPoint        = 1<<23
  #MaskTabletProximity    = 1<<24
  
  #MaskOtherMouseDown     = 1<<25
  #MaskOtherMouseUp       = 1<<26
  #MaskOtherMouseDragged  = 1<<27
  
  #MaskEventTypeGesture   = 1<<29
  #MaskEventTypeMagnify   = 1<<30
  #MaskEventTypeSwipe     = 1<<31
  #MaskEventTypeRotate    = 1<<18
  #MaskEventTypeBeginGesture = 1<<19
  #MaskEventTypeEndGesture   = 1<<20
  #MaskEventTypeSmartMagnify = 1<<32
  #MaskEventTypeQuickLook    = 1<<33
  
  Global eventTap, mask = #MaskMouseEntered | #MaskMouseExited | #MaskMouseMoved | #MaskCursorUpdate
  
  ProcedureC eventTapFunction(proxy, type, event, refcon)
    Protected NSEvent = CocoaMessage(0, 0, "NSEvent eventWithCGEvent:", event)
    
    If NSEvent
      Protected NSWindow = CocoaMessage(0, NSEvent, "window")
      
      If type = #NSMouseEntered
        If CocoaMessage(0, 0, "NSCursor currentCursor") <> CocoaMessage(0, 0, "NSCursor arrowCursor")
          Debug "enter - "+GetWindowData(0) +" "+ CocoaMessage(0, 0, "NSCursor currentCursor")
           CocoaMessage(0, CocoaMessage(0, 0, "NSCursor arrowCursor"), "set")
         EndIf
      ElseIf type = #NSMouseExited
        If GetWindowData(0) And GetWindowData(0) <> CocoaMessage(0, 0, "NSCursor currentCursor")
          Debug "leave - "+GetWindowData(0) +" "+ CocoaMessage(0, 0, "NSCursor currentCursor")
          CocoaMessage(0, GetWindowData(0), "set")
        EndIf
      ElseIf type = #NSMouseMoved
        
      ElseIf type = #NSCursorUpdate
        
      EndIf
    EndIf           
  EndProcedure
  
  #cghidEventTap = 0              ; Указывает, что отвод события размещается в точке, где системные события HID поступают на оконный сервер.
  #cgSessionEventTap = 1          ; Указывает, что отвод события размещается в точке, где события системы HID и удаленного управления входят в сеанс входа в систему.
  #cgAnnotatedSessionEventTap = 2 ; Указывает, что отвод события размещается в точке, где события сеанса были аннотированы для передачи в приложение.
  
  #headInsertEventTap = 0         ; Указывает, что новое касание события должно быть вставлено перед любым ранее существовавшим касанием события в том же месте.
  #tailAppendEventTap = 1         ; Указывает, что новое касание события должно быть вставлено после любого ранее существовавшего касания события в том же месте
  
  eventTap = CGEventTapCreate_(#cgAnnotatedSessionEventTap, #headInsertEventTap, 1, mask, @eventTapFunction(), 0) 
  If eventTap
    CocoaMessage(0, CocoaMessage(0, 0, "NSRunLoop currentRunLoop"), "addPort:", eventTap, "forMode:$", @"kCFRunLoopCommonModes")
  EndIf
CompilerEndIf

OpenWindow(0, 200, 100, 290, 120, "Display custom cursor")
ButtonGadget(0, WindowWidth(0) / 2 - 120, 40, 240, 25, "Change cursor to PNG image")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 0 And EventType() = #PB_EventType_LeftClick
        ChangeCursorToPNGImage(0, 0)
        ; SetWindowTitle(0, Str(Random(255)))
        DisableGadget(0, #True)
      EndIf
  EndSelect
ForEver
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: cursor from datasection

Post by Shardik »

I have found a different approach to change the cursor on MacOS to the default cursor when leaving the window. Like you I use CGEventTapCreate() to establish an event handler procedure for MacOS. This procedure is always activated when the mouse is moved and only checks with WindowMouseX() and WindowMouseY() if x or y is -1 and then switches to the default cursor (cursor has left the window) or switches back to the custom cursor when both x and y are not -1 (cursor is inside of window). Now SetWindowTitle() doesn't interfere anymore with the custom cursor on MacOS.

I have tested this example successfully on these MacOS versions with PB 5.73 x64:
  • 10.15.7 'Catalina'
  • 11.6.4 'Big Sur'
  • 12.2.1 + 12.3.1 'Monterey'

Code: Select all

EnableExplicit

UsePNGImageDecoder()

Define CustomCursor.I

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    ImportC ""
      gtk_widget_get_window(*Widget.GtkWidget)
    EndImport
  CompilerCase #PB_OS_MacOS
    ImportC ""
      CGEventTapCreate(Tap.I, Place.I, Options.I, EventsOfInterest.Q,
        Callback.I, *UserData)
    EndImport

    Define CursorInWindow.I
    Define EventTap.I
    
    ProcedureC EventTapHandler(Proxy.I, EventType.I, Event.I, *UserData)
      Shared CustomCursor.I
      Shared CursorInWindow.I

      If CustomCursor
        If WindowMouseX(0) = -1 Or WindowMouseY(0) = -1
          If CursorInWindow = #True
            CocoaMessage(0, CocoaMessage(0, 0, "NSCursor arrowCursor"), "set")
            CursorInWindow = #False
          EndIf
        Else
          If CursorInWindow = #False
            CocoaMessage(0, CustomCursor, "set")
            CursorInWindow = #True
          EndIf
        EndIf
      EndIf
    EndProcedure

    EventTap = CGEventTapCreate(0, 0, 1, #NSMouseMovedMask, @EventTapHandler(),
      0)
    
    If EventTap
      CocoaMessage(0, CocoaMessage(0, 0, "NSRunLoop currentRunLoop"),
        "addPort:", EventTap, "forMode:$", @"kCFRunLoopDefaultMode")
    EndIf
CompilerEndSelect

Procedure ChangeCursorToPNGImage(WindowID.I, ImageID.I)
  Shared CustomCursor.I

  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Linux
      CustomCursor = gdk_cursor_new_from_pixbuf_(gdk_display_get_default_(),
        ImageID(ImageID), 0, 0)
      gdk_window_set_cursor_(gtk_widget_get_window(WindowID(WindowID)),
        CustomCursor)
    CompilerCase #PB_OS_MacOS
      Protected Hotspot.NSPoint
      
      Hotspot\x = 1
      Hotspot\y = 1
      CustomCursor = CocoaMessage(0, 0, "NSCursor alloc")
      CocoaMessage(0, CustomCursor,
        "initWithImage:", ImageID(ImageID),
        "hotSpot:@", @Hotspot)
      CocoaMessage(0, CustomCursor, "set")
      CocoaMessage(0, WindowID(WindowID), "disableCursorRects")
    CompilerCase #PB_OS_Windows
      Protected Cursor.ICONINFO

      Cursor\fIcon = #False
      Cursor\xHotspot = 1
      Cursor\yHotspot = 1
      Cursor\hbmColor = ImageID(ImageID)
      Cursor\hbmMask = ImageID(ImageID)
      CustomCursor = CreateIconIndirect_(Cursor)
      SetClassLongPtr_(WindowID(WindowID), #GCL_HCURSOR, CustomCursor)
  CompilerEndSelect
EndProcedure

If LoadImage(0, #PB_Compiler_Home + "examples/sources/Data/world.png") = 0
  MessageRequester("Error",
    "Loading of image World.png failed!",
    #PB_MessageRequester_Error)
  End
EndIf

OpenWindow(0, 200, 100, 290, 120, "Display custom cursor")
ButtonGadget(0, WindowWidth(0) / 2 - 120, 40, 240, 25,
  "Change cursor to PNG image")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 0 And EventType() = #PB_EventType_LeftClick
        ChangeCursorToPNGImage(0, 0)
        DisableGadget(0, #True)
        SetWindowTitle(0, "Cursor changed into PNG image")
      EndIf
  EndSelect
ForEver
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: cursor from datasection

Post by mestnyi »

This is what I needed. Thank you very much.

Code: Select all

CocoaMessage(0, WindowID(WindowID), "disableCursorRects")
Post Reply