mirror of
https://github.com/glfw/glfw.git
synced 2024-11-25 11:35:11 +00:00
Add glfwSetWindowIcon
Adds support for setting window icons programmatically on platforms where this makes sense. Fixes #453. Closes #467.
This commit is contained in:
parent
793eef1d0a
commit
b823f7151e
@ -84,6 +84,7 @@ does not find Doxygen, the documentation will not be generated.
|
||||
- Added `glfwGetKeyName` for querying the layout-specific name of printable
|
||||
keys
|
||||
- Added `glfwWaitEventsTimeout` for waiting for events for a set amount of time
|
||||
- Added `glfwSetWindowIcon` for setting the icon of a window
|
||||
- Added `glfwGetTimerValue` and `glfwGetTimerFrequency` for raw timer access
|
||||
- Added `GLFWuint64` for platform-independent 64-bit unsigned values
|
||||
- Added `GLFW_NO_API` for creating window without contexts
|
||||
@ -221,6 +222,7 @@ skills.
|
||||
- Peoro
|
||||
- Braden Pellett
|
||||
- Arturo J. Pérez
|
||||
- Orson Peters
|
||||
- Emmanuel Gil Peyrot
|
||||
- Cyril Pichard
|
||||
- Pieroman
|
||||
@ -246,6 +248,7 @@ skills.
|
||||
- TTK-Bandit
|
||||
- Sergey Tikhomirov
|
||||
- A. Tombs
|
||||
- Ioannis Tsakpinis
|
||||
- Samuli Tuomola
|
||||
- urraka
|
||||
- Jari Vetoniemi
|
||||
|
@ -32,6 +32,11 @@ GLFW now supports window maximization with @ref glfwMaximizeWindow and the
|
||||
[GLFW_MAXIMIZED](@ref window_attribs_wnd) window hint and attribute.
|
||||
|
||||
|
||||
@subsection news_32_icon Window icon support
|
||||
|
||||
GLFW now supports setting the icon of windows with @ref glfwSetWindowIcon.
|
||||
|
||||
|
||||
@subsection news_32_focus Window input focus control
|
||||
|
||||
GLFW now supports giving windows input focus with @ref glfwFocusWindow.
|
||||
|
@ -617,6 +617,26 @@ glfwSetWindowTitle(window, u8"This is always a UTF-8 string");
|
||||
@endcode
|
||||
|
||||
|
||||
@subsection window_icon Window icon
|
||||
|
||||
Decorated windows have icons on some platforms. You can set this icon by
|
||||
specifying a list of candidate images with @ref glfwSetWindowIcon.
|
||||
|
||||
@code
|
||||
GLFWimage images[2];
|
||||
images[0] = load_icon("my_icon.png");
|
||||
images[1] = load_icon("my_icon_small.png");
|
||||
|
||||
glfwSetWindowIcon(window, 2, images);
|
||||
@endcode
|
||||
|
||||
To revert to the default window icon, pass in an empty image array.
|
||||
|
||||
@code
|
||||
glfwSetWindowIcon(window, 0, NULL);
|
||||
@endcode
|
||||
|
||||
|
||||
@subsection window_monitor Window monitor
|
||||
|
||||
Full screen windows are associated with a specific monitor. You can get the
|
||||
|
@ -1913,6 +1913,45 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value);
|
||||
*/
|
||||
GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
|
||||
|
||||
/*! @brief Sets the icon for the specified window.
|
||||
*
|
||||
* This function sets the icon of the specified window. If passed an array of
|
||||
* candidate images, those of or closest to the sizes desired by the system are
|
||||
* selected. If no images are specified, the window reverts to its default
|
||||
* icon.
|
||||
*
|
||||
* The desired image sizes varies depending on platform and system settings.
|
||||
* The selected images will be rescaled as needed. Good sizes include 16x16,
|
||||
* 32x32 and 48x48.
|
||||
*
|
||||
* @param[in] window The window whose icon to set.
|
||||
* @param[in] count The number of images in the specified array, or zero to
|
||||
* revert to the default window icon.
|
||||
* @param[in] images The images to create the icon from. This is ignored if
|
||||
* count is zero.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @pointer_lifetime The specified image data is copied before this function
|
||||
* returns.
|
||||
*
|
||||
* @remark @osx The GLFW window has no icon, as it is not a document
|
||||
* window, but the dock icon will be the same as the application bundle's icon.
|
||||
* For more information on bundles, see the
|
||||
* [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
|
||||
* in the Mac Developer Library.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref window_icon
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup window
|
||||
*/
|
||||
GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images);
|
||||
|
||||
/*! @brief Retrieves the position of the client area of the specified window.
|
||||
*
|
||||
* This function retrieves the position, in screen coordinates, of the
|
||||
|
@ -1032,6 +1032,12 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title)
|
||||
[window->ns.object setTitle:[NSString stringWithUTF8String:title]];
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images)
|
||||
{
|
||||
// Regular windows do not have icons
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
{
|
||||
const NSRect contentRect =
|
||||
|
@ -617,6 +617,11 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window);
|
||||
*/
|
||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title);
|
||||
|
||||
/*! @copydoc glfwSetWindowIcon
|
||||
* @ingroup platform
|
||||
*/
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const GLFWimage* images);
|
||||
|
||||
/*! @copydoc glfwGetWindowPos
|
||||
* @ingroup platform
|
||||
*/
|
||||
|
@ -403,6 +403,13 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
mir_surface_spec_release(spec);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
MirSurfaceSpec* spec;
|
||||
|
@ -191,6 +191,8 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(
|
||||
typedef struct _GLFWwindowWin32
|
||||
{
|
||||
HWND handle;
|
||||
HICON bigIcon;
|
||||
HICON smallIcon;
|
||||
|
||||
GLFWbool cursorTracked;
|
||||
GLFWbool iconified;
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
@ -66,6 +67,112 @@ static DWORD getWindowExStyle(const _GLFWwindow* window)
|
||||
return style;
|
||||
}
|
||||
|
||||
// Returns the image whose area most closely matches the desired one
|
||||
//
|
||||
static const GLFWimage* chooseImage(int count, const GLFWimage* images,
|
||||
int width, int height)
|
||||
{
|
||||
int i, leastDiff = INT_MAX;
|
||||
const GLFWimage* closest = NULL;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
const int currDiff = abs(images[i].width * images[i].height -
|
||||
width * height);
|
||||
if (currDiff < leastDiff)
|
||||
{
|
||||
closest = images + i;
|
||||
leastDiff = currDiff;
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
// Creates an RGBA icon or cursor
|
||||
//
|
||||
static HICON createIcon(const GLFWimage* image,
|
||||
int xhot, int yhot, GLFWbool icon)
|
||||
{
|
||||
int i;
|
||||
HDC dc;
|
||||
HICON handle;
|
||||
HBITMAP color, mask;
|
||||
BITMAPV5HEADER bi;
|
||||
ICONINFO ii;
|
||||
unsigned char* target = NULL;
|
||||
unsigned char* source = image->pixels;
|
||||
|
||||
ZeroMemory(&bi, sizeof(bi));
|
||||
bi.bV5Size = sizeof(BITMAPV5HEADER);
|
||||
bi.bV5Width = image->width;
|
||||
bi.bV5Height = -image->height;
|
||||
bi.bV5Planes = 1;
|
||||
bi.bV5BitCount = 32;
|
||||
bi.bV5Compression = BI_BITFIELDS;
|
||||
bi.bV5RedMask = 0x00ff0000;
|
||||
bi.bV5GreenMask = 0x0000ff00;
|
||||
bi.bV5BlueMask = 0x000000ff;
|
||||
bi.bV5AlphaMask = 0xff000000;
|
||||
|
||||
dc = GetDC(NULL);
|
||||
color = CreateDIBSection(dc,
|
||||
(BITMAPINFO*) &bi,
|
||||
DIB_RGB_COLORS,
|
||||
(void**) &target,
|
||||
NULL,
|
||||
(DWORD) 0);
|
||||
ReleaseDC(NULL, dc);
|
||||
|
||||
if (!color)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to create RGBA bitmap");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mask = CreateBitmap(image->width, image->height, 1, 1, NULL);
|
||||
if (!mask)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to create mask bitmap");
|
||||
DeleteObject(color);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < image->width * image->height; i++)
|
||||
{
|
||||
target[0] = source[2];
|
||||
target[1] = source[1];
|
||||
target[2] = source[0];
|
||||
target[3] = source[3];
|
||||
target += 4;
|
||||
source += 4;
|
||||
}
|
||||
|
||||
ZeroMemory(&ii, sizeof(ii));
|
||||
ii.fIcon = icon;
|
||||
ii.xHotspot = xhot;
|
||||
ii.yHotspot = yhot;
|
||||
ii.hbmMask = mask;
|
||||
ii.hbmColor = color;
|
||||
|
||||
handle = CreateIconIndirect(&ii);
|
||||
|
||||
DeleteObject(color);
|
||||
DeleteObject(mask);
|
||||
|
||||
if (!handle)
|
||||
{
|
||||
if (icon)
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create icon");
|
||||
else
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create cursor");
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Translate client window size to full window size according to styles
|
||||
//
|
||||
static void getFullWindowSize(DWORD style, DWORD exStyle,
|
||||
@ -886,6 +993,12 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
}
|
||||
|
||||
destroyWindow(window);
|
||||
|
||||
if (window->win32.bigIcon)
|
||||
DestroyIcon(window->win32.bigIcon);
|
||||
|
||||
if (window->win32.smallIcon)
|
||||
DestroyIcon(window->win32.smallIcon);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
@ -902,6 +1015,37 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
free(wideTitle);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images)
|
||||
{
|
||||
HICON bigIcon = NULL, smallIcon = NULL;
|
||||
|
||||
if (count)
|
||||
{
|
||||
const GLFWimage* bigImage = chooseImage(count, images,
|
||||
GetSystemMetrics(SM_CXICON),
|
||||
GetSystemMetrics(SM_CYICON));
|
||||
const GLFWimage* smallImage = chooseImage(count, images,
|
||||
GetSystemMetrics(SM_CXSMICON),
|
||||
GetSystemMetrics(SM_CYSMICON));
|
||||
|
||||
bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE);
|
||||
smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE);
|
||||
}
|
||||
|
||||
SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
|
||||
SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
|
||||
|
||||
if (window->win32.bigIcon)
|
||||
DestroyIcon(window->win32.bigIcon);
|
||||
|
||||
if (window->win32.smallIcon)
|
||||
DestroyIcon(window->win32.smallIcon);
|
||||
|
||||
window->win32.bigIcon = bigIcon;
|
||||
window->win32.smallIcon = smallIcon;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
{
|
||||
POINT pos = { 0, 0 };
|
||||
@ -1236,61 +1380,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
const GLFWimage* image,
|
||||
int xhot, int yhot)
|
||||
{
|
||||
HDC dc;
|
||||
HBITMAP bitmap, mask;
|
||||
BITMAPV5HEADER bi;
|
||||
ICONINFO ii;
|
||||
DWORD* target = 0;
|
||||
BYTE* source = (BYTE*) image->pixels;
|
||||
int i;
|
||||
|
||||
ZeroMemory(&bi, sizeof(bi));
|
||||
bi.bV5Size = sizeof(BITMAPV5HEADER);
|
||||
bi.bV5Width = image->width;
|
||||
bi.bV5Height = -image->height;
|
||||
bi.bV5Planes = 1;
|
||||
bi.bV5BitCount = 32;
|
||||
bi.bV5Compression = BI_BITFIELDS;
|
||||
bi.bV5RedMask = 0x00ff0000;
|
||||
bi.bV5GreenMask = 0x0000ff00;
|
||||
bi.bV5BlueMask = 0x000000ff;
|
||||
bi.bV5AlphaMask = 0xff000000;
|
||||
|
||||
dc = GetDC(NULL);
|
||||
bitmap = CreateDIBSection(dc, (BITMAPINFO*) &bi, DIB_RGB_COLORS,
|
||||
(void**) &target, NULL, (DWORD) 0);
|
||||
ReleaseDC(NULL, dc);
|
||||
|
||||
if (!bitmap)
|
||||
return GLFW_FALSE;
|
||||
|
||||
mask = CreateBitmap(image->width, image->height, 1, 1, NULL);
|
||||
if (!mask)
|
||||
{
|
||||
DeleteObject(bitmap);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < image->width * image->height; i++, target++, source += 4)
|
||||
{
|
||||
*target = (source[3] << 24) |
|
||||
(source[0] << 16) |
|
||||
(source[1] << 8) |
|
||||
source[2];
|
||||
}
|
||||
|
||||
ZeroMemory(&ii, sizeof(ii));
|
||||
ii.fIcon = FALSE;
|
||||
ii.xHotspot = xhot;
|
||||
ii.yHotspot = yhot;
|
||||
ii.hbmMask = mask;
|
||||
ii.hbmColor = bitmap;
|
||||
|
||||
cursor->win32.handle = (HCURSOR) CreateIconIndirect(&ii);
|
||||
|
||||
DeleteObject(bitmap);
|
||||
DeleteObject(mask);
|
||||
|
||||
cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE);
|
||||
if (!cursor->win32.handle)
|
||||
return GLFW_FALSE;
|
||||
|
||||
|
12
src/window.c
12
src/window.c
@ -447,6 +447,18 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title)
|
||||
_glfwPlatformSetWindowTitle(window, title);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle,
|
||||
int count, const GLFWimage* images)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
assert(count >= 0);
|
||||
assert(count == 0 || images != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
_glfwPlatformSetWindowIcon(window, count, images);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
|
@ -383,6 +383,13 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
wl_shell_surface_set_title(window->wl.shell_surface, title);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images)
|
||||
{
|
||||
// TODO
|
||||
fprintf(stderr, "_glfwPlatformSetWindowIcon not implemented yet\n");
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
{
|
||||
// A Wayland client is not aware of its position, so just warn and leave it
|
||||
|
@ -454,6 +454,8 @@ static void detectEWMH(void)
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME");
|
||||
_glfw.x11.NET_WM_ICON_NAME =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_ICON_NAME");
|
||||
_glfw.x11.NET_WM_ICON =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_ICON");
|
||||
_glfw.x11.NET_WM_PID =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PID");
|
||||
_glfw.x11.NET_WM_PING =
|
||||
|
@ -167,6 +167,7 @@ typedef struct _GLFWlibraryX11
|
||||
Atom WM_DELETE_WINDOW;
|
||||
Atom NET_WM_NAME;
|
||||
Atom NET_WM_ICON_NAME;
|
||||
Atom NET_WM_ICON;
|
||||
Atom NET_WM_PID;
|
||||
Atom NET_WM_PING;
|
||||
Atom NET_WM_STATE;
|
||||
|
@ -1536,6 +1536,51 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
XFlush(_glfw.x11.display);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images)
|
||||
{
|
||||
if (count)
|
||||
{
|
||||
int i, j, longCount = 0;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
longCount += 2 + images[i].width * images[i].height;
|
||||
|
||||
long* icon = calloc(longCount, sizeof(long));
|
||||
long* target = icon;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
*target++ = images[i].width;
|
||||
*target++ = images[i].height;
|
||||
|
||||
for (j = 0; j < images[i].width * images[i].height; i++)
|
||||
{
|
||||
*target++ = (images[i].pixels[i * 4 + 0] << 16) |
|
||||
(images[i].pixels[i * 4 + 1] << 8) |
|
||||
(images[i].pixels[i * 4 + 2] << 0) |
|
||||
(images[i].pixels[i * 4 + 3] << 24);
|
||||
}
|
||||
}
|
||||
|
||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.NET_WM_ICON,
|
||||
XA_CARDINAL, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char*) icon,
|
||||
longCount);
|
||||
|
||||
free(icon);
|
||||
}
|
||||
else
|
||||
{
|
||||
XDeleteProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.NET_WM_ICON);
|
||||
}
|
||||
|
||||
XFlush(_glfw.x11.display);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
{
|
||||
Window child;
|
||||
|
Loading…
Reference in New Issue
Block a user