mirror of
https://github.com/glfw/glfw.git
synced 2025-10-03 13:20:58 +00:00
Added window icon API and Win32 implementation.
This commit is contained in:
parent
acaddf9cd9
commit
4de19165c0
@ -62,6 +62,7 @@ GLFW bundles a number of dependencies in the `deps/` directory.
|
||||
|
||||
## Changelog
|
||||
|
||||
- Added `glfwSetWindowIcons` for setting window icons
|
||||
- Changed minimum required CMake version to 2.8.12
|
||||
- Bugfix: Initialization failed on headless systems
|
||||
- Bugfix: The cached current context could get out of sync
|
||||
@ -171,6 +172,7 @@ skills.
|
||||
- Arturo J. Pérez
|
||||
- Emmanuel Gil Peyrot
|
||||
- Cyril Pichard
|
||||
- Orson Peters
|
||||
- Pieroman
|
||||
- Jorge Rodriguez
|
||||
- Ed Ropple
|
||||
|
@ -1916,6 +1916,24 @@ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height)
|
||||
*/
|
||||
GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom);
|
||||
|
||||
/*! @brief Sets the application icons to use for the given window.
|
||||
* @param[in] window The window to set the icons for.
|
||||
* @param[in] icons A pointer to the first element of an array of GLFWimage structs.
|
||||
* @param[in] numicons The number of icons in the given array.
|
||||
* @ingroup window
|
||||
*
|
||||
* @note This function may only be called from the main thread.
|
||||
*
|
||||
* @note From all the given icons GLFW will automatically pick the most appropriate
|
||||
* size for the different locations in which the application icon can occur. For
|
||||
* example on Windows, if a larger and a smaller icon are given the larger icon
|
||||
* will be used for the ALT-TAB screen and the smaller for the taskbar.
|
||||
*
|
||||
* @note If the icon does not exactly fit the operating systems requirements for the
|
||||
* icon size the icon will be automatically resized.
|
||||
*/
|
||||
GLFWAPI void glfwSetWindowIcons(GLFWwindow* window, GLFWimage* icons, int numicons);
|
||||
|
||||
/*! @brief Iconifies the specified window.
|
||||
*
|
||||
* This function iconifies (minimizes) the specified window if it was
|
||||
|
@ -1042,6 +1042,11 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
*bottom = contentRect.origin.y - frameRect.origin.y;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcons(_GLFWwindow* window, GLFWimage *icons, int numicons)
|
||||
{
|
||||
/* TODO: implement this */
|
||||
}
|
||||
|
||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||
{
|
||||
[window->ns.object miniaturize:nil];
|
||||
|
@ -539,6 +539,11 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh
|
||||
*/
|
||||
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom);
|
||||
|
||||
/*! @copydoc glfwSetWindowIcons
|
||||
* @ingroup platform
|
||||
*/
|
||||
void _glfwPlatformSetWindowIcons(_GLFWwindow* window, GLFWimage* icons, int numicons);
|
||||
|
||||
/*! @copydoc glfwIconifyWindow
|
||||
* @ingroup platform
|
||||
*/
|
||||
|
@ -727,6 +727,136 @@ static void destroyWindow(_GLFWwindow* window)
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a Windows icon from a GLFWimage
|
||||
//
|
||||
static HICON createIcon(GLFWimage* image)
|
||||
{
|
||||
BITMAPV5HEADER header;
|
||||
HDC hdc;
|
||||
unsigned char* BGRAData;
|
||||
HBITMAP bitmap, mask;
|
||||
ICONINFO iconinfo;
|
||||
HICON icon;
|
||||
unsigned char* dibData;
|
||||
int i;
|
||||
|
||||
// fill in BITMAPV5HEADER to pass to CreateDIBSection
|
||||
header.bV5Size = sizeof(header);
|
||||
header.bV5Width = image->width;
|
||||
header.bV5Height = image->height;
|
||||
header.bV5Planes = 1;
|
||||
header.bV5BitCount = 32;
|
||||
header.bV5Compression = BI_BITFIELDS;
|
||||
header.bV5RedMask = 0x00ff0000;
|
||||
header.bV5GreenMask = 0x0000ff00;
|
||||
header.bV5BlueMask = 0x000000ff;
|
||||
header.bV5AlphaMask = 0xff000000;
|
||||
|
||||
// create a HBITMAP that we can write to
|
||||
hdc = GetDC(NULL);
|
||||
bitmap = CreateDIBSection(hdc, (BITMAPINFO*) &header, DIB_RGB_COLORS, (void**) &dibData, NULL, 0);
|
||||
ReleaseDC(NULL, hdc);
|
||||
|
||||
// first we need to convert RGBA to BGRA (yay Windows!)
|
||||
// we also need to convert lines, because Windows wants bottom-to-top RGBA
|
||||
BGRAData = malloc(image->width * image->height * 4);
|
||||
if (!BGRAData)
|
||||
{
|
||||
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < image->width * image->height; i++) {
|
||||
unsigned char *dst = BGRAData + 4 * i;
|
||||
unsigned char *src = image->pixels + 4 * i;
|
||||
|
||||
dst[0] = src[2]; // copy blue channel
|
||||
dst[1] = src[1]; // copy green channel
|
||||
dst[2] = src[0]; // copy red channel
|
||||
dst[3] = src[3]; // copy alpha channel
|
||||
}
|
||||
|
||||
// copy the BGRA data into dibData
|
||||
memcpy(dibData, BGRAData, image->width * image->height * 4);
|
||||
|
||||
// free the BGRA data
|
||||
free(BGRAData);
|
||||
|
||||
// create a mask that we don't use (but needed for iconinfo)
|
||||
mask = CreateBitmap(image->width, image->height, 1, 1, NULL);
|
||||
|
||||
iconinfo.fIcon = TRUE;
|
||||
iconinfo.hbmMask = mask;
|
||||
iconinfo.hbmColor = bitmap;
|
||||
|
||||
// create our icon
|
||||
icon = CreateIconIndirect(&iconinfo);
|
||||
|
||||
// clean up
|
||||
DeleteObject(mask);
|
||||
DeleteObject(bitmap);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
// Chooses the best fitting image given the images and desired size
|
||||
//
|
||||
static GLFWimage* bestFit(GLFWimage *icons, const int numicons, const int targetWidth, const int targetHeight)
|
||||
{
|
||||
GLFWimage *curIcon = icons;
|
||||
GLFWimage *bestIcon = curIcon;
|
||||
const double targetRatio = (double) targetWidth / targetHeight;
|
||||
|
||||
while (curIcon < icons + numicons)
|
||||
{
|
||||
// always use exact match
|
||||
if (curIcon->width == targetWidth && curIcon->height == targetHeight)
|
||||
{
|
||||
return curIcon;
|
||||
}
|
||||
|
||||
// at least wide or high enough, ratio preferably as close as possible
|
||||
if (curIcon->width >= targetWidth || curIcon->height >= targetHeight)
|
||||
{
|
||||
const double curRatio = (double) curIcon->width / curIcon->height;
|
||||
const double bestRatio = (double) bestIcon->width / bestIcon->height;
|
||||
double curDelta = targetRatio - curRatio;
|
||||
double bestDelta = targetRatio - bestRatio;
|
||||
|
||||
if (curDelta < 0)
|
||||
{
|
||||
curDelta = -curDelta;
|
||||
}
|
||||
|
||||
if (bestDelta < 0)
|
||||
{
|
||||
bestDelta = -bestDelta;
|
||||
}
|
||||
|
||||
// if our ratio is closer OR if the best icon so far isn't large
|
||||
// enough we'll become the new best icon
|
||||
if ((curDelta < bestDelta)
|
||||
|| (bestIcon->width < targetWidth && bestIcon->height < targetHeight))
|
||||
{
|
||||
bestIcon = curIcon;
|
||||
}
|
||||
}
|
||||
|
||||
// maybe nothing is wide or high enough, if that's the case
|
||||
// we'll get the largest thing available (in area)
|
||||
else if (bestIcon->width < targetWidth && bestIcon->height < targetHeight)
|
||||
{
|
||||
if (curIcon->width * curIcon->height > bestIcon->width * bestIcon->height)
|
||||
{
|
||||
bestIcon = curIcon;
|
||||
}
|
||||
}
|
||||
|
||||
++curIcon;
|
||||
}
|
||||
|
||||
return bestIcon;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
@ -929,6 +1059,18 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
*bottom = rect.bottom - height;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcons(_GLFWwindow* window, GLFWimage *icons, int numicons)
|
||||
{
|
||||
GLFWimage* normalicon;
|
||||
GLFWimage* smallicon;
|
||||
|
||||
normalicon = bestFit(icons, numicons, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
|
||||
smallicon = bestFit(icons, numicons, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
|
||||
|
||||
SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) createIcon(normalicon));
|
||||
SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) createIcon(smallicon));
|
||||
}
|
||||
|
||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||
{
|
||||
ShowWindow(window->win32.handle, SW_MINIMIZE);
|
||||
|
13
src/window.c
13
src/window.c
@ -513,6 +513,19 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle,
|
||||
_glfwPlatformGetWindowFrameSize(window, left, top, right, bottom);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetWindowIcons(GLFWwindow* handle, GLFWimage* icons, int numicons)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (numicons < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_glfwPlatformSetWindowIcons(window, icons, numicons);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwIconifyWindow(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
|
@ -1645,6 +1645,11 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
XFree(extents);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcons(_GLFWwindow* window, GLFWimage *icons, int numicons)
|
||||
{
|
||||
/* TODO: implement this */
|
||||
}
|
||||
|
||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||
{
|
||||
if (window->x11.overrideRedirect)
|
||||
|
@ -42,6 +42,9 @@ set_target_properties(accuracy PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Accuracy")
|
||||
add_executable(empty WIN32 MACOSX_BUNDLE empty.c ${TINYCTHREAD})
|
||||
set_target_properties(empty PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Empty Event")
|
||||
|
||||
add_executable(icons WIN32 MACOSX_BUNDLE icons.c)
|
||||
set_target_properties(icons PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Icons")
|
||||
|
||||
add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c)
|
||||
set_target_properties(sharing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Sharing")
|
||||
|
||||
@ -60,7 +63,8 @@ set_target_properties(windows PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Windows")
|
||||
target_link_libraries(empty "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}")
|
||||
target_link_libraries(threads "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}")
|
||||
|
||||
set(WINDOWS_BINARIES accuracy empty sharing tearing threads title windows cursoranim)
|
||||
set(WINDOWS_BINARIES accuracy empty icons sharing tearing threads title windows
|
||||
cursoranim)
|
||||
set(CONSOLE_BINARIES clipboard defaults events msaa gamma glfwinfo
|
||||
iconify joysticks monitors peter reopen cursor)
|
||||
|
||||
|
151
tests/icons.c
Normal file
151
tests/icons.c
Normal file
@ -0,0 +1,151 @@
|
||||
//========================================================================
|
||||
// Window icon test program
|
||||
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.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.
|
||||
//
|
||||
//========================================================================
|
||||
//
|
||||
// This program is used to test the icon feature.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// a simple glfw logo
|
||||
const char * const logo[] = {
|
||||
"................",
|
||||
"................",
|
||||
"...0000..0......",
|
||||
"...0.....0......",
|
||||
"...0.00..0......",
|
||||
"...0..0..0......",
|
||||
"...0000..0000...",
|
||||
"................",
|
||||
"................",
|
||||
"...000..0...0...",
|
||||
"...0....0...0...",
|
||||
"...000..0.0.0...",
|
||||
"...0....0.0.0...",
|
||||
"...0....00000...",
|
||||
"................",
|
||||
"................"
|
||||
};
|
||||
|
||||
const unsigned char icon_colors[5][4] = {
|
||||
{0x00, 0x00, 0x00, 0xff}, // black
|
||||
{0xff, 0x00, 0x00, 0xff}, // red
|
||||
{0x00, 0xff, 0x00, 0xff}, // green
|
||||
{0xff, 0x00, 0xff, 0xff}, // blue
|
||||
{0xff, 0xff, 0xff, 0xff} // white
|
||||
};
|
||||
|
||||
static int cur_icon_color = 0;
|
||||
|
||||
static void set_icon(GLFWwindow* window, int icon_color) {
|
||||
GLFWimage img;
|
||||
int x, y;
|
||||
char* pixels;
|
||||
|
||||
// create image
|
||||
img.width = 16;
|
||||
img.height = 16;
|
||||
pixels = malloc(img.width * img.height * 4);
|
||||
|
||||
if (!pixels)
|
||||
{
|
||||
glfwTerminate();
|
||||
|
||||
fprintf(stderr, "Failed to allocate memory.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (x = 0; x < 16; ++x)
|
||||
{
|
||||
for (y = 0; y < 16; ++y)
|
||||
{
|
||||
// 15 - y because we need to flip the icon
|
||||
if (logo[15 - y][x] == '0')
|
||||
memcpy(pixels + 4 * (x + y * img.width), icon_colors[icon_color], 4);
|
||||
else
|
||||
memset(pixels + 4 * (x + y * img.width), 0, 4); // transparency
|
||||
}
|
||||
}
|
||||
|
||||
img.pixels = pixels;
|
||||
|
||||
glfwSetWindowIcons(window, &img, 1);
|
||||
}
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
|
||||
if (action != GLFW_PRESS)
|
||||
return;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case GLFW_KEY_ESCAPE:
|
||||
glfwDestroyWindow(window);
|
||||
break;
|
||||
case GLFW_KEY_SPACE:
|
||||
cur_icon_color = (cur_icon_color + 1) % 5;
|
||||
set_icon(window, cur_icon_color);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
GLFWwindow* window;
|
||||
|
||||
if (!glfwInit())
|
||||
{
|
||||
fprintf(stderr, "Failed to initialize GLFW\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
window = glfwCreateWindow(800, 600, "Icons", NULL, NULL);
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
|
||||
fprintf(stderr, "Failed to open GLFW window\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
set_icon(window, cur_icon_color);
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
glfwTerminate();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue
Block a user