From bd4f79646f623e929e6aa22bea028952b515aeef Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 12 Jan 2023 10:30:10 -0500 Subject: Add general string hint interface This replaces the window title and class name APIs with a more general one that can be easily extended to other things, like icon names, more detailed application hints, and so on. --- src/common.c | 60 +++++++++++++++++++++++++++++++++++++++++++++------------- src/internal.c | 17 +++++++++++++++++ src/internal.h | 5 +++++ src/mac.m | 34 ++++++++++++++++++++++----------- src/types.h | 4 ++-- src/win.c | 34 ++++++++++++++++++--------------- src/x11.c | 30 +++++++++++++++++++---------- 7 files changed, 133 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/common.c b/src/common.c index 7113461..eafb07a 100644 --- a/src/common.c +++ b/src/common.c @@ -52,7 +52,7 @@ puglNewWorld(PuglWorldType type, PuglWorldFlags flags) world->startTime = puglGetTime(world); world->type = type; - puglSetString(&world->className, "Pugl"); + puglSetString(&world->strings[PUGL_CLASS_NAME], "Pugl"); return world; } @@ -61,7 +61,11 @@ void puglFreeWorld(PuglWorld* const world) { puglFreeWorldInternals(world); - free(world->className); + + for (size_t i = 0; i < PUGL_NUM_STRING_HINTS; ++i) { + free(world->strings[i]); + } + free(world->views); free(world); } @@ -79,16 +83,26 @@ puglGetWorldHandle(PuglWorld* world) } PuglStatus -puglSetClassName(PuglWorld* const world, const char* const name) +puglSetWorldString(PuglWorld* const world, + const PuglStringHint key, + const char* const value) { - puglSetString(&world->className, name); + if ((unsigned)key < 0 || (unsigned)key >= PUGL_NUM_STRING_HINTS) { + return PUGL_BAD_PARAMETER; + } + + puglSetString(&world->strings[key], value); return PUGL_SUCCESS; } const char* -puglGetClassName(const PuglWorld* world) +puglGetWorldString(const PuglWorld* const world, const PuglStringHint key) { - return world->className; + if ((unsigned)key < 0 || (unsigned)key >= PUGL_NUM_STRING_HINTS) { + return NULL; + } + + return world->strings[key]; } static void @@ -161,7 +175,10 @@ puglFreeView(PuglView* view) } } - free(view->title); + for (size_t i = 0; i < PUGL_NUM_STRING_HINTS; ++i) { + free(view->strings[i]); + } + puglFreeViewInternals(view); free(view); } @@ -239,6 +256,29 @@ puglGetViewHint(const PuglView* view, PuglViewHint hint) return PUGL_DONT_CARE; } +PuglStatus +puglSetViewString(PuglView* const view, + const PuglStringHint key, + const char* const value) +{ + if ((unsigned)key < 0 || (unsigned)key >= PUGL_NUM_STRING_HINTS) { + return PUGL_BAD_PARAMETER; + } + + puglSetString(&view->strings[key], value); + return puglViewStringChanged(view, key, view->strings[key]); +} + +const char* +puglGetViewString(const PuglView* const view, const PuglStringHint key) +{ + if ((unsigned)key < 0 || (unsigned)key >= PUGL_NUM_STRING_HINTS) { + return NULL; + } + + return view->strings[key]; +} + PuglRect puglGetFrame(const PuglView* view) { @@ -267,12 +307,6 @@ puglGetFrame(const PuglView* view) return frame; } -const char* -puglGetWindowTitle(const PuglView* const view) -{ - return view->title; -} - PuglStatus puglSetParentWindow(PuglView* view, PuglNativeView parent) { diff --git a/src/internal.c b/src/internal.c index c607fa7..06bf416 100644 --- a/src/internal.c +++ b/src/internal.c @@ -47,6 +47,10 @@ puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len) void puglSetString(char** dest, const char* string) { + if (*dest == string) { + return; + } + const size_t len = string ? strlen(string) : 0U; if (!len) { @@ -58,6 +62,19 @@ puglSetString(char** dest, const char* string) } } +PuglStatus +puglStoreViewString(PuglView* const view, + const PuglStringHint key, + const char* const value) +{ + if ((unsigned)key >= 0 && (unsigned)key < PUGL_NUM_STRING_HINTS) { + puglSetString(&view->strings[key], value); + return PUGL_SUCCESS; + } + + return PUGL_BAD_PARAMETER; +} + uint32_t puglDecodeUTF8(const uint8_t* buf) { diff --git a/src/internal.h b/src/internal.h index 6400422..f30532b 100644 --- a/src/internal.h +++ b/src/internal.h @@ -29,6 +29,11 @@ puglSetBlob(PuglBlob* dest, const void* data, size_t len); void puglSetString(char** dest, const char* string); +/// Handle a changed string property +PUGL_API +PuglStatus +puglViewStringChanged(PuglView* view, PuglStringHint key, const char* value); + /// Return the Unicode code point for `buf` or the replacement character uint32_t puglDecodeUTF8(const uint8_t* buf); diff --git a/src/mac.m b/src/mac.m index 945063a..a0b2017 100644 --- a/src/mac.m +++ b/src/mac.m @@ -1286,10 +1286,11 @@ puglRealize(PuglView* view) impl->window = window; [window setContentSize:framePt.size]; - if (view->title) { + const char* const title = view->strings[PUGL_WINDOW_TITLE]; + if (title) { NSString* titleString = - [[NSString alloc] initWithBytes:view->title - length:strlen(view->title) + [[NSString alloc] initWithBytes:title + length:strlen(title) encoding:NSUTF8StringEncoding]; [window setTitle:titleString]; @@ -1656,17 +1657,28 @@ puglGetNativeView(PuglView* view) } PuglStatus -puglSetWindowTitle(PuglView* view, const char* title) +puglViewStringChanged(PuglView* const view, + const PuglStringHint key, + const char* const value) { - puglSetString(&view->title, title); + if (!view->impl->window) { + return PUGL_SUCCESS; + } - if (view->impl->window) { - NSString* titleString = - [[NSString alloc] initWithBytes:title - length:strlen(title) - encoding:NSUTF8StringEncoding]; + switch (key) { + case PUGL_CLASS_NAME: + return PUGL_UNSUPPORTED; - [view->impl->window setTitle:titleString]; + case PUGL_WINDOW_TITLE: + if (view->impl->window) { + NSString* const titleString = + [[NSString alloc] initWithBytes:value + length:strlen(value) + encoding:NSUTF8StringEncoding]; + + [view->impl->window setTitle:titleString]; + } + break; } return PUGL_SUCCESS; diff --git a/src/types.h b/src/types.h index 12e4acf..9817474 100644 --- a/src/types.h +++ b/src/types.h @@ -53,12 +53,12 @@ struct PuglViewImpl { PuglInternals* impl; PuglHandle handle; PuglEventFunc eventFunc; - char* title; PuglNativeView parent; uintptr_t transientParent; PuglConfigureEvent lastConfigure; PuglHints hints; PuglViewSize sizeHints[PUGL_NUM_SIZE_HINTS]; + char* strings[PUGL_NUM_STRING_HINTS]; int defaultX; int defaultY; PuglViewStage stage; @@ -69,10 +69,10 @@ struct PuglViewImpl { struct PuglWorldImpl { PuglWorldInternals* impl; PuglWorldHandle handle; - char* className; double startTime; size_t numViews; PuglView** views; + char* strings[PUGL_NUM_STRING_HINTS]; PuglWorldType type; }; diff --git a/src/win.c b/src/win.c index b3ecf7f..db3f98c 100644 --- a/src/win.c +++ b/src/win.c @@ -269,7 +269,7 @@ puglRealize(PuglView* view) view->hints[PUGL_REFRESH_RATE] = (int)devMode.dmDisplayFrequency; // Register window class if necessary - if (!puglRegisterWindowClass(view->world->className)) { + if (!puglRegisterWindowClass(view->world->strings[PUGL_CLASS_NAME])) { return PUGL_REGISTRATION_FAILED; } @@ -280,7 +280,7 @@ puglRealize(PuglView* view) } // Set basic window hints and attributes - puglSetWindowTitle(view, view->title ? view->title : ""); + puglSetViewString(view, PUGL_WINDOW_TITLE, view->strings[PUGL_WINDOW_TITLE]); puglSetTransientParent(view, view->transientParent); view->impl->scaleFactor = puglWinGetViewScaleFactor(view); @@ -370,7 +370,7 @@ puglFreeViewInternals(PuglView* view) void puglFreeWorldInternals(PuglWorld* world) { - UnregisterClass(world->className, NULL); + UnregisterClass(world->strings[PUGL_CLASS_NAME], NULL); free(world->impl); } @@ -1153,12 +1153,16 @@ puglGetNativeView(PuglView* view) } PuglStatus -puglSetWindowTitle(PuglView* view, const char* title) +puglViewStringChanged(PuglView* const view, + const PuglStringHint key, + const char* const value) { - puglSetString(&view->title, title); + if (!view->impl->hwnd) { + return PUGL_SUCCESS; + } - if (view->impl->hwnd) { - wchar_t* wtitle = puglUtf8ToWideChar(title); + if (key == PUGL_WINDOW_TITLE) { + wchar_t* const wtitle = puglUtf8ToWideChar(value); if (wtitle) { SetWindowTextW(view->impl->hwnd, wtitle); free(wtitle); @@ -1548,19 +1552,19 @@ puglWinCreateWindow(PuglView* const view, HWND* const hwnd, HDC* const hdc) { - const char* className = (const char*)view->world->className; - const unsigned winFlags = puglWinGetWindowFlags(view); - const unsigned winExFlags = puglWinGetWindowExFlags(view); - const PuglRect frame = getInitialFrame(view); + const char* className = (const char*)view->world->strings[PUGL_CLASS_NAME]; // The meaning of "parent" depends on the window type (WS_CHILD) PuglNativeView parent = view->parent ? view->parent : view->transientParent; // Calculate initial window rectangle - RECT wr = {(long)frame.x, - (long)frame.y, - (long)frame.x + frame.width, - (long)frame.y + frame.height}; + const unsigned winFlags = puglWinGetWindowFlags(view); + const unsigned winExFlags = puglWinGetWindowExFlags(view); + const PuglRect frame = getInitialFrame(view); + RECT wr = {(long)frame.x, + (long)frame.y, + (long)frame.x + frame.width, + (long)frame.y + frame.height}; AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags); // Create window and get drawing context diff --git a/src/x11.c b/src/x11.c index 2511632..b4f68a7 100644 --- a/src/x11.c +++ b/src/x11.c @@ -625,9 +625,10 @@ puglRealize(PuglView* const view) #endif // Set basic window hints and attributes - XClassHint classHint = {world->className, world->className}; + char* const className = world->strings[PUGL_CLASS_NAME]; + XClassHint classHint = {className, className}; XSetClassHint(display, impl->win, &classHint); - puglSetWindowTitle(view, view->title ? view->title : ""); + puglSetViewString(view, PUGL_WINDOW_TITLE, view->strings[PUGL_WINDOW_TITLE]); puglSetTransientParent(view, view->transientParent); updateSizeHints(view); @@ -1881,23 +1882,32 @@ puglGetNativeView(PuglView* const view) } PuglStatus -puglSetWindowTitle(PuglView* const view, const char* const title) +puglViewStringChanged(PuglView* const view, + const PuglStringHint key, + const char* const value) { - Display* display = view->world->impl->display; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; + Display* const display = view->world->impl->display; + const PuglX11Atoms* atoms = &view->world->impl->atoms; + + if (!view->impl->win) { + return PUGL_SUCCESS; + } - puglSetString(&view->title, title); + switch (key) { + case PUGL_CLASS_NAME: + break; - if (view->impl->win) { - XStoreName(display, view->impl->win, title); + case PUGL_WINDOW_TITLE: + XStoreName(display, view->impl->win, value); XChangeProperty(display, view->impl->win, atoms->NET_WM_NAME, atoms->UTF8_STRING, 8, PropModeReplace, - (const uint8_t*)title, - (int)strlen(title)); + (const uint8_t*)value, + (int)strlen(value)); + break; } return PUGL_SUCCESS; -- cgit v1.2.1