Systray menu?

Mac OSX specific forum
User avatar
deseven
Enthusiast
Enthusiast
Posts: 367
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Systray menu?

Post by deseven »

Hello there.

How can i create a native OS X tray menu with PB?
For example:
Image
User avatar
deseven
Enthusiast
Enthusiast
Posts: 367
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Re: Systray menu?

Post by deseven »

Anyone?

Maybe someone can help relying on this example...
https://developer.apple.com/library/mac ... Intro.html
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Systray menu?

Post by Shardik »

deseven wrote:How can i create a native OS X tray menu with PB?
Sorry, this is a very simple first try and still doesn't look native. It displays a popup menu on clicking onto the systray icon...

Code: Select all

UsePNGImageDecoder()

OpenWindow(0, 270, 100, 300, 100, "SysTray Menu Example")

CreatePopupMenu(0)
MenuItem(0, "Show computer name")
MenuItem(1, "Show user name")

If LoadImage(0, #PB_Compiler_Home + "Examples/Sources/Data/World.png")
  AddSysTrayIcon(1, WindowID(0), ImageID(0))
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Break
    Case #PB_Event_SysTray
      If EventType() = #PB_EventType_LeftClick
        DisplayPopupMenu(0, WindowID(0))
      EndIf
    Case #PB_Event_Menu
      Select EventMenu()
        Case 0
          MessageRequester("Info", "Computer name: " + ComputerName())
        Case 1
          MessageRequester("Info", "User name: " + UserName())
      EndSelect
    EndSelect
  ForEver
EndIf
WilliamL
Addict
Addict
Posts: 1252
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: Systray menu?

Post by WilliamL »

Hey Shardik,

I tried your example and I don't get any errors but the icon doesn't appear.

I modified the 'Help' example and I don't see the icon there either. Still no errors.

Am I doing something wrong or is this a bug?

Code: Select all

UsePNGImageDecoder()

If OpenWindow(0, 100, 150, 300, 100, "PureBasic - SysTray Example", #PB_Window_SystemMenu)

  LoadImage(0,#PB_Compiler_Home + "examples/sources/Data/world.png")
  
  AddSysTrayIcon(1, WindowID(0), ImageID(0))
  AddSysTrayIcon(2, WindowID(0), ImageID(0))
  SysTrayIconToolTip(1, "Icon 1")
  SysTrayIconToolTip(2, "Icon 2")
  
  Repeat
    Event = WaitWindowEvent()
    
    If Event = #PB_Event_SysTray
      If EventType() = #PB_EventType_LeftDoubleClick
        MessageRequester("SysTray", "Left DoubleClick on SysTrayIcon "+Str(EventGadget()),0)
        
        ChangeSysTrayIcon (EventGadget(), LoadImage(0, IconName$))
        SysTrayIconToolTip(EventGadget(), "Changed !")
      EndIf
      
    EndIf
  Until Event = #PB_Event_CloseWindow
  
EndIf
MacBook Pro-M1 (2021), Sequoia 15.4, PB 6.20
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Systray menu?

Post by Shardik »

WilliamL wrote:I tried your example and I don't get any errors but the icon doesn't appear.
William,

I am sorry but I don't understand why you won't get the icon displayed running my code example. I tested my example with OS X 10.6.8 (Snow Leopard) and OS X 10.8.5 (Mountain Lion) compiled with PB 5.20 LTS x86 and PB 5.20 LTS x64 and in all cases the example works like a charme. You should see a colored world icon in the right system menu (in the left most position):

Image

When running my example will the window with the caption "SysTray Menu Example" be displayed? If not you should take a look with Finder whether the icon file World.png in your PB folder (subfolder Examples/Sources/Data) isn't there anymore...
WilliamL wrote:I modified the 'Help' example and I don't see the icon there either. Still no errors.
Your posted example displays 2 world icons in my system menu although it doesn't work as it should because on MacOS the EventType #PB_EventType_LeftDoubleClick isn't recognized. Only a simple #PB_EventType_LeftClick as in my example code is recognized from PB...
WilliamL
Addict
Addict
Posts: 1252
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: Systray menu?

Post by WilliamL »

Shardik,

Ok, I've made this mistake before! I think if I go back and search my posts I would find I asked this same question and made the same error. I was looking for the icon in the window and not the Mac menu! :oops: I think the reference to the WindowId throws me off. You can tell I don't use systrays at all. I just play with your examples and this one works fine with the pop-up menu.

Thanks for your contributions!
MacBook Pro-M1 (2021), Sequoia 15.4, PB 6.20
User avatar
deseven
Enthusiast
Enthusiast
Posts: 367
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Re: Systray menu?

Post by deseven »

Shardik wrote:
deseven wrote:How can i create a native OS X tray menu with PB?
Sorry, this is a very simple first try and still doesn't look native. It displays a popup menu on clicking onto the systray icon...
Sorry, but i know about CreatePopupMenu() and it's not what i'm looking for.
Also, it seems that right click doesn't work.

Code: Select all

If EventType() = #PB_EventType_RightClick ;always false
  DisplayPopupMenu(0, WindowID(0))
EndIf
However, thank you for trying to help me.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Systray menu?

Post by wilbert »

You could try with CocoaMessage() but it would be quite some work.
The NSStatusBar class allows you to create a NSStatusItem instance which has a method named setMenu that allows you to set a menu for the status item. :shock:
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Systray menu?

Post by Shardik »

deseven,

please try this true native solution. It uses all tricks I have learned from the numerous and fascinating Cocoa API examples of Cocoa framework master Wilbert. Therefore a big thank you has to go to Wilbert for his work on CocoaMessage(), the great amount of clever Cocoa API examples from him and the endless possibilities of Cocoa API programming on MacOS that his work finally made possible!

Code: Select all

EnableExplicit

#NSSquareStatusBarItemLength = -2

ImportC ""
  sel_registerName(MethodName.P-ASCII)
  class_addMethod(Class.I, Selector.I, Implementation.I, Types.P-ASCII)
EndImport

Enumeration #PB_Event_FirstCustomValue
  #EventDisplayComputerName
  #EventDisplayUserName
EndEnumeration

Structure MenuItemIDEntry
  ID.I
  Event.I
EndStructure

NewList MenuItemID.MenuItemIDEntry()

ProcedureC MenuItemHighlightedCallback(Object.I, Selector.I, MenuItem.I)
  Shared MenuItemID.MenuItemIDEntry()

  ForEach MenuItemID()
    If MenuItem = MenuItemID()\ID
      PostEvent(MenuItemID()\Event)
      Break
    EndIf
  Next
EndProcedure

Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
  "NSApplication sharedApplication"), "delegate")
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")
Define ItemLength.CGFloat = 32
Define Menu.I
Define NotificationCenter.I = CocoaMessage(0, 0,
  "NSNotificationCenter defaultCenter")
Define Selector.I = sel_registerName("menu:willHighlightItem:")
Define StatusBar.I
Define StatusItem.I

UsePNGImageDecoder()

OpenWindow(0, 270, 100, 300, 100, "SysTray Menu Example")

If LoadImage(0, #PB_Compiler_Home + "Examples/Sources/Data/World.png")
  StatusBar = CocoaMessage(0, 0, "NSStatusBar systemStatusBar")

  If StatusBar
    ; ----- Create icon in system status bar (SysTray)
    StatusItem = CocoaMessage(0, CocoaMessage(0, StatusBar,
      "statusItemWithLength:", #NSSquareStatusBarItemLength), "retain")

    If StatusItem
      CocoaMessage(0, StatusItem, "setLength:@", @ItemLength)
      CocoaMessage(0, StatusItem, "setImage:", ImageID(0))

      ; ----- Create menu with entries for click on SysTray icon
      Menu = CocoaMessage(0, CocoaMessage(0, 0, "NSMenu alloc"), "init")
      
      If Menu
        class_addMethod(DelegateClass, Selector,
          @MenuItemHighlightedCallback(), "v@:@")
        CocoaMessage(0, NotificationCenter,
          "addObserver:", AppDelegate,
          "selector:", Selector,
          "name:$", @"NSMenuDidBeginTrackingNotification",
          "object:", Menu)

        ; ----- Add first menu entry
        AddElement(MenuItemID())
        MenuItemID()\Event = #EventDisplayComputerName
        MenuItemID()\ID = CocoaMessage(0, Menu,
          "addItemWithTitle:$", @"Show computer name",
          "action:", 0,
          "keyEquivalent:$", @"")
        CocoaMessage(0, MenuItemID()\ID, "setAction:", Selector)
        
        ; ----- Add second menu entry
        AddElement(MenuItemID())
        MenuItemID()\Event = #EventDisplayUserName
        MenuItemID()\ID = CocoaMessage(0, Menu,
          "addItemWithTitle:$", @"Show user name",
          "action:", 0,
          "keyEquivalent:$", @"")
        CocoaMessage(0, MenuItemID()\ID, "setAction:", Selector)

        ; ----- Add menu to SysTray icon
        CocoaMessage(0, StatusItem, "setMenu:", Menu)
        CocoaMessage(0, Menu, "release")

        Repeat
          Select WaitWindowEvent()
            Case #PB_Event_CloseWindow
              Break
            Case #EventDisplayComputerName
              MessageRequester("Info", "Computer name: " + ComputerName())
            Case #EventDisplayUserName
              MessageRequester("Info", "User name: " + UserName())
          EndSelect
        ForEver
      EndIf
    EndIf
  EndIf
EndIf

CocoaMessage(0, NotificationCenter,
  "removeObserver:", AppDelegate,
  "name:$", @"NSMenuDidBeginTrackingNotification",
  "object:", 0)
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Systray menu?

Post by Shardik »

Wilbert has sent me a PM with a trick to obtain the NSMenu of a PB created popup menu which makes the task much easier and more straight forward. He also sent me this resulting much shorter code:

Code: Select all

EnableExplicit

#NSSquareStatusBarItemLength = -2

Define ItemLength.CGFloat = 32
Define StatusBar.I
Define StatusItem.I

UsePNGImageDecoder()

OpenWindow(0, 270, 100, 300, 100, "SysTray Menu Example")

If LoadImage(0, #PB_Compiler_Home + "Examples/Sources/Data/World.png")
  StatusBar = CocoaMessage(0, 0, "NSStatusBar systemStatusBar")
 
  If StatusBar
    ; ----- Create icon in system status bar (SysTray)
    StatusItem = CocoaMessage(0, CocoaMessage(0, StatusBar,
      "statusItemWithLength:", #NSSquareStatusBarItemLength), "retain")

    If StatusItem
      CocoaMessage(0, StatusItem, "setLength:@", @ItemLength)
      CocoaMessage(0, StatusItem, "setImage:", ImageID(0))
     
      ; ----- Create menu with entries for click on SysTray icon
      CreatePopupMenu(0)
      MenuItem(0, "Show computer name")
      MenuItem(1, "Show user name")
      CocoaMessage(0, StatusItem, "setMenu:",
        CocoaMessage(0, MenuID(0), "firstObject"))
     
      Repeat
        Select WaitWindowEvent()
          Case #PB_Event_CloseWindow
            Break
          Case #PB_Event_Menu
            Select EventMenu()
              Case 0
                MessageRequester("Info", "Computer name: " + ComputerName())
              Case 1
                MessageRequester("Info", "User name: " + UserName())
            EndSelect
        EndSelect
      ForEver
    EndIf
  EndIf
EndIf
User avatar
deseven
Enthusiast
Enthusiast
Posts: 367
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Re: Systray menu?

Post by deseven »

Wow guys, this should definitely go to the "Tips & Tricks" topic.
Thank you very much! :)

P.S. A very small addition:
Image

Code: Select all

CocoaMessage(0, StatusItem, "setHighlightMode:", #YES)
User avatar
mk-soft
Always Here
Always Here
Posts: 6202
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Systray menu?

Post by mk-soft »

Update for PB-v6.10

Code: Select all

EnableExplicit

#NSSquareStatusBarItemLength = -2

Define ItemLength.CGFloat = 32
Define StatusBar.I
Define StatusItem.I

UsePNGImageDecoder()

OpenWindow(0, 270, 100, 300, 100, "SysTray Menu Example")

If LoadImage(0, #PB_Compiler_Home + "Examples/Sources/Data/World.png")
  StatusBar = CocoaMessage(0, 0, "NSStatusBar systemStatusBar")
 
  If StatusBar
    ; ----- Create icon in system status bar (SysTray)
    StatusItem = CocoaMessage(0, CocoaMessage(0, StatusBar,
      "statusItemWithLength:", #NSSquareStatusBarItemLength), "retain")

    If StatusItem
      CocoaMessage(0, StatusItem, "setLength:@", @ItemLength)
      CocoaMessage(0, StatusItem, "setImage:", ImageID(0))
     
      ; ----- Create menu with entries for click on SysTray icon
      CreatePopupMenu(0)
      MenuItem(0, "Show computer name")
      MenuItem(1, "Show user name")
      
      CompilerIf #PB_Compiler_Version < 610
        ; Old __NSArrayM of NSMenu
        ;CocoaMessage(0, StatusItem, "setMenu:", CocoaMessage(0, MenuID(0), "firstObject"))
      CompilerElse  
        ; Now direct
        CocoaMessage(0, StatusItem, "setMenu:", MenuID(0))
      CompilerEndIf
      
      Repeat
        Select WaitWindowEvent()
          Case #PB_Event_CloseWindow
            Break
          Case #PB_Event_Menu
            Select EventMenu()
              Case 0
                MessageRequester("Info", "Computer name: " + ComputerName())
              Case 1
                MessageRequester("Info", "User name: " + UserName())
            EndSelect
        EndSelect
      ForEver
    EndIf
  EndIf
EndIf
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
mrbungle
Enthusiast
Enthusiast
Posts: 143
Joined: Wed Dec 30, 2020 3:18 am

Re: Systray menu?

Post by mrbungle »

It works, thank you
User avatar
mk-soft
Always Here
Always Here
Posts: 6202
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Systray menu?

Post by mk-soft »

Since PB v6.10 not longer needed

Code: Select all

; Associate the menu to the systray
  SysTrayIconMenu(0, MenuID(0))
See new PB Help
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
Post Reply