mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-02-05 18:00:43 +08:00
Add system tray support (#10873)
This commit is contained in:
@@ -78,6 +78,7 @@ LOCAL_SRC_FILES := \
|
||||
$(wildcard $(LOCAL_PATH)/src/time/unix/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/timer/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/timer/unix/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/tray/dummy/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/video/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/video/android/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/video/yuv2rgb/*.c))
|
||||
|
||||
@@ -1567,6 +1567,9 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
|
||||
CheckVivante()
|
||||
CheckVulkan()
|
||||
CheckQNXScreen()
|
||||
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/tray/unix/*.c")
|
||||
set(HAVE_SDL_TRAY TRUE)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
@@ -2075,6 +2078,9 @@ elseif(WINDOWS)
|
||||
set(HAVE_RENDER_VULKAN TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/tray/windows/*.c")
|
||||
set(HAVE_SDL_TRAY TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_HIDAPI)
|
||||
@@ -2351,6 +2357,11 @@ elseif(APPLE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MACOS)
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/tray/cocoa/*.m")
|
||||
set(HAVE_SDL_TRAY TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Minimum version for $<LINK_LIBRARY:feature,library-list>
|
||||
@@ -2973,6 +2984,8 @@ if(SDL_VIDEO)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
sdl_glob_sources(${SDL3_SOURCE_DIR}/src/tray/*.c)
|
||||
|
||||
if(SDL_GPU)
|
||||
if(HAVE_D3D11_H)
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/gpu/d3d11/*.c")
|
||||
@@ -3055,6 +3068,10 @@ if(NOT HAVE_SDL_PROCESS)
|
||||
set(SDL_PROCESS_DUMMY 1)
|
||||
sdl_glob_sources(${SDL3_SOURCE_DIR}/src/process/dummy/*.c)
|
||||
endif()
|
||||
if(NOT HAVE_SDL_TRAY)
|
||||
set(SDL_TRAY_DUMMY 1)
|
||||
sdl_glob_sources(${SDL3_SOURCE_DIR}/src/tray/dummy/*.c)
|
||||
endif()
|
||||
if(NOT HAVE_CAMERA)
|
||||
set(SDL_CAMERA_DRIVER_DUMMY 1)
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/camera/dummy/*.c")
|
||||
|
||||
@@ -592,6 +592,7 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_vulkan_internal.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_yuv_c.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_msctf.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_surface_utils.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_windowsclipboard.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_windowsevents.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_windowsframebuffer.h" />
|
||||
@@ -827,6 +828,16 @@
|
||||
<ClCompile Include="..\..\src\timer\windows\SDL_systimer.c" />
|
||||
<ClCompile Include="..\..\src\time\SDL_time.c" />
|
||||
<ClCompile Include="..\..\src\time\windows\SDL_systime.c" />
|
||||
<ClCompile Include="..\..\src\tray\dummy\SDL_tray.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\tray\windows\SDL_tray.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\video\dummy\SDL_nullevents.c" />
|
||||
<ClCompile Include="..\..\src\video\dummy\SDL_nullframebuffer.c" />
|
||||
<ClCompile Include="..\..\src\video\dummy\SDL_nullvideo.c" />
|
||||
@@ -855,6 +866,7 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_video_unsupported.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_vulkan_utils.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_yuv.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_surface_utils.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_windowsclipboard.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_windowsevents.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_windowsframebuffer.c" />
|
||||
@@ -889,4 +901,4 @@
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -181,6 +181,7 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_video_unsupported.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_vulkan_utils.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_yuv.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_surface_utils.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_windowsclipboard.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_windowsevents.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_windowsframebuffer.c" />
|
||||
@@ -217,6 +218,8 @@
|
||||
<ClCompile Include="..\..\src\storage\SDL_storage.c" />
|
||||
<ClCompile Include="..\..\src\time\SDL_time.c" />
|
||||
<ClCompile Include="..\..\src\time\windows\SDL_systime.c" />
|
||||
<ClCompile Include="..\..\src\tray\dummy\SDL_tray.c" />
|
||||
<ClCompile Include="..\..\src\tray\windows\SDL_tray.c" />
|
||||
<ClCompile Include="..\..\src\video\yuv2rgb\yuv_rgb_lsx.c" />
|
||||
<ClCompile Include="..\..\src\video\yuv2rgb\yuv_rgb_sse.c" />
|
||||
<ClCompile Include="..\..\src\video\yuv2rgb\yuv_rgb_std.c" />
|
||||
@@ -435,6 +438,7 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_vulkan_internal.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_yuv_c.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_msctf.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_surface_utils.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_windowsclipboard.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_windowsevents.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_windowsframebuffer.h" />
|
||||
|
||||
@@ -489,6 +489,7 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_vulkan_internal.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_yuv_c.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_msctf.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_surface_utils.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_windowsclipboard.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_windowsevents.h" />
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_windowsframebuffer.h" />
|
||||
@@ -671,6 +672,7 @@
|
||||
<ClCompile Include="..\..\src\timer\windows\SDL_systimer.c" />
|
||||
<ClCompile Include="..\..\src\time\SDL_time.c" />
|
||||
<ClCompile Include="..\..\src\time\windows\SDL_systime.c" />
|
||||
<ClCompile Include="..\..\src\tray\windows\SDL_tray.c" />
|
||||
<ClCompile Include="..\..\src\video\dummy\SDL_nullevents.c" />
|
||||
<ClCompile Include="..\..\src\video\dummy\SDL_nullframebuffer.c" />
|
||||
<ClCompile Include="..\..\src\video\dummy\SDL_nullvideo.c" />
|
||||
@@ -701,6 +703,7 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_video_unsupported.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_vulkan_utils.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_yuv.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_surface_utils.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_windowsclipboard.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_windowsevents.c" />
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_windowsframebuffer.c" />
|
||||
|
||||
@@ -690,6 +690,9 @@
|
||||
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb_std_func.h">
|
||||
<Filter>video\yuv2rgb</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_surface_utils.h">
|
||||
<Filter>video\windows</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\video\windows\SDL_windowsclipboard.h">
|
||||
<Filter>video\windows</Filter>
|
||||
</ClInclude>
|
||||
@@ -1229,6 +1232,9 @@
|
||||
<ClCompile Include="..\..\src\time\windows\SDL_systime.c">
|
||||
<Filter>time\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\tray\windows\SDL_tray.c">
|
||||
<Filter>video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\video\SDL_RLEaccel.c">
|
||||
<Filter>video</Filter>
|
||||
</ClCompile>
|
||||
@@ -1301,6 +1307,9 @@
|
||||
<ClCompile Include="..\..\src\video\dummy\SDL_nullvideo.c">
|
||||
<Filter>video\dummy</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_surface_utils.c">
|
||||
<Filter>video\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\video\windows\SDL_windowsclipboard.c">
|
||||
<Filter>video\windows</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
#include <SDL3/SDL_thread.h>
|
||||
#include <SDL3/SDL_time.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
#include <SDL3/SDL_tray.h>
|
||||
#include <SDL3/SDL_touch.h>
|
||||
#include <SDL3/SDL_version.h>
|
||||
#include <SDL3/SDL_video.h>
|
||||
|
||||
431
include/SDL3/SDL_tray.h
Normal file
431
include/SDL3/SDL_tray.h
Normal file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryTray
|
||||
*
|
||||
* System tray menu support.
|
||||
*/
|
||||
|
||||
#ifndef SDL_tray_h_
|
||||
#define SDL_tray_h_
|
||||
|
||||
#include <SDL3/SDL_error.h>
|
||||
|
||||
#include <SDL3/SDL_video.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct SDL_Tray SDL_Tray;
|
||||
typedef struct SDL_TrayMenu SDL_TrayMenu;
|
||||
typedef struct SDL_TrayEntry SDL_TrayEntry;
|
||||
|
||||
/**
|
||||
* Flags that control the creation of system tray entries.
|
||||
*
|
||||
* Some of these flags are required; exactly one of them must be specified at
|
||||
* the time a tray entry is created. Other flags are optional; zero or more of
|
||||
* those can be OR'ed together with the required flag.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
*/
|
||||
typedef Uint32 SDL_TrayEntryFlags;
|
||||
|
||||
#define SDL_TRAYENTRY_BUTTON 0x00000001u /**< Make the entry a simple button. Required. */
|
||||
#define SDL_TRAYENTRY_CHECKBOX 0x00000002u /**< Make the entry a checkbox. Required. */
|
||||
#define SDL_TRAYENTRY_SUBMENU 0x00000004u /**< Prepare the entry to have a submenu. Required */
|
||||
#define SDL_TRAYENTRY_DISABLED 0x80000000u /**< Make the entry disabled. Optional. */
|
||||
#define SDL_TRAYENTRY_CHECKED 0x40000000u /**< Make the entry checked. This is valid only for checkboxes. Optional. */
|
||||
|
||||
/**
|
||||
* A callback that is invoked when a tray entry is selected.
|
||||
*
|
||||
* \param userdata an optional pointer to pass extra data to the callback when
|
||||
* it will be invoked.
|
||||
* \param entry the tray entry that was selected.
|
||||
*
|
||||
* \sa SDL_SetTrayEntryCallback
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_TrayCallback)(void *userdata, SDL_TrayEntry *entry);
|
||||
|
||||
/**
|
||||
* Create an icon to be placed in the operating system's tray, or equivalent.
|
||||
*
|
||||
* Many platforms advise not using a system tray unless persistence is a
|
||||
* necessary feature. Avoid needlessly creating a tray icon, as the user may
|
||||
* feel like it clutters their interface.
|
||||
*
|
||||
* Using tray icons require the video subsystem.
|
||||
*
|
||||
* \param icon a surface to be used as icon. May be NULL.
|
||||
* \param tooltip a tooltip to be displayed when the mouse hovers the icon. Not
|
||||
* supported on all platforms. May be NULL.
|
||||
* \returns The newly created system tray icon.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_CreateTrayMenu
|
||||
* \sa SDL_GetTrayMenu
|
||||
* \sa SDL_DestroyTray
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Tray *SDLCALL SDL_CreateTray(SDL_Surface *icon, const char *tooltip);
|
||||
|
||||
/**
|
||||
* Updates the system tray icon's icon.
|
||||
*
|
||||
* \param tray the tray icon to be updated.
|
||||
* \param icon the new icon. May be NULL.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_CreateTray
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon);
|
||||
|
||||
/**
|
||||
* Updates the system tray icon's tooltip.
|
||||
*
|
||||
* \param tray the tray icon to be updated.
|
||||
* \param tooltip the new tooltip. May be NULL.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_CreateTray
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_SetTrayTooltip(SDL_Tray *tray, const char *tooltip);
|
||||
|
||||
/**
|
||||
* Create a menu for a system tray.
|
||||
*
|
||||
* This should be called at most once per tray icon.
|
||||
*
|
||||
* This function does the same thing as SDL_CreateTraySubmenu(), except that it
|
||||
* takes a SDL_Tray instead of a SDL_TrayEntry.
|
||||
*
|
||||
* A menu does not need to be destroyed; it will be destroyed with the tray.
|
||||
*
|
||||
* \param tray the tray to bind the menu to.
|
||||
* \returns the newly created menu.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_CreateTray
|
||||
* \sa SDL_GetTrayMenu
|
||||
* \sa SDL_GetTrayMenuParentTray
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTrayMenu(SDL_Tray *tray);
|
||||
|
||||
/**
|
||||
* Create a submenu for a system tray entry.
|
||||
*
|
||||
* This should be called at most once per tray entry.
|
||||
*
|
||||
* This function does the same thing as SDL_CreateTrayMenu, except that it
|
||||
* takes a SDL_TrayEntry instead of a SDL_Tray.
|
||||
*
|
||||
* A menu does not need to be destroyed; it will be destroyed with the tray.
|
||||
*
|
||||
* \param entry the tray entry to bind the menu to.
|
||||
* \returns the newly created menu.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
* \sa SDL_GetTraySubmenu
|
||||
* \sa SDL_GetTrayMenuParentEntry
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTraySubmenu(SDL_TrayEntry *entry);
|
||||
|
||||
/**
|
||||
* Gets a previously created tray menu.
|
||||
*
|
||||
* You should have called SDL_CreateTrayMenu() on the tray object. This
|
||||
* function allows you to fetch it again later.
|
||||
*
|
||||
* This function does the same thing as SDL_GetTraySubmenu(), except that it
|
||||
* takes a SDL_Tray instead of a SDL_TrayEntry.
|
||||
*
|
||||
* A menu does not need to be destroyed; it will be destroyed with the tray.
|
||||
*
|
||||
* \param tray the tray entry to bind the menu to.
|
||||
* \returns the newly created menu.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_CreateTray
|
||||
* \sa SDL_CreateTrayMenu
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayMenu(SDL_Tray *tray);
|
||||
|
||||
/**
|
||||
* Gets a previously created tray entry submenu.
|
||||
*
|
||||
* You should have called SDL_CreateTraySubenu() on the entry object. This
|
||||
* function allows you to fetch it again later.
|
||||
*
|
||||
* This function does the same thing as SDL_GetTrayMenu(), except that it
|
||||
* takes a SDL_TrayEntry instead of a SDL_Tray.
|
||||
*
|
||||
* A menu does not need to be destroyed; it will be destroyed with the tray.
|
||||
*
|
||||
* \param entry the tray entry to bind the menu to.
|
||||
* \returns the newly created menu.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
* \sa SDL_CreateTraySubmenu
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTraySubmenu(SDL_TrayEntry *entry);
|
||||
|
||||
/**
|
||||
* Returns a list of entries in the menu, in order.
|
||||
*
|
||||
* \param menu The menu to get entries from.
|
||||
* \param size An optional pointer to obtain the number of entries in the menu.
|
||||
* \returns the entries within the given menu. The pointer becomes invalid when
|
||||
* any function that inserts or deletes entries in the menu is called.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_RemoveTrayEntry
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
*/
|
||||
extern SDL_DECLSPEC const SDL_TrayEntry **SDLCALL SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size);
|
||||
|
||||
/**
|
||||
* Removes a tray entry.
|
||||
*
|
||||
* \param entry The entry to be deleted.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_GetTrayEntries
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_RemoveTrayEntry(SDL_TrayEntry *entry);
|
||||
|
||||
/**
|
||||
* Insert a tray entry at a given position.
|
||||
*
|
||||
* If label is NULL, the entry will be a separator. Many functions won't work
|
||||
* for an entry that is a separator.
|
||||
*
|
||||
* An entry does not need to be destroyed; it will be destroyed with the tray.
|
||||
*
|
||||
* \param menu the menu to append the entry to.
|
||||
* \param pos the desired position for the new entry. Entries at or following
|
||||
* this place will be moved. If pos is -1, the entry is appended.
|
||||
* \param label the text to be displayed on the entry, or NULL for a separator.
|
||||
* \param flags a combination of flags, some of which are mandatory.
|
||||
* \returns the newly created entry, or NULL if pos is out of bounds.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_TrayEntryFlags
|
||||
* \sa SDL_GetTrayEntries
|
||||
* \sa SDL_RemoveTrayEntry
|
||||
* \sa SDL_GetTrayEntryParent
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TrayEntry *SDLCALL SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags);
|
||||
|
||||
/**
|
||||
* Sets the label of an entry.
|
||||
*
|
||||
* An entry cannot change between a separator and an ordinary entry; that is,
|
||||
* it is not possible to set a non-NULL label on an entry that has a NULL label
|
||||
* (separators), or to set a NULL label to an entry that has a non-NULL label.
|
||||
* The function will silently fail if that happens.
|
||||
*
|
||||
* \param entry the entry to be updated.
|
||||
* \param label the new label for the entry.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_GetTrayEntries
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
* \sa SDL_GetTrayEntryLabel
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label);
|
||||
|
||||
/**
|
||||
* Gets the label of an entry.
|
||||
*
|
||||
* If the returned value is NULL, the entry is a separator.
|
||||
*
|
||||
* \param entry the entry to be read.
|
||||
* \returns the label of the entry.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_GetTrayEntries
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
* \sa SDL_SetTrayEntryLabel
|
||||
*/
|
||||
extern SDL_DECLSPEC const char *SDLCALL SDL_GetTrayEntryLabel(SDL_TrayEntry *entry);
|
||||
|
||||
/**
|
||||
* Sets whether or not an entry is checked.
|
||||
*
|
||||
* The entry must have been created with the SDL_TRAYENTRY_CHECKBOX flag.
|
||||
*
|
||||
* \param entry the entry to be updated.
|
||||
* \param checked SDL_TRUE if the entry should be checked; SDL_FALSE otherwise.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_GetTrayEntries
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
* \sa SDL_GetTrayEntryChecked
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_SetTrayEntryChecked(SDL_TrayEntry *entry, bool checked);
|
||||
|
||||
/**
|
||||
* Gets whether or not an entry is checked.
|
||||
*
|
||||
* The entry must have been created with the SDL_TRAYENTRY_CHECKBOX flag.
|
||||
*
|
||||
* \param entry the entry to be read.
|
||||
* \returns SDL_TRUE if the entry is checked; SDL_FALSE otherwise.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_GetTrayEntries
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
* \sa SDL_SetTrayEntryChecked
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetTrayEntryChecked(SDL_TrayEntry *entry);
|
||||
|
||||
/**
|
||||
* Sets whether or not an entry is enabled.
|
||||
*
|
||||
* \param entry the entry to be updated.
|
||||
* \param enabled SDL_TRUE if the entry should be enabled; SDL_FALSE otherwise.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_GetTrayEntries
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
* \sa SDL_GetTrayEntryEnabled
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_SetTrayEntryEnabled(SDL_TrayEntry *entry, bool enabled);
|
||||
|
||||
/**
|
||||
* Gets whether or not an entry is enabled.
|
||||
*
|
||||
* \param entry the entry to be read.
|
||||
* \returns SDL_TRUE if the entry is enabled; SDL_FALSE otherwise.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_GetTrayEntries
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
* \sa SDL_SetTrayEntryEnabled
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetTrayEntryEnabled(SDL_TrayEntry *entry);
|
||||
|
||||
/**
|
||||
* Sets a callback to be invoked when the entry is selected.
|
||||
*
|
||||
* \param entry the entry to be updated.
|
||||
* \param callback a callback to be invoked when the entry is selected.
|
||||
* \param userdata an optional pointer to pass extra data to the callback when
|
||||
* it will be invoked.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_GetTrayEntries
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_SetTrayEntryCallback(SDL_TrayEntry *entry, SDL_TrayCallback callback, void *userdata);
|
||||
|
||||
/**
|
||||
* Destroys a tray object.
|
||||
*
|
||||
* This also destroys all associated menus and entries.
|
||||
*
|
||||
* \param tray the tray icon to be destroyed.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_CreateTray
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_DestroyTray(SDL_Tray *tray);
|
||||
|
||||
/**
|
||||
* Gets the menu contianing a certain tray entry.
|
||||
*
|
||||
* \param entry the entry for which to get the parent menu.
|
||||
* \returns the parent menu.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_InsertTrayEntryAt
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayEntryParent(SDL_TrayEntry *entry);
|
||||
|
||||
/**
|
||||
* Gets the entry for which the menu is a submenu, if the current menu is a
|
||||
* submenu.
|
||||
*
|
||||
* Either this function or SDL_GetTrayMenuParentTray() will return non-NULL for
|
||||
* any given menu.
|
||||
*
|
||||
* \param menu the menu for which to get the parent entry.
|
||||
* \returns the parent entry, or NULL if this menu is not a submenu.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_CreateTraySubmenu
|
||||
* \sa SDL_GetTrayMenuParentTray
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TrayEntry *SDLCALL SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu);
|
||||
|
||||
/**
|
||||
* Gets the tray for which this menu is the first-level menu, if the current
|
||||
* menu isn't a submenu.
|
||||
*
|
||||
* Either this function or SDL_GetTrayMenuParentEntry() will return non-NULL for
|
||||
* any given menu.
|
||||
*
|
||||
* \param menu the menu for which to get the parent enttrayry.
|
||||
* \returns the parent tray, or NULL if this menu is a submenu.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_CreateTrayMenu
|
||||
* \sa SDL_GetTrayMenuParentEntry
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Tray *SDLCALL SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_tray_h_ */
|
||||
@@ -1208,6 +1208,27 @@ SDL3_0.0.0 {
|
||||
SDL_RenderTextureAffine;
|
||||
SDL_WaitAndAcquireGPUSwapchainTexture;
|
||||
SDL_RenderDebugTextFormat;
|
||||
SDL_CreateTray;
|
||||
SDL_SetTrayIcon;
|
||||
SDL_SetTrayTooltip;
|
||||
SDL_CreateTrayMenu;
|
||||
SDL_CreateTraySubmenu;
|
||||
SDL_GetTrayMenu;
|
||||
SDL_GetTraySubmenu;
|
||||
SDL_GetTrayEntries;
|
||||
SDL_RemoveTrayEntry;
|
||||
SDL_InsertTrayEntryAt;
|
||||
SDL_SetTrayEntryLabel;
|
||||
SDL_GetTrayEntryLabel;
|
||||
SDL_SetTrayEntryChecked;
|
||||
SDL_GetTrayEntryChecked;
|
||||
SDL_SetTrayEntryEnabled;
|
||||
SDL_GetTrayEntryEnabled;
|
||||
SDL_SetTrayEntryCallback;
|
||||
SDL_DestroyTray;
|
||||
SDL_GetTrayEntryParent;
|
||||
SDL_GetTrayMenuParentEntry;
|
||||
SDL_GetTrayMenuParentTray;
|
||||
# extra symbols go here (don't modify this line)
|
||||
local: *;
|
||||
};
|
||||
|
||||
@@ -1233,3 +1233,24 @@
|
||||
#define SDL_RenderTextureAffine SDL_RenderTextureAffine_REAL
|
||||
#define SDL_WaitAndAcquireGPUSwapchainTexture SDL_WaitAndAcquireGPUSwapchainTexture_REAL
|
||||
#define SDL_RenderDebugTextFormat SDL_RenderDebugTextFormat_REAL
|
||||
#define SDL_CreateTray SDL_CreateTray_REAL
|
||||
#define SDL_SetTrayIcon SDL_SetTrayIcon_REAL
|
||||
#define SDL_SetTrayTooltip SDL_SetTrayTooltip_REAL
|
||||
#define SDL_CreateTrayMenu SDL_CreateTrayMenu_REAL
|
||||
#define SDL_CreateTraySubmenu SDL_CreateTraySubmenu_REAL
|
||||
#define SDL_GetTrayMenu SDL_GetTrayMenu_REAL
|
||||
#define SDL_GetTraySubmenu SDL_GetTraySubmenu_REAL
|
||||
#define SDL_GetTrayEntries SDL_GetTrayEntries_REAL
|
||||
#define SDL_RemoveTrayEntry SDL_RemoveTrayEntry_REAL
|
||||
#define SDL_InsertTrayEntryAt SDL_InsertTrayEntryAt_REAL
|
||||
#define SDL_SetTrayEntryLabel SDL_SetTrayEntryLabel_REAL
|
||||
#define SDL_GetTrayEntryLabel SDL_GetTrayEntryLabel_REAL
|
||||
#define SDL_SetTrayEntryChecked SDL_SetTrayEntryChecked_REAL
|
||||
#define SDL_GetTrayEntryChecked SDL_GetTrayEntryChecked_REAL
|
||||
#define SDL_SetTrayEntryEnabled SDL_SetTrayEntryEnabled_REAL
|
||||
#define SDL_GetTrayEntryEnabled SDL_GetTrayEntryEnabled_REAL
|
||||
#define SDL_SetTrayEntryCallback SDL_SetTrayEntryCallback_REAL
|
||||
#define SDL_DestroyTray SDL_DestroyTray_REAL
|
||||
#define SDL_GetTrayEntryParent SDL_GetTrayEntryParent_REAL
|
||||
#define SDL_GetTrayMenuParentEntry SDL_GetTrayMenuParentEntry_REAL
|
||||
#define SDL_GetTrayMenuParentTray SDL_GetTrayMenuParentTray_REAL
|
||||
|
||||
@@ -1241,3 +1241,24 @@ SDL_DYNAPI_PROC(bool,SDL_WaitAndAcquireGPUSwapchainTexture,(SDL_GPUCommandBuffer
|
||||
#ifndef SDL_DYNAPI_PROC_NO_VARARGS
|
||||
SDL_DYNAPI_PROC(bool,SDL_RenderDebugTextFormat,(SDL_Renderer *a,float b,float c,SDL_PRINTF_FORMAT_STRING const char *d,...),(a,b,c,d),return)
|
||||
#endif
|
||||
SDL_DYNAPI_PROC(SDL_Tray*,SDL_CreateTray,(SDL_Surface *a,const char *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_SetTrayIcon,(SDL_Tray *a,SDL_Surface *b),(a,b),)
|
||||
SDL_DYNAPI_PROC(void,SDL_SetTrayTooltip,(SDL_Tray *a,const char *b),(a,b),)
|
||||
SDL_DYNAPI_PROC(SDL_TrayMenu*,SDL_CreateTrayMenu,(SDL_Tray *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_TrayMenu*,SDL_CreateTraySubmenu,(SDL_TrayEntry *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_TrayMenu*,SDL_GetTrayMenu,(SDL_Tray *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_TrayMenu*,SDL_GetTraySubmenu,(SDL_TrayEntry *a),(a),return)
|
||||
SDL_DYNAPI_PROC(const SDL_TrayEntry**,SDL_GetTrayEntries,(SDL_TrayMenu *a,int *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_RemoveTrayEntry,(SDL_TrayEntry *a),(a),)
|
||||
SDL_DYNAPI_PROC(SDL_TrayEntry*,SDL_InsertTrayEntryAt,(SDL_TrayMenu *a,int b,const char *c,SDL_TrayEntryFlags d),(a,b,c,d),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_SetTrayEntryLabel,(SDL_TrayEntry *a,const char *b),(a,b),)
|
||||
SDL_DYNAPI_PROC(const char*,SDL_GetTrayEntryLabel,(SDL_TrayEntry *a),(a),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_SetTrayEntryChecked,(SDL_TrayEntry *a,bool b),(a,b),)
|
||||
SDL_DYNAPI_PROC(bool,SDL_GetTrayEntryChecked,(SDL_TrayEntry *a),(a),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_SetTrayEntryEnabled,(SDL_TrayEntry *a,bool b),(a,b),)
|
||||
SDL_DYNAPI_PROC(bool,SDL_GetTrayEntryEnabled,(SDL_TrayEntry *a),(a),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_SetTrayEntryCallback,(SDL_TrayEntry *a,SDL_TrayCallback b,void *c),(a,b,c),)
|
||||
SDL_DYNAPI_PROC(void,SDL_DestroyTray,(SDL_Tray *a),(a),)
|
||||
SDL_DYNAPI_PROC(SDL_TrayMenu*,SDL_GetTrayEntryParent,(SDL_TrayEntry *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_TrayEntry*,SDL_GetTrayMenuParentEntry,(SDL_TrayMenu *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_Tray*,SDL_GetTrayMenuParentTray,(SDL_TrayMenu *a),(a),return)
|
||||
|
||||
458
src/tray/cocoa/SDL_tray.m
Normal file
458
src/tray/cocoa/SDL_tray.m
Normal file
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
#include "../../video/SDL_surface_c.h"
|
||||
|
||||
/* applicationDockMenu */
|
||||
|
||||
struct SDL_TrayMenu {
|
||||
NSMenu *nsmenu;
|
||||
|
||||
size_t nEntries;
|
||||
SDL_TrayEntry **entries;
|
||||
|
||||
SDL_Tray *parent_tray;
|
||||
SDL_TrayEntry *parent_entry;
|
||||
};
|
||||
|
||||
struct SDL_TrayEntry {
|
||||
NSMenuItem *nsitem;
|
||||
|
||||
SDL_TrayEntryFlags flags;
|
||||
SDL_TrayCallback callback;
|
||||
void *userdata;
|
||||
SDL_TrayMenu *submenu;
|
||||
|
||||
SDL_TrayMenu *parent;
|
||||
};
|
||||
|
||||
struct SDL_Tray {
|
||||
NSStatusBar *statusBar;
|
||||
NSStatusItem *statusItem;
|
||||
|
||||
SDL_TrayMenu *menu;
|
||||
};
|
||||
|
||||
static NSApplication *app = NULL;
|
||||
|
||||
@interface AppDelegate: NSObject <NSApplicationDelegate>
|
||||
- (IBAction)menu:(id)sender;
|
||||
@end
|
||||
|
||||
@implementation AppDelegate{}
|
||||
- (IBAction)menu:(id)sender
|
||||
{
|
||||
SDL_TrayEntry *entry = [[sender representedObject] pointerValue];
|
||||
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry->flags & SDL_TRAYENTRY_CHECKBOX) {
|
||||
SDL_SetTrayEntryChecked(entry, !SDL_GetTrayEntryChecked(entry));
|
||||
}
|
||||
|
||||
if (entry->callback) {
|
||||
entry->callback(entry->userdata, entry);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
static void DestroySDLMenu(SDL_TrayMenu *menu)
|
||||
{
|
||||
for (int i = 0; i < menu->nEntries; i++) {
|
||||
if (menu->entries[i] && menu->entries[i]->submenu) {
|
||||
DestroySDLMenu(menu->entries[i]->submenu);
|
||||
}
|
||||
SDL_free(menu->entries[i]);
|
||||
}
|
||||
|
||||
SDL_free(menu->entries);
|
||||
|
||||
if (menu->parent_entry) {
|
||||
[menu->parent_entry->parent->nsmenu setSubmenu:nil forItem:menu->parent_entry->nsitem];
|
||||
} else if (menu->parent_tray) {
|
||||
[menu->parent_tray->statusItem setMenu:nil];
|
||||
}
|
||||
|
||||
SDL_free(menu);
|
||||
}
|
||||
|
||||
SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
|
||||
{
|
||||
SDL_Tray *tray = (SDL_Tray *) SDL_malloc(sizeof(SDL_Tray));
|
||||
|
||||
AppDelegate *delegate = [[AppDelegate alloc] init];
|
||||
app = [NSApplication sharedApplication];
|
||||
[app setDelegate:delegate];
|
||||
|
||||
if (!tray) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_memset((void *) tray, 0, sizeof(*tray));
|
||||
|
||||
tray->statusItem = nil;
|
||||
tray->statusBar = [NSStatusBar systemStatusBar];
|
||||
tray->statusItem = [tray->statusBar statusItemWithLength:NSVariableStatusItemLength];
|
||||
[app activateIgnoringOtherApps:TRUE];
|
||||
|
||||
if (tooltip) {
|
||||
tray->statusItem.button.toolTip = [NSString stringWithUTF8String:tooltip];
|
||||
} else {
|
||||
tray->statusItem.button.toolTip = nil;
|
||||
}
|
||||
|
||||
if (icon) {
|
||||
SDL_Surface *iconfmt = SDL_ConvertSurface(icon, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!iconfmt) {
|
||||
goto skip_putting_an_icon;
|
||||
}
|
||||
|
||||
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **)&iconfmt->pixels
|
||||
pixelsWide:iconfmt->w
|
||||
pixelsHigh:iconfmt->h
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bytesPerRow:iconfmt->pitch
|
||||
bitsPerPixel:32];
|
||||
NSImage *iconimg = [[NSImage alloc] initWithSize:NSMakeSize(iconfmt->w, iconfmt->h)];
|
||||
[iconimg addRepresentation:bitmap];
|
||||
|
||||
/* A typical icon size is 22x22 on macOS. Failing to resize the icon
|
||||
may give oversized status bar buttons. */
|
||||
NSImage *iconimg22 = [[NSImage alloc] initWithSize:NSMakeSize(22, 22)];
|
||||
[iconimg22 lockFocus];
|
||||
[iconimg setSize:NSMakeSize(22, 22)];
|
||||
[iconimg drawInRect:NSMakeRect(0, 0, 22, 22)];
|
||||
[iconimg22 unlockFocus];
|
||||
|
||||
tray->statusItem.button.image = iconimg22;
|
||||
|
||||
SDL_DestroySurface(iconfmt);
|
||||
}
|
||||
|
||||
skip_putting_an_icon:
|
||||
return tray;
|
||||
}
|
||||
|
||||
void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon)
|
||||
{
|
||||
if (!icon) {
|
||||
tray->statusItem.button.image = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_Surface *iconfmt = SDL_ConvertSurface(icon, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!iconfmt) {
|
||||
tray->statusItem.button.image = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **)&iconfmt->pixels
|
||||
pixelsWide:iconfmt->w
|
||||
pixelsHigh:iconfmt->h
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bytesPerRow:iconfmt->pitch
|
||||
bitsPerPixel:32];
|
||||
NSImage *iconimg = [[NSImage alloc] initWithSize:NSMakeSize(iconfmt->w, iconfmt->h)];
|
||||
[iconimg addRepresentation:bitmap];
|
||||
|
||||
/* A typical icon size is 22x22 on macOS. Failing to resize the icon
|
||||
may give oversized status bar buttons. */
|
||||
NSImage *iconimg22 = [[NSImage alloc] initWithSize:NSMakeSize(22, 22)];
|
||||
[iconimg22 lockFocus];
|
||||
[iconimg setSize:NSMakeSize(22, 22)];
|
||||
[iconimg drawInRect:NSMakeRect(0, 0, 22, 22)];
|
||||
[iconimg22 unlockFocus];
|
||||
|
||||
tray->statusItem.button.image = iconimg22;
|
||||
|
||||
SDL_DestroySurface(iconfmt);
|
||||
}
|
||||
|
||||
void SDL_SetTrayTooltip(SDL_Tray *tray, const char *tooltip)
|
||||
{
|
||||
if (tooltip) {
|
||||
tray->statusItem.button.toolTip = [NSString stringWithUTF8String:tooltip];
|
||||
} else {
|
||||
tray->statusItem.button.toolTip = nil;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
SDL_TrayMenu *menu = SDL_malloc(sizeof(SDL_TrayMenu));
|
||||
|
||||
if (!menu) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_memset((void *) menu, 0, sizeof(*menu));
|
||||
|
||||
NSMenu *nsmenu = [[NSMenu alloc] init];
|
||||
[nsmenu setAutoenablesItems:FALSE];
|
||||
|
||||
[tray->statusItem setMenu:nsmenu];
|
||||
|
||||
tray->menu = menu;
|
||||
menu->nsmenu = nsmenu;
|
||||
menu->nEntries = 0;
|
||||
menu->entries = NULL;
|
||||
menu->parent_tray = tray;
|
||||
menu->parent_entry = NULL;
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
return tray->menu;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (entry->submenu) {
|
||||
SDL_SetError("Tray entry submenu already exists");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(entry->flags & SDL_TRAYENTRY_SUBMENU)) {
|
||||
SDL_SetError("Cannot create submenu for entry not created with SDL_TRAYENTRY_SUBMENU");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *menu = SDL_malloc(sizeof(SDL_TrayMenu));
|
||||
|
||||
if (!menu) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_memset((void *) menu, 0, sizeof(*menu));
|
||||
|
||||
NSMenu *nsmenu = [[NSMenu alloc] init];
|
||||
[nsmenu setAutoenablesItems:FALSE];
|
||||
|
||||
entry->submenu = menu;
|
||||
menu->nsmenu = nsmenu;
|
||||
menu->nEntries = 0;
|
||||
menu->entries = NULL;
|
||||
menu->parent_tray = NULL;
|
||||
menu->parent_entry = entry;
|
||||
|
||||
[entry->parent->nsmenu setSubmenu:nsmenu forItem:entry->nsitem];
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_GetTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
return entry->submenu;
|
||||
}
|
||||
|
||||
const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size)
|
||||
{
|
||||
if (size) {
|
||||
*size = menu->nEntries;
|
||||
}
|
||||
|
||||
return (const SDL_TrayEntry **) menu->entries;
|
||||
}
|
||||
|
||||
void SDL_RemoveTrayEntry(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *menu = entry->parent;
|
||||
|
||||
bool found = false;
|
||||
for (int i = 0; i < menu->nEntries - 1; i++) {
|
||||
if (menu->entries[i] == entry) {
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
menu->entries[i] = menu->entries[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->submenu) {
|
||||
DestroySDLMenu(entry->submenu);
|
||||
}
|
||||
|
||||
menu->nEntries--;
|
||||
SDL_TrayEntry ** new_entries = SDL_realloc(menu->entries, menu->nEntries * sizeof(SDL_TrayEntry *));
|
||||
|
||||
/* Not sure why shrinking would fail, but even if it does, we can live with a "too big" array */
|
||||
if (new_entries) {
|
||||
menu->entries = new_entries;
|
||||
}
|
||||
|
||||
[menu->nsmenu removeItem:entry->nsitem];
|
||||
|
||||
SDL_free(entry);
|
||||
}
|
||||
|
||||
SDL_TrayEntry *SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags)
|
||||
{
|
||||
if (pos < -1 || pos > (int) menu->nEntries) {
|
||||
SDL_InvalidParamError("pos");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pos == -1) {
|
||||
pos = menu->nEntries;
|
||||
}
|
||||
|
||||
SDL_TrayEntry *entry = SDL_malloc(sizeof(SDL_TrayEntry));
|
||||
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_memset((void *) entry, 0, sizeof(*entry));
|
||||
|
||||
SDL_TrayEntry **new_entries = (SDL_TrayEntry **) SDL_realloc(menu->entries, (menu->nEntries + 1) * sizeof(SDL_TrayEntry *));
|
||||
|
||||
if (!new_entries) {
|
||||
SDL_free(entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
menu->entries = new_entries;
|
||||
menu->nEntries++;
|
||||
|
||||
for (int i = menu->nEntries - 1; i > pos; i--) {
|
||||
menu->entries[i] = menu->entries[i - 1];
|
||||
}
|
||||
|
||||
new_entries[pos] = entry;
|
||||
|
||||
NSMenuItem *nsitem;
|
||||
if (label == NULL) {
|
||||
nsitem = [NSMenuItem separatorItem];
|
||||
} else {
|
||||
nsitem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithUTF8String:label] action:@selector(menu:) keyEquivalent:@""];
|
||||
[nsitem setEnabled:((flags & SDL_TRAYENTRY_DISABLED) ? FALSE : TRUE)];
|
||||
[nsitem setState:((flags & SDL_TRAYENTRY_CHECKED) ? NSControlStateValueOn : NSControlStateValueOff)];
|
||||
[nsitem setRepresentedObject:[NSValue valueWithPointer:entry]];
|
||||
}
|
||||
|
||||
[menu->nsmenu insertItem:nsitem atIndex:pos];
|
||||
|
||||
entry->nsitem = nsitem;
|
||||
entry->flags = flags;
|
||||
entry->callback = NULL;
|
||||
entry->userdata = NULL;
|
||||
entry->submenu = NULL;
|
||||
entry->parent = menu;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label)
|
||||
{
|
||||
[entry->nsitem setTitle:[NSString stringWithUTF8String:label]];
|
||||
}
|
||||
|
||||
const char *SDL_GetTrayEntryLabel(SDL_TrayEntry *entry)
|
||||
{
|
||||
return [[entry->nsitem title] UTF8String];
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryChecked(SDL_TrayEntry *entry, bool checked)
|
||||
{
|
||||
[entry->nsitem setState:(checked ? NSControlStateValueOn : NSControlStateValueOff)];
|
||||
}
|
||||
|
||||
bool SDL_GetTrayEntryChecked(SDL_TrayEntry *entry)
|
||||
{
|
||||
return entry->nsitem.state == NSControlStateValueOn;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryEnabled(SDL_TrayEntry *entry, bool enabled)
|
||||
{
|
||||
if (!(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
SDL_SetError("Cannot update check for entry not created with SDL_TRAYENTRY_CHECKBOX");
|
||||
return;
|
||||
}
|
||||
|
||||
[entry->nsitem setEnabled:(enabled ? YES : NO)];
|
||||
}
|
||||
|
||||
bool SDL_GetTrayEntryEnabled(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
SDL_SetError("Cannot fetch check for entry not created with SDL_TRAYENTRY_CHECKBOX");
|
||||
return false;
|
||||
}
|
||||
|
||||
return entry->nsitem.enabled;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryCallback(SDL_TrayEntry *entry, SDL_TrayCallback callback, void *userdata)
|
||||
{
|
||||
entry->callback = callback;
|
||||
entry->userdata = userdata;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayEntryParent(SDL_TrayEntry *entry)
|
||||
{
|
||||
return entry->parent;
|
||||
}
|
||||
|
||||
SDL_TrayEntry *SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu)
|
||||
{
|
||||
return menu->parent_entry;
|
||||
}
|
||||
|
||||
SDL_Tray *SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu)
|
||||
{
|
||||
return menu->parent_tray;
|
||||
}
|
||||
|
||||
void SDL_DestroyTray(SDL_Tray *tray)
|
||||
{
|
||||
if (!tray) {
|
||||
return;
|
||||
}
|
||||
|
||||
[[NSStatusBar systemStatusBar] removeStatusItem:tray->statusItem];
|
||||
|
||||
if (tray->menu) {
|
||||
DestroySDLMenu(tray->menu);
|
||||
}
|
||||
|
||||
SDL_free(tray);
|
||||
}
|
||||
139
src/tray/dummy/SDL_tray.c
Normal file
139
src/tray/dummy/SDL_tray.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
void SDL_SetTrayTooltip(SDL_Tray *tray, const char *tooltip)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_GetTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SDL_RemoveTrayEntry(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
SDL_TrayEntry *SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
const char *SDL_GetTrayEntryLabel(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryChecked(SDL_TrayEntry *entry, bool checked)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
bool SDL_GetTrayEntryChecked(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return false;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryEnabled(SDL_TrayEntry *entry, bool enabled)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
bool SDL_GetTrayEntryEnabled(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return false;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryCallback(SDL_TrayEntry *entry, SDL_TrayCallback callback, void *userdata)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayEntryParent(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_TrayEntry *SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_Tray *SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SDL_DestroyTray(SDL_Tray *tray)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
664
src/tray/unix/SDL_tray.c
Normal file
664
src/tray/unix/SDL_tray.c
Normal file
File diff suppressed because it is too large
Load Diff
589
src/tray/windows/SDL_tray.c
Normal file
589
src/tray/windows/SDL_tray.c
Normal file
File diff suppressed because it is too large
Load Diff
95
src/video/windows/SDL_surface_utils.c
Normal file
95
src/video/windows/SDL_surface_utils.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_surface_utils.h"
|
||||
|
||||
#include "../SDL_surface_c.h"
|
||||
|
||||
HICON CreateIconFromSurface(SDL_Surface *surface)
|
||||
{
|
||||
SDL_Surface *s = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The dimensions will be needed after s is freed */
|
||||
const int width = s->w;
|
||||
const int height = s->h;
|
||||
|
||||
BITMAPINFO bmpInfo;
|
||||
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
|
||||
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmpInfo.bmiHeader.biWidth = width;
|
||||
bmpInfo.bmiHeader.biHeight = -height; /* Top-down bitmap */
|
||||
bmpInfo.bmiHeader.biPlanes = 1;
|
||||
bmpInfo.bmiHeader.biBitCount = 32;
|
||||
bmpInfo.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
HDC hdc = GetDC(NULL);
|
||||
void* pBits = NULL;
|
||||
HBITMAP hBitmap = CreateDIBSection(hdc, &bmpInfo, DIB_RGB_COLORS, &pBits, NULL, 0);
|
||||
if (!hBitmap) {
|
||||
ReleaseDC(NULL, hdc);
|
||||
SDL_DestroySurface(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_memcpy(pBits, s->pixels, width * height * 4);
|
||||
|
||||
SDL_DestroySurface(s);
|
||||
|
||||
HBITMAP hMask = CreateBitmap(width, height, 1, 1, NULL);
|
||||
if (!hMask) {
|
||||
DeleteObject(hBitmap);
|
||||
ReleaseDC(NULL, hdc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HDC hdcMem = CreateCompatibleDC(hdc);
|
||||
HGDIOBJ oldBitmap = SelectObject(hdcMem, hMask);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
BYTE* pixel = (BYTE*)pBits + (y * width + x) * 4;
|
||||
BYTE alpha = pixel[3];
|
||||
COLORREF maskColor = (alpha == 0) ? RGB(0, 0, 0) : RGB(255, 255, 255);
|
||||
SetPixel(hdcMem, x, y, maskColor);
|
||||
}
|
||||
}
|
||||
|
||||
ICONINFO iconInfo;
|
||||
iconInfo.fIcon = TRUE;
|
||||
iconInfo.xHotspot = 0;
|
||||
iconInfo.yHotspot = 0;
|
||||
iconInfo.hbmMask = hMask;
|
||||
iconInfo.hbmColor = hBitmap;
|
||||
|
||||
HICON hIcon = CreateIconIndirect(&iconInfo);
|
||||
|
||||
SelectObject(hdcMem, oldBitmap);
|
||||
DeleteDC(hdcMem);
|
||||
DeleteObject(hBitmap);
|
||||
DeleteObject(hMask);
|
||||
ReleaseDC(NULL, hdc);
|
||||
|
||||
return hIcon;
|
||||
}
|
||||
38
src/video/windows/SDL_surface_utils.h
Normal file
38
src/video/windows/SDL_surface_utils.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_surface_utils_h_
|
||||
#define SDL_surface_utils_h_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern HICON CreateIconFromSurface(SDL_Surface *surface);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -407,6 +407,7 @@ add_sdl_test_executable(testdialog SOURCES testdialog.c)
|
||||
add_sdl_test_executable(testtime SOURCES testtime.c)
|
||||
add_sdl_test_executable(testmanymouse SOURCES testmanymouse.c)
|
||||
add_sdl_test_executable(testmodal SOURCES testmodal.c)
|
||||
add_sdl_test_executable(testtray SOURCES testtray.c)
|
||||
|
||||
|
||||
add_sdl_test_executable(testprocess
|
||||
|
||||
BIN
test/sdl-test_round.bmp
Normal file
BIN
test/sdl-test_round.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 144 KiB |
599
test/testtray.c
Normal file
599
test/testtray.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user