From b632fef3b13dc082acbbbd8aaf6898c663da1c0b Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 5 Nov 2014 13:35:39 -0500 Subject: [PATCH] Implemented TextField.ReadOnly() on Mac OS X. Began standardizing window class name access on Windows. --- basicctrls_darwin.m | 12 ++++++++++++ common_windows.c | 4 ++-- objc_darwin.h | 2 ++ textfield_darwin.go | 10 ++++++++++ uitask_windows.c | 11 ++--------- winapi_windows.h | 7 +++++++ 6 files changed, 35 insertions(+), 11 deletions(-) diff --git a/basicctrls_darwin.m b/basicctrls_darwin.m index 873882e..b91862e 100644 --- a/basicctrls_darwin.m +++ b/basicctrls_darwin.m @@ -136,6 +136,7 @@ id newTextField(void) NSTextField *t; t = [[NSTextField alloc] initWithFrame:NSZeroRect]; + [t setSelectable:YES]; // otherwise the setting is masked by the editable default of YES return finishNewTextField((id) t, YES); } @@ -144,6 +145,7 @@ id newPasswordField(void) NSSecureTextField *t; t = [[NSSecureTextField alloc] initWithFrame:NSZeroRect]; + [t setSelectable:YES]; // otherwise the setting is masked by the editable default of YES return finishNewTextField((id) t, YES); } @@ -184,6 +186,16 @@ void textfieldCloseInvalidPopover(id popover) // don't release; close does that already } +BOOL textfieldEditable(id textfield) +{ + return [toNSTextField(textfield) isEditable]; +} + +void textfieldSetEditable(id textfield, BOOL editable) +{ + [toNSTextField(textfield) setEditable:editable]; +} + id newLabel(void) { NSTextField *l; diff --git a/common_windows.c b/common_windows.c index 207b691..9e67a0c 100644 --- a/common_windows.c +++ b/common_windows.c @@ -100,7 +100,7 @@ void paintControlBackground(HWND hwnd, HDC dc) HWND parent; RECT r; POINT p, pOrig; - WCHAR classname[128] = L""; // more than enough to avoid collisions + WCHAR classname[maxClassName + 1] = L""; parent = hwnd; for (;;) { @@ -110,7 +110,7 @@ void paintControlBackground(HWND hwnd, HDC dc) // wine sends these messages early, yay... if (parent == msgwin) return; - if (GetClassNameW(parent, classname, 128) == 0) + if (GetClassNameW(parent, classname, maxClassName) == 0) xpanic("error getting name of focused window class in paintControlBackground()", GetLastError()); // skip groupboxes; they're (supposed to be) transparent if (_wcsicmp(classname, L"button") != 0) diff --git a/objc_darwin.h b/objc_darwin.h index 7ed69d1..e8b7752 100644 --- a/objc_darwin.h +++ b/objc_darwin.h @@ -75,6 +75,8 @@ extern const char *textfieldText(id); extern void textfieldSetText(id, char *); extern id textfieldOpenInvalidPopover(id, char *); extern void textfieldCloseInvalidPopover(id); +extern BOOL textfieldEditable(id); +extern void textfieldSetEditable(id, BOOL); extern id newLabel(void); extern id newGroup(id); extern const char *groupText(id); diff --git a/textfield_darwin.go b/textfield_darwin.go index bf63073..c61a1b9 100644 --- a/textfield_darwin.go +++ b/textfield_darwin.go @@ -62,6 +62,16 @@ func (t *textfield) Invalid(reason string) { t.invalid = C.textfieldOpenInvalidPopover(t.id, creason) } +// note that the property here is editable, which is the opposite of read-only + +func (t *textfield) ReadOnly() bool { + return !fromBOOL(C.textfieldEditable(t.id)) +} + +func (t *textfield) SetReadOnly(readonly bool) { + C.textfieldSetEditable(t.id, toBOOL(!readonly)) +} + //export textfieldChanged func textfieldChanged(data unsafe.Pointer) { t := (*textfield)(data) diff --git a/uitask_windows.c b/uitask_windows.c index dec6ed2..49937c9 100644 --- a/uitask_windows.c +++ b/uitask_windows.c @@ -3,10 +3,6 @@ #include "winapi_windows.h" #include "_cgo_export.h" -// note that this includes the terminating '\0' -// this also assumes WC_TABCONTROL is longer than areaWindowClass -#define NCLASSNAME (sizeof WC_TABCONTROL / sizeof WC_TABCONTROL[0]) - void uimsgloop_area(HWND active, HWND focus, MSG *msg) { MSG copy; @@ -63,7 +59,7 @@ void uimsgloop(void) MSG msg; int res; HWND active, focus; - WCHAR classchk[NCLASSNAME]; + WCHAR classchk[maxClassName + 1]; BOOL dodlgmessage; for (;;) { @@ -82,12 +78,9 @@ void uimsgloop(void) // bit of logic involved here: // we don't want dialog messages passed into Areas, so we don't call IsDialogMessageW() there // as for Tabs, we can't have both WS_TABSTOP and WS_EX_CONTROLPARENT set at the same time, so we hotswap the two styles to get the behavior we want - // theoretically we could use the class atom to avoid a wcscmp() - // however, raymond chen advises against this - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/11/240744.aspx (and we're not in control of the Tab class, before you say anything) - // we could also theoretically just send msgAreaDefocuses directly, but what DefWindowProc() does to a WM_APP message is undocumented focus = GetFocus(); if (focus != NULL) { - if (GetClassNameW(focus, classchk, NCLASSNAME) == 0) + if (GetClassNameW(focus, classchk, maxClassName) == 0) xpanic("error getting name of focused window class for Area check", GetLastError()); if (_wcsicmp(classchk, areaWindowClass) == 0) { uimsgloop_area(active, focus, &msg); diff --git a/winapi_windows.h b/winapi_windows.h index 9642397..db3b49e 100644 --- a/winapi_windows.h +++ b/winapi_windows.h @@ -41,6 +41,13 @@ enum { msgOpenFileDone, }; +// there are a number of places where we need to know what window class an arbitrary handle has +// theoretically we could use the class atom to avoid a _wcsicmp() +// however, raymond chen advises against this - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/11/240744.aspx (and we're not in control of the Tab class, before you say anything) +// MSDN says 256 is the maximum length of a class name; add a few characters just to be safe (because it doesn't say whether this includes the terminating null character) +// TODO localize this to a helper function +#define maxClassName 260 + // uitask_windows.c extern void uimsgloop(void); extern void issue(void *);