diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index d7f9174a..60898844 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -98,6 +98,7 @@ video tutorials. - IntellectualKitty - Aaron Jacobs - JannikGM + - Andreas O. Jansen - Erik S. V. Jansson - jjYBdx4IL - Toni Jovanoski diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index b7826263..a03e7d72 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3391,7 +3391,7 @@ GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* i * * @ingroup window */ -GLFWAPI void glfwSetWindowTaskbarProgress(GLFWwindow* window, const int progressState, double value); +GLFWAPI void glfwSetWindowTaskbarProgress(GLFWwindow* window, int progressState, double value); /*! @brief Retrieves the position of the content area of the specified window. * diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 2eff6a9a..cabc6424 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -649,6 +649,12 @@ int _glfwInitCocoa(void) void _glfwTerminateCocoa(void) { @autoreleasepool { + + if (_glfw.ns.dockProgressIndicator != nil) + { + [_glfw.ns.dockProgressIndicator removeFromSuperview]; + [_glfw.ns.dockProgressIndicator release]; + } if (_glfw.ns.inputSource) { diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 4323a874..59a958a5 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -189,6 +189,8 @@ typedef struct _GLFWlibraryNS PFN_LMGetKbdType GetKbdType; CFStringRef kPropertyUnicodeKeyLayoutData; } tis; + + id dockProgressIndicator; } _GLFWlibraryNS; // Cocoa-specific per-monitor data @@ -218,7 +220,7 @@ GLFWbool _glfwCreateWindowCocoa(_GLFWwindow* window, const _GLFWwndconfig* wndco void _glfwDestroyWindowCocoa(_GLFWwindow* window); void _glfwSetWindowTitleCocoa(_GLFWwindow* window, const char* title); void _glfwSetWindowIconCocoa(_GLFWwindow* window, int count, const GLFWimage* images); -void _glfwSetWindowTaskbarProgressCocoa(_GLFWwindow* window, const int taskbarState, double value); +void _glfwSetWindowTaskbarProgressCocoa(_GLFWwindow* window, int progressState, double value); void _glfwGetWindowPosCocoa(_GLFWwindow* window, int* xpos, int* ypos); void _glfwSetWindowPosCocoa(_GLFWwindow* window, int xpos, int ypos); void _glfwGetWindowSizeCocoa(_GLFWwindow* window, int* width, int* height); diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 7eaaf503..b86256ab 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1032,77 +1032,58 @@ void _glfwSetWindowIconCocoa(_GLFWwindow* window, "Cocoa: Regular windows do not have icons on macOS"); } -// TODO: potential enhancement: use float or double for higher precision than int. -// TODO: potential enhancement: also specify the source's weight. Used for calculating the combined progress. -// TODO: move static progressIndicator to _glfw.ns. Remove/release in glfwTerminate. // TODO: allow multiple windows to set values. Use the combined progress for all of them; example: [35%, 70%, 90%] => 65%. -// FIXME: Switching from INDETERMINATE to NORMAL, PAUSED or ERROR requires 2 invocations. -void _glfwSetWindowTaskbarProgressCocoa(_GLFWwindow* window, const int progressState, double value) +// TODO: documentation remarks for MacOS +void _glfwSetWindowTaskbarProgressCocoa(_GLFWwindow* window, int progressState, double value) { - static NSProgressIndicator* progressIndicator; - - _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, - "Cocoa: Window taskbar progress is not implemented"); + NSProgressIndicator* indicator = _glfw.ns.dockProgressIndicator; NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile]; - if (progressIndicator == nil) + if (indicator == nil) { if ([dockTile contentView] == nil) { NSImageView *iconView = [[NSImageView alloc] init]; [iconView setImage:[[NSApplication sharedApplication] applicationIconImage]]; [dockTile setContentView:iconView]; + [iconView release]; } NSView* contentView = [dockTile contentView]; - //progressIndicator = [[NSProgressIndicator alloc] init]; - progressIndicator = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, contentView.frame.size.width, 15.0f)]; - [progressIndicator setStyle:NSProgressIndicatorStyleBar]; - [progressIndicator setControlSize:NSControlSizeLarge]; - [progressIndicator setMinValue:0.0f]; - [progressIndicator setMaxValue:100.0f]; + indicator = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, contentView.frame.size.width, 15.0f)]; + [indicator setStyle:NSProgressIndicatorStyleBar]; + [indicator setControlSize:NSControlSizeLarge]; + [indicator setMinValue:0.0f]; + [indicator setMaxValue:1.0f]; - [progressIndicator setAccessibilityLabel:@"LABEL"]; - [progressIndicator setAccessibilityHelp:@"HELP"]; - [progressIndicator setToolTip:@"TOOLTIP"]; + [contentView addSubview:indicator]; - [contentView addSubview:progressIndicator]; - - /* - NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem:progressIndicator - attribute:NSLayoutAttributeWidth - relatedBy:NSLayoutRelationEqual - toItem:contentView - attribute:NSLayoutAttributeWidth - multiplier:1.0f - constant:0.0f]; - - [contentView addConstraint:constraint];*/ - - [progressIndicator release]; + _glfw.ns.dockProgressIndicator = indicator; } + // FIXME: Switching from INDETERMINATE to NORMAL, PAUSED or ERROR requires 2 invocations in different frames. + // In MacOS 12 (and probably other versions), an indeterminate progress bar is rendered as a normal bar + // with 0.0 progress. So when calling [progressIndicator setIndeterminate:YES], the indicator actually + // sets its doubleValue to 0.0. + // The bug is caused by NSProgressIndicator not immediately updating its value when it's increasing. + // This code illustrates the exact same problem, but this time from NORMAL, PAUSED and ERROR to INDETERMINATE: + // + // if (progressState == GLFW_TASKBAR_PROGRESS_INDETERMINATE) + // [progressIndicator setDoubleValue:0.75]; + // else + // [progressIndicator setDoubleValue:0.25]; + // + // This is likely a bug in Cocoa. + // + // FIXME: Progress increments are delayed + // What this also means, is that each time the progress increments, the bar's progress will be 1 frame delayed, + // and only updated once a higher or similar value is again set the next frame. - switch (progressState) - { - case GLFW_TASKBAR_PROGRESS_DISABLED: - [progressIndicator setIndeterminate:NO]; - [progressIndicator setHidden:YES]; - break; - case GLFW_TASKBAR_PROGRESS_INDETERMINATE: - [progressIndicator setIndeterminate:YES]; - [progressIndicator setHidden:NO]; - break; - case GLFW_TASKBAR_PROGRESS_NORMAL: - case GLFW_TASKBAR_PROGRESS_PAUSED: - case GLFW_TASKBAR_PROGRESS_ERROR: - [progressIndicator setIndeterminate:NO]; - [progressIndicator setHidden:NO]; - break; - } - [progressIndicator setDoubleValue:value]; + [indicator setIndeterminate:progressState == GLFW_TASKBAR_PROGRESS_INDETERMINATE]; + [indicator setHidden:progressState == GLFW_TASKBAR_PROGRESS_DISABLED]; + [indicator setDoubleValue:value]; [dockTile display]; } diff --git a/src/null_platform.h b/src/null_platform.h index a4e5e4ad..c430eb37 100644 --- a/src/null_platform.h +++ b/src/null_platform.h @@ -89,7 +89,7 @@ GLFWbool _glfwCreateWindowNull(_GLFWwindow* window, const _GLFWwndconfig* wndcon void _glfwDestroyWindowNull(_GLFWwindow* window); void _glfwSetWindowTitleNull(_GLFWwindow* window, const char* title); void _glfwSetWindowIconNull(_GLFWwindow* window, int count, const GLFWimage* images); -void _glfwSetWindowTaskbarProgressNull(_GLFWwindow* window, const int taskbarState, double value); +void _glfwSetWindowTaskbarProgressNull(_GLFWwindow* window, int progressState, double value); void _glfwSetWindowMonitorNull(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); void _glfwGetWindowPosNull(_GLFWwindow* window, int* xpos, int* ypos); void _glfwSetWindowPosNull(_GLFWwindow* window, int xpos, int ypos); diff --git a/src/null_window.c b/src/null_window.c index 2638827e..812c7ab3 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -187,7 +187,7 @@ void _glfwSetWindowIconNull(_GLFWwindow* window, int count, const GLFWimage* ima { } -void _glfwSetWindowTaskbarProgressNull(_GLFWwindow* window, const int progressState, double value) +void _glfwSetWindowTaskbarProgressNull(_GLFWwindow* window, int progressState, double value) { } diff --git a/src/win32_platform.h b/src/win32_platform.h index 34847e81..b84d46a3 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -618,7 +618,7 @@ GLFWbool _glfwCreateWindowWin32(_GLFWwindow* window, const _GLFWwndconfig* wndco void _glfwDestroyWindowWin32(_GLFWwindow* window); void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title); void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images); -void _glfwSetWindowTaskbarProgressWin32(_GLFWwindow* window, const int taskbarState, double value); +void _glfwSetWindowTaskbarProgressWin32(_GLFWwindow* window, int progressState, double value); void _glfwGetWindowPosWin32(_GLFWwindow* window, int* xpos, int* ypos); void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos); void _glfwGetWindowSizeWin32(_GLFWwindow* window, int* width, int* height); diff --git a/src/win32_window.c b/src/win32_window.c index 44a2ae00..e68d2839 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1596,7 +1596,7 @@ void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* im } } -void _glfwSetWindowTaskbarProgressWin32(_GLFWwindow* window, const int progressState, double value) +void _glfwSetWindowTaskbarProgressWin32(_GLFWwindow* window, int progressState, double value) { HRESULT res = S_OK; int winProgressState = 0; diff --git a/src/window.c b/src/window.c index c68b7fd6..c7aca29d 100644 --- a/src/window.c +++ b/src/window.c @@ -558,7 +558,7 @@ GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle, _glfw.platform.setWindowIcon(window, count, images); } -GLFWAPI void glfwSetWindowTaskbarProgress(GLFWwindow* handle, const int progressState, double value) +GLFWAPI void glfwSetWindowTaskbarProgress(GLFWwindow* handle, int progressState, double value) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_platform.h b/src/wl_platform.h index fabc90a2..918f232d 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -446,7 +446,7 @@ GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window, const _GLFWwndconfig* wnd void _glfwDestroyWindowWayland(_GLFWwindow* window); void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title); void _glfwSetWindowIconWayland(_GLFWwindow* window, int count, const GLFWimage* images); -void _glfwSetWindowTaskbarProgressWayland(_GLFWwindow* window, const int taskbarState, double value); +void _glfwSetWindowTaskbarProgressWayland(_GLFWwindow* window, int progressState, double value); void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos); void _glfwSetWindowPosWayland(_GLFWwindow* window, int xpos, int ypos); void _glfwGetWindowSizeWayland(_GLFWwindow* window, int* width, int* height); diff --git a/src/wl_window.c b/src/wl_window.c index f35072d5..a4460e93 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1902,11 +1902,11 @@ void _glfwSetWindowIconWayland(_GLFWwindow* window, "Wayland: The platform does not support setting the window icon"); } -void _glfwSetWindowTaskbarProgressWayland(_GLFWwindow* window, const int taskbarState, double value) +void _glfwSetWindowTaskbarProgressWayland(_GLFWwindow* window, const int progressState, double value) { (void)window; - const dbus_bool_t progressVisible = (taskbarState != GLFW_TASKBAR_PROGRESS_DISABLED); + const dbus_bool_t progressVisible = (progressState != GLFW_TASKBAR_PROGRESS_DISABLED); _glfwUpdateTaskbarProgressDBusPOSIX(progressVisible, value); } diff --git a/src/x11_platform.h b/src/x11_platform.h index 6eeeab4e..96280653 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -905,7 +905,7 @@ GLFWbool _glfwCreateWindowX11(_GLFWwindow* window, const _GLFWwndconfig* wndconf void _glfwDestroyWindowX11(_GLFWwindow* window); void _glfwSetWindowTitleX11(_GLFWwindow* window, const char* title); void _glfwSetWindowIconX11(_GLFWwindow* window, int count, const GLFWimage* images); -void _glfwSetWindowTaskbarProgressX11(_GLFWwindow* window, const int taskbarState, double value); +void _glfwSetWindowTaskbarProgressX11(_GLFWwindow* window, int progressState, double value); void _glfwGetWindowPosX11(_GLFWwindow* window, int* xpos, int* ypos); void _glfwSetWindowPosX11(_GLFWwindow* window, int xpos, int ypos); void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height); diff --git a/src/x11_window.c b/src/x11_window.c index 236ecc45..6c2297ef 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2152,11 +2152,11 @@ void _glfwSetWindowIconX11(_GLFWwindow* window, int count, const GLFWimage* imag XFlush(_glfw.x11.display); } -void _glfwSetWindowTaskbarProgressX11(_GLFWwindow* window, const int taskbarState, double value) +void _glfwSetWindowTaskbarProgressX11(_GLFWwindow* window, int progressState, double value) { (void)window; - const dbus_bool_t progressVisible = (taskbarState != GLFW_TASKBAR_PROGRESS_DISABLED); + const dbus_bool_t progressVisible = (progressState != GLFW_TASKBAR_PROGRESS_DISABLED); _glfwUpdateTaskbarProgressDBusPOSIX(progressVisible, value); } diff --git a/tests/window.c b/tests/window.c index da096f12..f36a1dda 100644 --- a/tests/window.c +++ b/tests/window.c @@ -419,28 +419,21 @@ int main(int argc, char** argv) nk_layout_row_dynamic(nk, 30, 5); static int state = GLFW_TASKBAR_PROGRESS_DISABLED; - static int progress = 0; static float progress = 0; if(nk_button_label(nk, "No progress")) - glfwSetWindowTaskbarProgress(window, state = GLFW_TASKBAR_PROGRESS_DISABLED, progress); - glfwSetWindowTaskbarProgress(window, GLFW_TASKBAR_PROGRESS_DISABLED, (double)progress); + glfwSetWindowTaskbarProgress(window, state = GLFW_TASKBAR_PROGRESS_DISABLED, (double) progress); if (nk_button_label(nk, "Indeterminate")) - glfwSetWindowTaskbarProgress(window, state = GLFW_TASKBAR_PROGRESS_INDETERMINATE, progress); - glfwSetWindowTaskbarProgress(window, GLFW_TASKBAR_PROGRESS_INDETERMINATE, (double)progress); + glfwSetWindowTaskbarProgress(window, state = GLFW_TASKBAR_PROGRESS_INDETERMINATE, (double) progress); if (nk_button_label(nk, "Normal")) - glfwSetWindowTaskbarProgress(window, state = GLFW_TASKBAR_PROGRESS_NORMAL, progress); - glfwSetWindowTaskbarProgress(window, GLFW_TASKBAR_PROGRESS_NORMAL, (double)progress); + glfwSetWindowTaskbarProgress(window, state = GLFW_TASKBAR_PROGRESS_NORMAL, (double) progress); if (nk_button_label(nk, "Error")) - glfwSetWindowTaskbarProgress(window, state = GLFW_TASKBAR_PROGRESS_ERROR, progress); - glfwSetWindowTaskbarProgress(window, GLFW_TASKBAR_PROGRESS_ERROR, (double)progress); + glfwSetWindowTaskbarProgress(window, state = GLFW_TASKBAR_PROGRESS_ERROR, (double) progress); if (nk_button_label(nk, "Paused")) - glfwSetWindowTaskbarProgress(window, state = GLFW_TASKBAR_PROGRESS_PAUSED, progress); - glfwSetWindowTaskbarProgress(window, GLFW_TASKBAR_PROGRESS_PAUSED, (double)progress); + glfwSetWindowTaskbarProgress(window, state = GLFW_TASKBAR_PROGRESS_PAUSED, (double) progress); nk_label(nk, "Progress: ", NK_TEXT_ALIGN_LEFT); - if (nk_slider_int(nk, 0, &progress, 100, 1)) - glfwSetWindowTaskbarProgress(window, state, progress); - nk_slider_float(nk, 0.0f, &progress, 1.0f, 0.05f); + if (nk_slider_float(nk, 0.0f, &progress, 1.0f, 0.05f)) + glfwSetWindowTaskbarProgress(window, state, (double) progress); } nk_end(nk);