From e34c561ed5bedeb180437ec165882b98d70d38c1 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Thu, 16 Apr 2015 20:33:28 -0400 Subject: [PATCH] Split the rewrite into a new repository. --- README.md | 4 + new/GNUmakefile | 62 ------ new/TODO.md | 27 --- new/darwin/GNUmakeinc.mk | 19 -- new/darwin/alloc.m | 44 ---- new/darwin/button.m | 86 -------- new/darwin/checkbox.m | 107 ---------- new/darwin/entry.m | 73 ------- new/darwin/init.m | 67 ------ new/darwin/label.m | 59 ------ new/darwin/main.m | 27 --- new/darwin/newcontrol.m | 231 -------------------- new/darwin/parent.m | 118 ----------- new/darwin/tab.m | 73 ------- new/darwin/text.m | 19 -- new/darwin/uipriv_darwin.h | 40 ---- new/darwin/util.m | 20 -- new/darwin/window.m | 162 -------------- new/leaks.awk | 56 ----- new/parentplan | 57 ----- new/stack.c | 398 ----------------------------------- new/test.c | 337 ----------------------------- new/ui.idl | 161 -------------- new/ui_darwin.h | 25 --- new/ui_unix.h | 20 -- new/ui_windows.h | 59 ------ new/uipriv.h | 10 - new/unix/GNUmakeinc.mk | 18 -- new/unix/alloc.c | 33 --- new/unix/button.c | 71 ------- new/unix/checkbox.c | 95 --------- new/unix/entry.c | 45 ---- new/unix/init.c | 23 -- new/unix/label.c | 49 ----- new/unix/main.c | 23 -- new/unix/newcontrol.c | 225 -------------------- new/unix/parent.c | 183 ---------------- new/unix/tab.c | 61 ------ new/unix/uipriv_unix.h | 14 -- new/unix/util.c | 7 - new/unix/window.c | 137 ------------ new/windows/GNUmakeinc.mk | 33 --- new/windows/alloc.c | 49 ----- new/windows/button.c | 112 ---------- new/windows/checkbox.c | 129 ------------ new/windows/comctl32.c | 105 --------- new/windows/debug.c | 111 ---------- new/windows/entry.c | 69 ------ new/windows/init.c | 112 ---------- new/windows/label.c | 73 ------- new/windows/main.c | 56 ----- new/windows/newcontrol.c | 237 --------------------- new/windows/parent.c | 268 ----------------------- new/windows/tab.c | 190 ----------------- new/windows/text.c | 55 ----- new/windows/uipriv_windows.h | 69 ------ new/windows/util.c | 73 ------- new/windows/window.c | 216 ------------------- 58 files changed, 4 insertions(+), 5298 deletions(-) delete mode 100644 new/GNUmakefile delete mode 100644 new/TODO.md delete mode 100644 new/darwin/GNUmakeinc.mk delete mode 100644 new/darwin/alloc.m delete mode 100644 new/darwin/button.m delete mode 100644 new/darwin/checkbox.m delete mode 100644 new/darwin/entry.m delete mode 100644 new/darwin/init.m delete mode 100644 new/darwin/label.m delete mode 100644 new/darwin/main.m delete mode 100644 new/darwin/newcontrol.m delete mode 100644 new/darwin/parent.m delete mode 100644 new/darwin/tab.m delete mode 100644 new/darwin/text.m delete mode 100644 new/darwin/uipriv_darwin.h delete mode 100644 new/darwin/util.m delete mode 100644 new/darwin/window.m delete mode 100644 new/leaks.awk delete mode 100644 new/parentplan delete mode 100644 new/stack.c delete mode 100644 new/test.c delete mode 100644 new/ui.idl delete mode 100644 new/ui_darwin.h delete mode 100644 new/ui_unix.h delete mode 100644 new/ui_windows.h delete mode 100644 new/uipriv.h delete mode 100644 new/unix/GNUmakeinc.mk delete mode 100644 new/unix/alloc.c delete mode 100644 new/unix/button.c delete mode 100644 new/unix/checkbox.c delete mode 100644 new/unix/entry.c delete mode 100644 new/unix/init.c delete mode 100644 new/unix/label.c delete mode 100644 new/unix/main.c delete mode 100644 new/unix/newcontrol.c delete mode 100644 new/unix/parent.c delete mode 100644 new/unix/tab.c delete mode 100644 new/unix/uipriv_unix.h delete mode 100644 new/unix/util.c delete mode 100644 new/unix/window.c delete mode 100644 new/windows/GNUmakeinc.mk delete mode 100644 new/windows/alloc.c delete mode 100644 new/windows/button.c delete mode 100644 new/windows/checkbox.c delete mode 100644 new/windows/comctl32.c delete mode 100644 new/windows/debug.c delete mode 100644 new/windows/entry.c delete mode 100644 new/windows/init.c delete mode 100644 new/windows/label.c delete mode 100644 new/windows/main.c delete mode 100644 new/windows/newcontrol.c delete mode 100644 new/windows/parent.c delete mode 100644 new/windows/tab.c delete mode 100644 new/windows/text.c delete mode 100644 new/windows/uipriv_windows.h delete mode 100644 new/windows/util.c delete mode 100644 new/windows/window.c diff --git a/README.md b/README.md index 428be480..ce5d158e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # ui: platform-native GUI library for Go +## NOTE + +ui is currently being rewritten for stability. The guts of the package will now be in C. For progress updates, see [the new repo for the C backend](https://github.com/andlabs/libui/). + ## Feature requests wanted! (Really; IDK what to add next!) This is a library that aims to provide simple GUI software development in Go. It runs on/requires: diff --git a/new/GNUmakefile b/new/GNUmakefile deleted file mode 100644 index 457efe40..00000000 --- a/new/GNUmakefile +++ /dev/null @@ -1,62 +0,0 @@ -# 15 april 2015 - -OBJDIR = .obj - -# MAME does this so :/ -ifeq ($(OS),Windows_NT) -OS = windows -endif - -ifndef OS -UNAME = $(shell uname -s) -ifeq ($(UNAME),Darwin) -OS = darwin -else -OS = unix -endif -endif - -CFILES = \ - stack.c \ - test.c -HFILES = \ - ui.h \ - uipriv.h \ - ui_$(OS).h \ - $(OS)/uipriv_$(OS).h - -xCFLAGS = \ - -g \ - -Wall -Wextra \ - -Wno-unused-parameter \ - --std=c99 \ - $(CFLAGS) -xLDFLAGS = \ - -g \ - $(LDFLAGS) - -include $(OS)/GNUmakeinc.mk -xOSCFILES = $(OSCFILES:%=$(OS)/%) -xOSMFILES = $(OSMFILES:%=$(OS)/%) - -OFILES = $(CFILES:%.c=$(OBJDIR)/%.o) \ - $(xOSCFILES:$(OS)/%.c=$(OBJDIR)/%_$(OS).o) \ - $(xOSMFILES:$(OS)/%.m=$(OBJDIR)/%_$(OS).o) - -$(OUT): $(OFILES) - $(CC) -o $(OUT) $(OFILES) $(xLDFLAGS) - -$(OBJDIR)/%.o: %.c $(OBJDIR) $(HFILES) - $(CC) -o $@ -c $< $(xCFLAGS) - -$(OBJDIR)/%_$(OS).o: $(OS)/%.c $(OBJDIR) $(HFILES) - $(CC) -o $@ -c $< $(xCFLAGS) - -$(OBJDIR)/%_$(OS).o: $(OS)/%.m $(OBJDIR) $(HFILES) - $(CC) -o $@ -c $< $(xCFLAGS) - -$(OBJDIR): - mkdir -p $(OBJDIR) - -ui.h: ui.idl - idl2h < ui.idl > ui.h diff --git a/new/TODO.md b/new/TODO.md deleted file mode 100644 index d3004f0c..00000000 --- a/new/TODO.md +++ /dev/null @@ -1,27 +0,0 @@ -- change all private names to uipXxxx -- make it so Windows API calls that do logLastError(), etc. abort whatever they're doing and not try to continue, just like wintable -- figure out what to cleanup in darwin terminate: - - delegate - - deleted objects view -- assign control IDs on windows - - GWL(P)_ID - - related? [12:25] And the blue outline on those buttons [ALL clicked buttons on Windows 7] won't go away - - I get this too -- make sure all terminology is consistent -- 32-bit Mac OS X support (requires lots of code changes) -- add a test for hidden controls when a window is shown -- SWP_NOCOPYBITS (or was it WS_CLIPCHILDREN?) - - buttons not in tab get drawover issues - - buttons in tab without transparent drawing code get copied into the label when stack shown and rehidden -- see if we can clean up the backends - - rename all method implementations to typeMethod - - especially clean up the Darwin backend - -ultimately: -- make everything vtable-based - - provide macros for the vtables - - figure out where updateParent() plays into this - - figure out what to do about custom containers - - rename container to parent? - - make the code flow of all platforms fully symmetrical -- add some sort of runtime type checking diff --git a/new/darwin/GNUmakeinc.mk b/new/darwin/GNUmakeinc.mk deleted file mode 100644 index 22ca1e3e..00000000 --- a/new/darwin/GNUmakeinc.mk +++ /dev/null @@ -1,19 +0,0 @@ -OSMFILES = \ - alloc.m \ - button.m \ - checkbox.m \ - entry.m \ - init.m \ - label.m \ - main.m \ - newcontrol.m \ - parent.m \ - tab.m \ - text.m \ - util.m \ - window.m - -xCFLAGS += -mmacosx-version-min=10.7 -DMACOSX_DEPLOYMENT_TARGET=10.7 -xLDFLAGS += -mmacosx-version-min=10.7 -lobjc -framework Foundation -framework AppKit - -OUT = new diff --git a/new/darwin/alloc.m b/new/darwin/alloc.m deleted file mode 100644 index 8f539af7..00000000 --- a/new/darwin/alloc.m +++ /dev/null @@ -1,44 +0,0 @@ -// 4 december 2014 -#import -#import "uipriv_darwin.h" - -void *uiAlloc(size_t size, const char *type) -{ - void *out; - - out = malloc(size); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiAlloc() allocating %s\n", type); - abort(); - } - memset(out, 0, size); - if (options.debugLogAllocations) - fprintf(stderr, "%p alloc %s\n", out, type); - return out; -} - -void *uiRealloc(void *p, size_t size, const char *type) -{ - void *out; - - if (p == NULL) - return uiAlloc(size, type); - out = realloc(p, size); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiRealloc() reallocating %s\n", type); - abort(); - } - // TODO zero the extra memory - if (options.debugLogAllocations) - fprintf(stderr, "%p realloc %p\n", p, out); - return out; -} - -void uiFree(void *p) -{ - if (p == NULL) - return; - free(p); - if (options.debugLogAllocations) - fprintf(stderr, "%p free\n", p); -} diff --git a/new/darwin/button.m b/new/darwin/button.m deleted file mode 100644 index 3ec8a549..00000000 --- a/new/darwin/button.m +++ /dev/null @@ -1,86 +0,0 @@ -// 7 april 2015 -#import "uipriv_darwin.h" - -@interface uiNSButton : NSButton -@property uiButton *uiB; -@property void (*uiOnClicked)(uiButton *, void *); -@property void *uiOnClickedData; -@end - -@implementation uiNSButton - -- (void)viewDidMoveToSuperview -{ - if (uiDarwinControlFreeWhenAppropriate(uiControl(self.uiB), [self superview])) { - [self setTarget:nil]; - self.uiB = NULL; - } - [super viewDidMoveToSuperview]; -} - -- (IBAction)uiButtonClicked:(id)sender -{ - (*(self.uiOnClicked))(self.uiB, self.uiOnClickedData); -} - -@end - -static void defaultOnClicked(uiButton *c, void *data) -{ - // do nothing -} - -static char *buttonText(uiButton *bb) -{ - uiNSButton *b; - - b = (uiNSButton *) uiControlHandle(uiControl(bb)); - return uiDarwinNSStringToText([b title]); -} - -static void buttonSetText(uiButton *bb, const char *text) -{ - uiNSButton *b; - - b = (uiNSButton *) uiControlHandle(uiControl(bb)); - [b setTitle:toNSString(text)]; -} - -static void buttonOnClicked(uiButton *bb, void (*f)(uiButton *, void *), void *data) -{ - uiNSButton *b; - - b = (uiNSButton *) uiControlHandle(uiControl(bb)); - b.uiOnClicked = f; - b.uiOnClickedData = data; -} - -uiButton *uiNewButton(const char *text) -{ - uiButton *b; - uiNSButton *bb; - - b = uiNew(uiButton); - - uiDarwinNewControl(uiControl(b), [uiNSButton class], NO, NO); - bb = (uiNSButton *) uiControlHandle(uiControl(b)); - - [bb setTitle:toNSString(text)]; - [bb setButtonType:NSMomentaryPushInButton]; - [bb setBordered:YES]; - [bb setBezelStyle:NSRoundedBezelStyle]; - setStandardControlFont((NSControl *) bb); - - [bb setTarget:bb]; - [bb setAction:@selector(uiButtonClicked:)]; - - bb.uiOnClicked = defaultOnClicked; - - uiButton(b)->Text = buttonText; - uiButton(b)->SetText = buttonSetText; - uiButton(b)->OnClicked = buttonOnClicked; - - bb.uiB = b; - - return bb.uiB; -} diff --git a/new/darwin/checkbox.m b/new/darwin/checkbox.m deleted file mode 100644 index a7ccfb33..00000000 --- a/new/darwin/checkbox.m +++ /dev/null @@ -1,107 +0,0 @@ -// 7 april 2015 -#import "uipriv_darwin.h" - -@interface uiCheckboxNSButton : NSButton -@property uiCheckbox *uiC; -@property void (*uiOnToggled)(uiCheckbox *, void *); -@property void *uiOnToggledData; -@end - -@implementation uiCheckboxNSButton - -- (void)viewDidMoveToSuperview -{ - if (uiDarwinControlFreeWhenAppropriate(uiControl(self.uiC), [self superview])) { - [self setTarget:nil]; - self.uiC = NULL; - } - [super viewDidMoveToSuperview]; -} - -- (IBAction)uiCheckboxToggled:(id)sender -{ - (*(self.uiOnToggled))(self.uiC, self.uiOnToggledData); -} - -@end - -static void defaultOnToggled(uiCheckbox *c, void *data) -{ - // do nothing -} - -static char *checkboxText(uiCheckbox *c) -{ - uiCheckboxNSButton *cc; - - cc = (uiCheckboxNSButton *) uiControlHandle(uiControl(c)); - return uiDarwinNSStringToText([cc title]); -} - -static void checkboxSetText(uiCheckbox *c, const char *text) -{ - uiCheckboxNSButton *cc; - - cc = (uiCheckboxNSButton *) uiControlHandle(uiControl(c)); - [cc setTitle:toNSString(text)]; -} - -static void checkboxOnToggled(uiCheckbox *c, void (*f)(uiCheckbox *, void *), void *data) -{ - uiCheckboxNSButton *cc; - - cc = (uiCheckboxNSButton *) uiControlHandle(uiControl(c)); - cc.uiOnToggled = f; - cc.uiOnToggledData = data; -} - -static int checkboxChecked(uiCheckbox *c) -{ - uiCheckboxNSButton *cc; - - cc = (uiCheckboxNSButton *) uiControlHandle(uiControl(c)); - return [cc state] == NSOnState; -} - -static void checkboxSetChecked(uiCheckbox *c, int checked) -{ - uiCheckboxNSButton *cc; - NSInteger state; - - cc = (uiCheckboxNSButton *) uiControlHandle(uiControl(c)); - state = NSOnState; - if (!checked) - state = NSOffState; - [cc setState:state]; -} - -uiCheckbox *uiNewCheckbox(const char *text) -{ - uiCheckbox *c; - uiCheckboxNSButton *cc; - - c = uiNew(uiCheckbox); - - uiDarwinNewControl(uiControl(c), [uiCheckboxNSButton class], NO, NO); - cc = (uiCheckboxNSButton *) uiControlHandle(uiControl(c)); - - [cc setTitle:toNSString(text)]; - [cc setButtonType:NSSwitchButton]; - [cc setBordered:NO]; - setStandardControlFont((NSControl *) cc); - - [cc setTarget:cc]; - [cc setAction:@selector(uiCheckboxToggled:)]; - - cc.uiOnToggled = defaultOnToggled; - - uiCheckbox(c)->Text = checkboxText; - uiCheckbox(c)->SetText = checkboxSetText; - uiCheckbox(c)->OnToggled = checkboxOnToggled; - uiCheckbox(c)->Checked = checkboxChecked; - uiCheckbox(c)->SetChecked = checkboxSetChecked; - - cc.uiC = c; - - return cc.uiC; -} diff --git a/new/darwin/entry.m b/new/darwin/entry.m deleted file mode 100644 index 71891562..00000000 --- a/new/darwin/entry.m +++ /dev/null @@ -1,73 +0,0 @@ -// 9 april 2015 -#import "uipriv_darwin.h" - -@interface uiNSTextField : NSTextField -@property uiEntry *uiE; -@end - -@implementation uiNSTextField - -- (void)viewDidMoveToSuperview -{ - if (uiDarwinControlFreeWhenAppropriate(uiControl(self.uiE), [self superview])) { - [self setTarget:nil]; - self.uiE = NULL; - } - [super viewDidMoveToSuperview]; -} - -@end - -static char *entryText(uiEntry *e) -{ - uiNSTextField *t; - - t = (uiNSTextField *) uiControlHandle(uiControl(e)); - return uiDarwinNSStringToText([t stringValue]); -} - -static void entrySetText(uiEntry *e, const char *text) -{ - uiNSTextField *t; - - t = (uiNSTextField *) uiControlHandle(uiControl(e)); - [t setStringValue:toNSString(text)]; -} - -// TOOD move elsewhere -// these are based on interface builder defaults; my comments in the old code weren't very good so I don't really know what talked about what, sorry :/ -void finishNewTextField(NSTextField *t, BOOL isEntry) -{ - setStandardControlFont((id) t); - - // THE ORDER OF THESE CALLS IS IMPORTANT; CHANGE IT AND THE BORDERS WILL DISAPPEAR - [t setBordered:NO]; - [t setBezelStyle:NSTextFieldSquareBezel]; - [t setBezeled:isEntry]; - - // we don't need to worry about substitutions/autocorrect here; see window_darwin.m for details - - [[t cell] setLineBreakMode:NSLineBreakByClipping]; - [[t cell] setScrollable:YES]; -} - -uiEntry *uiNewEntry(void) -{ - uiEntry *e; - uiNSTextField *t; - - e = uiNew(uiEntry); - - uiDarwinNewControl(uiControl(e), [uiNSTextField class], NO, NO); - t = (uiNSTextField *) uiControlHandle(uiControl(e)); - - [t setSelectable:YES]; // otherwise the setting is masked by the editable default of YES - finishNewTextField((NSTextField *) t, YES); - - uiEntry(e)->Text = entryText; - uiEntry(e)->SetText = entrySetText; - - t.uiE = e; - - return t.uiE; -} diff --git a/new/darwin/init.m b/new/darwin/init.m deleted file mode 100644 index 4f14a0a6..00000000 --- a/new/darwin/init.m +++ /dev/null @@ -1,67 +0,0 @@ -// 6 april 2015 -#import "uipriv_darwin.h" - -@interface uiApplication : NSApplication -@end - -@implementation uiApplication - -// hey look! we're overriding terminate:! -// we're going to make sure we can go back to main() whether Cocoa likes it or not! -// and just how are we going to do that, hm? -// (note: this is called after applicationShouldTerminate:) -- (void)terminate:(id)sender -{ - // yes that's right folks: DO ABSOLUTELY NOTHING. - // the magic is [NSApp run] will just... stop. - - // for debugging - NSLog(@"in terminate:"); -} - -@end - -@interface uiAppDelegate : NSObject -@end - -@implementation uiAppDelegate - -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app -{ - // for debugging - NSLog(@"in applicationShouldTerminate:"); - return NSTerminateNow; -} - -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app -{ - return NO; -} - -@end - -// we are not in control of the actual lifetimes and refcounts of NSViews (see http://stackoverflow.com/a/29523141/3408572) -// when we're done with a view, it'll be added as a subview of this one, and this one will be released on application shutdown -// we need this separate view because it's possible for controls to have no parent but still be alive -NSView *destroyedControlsView; - -uiInitOptions options; - -const char *uiInit(uiInitOptions *o) -{ - options = *o; - [uiApplication sharedApplication]; - // don't check for a NO return; something (launch services?) causes running from application bundles to always return NO when asking to change activation policy, even if the change is to the same activation policy! - // see https://github.com/andlabs/ui/issues/6 - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - [NSApp setDelegate:[uiAppDelegate new]]; - - // we can use a stock NSView for this - destroyedControlsView = [[NSView alloc] initWithFrame:NSZeroRect]; - - return NULL; -} - -void uiFreeInitError(const char *err) -{ -} diff --git a/new/darwin/label.m b/new/darwin/label.m deleted file mode 100644 index 56780d01..00000000 --- a/new/darwin/label.m +++ /dev/null @@ -1,59 +0,0 @@ -// 9 april 2015 -#import "uipriv_darwin.h" - -@interface uiLabelNSTextField : NSTextField -@property uiLabel *uiL; -@end - -@implementation uiLabelNSTextField - -- (void)viewDidMoveToSuperview -{ - if (uiDarwinControlFreeWhenAppropriate(uiControl(self.uiL), [self superview])) { - [self setTarget:nil]; - self.uiL = NULL; - } - [super viewDidMoveToSuperview]; -} - -@end - -static char *labelText(uiLabel *l) -{ - uiLabelNSTextField *t; - - t = (uiLabelNSTextField *) uiControlHandle(uiControl(l)); - return uiDarwinNSStringToText([t stringValue]); -} - -static void labelSetText(uiLabel *l, const char *text) -{ - uiLabelNSTextField *t; - - t = (uiLabelNSTextField *) uiControlHandle(uiControl(l)); - [t setStringValue:toNSString(text)]; -} - -uiLabel *uiNewLabel(const char *text) -{ - uiLabel *l; - uiLabelNSTextField *t; - - l = uiNew(uiLabel); - - uiDarwinNewControl(uiControl(l), [uiLabelNSTextField class], NO, NO); - t = (uiLabelNSTextField *) uiControlHandle(uiControl(l)); - - [t setStringValue:toNSString(text)]; - [t setEditable:NO]; - [t setSelectable:NO]; - [t setDrawsBackground:NO]; - finishNewTextField((NSTextField *) t, NO); - - uiLabel(l)->Text = labelText; - uiLabel(l)->SetText = labelSetText; - - t.uiL = l; - - return t.uiL; -} diff --git a/new/darwin/main.m b/new/darwin/main.m deleted file mode 100644 index 8663b58c..00000000 --- a/new/darwin/main.m +++ /dev/null @@ -1,27 +0,0 @@ -// 6 april 2015 -#import "uipriv_darwin.h" - -// #qo LDFLAGS: -lobjc -framework Foundation -framework AppKit - -void uiMain(void) -{ - [NSApp run]; -} - -void uiQuit(void) -{ - NSEvent *e; - - [NSApp stop:NSApp]; - // stop: won't register until another event has passed; let's synthesize one - e = [NSEvent otherEventWithType:NSApplicationDefined - location:NSZeroPoint - modifierFlags:0 - timestamp:[[NSProcessInfo processInfo] systemUptime] - windowNumber:0 - context:[NSGraphicsContext currentContext] - subtype:0 - data1:0 - data2:0]; - [NSApp postEvent:e atStart:NO]; // let pending events take priority (this is what PostQuitMessage() on Windows does so we have to do it here too for parity; thanks to mikeash in irc.freenode.net/#macdev for confirming that this parameter should indeed be NO) -} diff --git a/new/darwin/newcontrol.m b/new/darwin/newcontrol.m deleted file mode 100644 index 12967c53..00000000 --- a/new/darwin/newcontrol.m +++ /dev/null @@ -1,231 +0,0 @@ -// 7 april 2015 -#include "uipriv_darwin.h" - -typedef struct singleView singleView; - -struct singleView { - NSView *view; - NSScrollView *scrollView; - NSView *immediate; // the control that is added to the parent container; either view or scrollView - uiParent *parent; - BOOL userHid; - BOOL containerHid; - BOOL userDisabled; - BOOL containerDisabled; -}; - -static void singleDestroy(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - [destroyedControlsView addSubview:s->immediate]; -} - -static uintptr_t singleHandle(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - return (uintptr_t) (s->view); -} - -static void singleSetParent(uiControl *c, uiParent *parent) -{ - singleView *s = (singleView *) (c->Internal); - NSView *parentView; - uiParent *oldparent; - - oldparent = s->parent; - s->parent = parent; - if (oldparent != NULL) { - [s->immediate removeFromSuperview]; - uiParentUpdate(oldparent); - } - if (s->parent != NULL) { - // TODO uiControlView(), uiParentView() - parentView = (NSView *) uiParentHandle(s->parent); - [parentView addSubview:s->immediate]; - uiParentUpdate(s->parent); - } -} - -// also good for NSBox and NSProgressIndicator -static void singlePreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - singleView *s = (singleView *) (c->Internal); - NSControl *control; - NSRect r; - - control = (NSControl *) (s->view); - [control sizeToFit]; - // use alignmentRect here instead of frame because we'll be resizing based on that - r = [control alignmentRectForFrame:[control frame]]; - *width = (intmax_t) r.size.width; - *height = (intmax_t) r.size.height; -} - -static void singleResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) -{ - singleView *s = (singleView *) (c->Internal); - NSRect frame; - - frame.origin.x = x; - // mac os x coordinate system has (0,0) in the lower-left - frame.origin.y = ([[s->immediate superview] bounds].size.height - height) - y; - frame.size.width = width; - frame.size.height = height; - frame = [s->immediate frameForAlignmentRect:frame]; - [s->immediate setFrame:frame]; -} - -static int singleVisible(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - if (s->userHid) - return 0; - return 1; -} - -static void singleShow(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - s->userHid = NO; - if (!s->containerHid) { - [s->immediate setHidden:NO]; - if (s->parent != NULL) - uiParentUpdate(s->parent); - } -} - -static void singleHide(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - s->userHid = YES; - [s->immediate setHidden:YES]; - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void singleContainerShow(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - s->containerHid = NO; - if (!s->userHid) { - [s->immediate setHidden:NO]; - if (s->parent != NULL) - uiParentUpdate(s->parent); - } -} - -static void singleContainerHide(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - s->containerHid = YES; - [s->immediate setHidden:YES]; - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void enable(singleView *s) -{ - if ([s->view respondsToSelector:@selector(setEnabled:)]) - [((NSControl *) (s->view)) setEnabled:YES]; -} - -static void disable(singleView *s) -{ - if ([s->view respondsToSelector:@selector(setEnabled:)]) - [((NSControl *) (s->view)) setEnabled:NO]; -} - -static void singleEnable(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - s->userDisabled = NO; - if (!s->containerDisabled) - enable(s); -} - -static void singleDisable(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - s->userDisabled = YES; - disable(s); -} - -static void singleContainerEnable(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - s->containerDisabled = NO; - if (!s->userDisabled) - enable(s); -} - -static void singleContainerDisable(uiControl *c) -{ - singleView *s = (singleView *) (c->Internal); - - s->containerDisabled = YES; - disable(s); -} - -void uiDarwinNewControl(uiControl *c, Class class, BOOL inScrollView, BOOL scrollViewHasBorder) -{ - singleView *s; - - s = uiNew(singleView); - // thanks to autoxr and arwyn in irc.freenode.net/#macdev - s->view = (NSView *) [[class alloc] initWithFrame:NSZeroRect]; - s->immediate = s->view; - - if (inScrollView) { - s->scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect]; - [s->scrollView setDocumentView:s->view]; - [s->scrollView setHasHorizontalScroller:YES]; - [s->scrollView setHasVerticalScroller:YES]; - [s->scrollView setAutohidesScrollers:YES]; - if (scrollViewHasBorder) - [s->scrollView setBorderType:NSBezelBorder]; - else - [s->scrollView setBorderType:NSNoBorder]; - s->immediate = (NSView *) (s->scrollView); - } - - // and keep a reference to s->immediate for when we remove the control from its parent - [s->immediate retain]; - - c->Internal = s; - c->Destroy = singleDestroy; - c->Handle = singleHandle; - c->SetParent = singleSetParent; - c->PreferredSize = singlePreferredSize; - c->Resize = singleResize; - c->Visible = singleVisible; - c->Show = singleShow; - c->Hide = singleHide; - c->ContainerShow = singleContainerShow; - c->ContainerHide = singleContainerHide; - c->Enable = singleEnable; - c->Disable = singleDisable; - c->ContainerEnable = singleContainerEnable; - c->ContainerDisable = singleContainerDisable; -} - -BOOL uiDarwinControlFreeWhenAppropriate(uiControl *c, NSView *newSuperview) -{ - singleView *s = (singleView *) (c->Internal); - - if (newSuperview == destroyedControlsView) { - [s->immediate release]; // we don't need the reference anymore - uiFree(s); - return YES; - } - return NO; -} diff --git a/new/darwin/parent.m b/new/darwin/parent.m deleted file mode 100644 index abf0e590..00000000 --- a/new/darwin/parent.m +++ /dev/null @@ -1,118 +0,0 @@ -// 4 august 2014 -#import "uipriv_darwin.h" - -// calling -[className] on the content views of NSWindow, NSTabItem, and NSBox all return NSView, so I'm assuming I just need to override these -// fornunately: -// - NSWindow resizing calls -[setFrameSize:] (but not -[setFrame:]) -// - NSTabView resizing calls both -[setFrame:] and -[setFrameSIze:] on the current tab -// - NSTabView switching tabs calls both -[setFrame:] and -[setFrameSize:] on the new tab -// so we just override setFrameSize: -// thanks to mikeash and JtRip in irc.freenode.net/#macdev -@interface uipParent : NSView { -// TODO -@public - uiControl *child; - intmax_t marginLeft; - intmax_t marginTop; - intmax_t marginRight; - intmax_t marginBottom; -} -- (void)uiUpdateNow; -@end - -@implementation uipParent - -uiLogObjCClassAllocations - -- (void)viewDidMoveToSuperview -{ - // we can't just use nil because NSTabView will set page views to nil when they're tabbed away - // this means that we have to explicitly move them to the destroyed controls view when we're done with them, and likewise in NSWindow - if ([self superview] == destroyedControlsView) - if (self->child != NULL) { - uiControlDestroy(self->child); - self->child = NULL; - [self release]; - } - [super viewDidMoveToSuperview]; -} - -- (void)setFrameSize:(NSSize)s -{ - [super setFrameSize:s]; - [self uiUpdateNow]; -} - -// These are based on measurements from Interface Builder. -// These seem to be based on Auto Layout constants, but I don't see an API that exposes these... -// This one is 8 for most pairs of controls that I've tried; the only difference is between two pushbuttons, where it's 12... -#define macXPadding 8 -// Likewise, this one appears to be 12 for pairs of push buttons... -#define macYPadding 8 - -- (void)uiUpdateNow -{ - uiSizing d; - intmax_t x, y, width, height; - - if (self->child == NULL) - return; - x = [self bounds].origin.x + self->marginLeft; - y = [self bounds].origin.y + self->marginTop; - width = [self bounds].size.width - (self->marginLeft + self->marginRight); - height = [self bounds].size.height - (self->marginTop + self->marginBottom); - d.xPadding = macXPadding; - d.yPadding = macYPadding; - uiControlResize(self->child, x, y, width, height, &d); -} - -@end - -static uintptr_t parentHandle(uiParent *p) -{ - uipParent *pp = (uipParent *) (p->Internal); - - return (uintptr_t) pp; -} - -static void parentSetChild(uiParent *p, uiControl *child) -{ - uipParent *pp = (uipParent *) (p->Internal); - - pp->child = child; - if (pp->child != NULL) - uiControlSetParent(child, p); -} - -static void parentSetMargins(uiParent *p, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom) -{ - uipParent *pp = (uipParent *) (p->Internal); - - pp->marginLeft = left; - pp->marginTop = top; - pp->marginRight = right; - pp->marginBottom = bottom; -} - -static void parentUpdate(uiParent *p) -{ - uipParent *pp = (uipParent *) (p->Internal); - - [pp uiUpdateNow]; -} - -uiParent *uiNewParent(uintptr_t osParent) -{ - uiParent *p; - - p = uiNew(uiParent); - p->Internal = [[uipParent alloc] initWithFrame:NSZeroRect]; - p->Handle = parentHandle; - p->SetChild = parentSetChild; - p->SetMargins = parentSetMargins; - p->Update = parentUpdate; - // don't use osParent; we'll need to call specific selectors to set the parent view - // and keep the view alive so we can release it properly later - [((uipParent *) (p->Internal)) retain]; - return p; -} \ No newline at end of file diff --git a/new/darwin/tab.m b/new/darwin/tab.m deleted file mode 100644 index b84ee9af..00000000 --- a/new/darwin/tab.m +++ /dev/null @@ -1,73 +0,0 @@ -// 12 april 2015 -#import "uipriv_darwin.h" - -// TODO -// - verify margins against extra space around the tab -// - free child containers properly - -@interface uiNSTabView : NSTabView -@property uiTab *uiT; -@end - -@implementation uiNSTabView - -- (void)viewDidMoveToSuperview -{ - // TODO free all tabs explicitly - if (uiDarwinControlFreeWhenAppropriate(uiControl(self.uiT), [self superview])) - self.uiT = NULL; - [super viewDidMoveToSuperview]; -} - -@end - -// the default new control implementation uses -sizeToFit, which we don't have with NSTabView -// fortunately, we do have -minimumSize -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - uiNSTabView *tv; - NSSize s; - - tv = (uiNSTabView *) uiControlHandle(c); - s = [tv minimumSize]; - *width = (intmax_t) (s.width); - *height = (intmax_t) (s.height); -} - -static void tabAddPage(uiTab *t, const char *name, uiControl *child) -{ - uiNSTabView *tv; - uiParent *content; - NSTabViewItem *i; - - content = uiNewParent(0); - uiParentSetChild(content, child); - - i = [[NSTabViewItem alloc] initWithIdentifier:nil]; - [i setLabel:toNSString(name)]; - [i setView:((NSView *) uiParentHandle(content))]; - tv = (uiNSTabView *) uiControlHandle(uiControl(t)); - [tv addTabViewItem:i]; -} - -uiTab *uiNewTab(void) -{ - uiTab *t; - uiNSTabView *tv; - - t = uiNew(uiTab); - - uiDarwinNewControl(uiControl(t), [uiNSTabView class], NO, NO); - tv = (uiNSTabView *) uiControlHandle(uiControl(t)); - - // also good for NSTabView (same selector and everything) - setStandardControlFont((NSControl *) tv); - - uiControl(t)->PreferredSize = preferredSize; - - uiTab(t)->AddPage = tabAddPage; - - tv.uiT = t; - - return tv.uiT; -} diff --git a/new/darwin/text.m b/new/darwin/text.m deleted file mode 100644 index f0d3dab6..00000000 --- a/new/darwin/text.m +++ /dev/null @@ -1,19 +0,0 @@ -// 10 april 2015 -#import "uipriv_darwin.h" - -char *uiDarwinNSStringToText(NSString *s) -{ - char *out; - - out = strdup([s UTF8String]); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiDarwinNSStringToText()\n"); - abort(); - } - return out; -} - -void uiFreeText(char *s) -{ - free(s); -} diff --git a/new/darwin/uipriv_darwin.h b/new/darwin/uipriv_darwin.h deleted file mode 100644 index 36de1f12..00000000 --- a/new/darwin/uipriv_darwin.h +++ /dev/null @@ -1,40 +0,0 @@ -// 6 january 2015 -#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_7 -#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_7 -#import -#import "../uipriv.h" -#import "../ui_darwin.h" - -#define toNSString(str) [NSString stringWithUTF8String:(str)] -#define fromNSString(str) [(str) UTF8String] - -#define uiLogObjCClassAllocations \ -+ (id)alloc \ -{ \ - id thing; \ - thing = [super alloc]; \ - if (options.debugLogAllocations) \ - fprintf(stderr, "%p alloc %s\n", thing, [[self className] UTF8String]); \ - return thing; \ -} \ -- (void)dealloc \ -{ \ - [super dealloc]; \ - if (options.debugLogAllocations) \ - fprintf(stderr, "%p free\n", self); \ -} - -// init_darwin.m -extern NSView *destroyedControlsView; - -// util_darwin.m -extern void setStandardControlFont(NSControl *); -extern void disableAutocorrect(NSTextView *); - -// These are based on measurements from Interface Builder. -// These seem to be based on Auto Layout constants, but I don't see an API that exposes these... -#define macXMargin 20 -#define macYMargin 20 - -// entry_darwin.m -extern void finishNewTextField(NSTextField *, BOOL); diff --git a/new/darwin/util.m b/new/darwin/util.m deleted file mode 100644 index 906a0ead..00000000 --- a/new/darwin/util.m +++ /dev/null @@ -1,20 +0,0 @@ -// 7 april 2015 -#import "uipriv_darwin.h" - -// also fine for NSCells and NSTexts (NSTextViews) -void setStandardControlFont(NSControl *control) -{ - [control setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]]; -} - -void disableAutocorrect(NSTextView *tv) -{ - [tv setEnabledTextCheckingTypes:0]; - [tv setAutomaticDashSubstitutionEnabled:NO]; - // don't worry about automatic data detection; it won't change stringValue (thanks pretty_function in irc.freenode.net/#macdev) - [tv setAutomaticSpellingCorrectionEnabled:NO]; - [tv setAutomaticTextReplacementEnabled:NO]; - [tv setAutomaticQuoteSubstitutionEnabled:NO]; - [tv setAutomaticLinkDetectionEnabled:NO]; - [tv setSmartInsertDeleteEnabled:NO]; -} diff --git a/new/darwin/window.m b/new/darwin/window.m deleted file mode 100644 index c243374a..00000000 --- a/new/darwin/window.m +++ /dev/null @@ -1,162 +0,0 @@ -// 6 april 2015 -#import "uipriv_darwin.h" - -// TODO -// - free chilld containers properly - -@interface uiWindowDelegate : NSObject -@property (assign) NSWindow *w; -@property uiParent *content; -@property int (*onClosing)(uiWindow *, void *); -@property void *onClosingData; -@property struct window *uiw; -@end - -@implementation uiWindowDelegate - -uiLogObjCClassAllocations - -- (BOOL)windowShouldClose:(id)win -{ - // return exact constants to be safe - if ((*(self.onClosing))(uiWindow(self.uiw), self.onClosingData)) - return YES; - return NO; -} - -// after this method returns we assume the window will be released (see below), so we can go too -- (void)windowWillClose:(NSNotification *)note -{ - [self.w setDelegate:nil]; // see http://stackoverflow.com/a/29523141/3408572 - - // when we reach this point, we need to ensure that all the window's children are destroyed (for OS parity) - // because we need to set the content view's superview to the destroyed controls view to trigger deletion, we need to do this manually - // first, replace the current content view... - [self.w setContentView:[[NSView alloc] initWithFrame:NSZeroRect]]; - // ...then, trigger the deletion - [destroyedControlsView addSubview:((NSView *) uiParentHandle(self.content))]; - - uiFree(self.uiw); - [self release]; -} - -@end - -struct window { - uiWindow w; - uiWindowDelegate *d; - int margined; -}; - -static int defaultOnClosing(uiWindow *w, void *data) -{ - return 1; -} - -#define D (((struct window *) w)->d) - -static void windowDestroy(uiWindow *w) -{ - [D.w close]; -} - -static uintptr_t windowHandle(uiWindow *w) -{ - return (uintptr_t) (D.w); -} - -static char *windowTitle(uiWindow *w) -{ - return uiDarwinNSStringToText([D.w title]); -} - -static void windowSetTitle(uiWindow *w, const char *title) -{ - [D.w setTitle:toNSString(title)]; -} - -static void windowShow(uiWindow *w) -{ - [D.w makeKeyAndOrderFront:D.w]; -} - -static void windowHide(uiWindow *w) -{ - [D.w orderOut:D.w]; -} - -static void windowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data) -{ - D.onClosing = f; - D.onClosingData = data; -} - -static void windowSetChild(uiWindow *w, uiControl *c) -{ - uiParentSetChild(D.content, c); -} - -static int windowMargined(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - return w->margined; -} - -static void windowSetMargined(uiWindow *ww, int margined) -{ - struct window *w = (struct window *) ww; - - w->margined = margined; - if (w->margined) - uiParentSetMargins(D.content, macXMargin, macYMargin, macXMargin, macYMargin); - else - uiParentSetMargins(D.content, 0, 0, 0, 0); - uiParentUpdate(D.content); -} - -uiWindow *uiNewWindow(const char *title, int width, int height) -{ - uiWindowDelegate *d; - - d = [uiWindowDelegate new]; - - d.w = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, (CGFloat) width, (CGFloat) height) - styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) - backing:NSBackingStoreBuffered - defer:YES]; - [d.w setTitle:toNSString(title)]; - - // we do not want substitutions - // text fields, labels, etc. take their smart quotes and other autocorrect settings from their parent window, which provides a shared "field editor" - // so we have to turn them off here - // thanks akempgen in irc.freenode.net/#macdev - // for some reason, this selector returns NSText but is documented to return NSTextView... - // NOTE: if you disagree with me about disabling substitutions, start a github issue with why and I'll be happy to consider it - disableAutocorrect((NSTextView *) [d.w fieldEditor:YES forObject:nil]); - - // this is what will destroy the window on close - [d.w setReleasedWhenClosed:YES]; - - d.content = uiNewParent(0); - [d.w setContentView:((NSView *) uiParentHandle(d.content))]; - - d.onClosing = defaultOnClosing; - [d.w setDelegate:d]; - - d.uiw = uiNew(struct window); - d.uiw->d = d; - - uiWindow(d.uiw)->Destroy = windowDestroy; - uiWindow(d.uiw)->Handle = windowHandle; - uiWindow(d.uiw)->Title = windowTitle; - uiWindow(d.uiw)->SetTitle = windowSetTitle; - uiWindow(d.uiw)->Show = windowShow; - uiWindow(d.uiw)->Hide = windowHide; - uiWindow(d.uiw)->OnClosing = windowOnClosing; - uiWindow(d.uiw)->SetChild = windowSetChild; - uiWindow(d.uiw)->Margined = windowMargined; - uiWindow(d.uiw)->SetMargined = windowSetMargined; - - return uiWindow(d.uiw); -} diff --git a/new/leaks.awk b/new/leaks.awk deleted file mode 100644 index 1d19ea88..00000000 --- a/new/leaks.awk +++ /dev/null @@ -1,56 +0,0 @@ -# 7 april 2015 - -$2 == "alloc" { - if ($1 in A) { - problem($1 " already allocated (" A[$1] "); allocated at " NR) - next - } - A[$1] = type() - next -} - -$2 == "realloc" { - if (!($1 in A)) { - problem($1 " not yet allocated; reallocated at " NR) - next - } - if ($3 in A) { - problem($3 " already allocated (" A[$3] "); reallocated at " NR) - next - } - t = A[$1] - delete A[$1] - A[$3] = t - next -} - -$2 == "free" { - if (!($1 in A)) { - problem($1 " not yet allocated; freed at " NR) - next - } - delete A[$1] - next -} - -{ problem("unrecognized line " $0 " at " NR) } - -END { - for (i in A) - problem("leaked " A[i] " at " i) - close("/dev/stderr") - if (hasProblems) - exit 1 -} - -function problem(s) { - print s > "/dev/stderr" - hasProblems = 1 -} - -function type( s, i) { - s = $3 - for (i = 4; i <= NF; i++) - s = s " " $i - return s -} diff --git a/new/parentplan b/new/parentplan deleted file mode 100644 index 83c581e0..00000000 --- a/new/parentplan +++ /dev/null @@ -1,57 +0,0 @@ -current situation - -let's say the control hierarchy is -w window - p parent -c stack - d stack - e button - f button - g button -h button -i entry - -w = NewWindow() - p = NewParent(w.Handle) -w.SetChild(c) - p.SetChild(c) - c.SetParent(p) - d.SetParent(p) - e.SetParent(p) - f.SetParent(p) - g.SetParent(p) - p.Update() - c.Resize() -c.Add(h) - h.SetParent(p) - p.Update() - c.Resize() -d.Remove(1) - f.SetParent(NULL) - p.Update() - c.Resize() -g.Hide() - p.Update() - c.Resize() -w.SetChild(i) - p.SetChild(i) - c.SetParent(NULL) - d.SetParent(NULL) - ... - i.SetParent(p) - ... - p.Update() - i.Resize() -w.SetChild(NULL) - p.SetChild(NULL) - i.SetParent(NULL) - p.Update() -w.SetChild(i) - (again) -w.Destroy() - p.Destroy() - i.Destroy() - -TODO -- rename these methods -- p.DeferUpdate()/p.EndDeferUpdate() diff --git a/new/stack.c b/new/stack.c deleted file mode 100644 index 8a3906f2..00000000 --- a/new/stack.c +++ /dev/null @@ -1,398 +0,0 @@ -// 7 april 2015 -#include "uipriv.h" - -// TODO -// - rename to uiBox - -typedef struct stack stack; -typedef struct stackControl stackControl; - -struct stack { - uiStack s; - stackControl *controls; - uintmax_t len; - uintmax_t cap; - int vertical; - uiParent *parent; - int padded; - int userHid; - int containerHid; - int userDisabled; - int containerDisabled; -}; - -struct stackControl { - uiControl *c; - int stretchy; - intmax_t width; // both used by resize(); preallocated to save time and reduce risk of failure - intmax_t height; -}; - -static void stackDestroy(uiControl *c) -{ - stack *s = (stack *) c; - uintmax_t i; - - for (i = 0; i < s->len; i++) - uiControlDestroy(s->controls[i].c); - uiFree(s->controls); - uiFree(s); -} - -static uintptr_t stackHandle(uiControl *c) -{ - return 0; -} - -static void stackSetParent(uiControl *c, uiParent *parent) -{ - stack *s = (stack *) c; - uintmax_t i; - uiParent *oldparent; - - oldparent = s->parent; - s->parent = parent; - for (i = 0; i < s->len; i++) - uiControlSetParent(s->controls[i].c, s->parent); - if (oldparent != NULL) - uiParentUpdate(oldparent); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void stackPreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - stack *s = (stack *) c; - int xpadding, ypadding; - uintmax_t nStretchy; - // these two contain the largest preferred width and height of all stretchy controls in the stack - // all stretchy controls will use this value to determine the final preferred size - intmax_t maxStretchyWidth, maxStretchyHeight; - uintmax_t i; - intmax_t preferredWidth, preferredHeight; - - *width = 0; - *height = 0; - if (s->len == 0) - return; - - // 0) get this Stack's padding - xpadding = 0; - ypadding = 0; - if (s->padded) { - xpadding = d->xPadding; - ypadding = d->yPadding; - } - - // 1) initialize the desired rect with the needed padding - if (s->vertical) - *height = (s->len - 1) * ypadding; - else - *width = (s->len - 1) * xpadding; - - // 2) add in the size of non-stretchy controls and get (but not add in) the largest widths and heights of stretchy controls - // we still add in like direction of stretchy controls - nStretchy = 0; - maxStretchyWidth = 0; - maxStretchyHeight = 0; - for (i = 0; i < s->len; i++) { - if (!uiControlVisible(s->controls[i].c)) - continue; - uiControlPreferredSize(s->controls[i].c, d, &preferredWidth, &preferredHeight); - if (s->controls[i].stretchy) { - nStretchy++; - if (maxStretchyWidth < preferredWidth) - maxStretchyWidth = preferredWidth; - if (maxStretchyHeight < preferredHeight) - maxStretchyHeight = preferredHeight; - } - if (s->vertical) { - if (*width < preferredWidth) - *width = preferredWidth; - if (!s->controls[i].stretchy) - *height += preferredHeight; - } else { - if (!s->controls[i].stretchy) - *width += preferredWidth; - if (*height < preferredHeight) - *height = preferredHeight; - } - } - - // 3) and now we can add in stretchy controls - if (s->vertical) - *height += nStretchy * maxStretchyHeight; - else - *width += nStretchy * maxStretchyWidth; -} - -static void stackResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) -{ - stack *s = (stack *) c; - int xpadding, ypadding; - uintmax_t nStretchy; - intmax_t stretchywid, stretchyht; - uintmax_t i; - intmax_t preferredWidth, preferredHeight; - - if (s->len == 0) - return; - - // -1) get this Stack's padding - xpadding = 0; - ypadding = 0; - if (s->padded) { - xpadding = d->xPadding; - ypadding = d->yPadding; - } - - // 0) inset the available rect by the needed padding - if (s->vertical) - height -= (s->len - 1) * ypadding; - else - width -= (s->len - 1) * xpadding; - - // 1) get width and height of non-stretchy controls - // this will tell us how much space will be left for stretchy controls - stretchywid = width; - stretchyht = height; - nStretchy = 0; - for (i = 0; i < s->len; i++) { - if (!uiControlVisible(s->controls[i].c)) - continue; - if (s->controls[i].stretchy) { - nStretchy++; - continue; - } - uiControlPreferredSize(s->controls[i].c, d, &preferredWidth, &preferredHeight); - if (s->vertical) { // all controls have same width - s->controls[i].width = width; - s->controls[i].height = preferredHeight; - stretchyht -= preferredHeight; - } else { // all controls have same height - s->controls[i].width = preferredWidth; - s->controls[i].height = height; - stretchywid -= preferredWidth; - } - } - - // 2) now get the size of stretchy controls - if (nStretchy != 0) - if (s->vertical) - stretchyht /= nStretchy; - else - stretchywid /= nStretchy; - for (i = 0; i < s->len; i++) { - if (!uiControlVisible(s->controls[i].c)) - continue; - if (s->controls[i].stretchy) { - s->controls[i].width = stretchywid; - s->controls[i].height = stretchyht; - } - } - - // 3) now we can position controls - for (i = 0; i < s->len; i++) { - if (!uiControlVisible(s->controls[i].c)) - continue; - uiControlResize(s->controls[i].c, x, y, s->controls[i].width, s->controls[i].height, d); - if (s->vertical) - y += s->controls[i].height + ypadding; - else - x += s->controls[i].width + xpadding; - } -} - -static int stackVisible(uiControl *c) -{ - stack *s = (stack *) c; - - return !(s->userHid); -} - -static void stackShow(uiControl *c) -{ - stack *s = (stack *) c; - uintmax_t i; - - s->userHid = 0; - if (!s->containerHid) { - for (i = 0; i < s->len; i++) - uiControlContainerShow(s->controls[i].c); - if (s->parent != NULL) - uiParentUpdate(s->parent); - } -} - -static void stackHide(uiControl *c) -{ - stack *s = (stack *) c; - uintmax_t i; - - s->userHid = 1; - for (i = 0; i < s->len; i++) - uiControlContainerHide(s->controls[i].c); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void stackContainerShow(uiControl *c) -{ - stack *s = (stack *) c; - uintmax_t i; - - s->containerHid = 0; - if (!s->userHid) { - for (i = 0; i < s->len; i++) - uiControlContainerShow(s->controls[i].c); - if (s->parent != NULL) - uiParentUpdate(s->parent); - } -} - -static void stackContainerHide(uiControl *c) -{ - stack *s = (stack *) c; - uintmax_t i; - - s->containerHid = 1; - for (i = 0; i < s->len; i++) - uiControlContainerHide(s->controls[i].c); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void stackEnable(uiControl *c) -{ - stack *s = (stack *) c; - uintmax_t i; - - s->userDisabled = 0; - if (!s->containerDisabled) - for (i = 0; i < s->len; i++) - uiControlContainerEnable(s->controls[i].c); -} - -static void stackDisable(uiControl *c) -{ - stack *s = (stack *) c; - uintmax_t i; - - s->userDisabled = 1; - for (i = 0; i < s->len; i++) - uiControlContainerDisable(s->controls[i].c); -} - -static void stackContainerEnable(uiControl *c) -{ - stack *s = (stack *) c; - uintmax_t i; - - s->containerDisabled = 0; - if (!s->userDisabled) - for (i = 0; i < s->len; i++) - uiControlContainerEnable(s->controls[i].c); -} - -static void stackContainerDisable(uiControl *c) -{ - stack *s = (stack *) c; - uintmax_t i; - - s->containerDisabled = 1; - for (i = 0; i < s->len; i++) - uiControlContainerDisable(s->controls[i].c); -} - -#define stackCapGrow 32 - -static void stackAppend(uiStack *ss, uiControl *c, int stretchy) -{ - stack *s = (stack *) ss; - - if (s->len >= s->cap) { - s->cap += stackCapGrow; - s->controls = (stackControl *) uiRealloc(s->controls, s->cap * sizeof (stackControl), "stackControl[]"); - } - s->controls[s->len].c = c; - s->controls[s->len].stretchy = stretchy; - s->len++; // must be here for parent updates to work - if (s->parent != NULL) { - uiControlSetParent(s->controls[s->len - 1].c, s->parent); - uiParentUpdate(s->parent); - } -} - -static void stackDelete(uiStack *ss, uintmax_t index) -{ - stack *s = (stack *) ss; - uiControl *removed; - uintmax_t i; - - removed = s->controls[index].c; - // TODO switch to memmove? - for (i = index; i < s->len - 1; i++) - s->controls[i] = s->controls[i + 1]; - // TODO memset the last one to NULL - s->len--; - if (s->parent != NULL) { - uiControlSetParent(removed, NULL); - uiParentUpdate(s->parent); - } -} - -static int stackPadded(uiStack *ss) -{ - stack *s = (stack *) ss; - - return s->padded; -} - -static void stackSetPadded(uiStack *ss, int padded) -{ - stack *s = (stack *) ss; - - s->padded = padded; - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -uiStack *uiNewHorizontalStack(void) -{ - stack *s; - - s = uiNew(stack); - - uiControl(s)->Destroy = stackDestroy; - uiControl(s)->Handle = stackHandle; - uiControl(s)->SetParent = stackSetParent; - uiControl(s)->PreferredSize = stackPreferredSize; - uiControl(s)->Resize = stackResize; - uiControl(s)->Visible = stackVisible; - uiControl(s)->Show = stackShow; - uiControl(s)->Hide = stackHide; - uiControl(s)->ContainerShow = stackContainerShow; - uiControl(s)->ContainerHide = stackContainerHide; - uiControl(s)->Enable = stackEnable; - uiControl(s)->Disable = stackDisable; - uiControl(s)->ContainerEnable = stackContainerEnable; - uiControl(s)->ContainerDisable = stackContainerDisable; - - uiStack(s)->Append = stackAppend; - uiStack(s)->Delete = stackDelete; - uiStack(s)->Padded = stackPadded; - uiStack(s)->SetPadded = stackSetPadded; - - return uiStack(s); -} - -uiStack *uiNewVerticalStack(void) -{ - uiStack *ss; - stack *s; - - ss = uiNewHorizontalStack(); - s = (stack *) ss; - s->vertical = 1; - return ss; -} diff --git a/new/test.c b/new/test.c deleted file mode 100644 index b8ee4189..00000000 --- a/new/test.c +++ /dev/null @@ -1,337 +0,0 @@ -// 6 april 2015 -#include "ui.h" -#include -#include - -// TODO convert to using the new conversion macros - -int onClosing(uiWindow *w, void *data) -{ - printf("in closing!\n"); - uiQuit(); - return 1; -} - -uiEntry *e; - -static void getWindowText(uiButton *b, void *data) -{ - char *text; - - text = uiWindowTitle(uiWindow(data)); - uiEntrySetText(e, text); - uiFreeText(text); -} - -static void setWindowText(uiButton *b, void *data) -{ - char *text; - - text = uiEntryText(e); - uiWindowSetTitle(uiWindow(data), text); - uiFreeText(text); -} - -static void getButtonText(uiButton *b, void *data) -{ - char *text; - - text = uiButtonText(uiButton(data)); - uiEntrySetText(e, text); - uiFreeText(text); -} - -static void setButtonText(uiButton *b, void *data) -{ - char *text; - - text = uiEntryText(e); - uiButtonSetText(uiButton(data), text); - uiFreeText(text); -} - -static void getCheckboxText(uiButton *b, void *data) -{ - char *text; - - text = uiCheckboxText(uiCheckbox(data)); - uiEntrySetText(e, text); - uiFreeText(text); -} - -static void setCheckboxText(uiButton *b, void *data) -{ - char *text; - - text = uiEntryText(e); - uiCheckboxSetText(uiCheckbox(data), text); - uiFreeText(text); -} - -uiWindow *w; -#define nStacks 11 -uiStack *stacks[nStacks]; -uiCheckbox *spaced; - -static void setSpaced(int spaced) -{ - int i; - - uiWindowSetMargined(w, spaced); - for (i = 0; i < nStacks; i++) - uiStackSetPadded(stacks[i], spaced); -} - -static void toggleSpaced(uiCheckbox *c, void *data) -{ - int s; - - s = uiCheckboxChecked(spaced); - printf("toggled %d\n", s); - setSpaced(s); -} - -// these will also be used to test if setting checks will trigger events -static void forceSpacedOn(uiButton *b, void *data) -{ - uiCheckboxSetChecked(spaced, 1); -} - -static void forceSpacedOff(uiButton *b, void *data) -{ - uiCheckboxSetChecked(spaced, 0); -} - -static void showSpaced(uiButton *b, void *data) -{ - char msg[] = { 'm', ' ', '0', ' ', 'p', ' ', '0', '\0' }; - - if (uiWindowMargined(w)) - msg[2] = '1'; - if (uiStackPadded(stacks[0])) - msg[6] = '1'; - uiEntrySetText(e, msg); -} - -static void showControl(uiButton *b, void *data) -{ - uiControlShow(uiControl(data)); -} - -static void hideControl(uiButton *b, void *data) -{ - uiControlHide(uiControl(data)); -} - -static void enableControl(uiButton *b, void *data) -{ - uiControlEnable(uiControl(data)); -} - -static void disableControl(uiButton *b, void *data) -{ - uiControlDisable(uiControl(data)); -} - -static void getLabelText(uiButton *b, void *data) -{ - char *text; - - text = uiLabelText(uiLabel(data)); - uiEntrySetText(e, text); - uiFreeText(text); -} - -static void setLabelText(uiButton *b, void *data) -{ - char *text; - - text = uiEntryText(e); - uiLabelSetText(uiLabel(data), text); - uiFreeText(text); -} - -uiStack *firstStack; -uiStack *secondStack; -uiLabel *movingLabel; - -static void moveToFirst(uiButton *b, void *data) -{ - uiStackDelete(secondStack, 1); - uiStackAppend(firstStack, uiControl(movingLabel), 1); -} - -static void moveToSecond(uiButton *b, void *data) -{ - uiStackDelete(firstStack, 1); - uiStackAppend(secondStack, uiControl(movingLabel), 1); -} - -int main(int argc, char *argv[]) -{ - uiInitOptions o; - int i; - const char *err; - uiButton *getButton, *setButton; - uiLabel *label; - uiTab *tab; - int page2stack; - - memset(&o, 0, sizeof (uiInitOptions)); - for (i = 1; i < argc; i++) - if (strcmp(argv[i], "leaks") == 0) - o.debugLogAllocations = 1; - else { - fprintf(stderr, "%s: unrecognized option %s\n", argv[0], argv[i]); - return 1; - } - - err = uiInit(&o); - if (err != NULL) { - fprintf(stderr, "error initializing ui: %s\n", err); - uiFreeInitError(err); - return 1; - } - - w = uiNewWindow("Hello", 320, 240); - uiWindowOnClosing(w, onClosing, NULL); - - stacks[0] = uiNewVerticalStack(); - - e = uiNewEntry(); - uiStackAppend(stacks[0], uiControl(e), 0); - - i = 1; - - stacks[i] = uiNewHorizontalStack(); - getButton = uiNewButton("Get Window Text"); - uiButtonOnClicked(getButton, getWindowText, w); - setButton = uiNewButton("Set Window Text"); - uiButtonOnClicked(setButton, setWindowText, w); - uiStackAppend(stacks[i], uiControl(getButton), 1); - uiStackAppend(stacks[i], uiControl(setButton), 1); - uiStackAppend(stacks[0], uiControl(stacks[i]), 0); - i++; - - stacks[i] = uiNewHorizontalStack(); - getButton = uiNewButton("Get Button Text"); - uiButtonOnClicked(getButton, getButtonText, getButton); - setButton = uiNewButton("Set Button Text"); - uiButtonOnClicked(setButton, setButtonText, getButton); - uiStackAppend(stacks[i], uiControl(getButton), 1); - uiStackAppend(stacks[i], uiControl(setButton), 1); - uiStackAppend(stacks[0], uiControl(stacks[i]), 0); - i++; - - // this will also be used to make sure tab stops work properly when inserted out of creation order, especially on Windows - spaced = uiNewCheckbox("Spaced"); - uiCheckboxOnToggled(spaced, toggleSpaced, NULL); - - stacks[i] = uiNewHorizontalStack(); - getButton = uiNewButton("Get Checkbox Text"); - uiButtonOnClicked(getButton, getCheckboxText, spaced); - setButton = uiNewButton("Set Checkbox Text"); - uiButtonOnClicked(setButton, setCheckboxText, spaced); - uiStackAppend(stacks[i], uiControl(getButton), 1); - uiStackAppend(stacks[i], uiControl(setButton), 1); - uiStackAppend(stacks[0], uiControl(stacks[i]), 0); - i++; - - label = uiNewLabel("Label"); - - stacks[i] = uiNewHorizontalStack(); - getButton = uiNewButton("Get Label Text"); - uiButtonOnClicked(getButton, getLabelText, label); - setButton = uiNewButton("Set Label Text"); - uiButtonOnClicked(setButton, setLabelText, label); - uiStackAppend(stacks[i], uiControl(getButton), 1); - uiStackAppend(stacks[i], uiControl(setButton), 1); - uiStackAppend(stacks[0], uiControl(stacks[i]), 0); - i++; - - stacks[i] = uiNewHorizontalStack(); - uiStackAppend(stacks[i], uiControl(spaced), 1); - getButton = uiNewButton("On"); - uiButtonOnClicked(getButton, forceSpacedOn, NULL); - setButton = uiNewButton("Off"); - uiButtonOnClicked(setButton, forceSpacedOff, NULL); - uiStackAppend(stacks[i], uiControl(getButton), 0); - uiStackAppend(stacks[i], uiControl(setButton), 0); - setButton = uiNewButton("Show"); - uiButtonOnClicked(setButton, showSpaced, NULL); - uiStackAppend(stacks[i], uiControl(setButton), 0); - uiStackAppend(stacks[0], uiControl(stacks[i]), 0); - i++; - - stacks[i] = uiNewHorizontalStack(); - getButton = uiNewButton("Button"); - uiStackAppend(stacks[i], uiControl(getButton), 1); - setButton = uiNewButton("Show"); - uiButtonOnClicked(setButton, showControl, getButton); - uiStackAppend(stacks[i], uiControl(setButton), 0); - setButton = uiNewButton("Hide"); - uiButtonOnClicked(setButton, hideControl, getButton); - uiStackAppend(stacks[i], uiControl(setButton), 0); - setButton = uiNewButton("Enable"); - uiButtonOnClicked(setButton, enableControl, getButton); - uiStackAppend(stacks[i], uiControl(setButton), 0); - setButton = uiNewButton("Disable"); - uiButtonOnClicked(setButton, disableControl, getButton); - uiStackAppend(stacks[i], uiControl(setButton), 0); - uiStackAppend(stacks[0], uiControl(stacks[i]), 0); - i++; - - stacks[i] = uiNewHorizontalStack(); - setButton = uiNewButton("Show Stack"); - uiButtonOnClicked(setButton, showControl, stacks[i - 1]); - uiStackAppend(stacks[i], uiControl(setButton), 1); - setButton = uiNewButton("Hide Stack"); - uiButtonOnClicked(setButton, hideControl, stacks[i - 1]); - uiStackAppend(stacks[i], uiControl(setButton), 1); - setButton = uiNewButton("Enable Stack"); - uiButtonOnClicked(setButton, enableControl, stacks[i - 1]); - uiStackAppend(stacks[i], uiControl(setButton), 1); - setButton = uiNewButton("Disable Stack"); - uiButtonOnClicked(setButton, disableControl, stacks[i - 1]); - uiStackAppend(stacks[i], uiControl(setButton), 1); - uiStackAppend(stacks[0], uiControl(stacks[i]), 0); - i++; - - uiStackAppend(stacks[0], uiControl(label), 0); - - tab = uiNewTab(); - uiWindowSetChild(w, uiControl(tab)); - uiTabAddPage(tab, "Page 1", uiControl(stacks[0])); - - page2stack = i; - stacks[i] = uiNewVerticalStack(); - uiTabAddPage(tab, "Page 2", uiControl(stacks[i])); - i++; - - stacks[i] = uiNewHorizontalStack(); - firstStack = stacks[i]; - getButton = uiNewButton("Move Here"); - uiButtonOnClicked(getButton, moveToFirst, NULL); - uiStackAppend(stacks[i], uiControl(getButton), 0); - movingLabel = uiNewLabel("This label moves!"); - uiStackAppend(stacks[i], uiControl(movingLabel), 1); - uiStackAppend(stacks[page2stack], uiControl(stacks[i]), 0); - i++; - - stacks[i] = uiNewHorizontalStack(); - secondStack = stacks[i]; - getButton = uiNewButton("Move Here"); - uiButtonOnClicked(getButton, moveToSecond, NULL); - uiStackAppend(stacks[i], uiControl(getButton), 0); - uiStackAppend(stacks[page2stack], uiControl(stacks[i]), 0); - i++; - - if (i != nStacks) { - fprintf(stderr, "forgot to update nStacks (expected %d)\n", i); - return 1; - } - uiWindowShow(w); - uiMain(); - printf("after uiMain()\n"); - return 0; -} diff --git a/new/ui.idl b/new/ui.idl deleted file mode 100644 index e8200023..00000000 --- a/new/ui.idl +++ /dev/null @@ -1,161 +0,0 @@ -// 6 april 2015 - -// This is not an IDL file for the conventional RPC or Microsoft IDLs. -// Instead, this is for a custom IDL of my own creation. -// You can find it at github.com/andlabs/pgidl - -package ui { - -// TODO autogenerate this somehow -// TODO alternatively, move AFTER typedefs -raw "#ifndef __UI_UI_H__"; -raw "#define __UI_UI_H__"; - -raw "#include "; - -// TODO note that should be initialized to zero -struct InitOptions { - // TODO cbSize - - // If nonzero, allocations will be logged to stderr. - // See leaks.awk. - field debugLogAllocations int; -}; - -// TODO const char -raw "const char *uiInit(uiInitOptions *);"; -raw "void uiFreeInitError(const char *);"; - -func Main(void); -func Quit(void); - -func FreeText(text *char); - -raw "typedef struct uiSizingSys uiSizingSys;"; - -struct Sizing { - field xPadding intmax_t; - field yPadding intmax_t; - field sys *uiSizingSys; -}; - -interface Control { - field Internal *void; // for use by ui only - func Destroy(void); - func Handle(void) uintptr_t; - func SetParent(p *Parent); - func PreferredSize(d *Sizing, width *intmax_t, height *intmax_t); - func Resize(x intmax_t, y intmax_t, width intmax_t, height intmax_t, d *Sizing); - func Visible(void) int; - func Show(void); - func Hide(void); - func ContainerShow(void); - func ContainerHide(void); - func Enable(void); - func Disable(void); - func ContainerEnable(void); - func ContainerDisable(void); -}; - -// Parent represents an OS control that hosts other OS controls. -// It is used internally by package ui and by implementations. -// Window, Tab, and Group all use uiParents to store their controls. -interface Parent { - // Internal points to internal data. - // Do not access or alter this field. - field Internal *void; - - // TODO destroy - // TODO object destruction debug handler - - // Handle returns the window handle of the uiParent. - // On Windows, this is a HWND. - // On GTK+, this is a GtkContainer. - // On Mac OS X, this is a NSView. - func Handle(void) uintptr_t; - - // TODO rename and clean this up - // SetChild sets the uiControl that this uiParent relegates. - // It calls uiControl.SetParent() which should, in turn, call uiParent.Update(). - // The uiParent should already not have a child and the uiControl should already not have a parent. - // - // child can be NULL, in which case the uiParent has no children. - // This version should also call uiControl.SetParent(), passing NULL. - // - // If this uiParent has a child already, then the current child is replaced with the new one. - func SetChild(c *Control); - - // SetMargins sets the margins of the uiParent to the given margins. - // It does not call uiParent.Update(); its caller must. - // The units of the margins are backend-defined. - // The initial margins are all 0. - func SetMargins(left intmax_t, top intmax_t, right intmax_t, bottom intmax_t); - - // TODO Resize? - - // Update tells the uiParent to re-layout its children immediately. - // It is called when a widget is shown or hidden or when a control is added or removed from a container such as uiStack. - func Update(void); -}; -func NewParent(osParent uintptr_t) *Parent; - -interface Window { - field Internal *void; - func Destroy(void); - func Handle(void) uintptr_t; - func Title(void) *char; - func SetTitle(title *const char); - func Show(void); - func Hide(void); - func OnClosing(f *func(w *Window, data *void) int, data *void); - func SetChild(c *Control); - func Margined(void) int; - func SetMargined(margined int); -}; -func NewWindow(title *const char, width int, height int) *Window; - -interface Button from Control { - func Text(void) *char; - func SetText(text *const char); - func OnClicked(f *func(b *Button, data *void), data *void); -}; -func NewButton(text *const char) *Button; - -interface Stack from Control { - func Append(c *Control, stretchy int); - func Delete(index uintmax_t); - func Padded(void) int; - func SetPadded(padded int); -}; -func NewHorizontalStack(void) *Stack; -func NewVerticalStack(void) *Stack; - -interface Entry from Control { - func Text(void) *char; - func SetText(text *const char); -}; -func NewEntry(void) *Entry; - -interface Checkbox from Control { - func Text(void) *char; - func SetText(text *const char); - func OnToggled(f *func(c *Checkbox, data *void), data *void); - func Checked(void) int; - func SetChecked(checked int); -}; -func NewCheckbox(text *const char) *Checkbox; - -interface Label from Control { - func Text(void) *char; - func SetText(text *const char); -}; -func NewLabel(text *const char) *Label; - -interface Tab from Control { - func AddPage(name *const char, c *Control); -}; -func NewTab(void) *Tab; - -raw "#endif"; - -}; diff --git a/new/ui_darwin.h b/new/ui_darwin.h deleted file mode 100644 index cab61d15..00000000 --- a/new/ui_darwin.h +++ /dev/null @@ -1,25 +0,0 @@ -// 7 april 2015 - -/* -This file assumes that you have imported and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls on Mac OS X. -*/ - -#ifndef __UI_UI_DARWIN_H__ -#define __UI_UI_DARWIN_H__ - -// uiDarwinNewControl() initializes the given uiControl with the given Cocoa control inside. -// The second parameter should come from [RealControlType class]. -// The two scrollView parameters allow placing scrollbars on the new control. -// Your control must call uiDarwinControlFreeWhenAppropriate() on the returned uiControl in its -[viewDidMoveToSuperview] method. -// If it returns a value other than NO, then the uiControl has been freed and you should set references to it to NULL. -extern void uiDarwinNewControl(uiControl *c, Class class, BOOL inScrollView, BOOL scrollViewHasBorder); -extern BOOL uiDarwinControlFreeWhenAppropriate(uiControl *c, NSView *newSuperview); - -// You can use this function from within your control implementations to return text strings that can be freed with uiTextFree(). -extern char *uiDarwinNSStringToText(NSString *); - -struct uiSizingSys { - // this structure currently left blank -}; - -#endif diff --git a/new/ui_unix.h b/new/ui_unix.h deleted file mode 100644 index 3911416b..00000000 --- a/new/ui_unix.h +++ /dev/null @@ -1,20 +0,0 @@ -// 7 april 2015 - -/* -This file assumes that you have included and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls on Unix systems that use GTK+ to provide their UI (currently all except Mac OS X). -*/ - -#ifndef __UI_UI_UNIX_H__ -#define __UI_UI_UNIX_H__ - -// uiUnixNewControl() creates a new uiControl with the given GTK+ control inside, storing it in the uiControl at c. -// The second parameter is the type of the control, as passed to the first argument of g_object_new(). -// The two scrolledWindow parameters allow placing scrollbars on the new control. -// The firstProperty parameter and beyond allow passing construct properties to the new control, as with g_object_new(); end this list with NULL. -extern void uiUnixNewControl(uiControl *c, GType type, gboolean inScrolledWindow, gboolean scrolledWindowHasBorder, const char *firstProperty, ...); - -struct uiSizingSys { - // this structure currently left blank -}; - -#endif diff --git a/new/ui_windows.h b/new/ui_windows.h deleted file mode 100644 index 806cac15..00000000 --- a/new/ui_windows.h +++ /dev/null @@ -1,59 +0,0 @@ -// 7 april 2015 - -/* -This file assumes that you have included and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls in Windows. -*/ - -#ifndef __UI_UI_WINDOWS_H__ -#define __UI_UI_WINDOWS_H__ - -// Correctness macros. -#define uiControlHWND(c) ((HWND) uiControlHandle(c)) -#define uiParentHWND(p) ((HWND) uiParentHandle(p)) - -// uiWindowsNewControl() initializes the given uiControl with the given Windows API control inside. -// You will need to provide the preferredSize() method yourself. -typedef struct uiWindowsNewControlParams uiWindowsNewControlParams; -struct uiWindowsNewControlParams { - // These match the CreateWindowExW() function. - DWORD dwExStyle; - LPCWSTR lpClassName; - LPCWSTR lpWindowName; - DWORD dwStyle; // WS_CHILD and WS_VISIBLE are automatically applied. - HINSTANCE hInstance; - - // Set this to non-FALSE to use the standard control font used by other ui controls. - BOOL useStandardControlFont; - - // These are called when the control sends a WM_COMMAND or WM_NOTIFY (respectively) to its parent. - // ui redirects the message back and calls these functions. - // Store the result in *lResult and return any non-FALSE value (such as TRUE) to return the given result; return FALSE to pass the notification up to your window procedure. - // Note that these are only issued if they come from the uiControl itself; notifications from children of the uiControl (such as a header control) will be received normally. - BOOL (*onWM_COMMAND)(uiControl *c, WORD code, LRESULT *lResult); - BOOL (*onWM_NOTIFY)(uiControl *c, NMHDR *nm, LRESULT *lResult); - // This is called in WM_DESTROY. - void (*onWM_DESTROY)(uiControl *c); -}; -void uiWindowsNewControl(uiControl *c, uiWindowsNewControlParams *p); - -// This contains the Windows-specific parts of the uiSizing structure. -// baseX and baseY are the dialog base units. -// internalLeading is the standard control font's internal leading; labels in uiForms use this for correct Y positioning. -struct uiSizingSys { - int baseX; - int baseY; - LONG internalLeading; -}; -// Use these in your preferredSize() implementation with baseX and baseY. -#define uiDlgUnitsToX(dlg, baseX) MulDiv((dlg), baseX, 4) -#define uiDlgUnitsToY(dlg, baseY) MulDiv((dlg), baseY, 8) - -// and use this if you need the text of the window width -extern intmax_t uiWindowsWindowTextWidth(HWND hwnd); - -// these functions get and set the window text for such a uiControl -// the value returned should be freed with uiFreeText() -extern char *uiWindowsControlText(uiControl *); -extern void uiWindowsControlSetText(uiControl *, const char *); - -#endif diff --git a/new/uipriv.h b/new/uipriv.h deleted file mode 100644 index 7cc17956..00000000 --- a/new/uipriv.h +++ /dev/null @@ -1,10 +0,0 @@ -// 6 april 2015 -#include -#include "ui.h" - -extern uiInitOptions options; - -extern void *uiAlloc(size_t, const char *); -#define uiNew(T) ((T *) uiAlloc(sizeof (T), #T )) -extern void *uiRealloc(void *, size_t, const char *); -extern void uiFree(void *); diff --git a/new/unix/GNUmakeinc.mk b/new/unix/GNUmakeinc.mk deleted file mode 100644 index 4f707b3d..00000000 --- a/new/unix/GNUmakeinc.mk +++ /dev/null @@ -1,18 +0,0 @@ -OSCFILES = \ - alloc.c \ - button.c \ - checkbox.c \ - entry.c \ - init.c \ - label.c \ - main.c \ - newcontrol.c \ - parent.c \ - tab.c \ - util.c \ - window.c - -xCFLAGS += `pkg-config --cflags gtk+-3.0` -xLDFLAGS += `pkg-config --libs gtk+-3.0` - -OUT = new diff --git a/new/unix/alloc.c b/new/unix/alloc.c deleted file mode 100644 index 33482b25..00000000 --- a/new/unix/alloc.c +++ /dev/null @@ -1,33 +0,0 @@ -// 7 april 2015 -#include -#include "uipriv_unix.h" - -void *uiAlloc(size_t size, const char *type) -{ - void *out; - - out = g_malloc0(size); - if (options.debugLogAllocations) - fprintf(stderr, "%p alloc %s\n", out, type); - return out; -} - -void *uiRealloc(void *p, size_t size, const char *type) -{ - void *out; - - if (p == NULL) - return uiAlloc(size, type); - // TODO fill with 0s - out = g_realloc(p, size); - if (options.debugLogAllocations) - fprintf(stderr, "%p realloc %p\n", p, out); - return out; -} - -void uiFree(void *p) -{ - g_free(p); - if (options.debugLogAllocations) - fprintf(stderr, "%p free\n", p); -} diff --git a/new/unix/button.c b/new/unix/button.c deleted file mode 100644 index 404d7a87..00000000 --- a/new/unix/button.c +++ /dev/null @@ -1,71 +0,0 @@ -// 7 april 2015 -#include "uipriv_unix.h" - -struct button { - uiButton b; - void (*onClicked)(uiButton *, void *); - void *onClickedData; -}; - -static void clicked(GtkButton *button, gpointer data) -{ - struct button *b = (struct button *) data; - - (*(b->onClicked))(uiButton(b), b->onClickedData); -} - -static void defaultOnClicked(uiButton *b, void *data) -{ - // do nothing -} - -static void destroy(GtkWidget *widget, gpointer data) -{ - struct button *b = (struct button *) data; - - uiFree(b); -} - -#define BUTTON(b) GTK_BUTTON(widget(b)) - -static char *buttonText(uiButton *bb) -{ - return g_strdup(gtk_button_get_label(BUTTON(bb))); -} - -static void buttonSetText(uiButton *bb, const char *text) -{ - gtk_button_set_label(BUTTON(bb), text); -} - -static void buttonOnClicked(uiButton *bb, void (*f)(uiButton *, void *), void *data) -{ - struct button *b = (struct button *) bb; - - b->onClicked = f; - b->onClickedData = data; -} - -uiButton *uiNewButton(const char *text) -{ - struct button *b; - GtkWidget *widget; - - b = uiNew(struct button); - - uiUnixNewControl(uiControl(b), GTK_TYPE_BUTTON, - FALSE, FALSE, - "label", text, - NULL); - - widget = WIDGET(b); - g_signal_connect(widget, "clicked", G_CALLBACK(clicked), b); - g_signal_connect(widget, "destroy", G_CALLBACK(destroy), b); - b->onClicked = defaultOnClicked; - - uiButton(b)->Text = buttonText; - uiButton(b)->SetText = buttonSetText; - uiButton(b)->OnClicked = buttonOnClicked; - - return uiButton(b); -} diff --git a/new/unix/checkbox.c b/new/unix/checkbox.c deleted file mode 100644 index f3563a16..00000000 --- a/new/unix/checkbox.c +++ /dev/null @@ -1,95 +0,0 @@ -// 7 april 2015 -#include "uipriv_unix.h" - -struct checkbox { - uiCheckbox c; - void (*onToggled)(uiCheckbox *, void *); - void *onToggledData; - gulong onToggledSignal; -}; - -static void onToggled(GtkToggleButton *b, gpointer data) -{ - struct checkbox *c = (struct checkbox *) data; - - (*(c->onToggled))(uiCheckbox(c), c->onToggledData); -} - -static void defaultOnToggled(uiCheckbox *c, void *data) -{ - // do nothing -} - -static void onDestroy(GtkWidget *widget, gpointer data) -{ - struct checkbox *c = (struct checkbox *) data; - - uiFree(c); -} - -#define CHECKBOX(c) GTK_CHECK_BUTTON(uiControlHandle(uiControl(c))) - -static char *getText(uiCheckbox *c) -{ - return g_strdup(gtk_button_get_label(GTK_BUTTON(CHECKBOX(c)))); -} - -static void setText(uiCheckbox *c, const char *text) -{ - gtk_button_set_label(GTK_BUTTON(CHECKBOX(c)), text); -} - -static void setOnToggled(uiCheckbox *cc, void (*f)(uiCheckbox *, void *), void *data) -{ - struct checkbox *c = (struct checkbox *) cc; - - c->onToggled = f; - c->onToggledData = data; -} - -static int getChecked(uiCheckbox *c) -{ - return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(CHECKBOX(c))) != FALSE; -} - -static void setChecked(uiCheckbox *cc, int checked) -{ - struct checkbox *c = (struct checkbox *) cc; - GtkToggleButton *button; - gboolean active; - - active = FALSE; - if (checked) - active = TRUE; - // we need to inhibit sending of ::toggled because this WILL send a ::toggled otherwise - button = GTK_TOGGLE_BUTTON(CHECKBOX(c)); - g_signal_handler_block(button, c->onToggledSignal); - gtk_toggle_button_set_active(button, active); - g_signal_handler_unblock(button, c->onToggledSignal); -} - -uiCheckbox *uiNewCheckbox(const char *text) -{ - struct checkbox *c; - GtkWidget *widget; - - c = uiNew(struct checkbox); - - uiUnixNewControl(uiControl(c), GTK_TYPE_CHECK_BUTTON, - FALSE, FALSE, - "label", text, - NULL); - - widget = GTK_WIDGET(CHECKBOX(c)); - g_signal_connect(widget, "destroy", G_CALLBACK(onDestroy), c); - c->onToggledSignal = g_signal_connect(widget, "toggled", G_CALLBACK(onToggled), c); - c->onToggled = defaultOnToggled; - - uiCheckbox(c)->Text = getText; - uiCheckbox(c)->SetText = setText; - uiCheckbox(c)->OnToggled = setOnToggled; - uiCheckbox(c)->Checked = getChecked; - uiCheckbox(c)->SetChecked = setChecked; - - return uiCheckbox(c); -} diff --git a/new/unix/entry.c b/new/unix/entry.c deleted file mode 100644 index 4731f68d..00000000 --- a/new/unix/entry.c +++ /dev/null @@ -1,45 +0,0 @@ -// 8 april 2015 -#include "uipriv_unix.h" - -struct entry { - uiEntry e; -}; - -static void onDestroy(GtkWidget *widget, gpointer data) -{ - struct entry *e = (struct entry *) data; - - uiFree(e); -} - -#define ENTRY(e) GTK_ENTRY(uiControlHandle(uiControl(e))) - -static char *getText(uiEntry *e) -{ - return g_strdup(gtk_entry_get_text(ENTRY(e))); -} - -static void setText(uiEntry *e, const char *text) -{ - gtk_entry_set_text(ENTRY(e), text); -} - -uiEntry *uiNewEntry(void) -{ - struct entry *e; - GtkWidget *widget; - - e = uiNew(struct entry); - - uiUnixNewControl(uiControl(e), GTK_TYPE_ENTRY, - FALSE, FALSE, - NULL); - - widget = GTK_WIDGET(ENTRY(e)); - g_signal_connect(widget, "destroy", G_CALLBACK(onDestroy), e); - - uiEntry(e)->Text = getText; - uiEntry(e)->SetText = setText; - - return uiEntry(e); -} diff --git a/new/unix/init.c b/new/unix/init.c deleted file mode 100644 index b10c05b0..00000000 --- a/new/unix/init.c +++ /dev/null @@ -1,23 +0,0 @@ -// 6 april 2015 -#include "uipriv_unix.h" - -uiInitOptions options; - -const char *uiInit(uiInitOptions *o) -{ - GError *err = NULL; - const char *msg; - - options = *o; - if (gtk_init_with_args(NULL, NULL, NULL, NULL, NULL, &err) == FALSE) { - msg = g_strdup(err->message); - g_error_free(err); - return msg; - } - return NULL; -} - -void uiFreeInitError(const char *err) -{ - g_free((gpointer) err); -} diff --git a/new/unix/label.c b/new/unix/label.c deleted file mode 100644 index 1a7aa284..00000000 --- a/new/unix/label.c +++ /dev/null @@ -1,49 +0,0 @@ -// 11 april 2015 -#include "uipriv_unix.h" - -struct label { - uiLabel l; -}; - -static void onDestroy(GtkWidget *widget, gpointer data) -{ - struct label *l = (struct label *) data; - - uiFree(l); -} - -#define LABEL(l) GTK_LABEL(uiControlHandle(uiControl(l))) - -static char *getText(uiLabel *l) -{ - // TODO change g_strdup() to a wrapper function for export in ui_unix.h - return g_strdup(gtk_label_get_text(LABEL(l))); -} - -static void setText(uiLabel *l, const char *text) -{ - gtk_label_set_text(LABEL(l), text); -} - -uiLabel *uiNewLabel(const char *text) -{ - struct label *l; - GtkWidget *widget; - - l = uiNew(struct label); - - uiUnixNewControl(uiControl(l), GTK_TYPE_LABEL, - FALSE, FALSE, - "label", text, - "xalign", 0.0, // note: must be a float constant, otherwise the ... will turn it into an int and we get segfaults on some platforms (thanks ebassi in irc.gimp.net/#gtk+) - // TODO yalign 0? - NULL); - - widget = GTK_WIDGET(LABEL(l)); - g_signal_connect(widget, "destroy", G_CALLBACK(onDestroy), l); - - uiLabel(l)->Text = getText; - uiLabel(l)->SetText = setText; - - return uiLabel(l); -} diff --git a/new/unix/main.c b/new/unix/main.c deleted file mode 100644 index 10af782e..00000000 --- a/new/unix/main.c +++ /dev/null @@ -1,23 +0,0 @@ -// 6 april 2015 -#include "uipriv_unix.h" - -// #qo pkg-config: gtk+-3.0 - -void uiMain(void) -{ - gtk_main(); -} - -// gtk_main_quit() may run immediately, or it may wait for other pending events; "it depends" (thanks mclasen in irc.gimp.net/#gtk+) -// PostQuitMessage() on Windows always waits, so we must do so too -// we'll do it by using an idle callback -static gboolean quit(gpointer data) -{ - gtk_main_quit(); - return FALSE; -} - -void uiQuit(void) -{ - gdk_threads_add_idle(quit, NULL); -} diff --git a/new/unix/newcontrol.c b/new/unix/newcontrol.c deleted file mode 100644 index d23e1903..00000000 --- a/new/unix/newcontrol.c +++ /dev/null @@ -1,225 +0,0 @@ -// 7 april 2015 -#include "uipriv_unix.h" - -typedef struct singleWidget singleWidget; - -struct singleWidget { - GtkWidget *widget; - GtkWidget *scrolledWindow; - GtkWidget *immediate; // the widget that is added to the parent container; either widget or scrolledWindow - uiParent *parent; - gboolean userHid; - gboolean containerHid; - gboolean userDisabled; - gboolean containerDisabled; -}; - -static void singleDestroy(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - gtk_widget_destroy(s->immediate); -} - -static uintptr_t singleHandle(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - return (uintptr_t) (s->widget); -} - -static void singleSetParent(uiControl *c, uiParent *parent) -{ - singleWidget *s = (singleWidget *) (c->Internal); - uiParent *oldparent; - - oldparent = s->parent; - s->parent = parent; - if (oldparent != NULL) { - gtk_container_remove(GTK_CONTAINER(uiParentHandle(oldparent)), s->immediate); - uiParentUpdate(oldparent); - } - if (s->parent != NULL) { - gtk_container_add(GTK_CONTAINER(uiParentHandle(s->parent)), s->immediate); - uiParentUpdate(s->parent); - } -} - -static void singlePreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - singleWidget *s = (singleWidget *) (c->Internal); - GtkRequisition natural; - - // use the natural size as the minimum size is an *absolute* minimum - // for example, if a label has ellipsizing on, it can be the width of the ellipses, not the text - // there is a warning about height-for-width sizing, but in my tests this isn't an issue - gtk_widget_get_preferred_size(s->widget, NULL, &natural); - *width = natural.width; - *height = natural.height; -} - -static void singleResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) -{ - singleWidget *s = (singleWidget *) (c->Internal); - GtkAllocation a; - - a.x = x; - a.y = y; - a.width = width; - a.height = height; - gtk_widget_size_allocate(s->immediate, &a); -} - -static int singleVisible(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - if (s->userHid) - return 0; - return 1; -} - -static void singleShow(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - s->userHid = FALSE; - if (!s->containerHid) { - gtk_widget_show_all(s->immediate); - if (s->parent != NULL) - uiParentUpdate(s->parent); - } -} - -static void singleHide(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - s->userHid = TRUE; - gtk_widget_hide(s->immediate); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void singleContainerShow(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - s->containerHid = FALSE; - if (!s->userHid) { - gtk_widget_show_all(s->immediate); - if (s->parent != NULL) - uiParentUpdate(s->parent); - } -} - -static void singleContainerHide(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - s->containerHid = TRUE; - gtk_widget_hide(s->immediate); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void singleEnable(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - s->userDisabled = FALSE; - if (!s->containerDisabled) - gtk_widget_set_sensitive(s->immediate, TRUE); -} - -static void singleDisable(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - s->userDisabled = TRUE; - gtk_widget_set_sensitive(s->immediate, FALSE); -} - -static void singleContainerEnable(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - s->containerDisabled = FALSE; - if (!s->userDisabled) - gtk_widget_set_sensitive(s->immediate, TRUE); -} - -static void singleContainerDisable(uiControl *c) -{ - singleWidget *s = (singleWidget *) (c->Internal); - - s->containerDisabled = TRUE; - gtk_widget_set_sensitive(s->immediate, FALSE); -} - -static void onDestroy(GtkWidget *widget, gpointer data) -{ - singleWidget *s = (singleWidget *) data; - - uiFree(s); -} - -void uiUnixNewControl(uiControl *c, GType type, gboolean inScrolledWindow, gboolean scrolledWindowHasBorder, const char *firstProperty, ...) -{ - singleWidget *s; - va_list ap; - - s = uiNew(singleWidget); - - va_start(ap, firstProperty); - s->widget = GTK_WIDGET(g_object_new_valist(type, firstProperty, ap)); - va_end(ap); - s->immediate = s->widget; - - if (inScrolledWindow) { - s->scrolledWindow = gtk_scrolled_window_new(NULL, NULL); - if (!GTK_IS_SCROLLABLE(s->widget)) - gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(s->scrolledWindow), s->widget); - else - gtk_container_add(GTK_CONTAINER(s->scrolledWindow), s->widget); - if (scrolledWindowHasBorder) - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(s->scrolledWindow), GTK_SHADOW_IN); - s->immediate = s->scrolledWindow; - } - - // we need to keep an extra reference on the immediate widget - // this is so uiControlDestroy() can work regardless of when it is called and who calls it - // without this: - // - end user call works (only one ref) - // - call in uiContainer destructor fails (uiContainer ref freed) - // with this: - // - end user call works (shoudn't be in any container) - // - call in uiContainer works (both refs freed) - // this also ensures singleRemoveParent() works properly - g_object_ref_sink(s->immediate); - - // assign s later; we still need it for one more thing - c->Destroy = singleDestroy; - c->Handle = singleHandle; - c->SetParent = singleSetParent; - c->PreferredSize = singlePreferredSize; - c->Resize = singleResize; - c->Visible = singleVisible; - c->Show = singleShow; - c->Hide = singleHide; - c->ContainerShow = singleContainerShow; - c->ContainerHide = singleContainerHide; - c->Enable = singleEnable; - c->Disable = singleDisable; - c->ContainerEnable = singleContainerEnable; - c->ContainerDisable = singleContainerDisable; - - // and let's free everything with the immediate widget - // we send s as data instead of c just in case c is gone by then - g_signal_connect(s->immediate, "destroy", G_CALLBACK(onDestroy), s); - - // finally, call gtk_widget_show_all() here to set the initial visibility of the widget - gtk_widget_show_all(s->immediate); - - c->Internal = s; -} diff --git a/new/unix/parent.c b/new/unix/parent.c deleted file mode 100644 index 54d5d066..00000000 --- a/new/unix/parent.c +++ /dev/null @@ -1,183 +0,0 @@ -// 13 august 2014 -#include "uipriv_unix.h" - -#define uipParentType (uipParent_get_type()) -#define uipParent(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), uipParentType, uipParent)) -#define uipIsParent(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), uipParentType)) -#define uipParentClass(class) (G_TYPE_CHECK_CLASS_CAST((class), uipParentType, uipParentClass)) -#define uipIsParentClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), uipParent)) -#define uipGetParentClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), uipParentType, uipParentClass)) - -typedef struct uipParent uipParent; -typedef struct uipParentClass uipParentClass; - -struct uipParent { - GtkContainer parent_instance; - // this is what triggers the resizing of all the children - uiControl *child; - // these are the actual children widgets of the container as far as GTK+ is concerned - GPtrArray *children; // for forall() - intmax_t marginLeft; - intmax_t marginTop; - intmax_t marginRight; - intmax_t marginBottom; -}; - -struct uipParentClass { - GtkContainerClass parent_class; -}; - -G_DEFINE_TYPE(uipParent, uipParent, GTK_TYPE_CONTAINER) - -static void uipParent_init(uipParent *p) -{ - if (options.debugLogAllocations) - fprintf(stderr, "%p alloc uipParent\n", p); - p->children = g_ptr_array_new(); - gtk_widget_set_has_window(GTK_WIDGET(p), FALSE); -} - -// instead of having GtkContainer itself unref all our controls, we'll run our own uiControlDestroy() functions for child, which will do that and more -// we still chain up because we need to, but by that point there will be no children for GtkContainer to free -static void uipParent_dispose(GObject *obj) -{ - uipParent *p = uipParent(obj); - - if (p->children != NULL) { - g_ptr_array_unref(p->children); - p->children = NULL; - } - if (p->child != NULL) { - uiControlDestroy(p->child); - p->child = NULL; - } - G_OBJECT_CLASS(uipParent_parent_class)->dispose(obj); -} - -static void uipParent_finalize(GObject *obj) -{ - G_OBJECT_CLASS(uipParent_parent_class)->finalize(obj); - if (options.debugLogAllocations) - fprintf(stderr, "%p free\n", obj); -} - -static void uipParent_add(GtkContainer *container, GtkWidget *widget) -{ - uipParent *p = uipParent(container); - - gtk_widget_set_parent(widget, GTK_WIDGET(p)); - if (p->children != NULL) - g_ptr_array_add(p->children, widget); -} - -static void uipParent_remove(GtkContainer *container, GtkWidget *widget) -{ - uipParent *p = uipParent(container); - - gtk_widget_unparent(widget); - if (p->children != NULL) - g_ptr_array_remove(p->children, widget); -} - -#define gtkXPadding 12 -#define gtkYPadding 6 - -static void uipParent_size_allocate(GtkWidget *widget, GtkAllocation *allocation) -{ - uipParent *p = uipParent(widget); - uiSizing d; - intmax_t x, y, width, height; - - gtk_widget_set_allocation(GTK_WIDGET(p), allocation); - if (p->child == NULL) - return; - x = allocation->x + p->marginLeft; - y = allocation->y + p->marginTop; - width = allocation->width - (p->marginLeft + p->marginRight); - height = allocation->height - (p->marginTop + p->marginBottom); - d.xPadding = gtkXPadding; - d.yPadding = gtkYPadding; - uiControlResize(p->child, x, y, width, height, &d); -} - -struct forall { - GtkCallback callback; - gpointer data; -}; - -static void doforall(gpointer obj, gpointer data) -{ - struct forall *s = (struct forall *) data; - - (*(s->callback))(GTK_WIDGET(obj), s->data); -} - -static void uipParent_forall(GtkContainer *container, gboolean includeInternals, GtkCallback callback, gpointer data) -{ - uipParent *p = uipParent(container); - struct forall s; - - s.callback = callback; - s.data = data; - if (p->children != NULL) - g_ptr_array_foreach(p->children, doforall, &s); -} - -static void uipParent_class_init(uipParentClass *class) -{ - G_OBJECT_CLASS(class)->dispose = uipParent_dispose; - G_OBJECT_CLASS(class)->finalize = uipParent_finalize; - GTK_WIDGET_CLASS(class)->size_allocate = uipParent_size_allocate; - GTK_CONTAINER_CLASS(class)->add = uipParent_add; - GTK_CONTAINER_CLASS(class)->remove = uipParent_remove; - GTK_CONTAINER_CLASS(class)->forall = uipParent_forall; -} - -static uintptr_t parentHandle(uiParent *p) -{ - uipParent *pp = uipParent(p->Internal); - - return (uintptr_t) pp; -} - -static void parentSetChild(uiParent *p, uiControl *child) -{ - uipParent *pp = uipParent(p->Internal); - - pp->child = child; - if (pp->child != NULL) - uiControlSetParent(child, p); -} - -static void parentSetMargins(uiParent *p, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom) -{ - uipParent *pp = uipParent(p->Internal); - - pp->marginLeft = left; - pp->marginTop = top; - pp->marginRight = right; - pp->marginBottom = bottom; -} - -static void parentUpdate(uiParent *p) -{ - uipParent *pp = uipParent(p->Internal); - - gtk_widget_queue_resize(GTK_WIDGET(pp)); -} - -uiParent *uiNewParent(uintptr_t osParent) -{ - uiParent *p; - - p = uiNew(uiParent); - p->Internal = g_object_new(uipParentType, NULL); - p->Handle = parentHandle; - p->SetChild = parentSetChild; - p->SetMargins = parentSetMargins; - p->Update = parentUpdate; - gtk_container_add(GTK_CONTAINER(osParent), GTK_WIDGET(p->Internal)); - // and make it visible by default - gtk_widget_show_all(GTK_WIDGET(p->Internal)); - return p; -} diff --git a/new/unix/tab.c b/new/unix/tab.c deleted file mode 100644 index bb168f56..00000000 --- a/new/unix/tab.c +++ /dev/null @@ -1,61 +0,0 @@ -// 12 april 2015 -#include "uipriv_unix.h" - -struct tab { - uiTab t; - uiParent **pages; - uintmax_t len; - uintmax_t cap; -}; - -static void onDestroy(GtkWidget *widget, gpointer data) -{ - struct tab *t = (struct tab *) data; - - uiFree(t->pages); - uiFree(t); -} - -#define TAB(t) GTK_NOTEBOOK(uiControlHandle(uiControl(t))) - -#define tabCapGrow 32 - -static void addPage(uiTab *tt, const char *name, uiControl *child) -{ - struct tab *t = (struct tab *) tt; - GtkWidget *notebook; - uiParent *content; - - if (t->len >= t->cap) { - t->cap += tabCapGrow; - t->pages = (uiParent **) uiRealloc(t->pages, t->cap * sizeof (uiParent *), "uiParent *[]"); - } - - notebook = GTK_WIDGET(TAB(t)); - content = uiNewParent((uintptr_t) notebook); - uiParentSetChild(content, child); - uiParentUpdate(content); - gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook), GTK_WIDGET(uiParentHandle(content)), name); - - t->pages[t->len] = content; - t->len++; -} - -uiTab *uiNewTab(void) -{ - struct tab *t; - GtkWidget *widget; - - t = uiNew(struct tab); - - uiUnixNewControl(uiControl(t), GTK_TYPE_NOTEBOOK, - FALSE, FALSE, - NULL); - - widget = GTK_WIDGET(TAB(t)); - g_signal_connect(widget, "destroy", G_CALLBACK(onDestroy), t); - - uiTab(t)->AddPage = addPage; - - return uiTab(t); -} diff --git a/new/unix/uipriv_unix.h b/new/unix/uipriv_unix.h deleted file mode 100644 index 0f460cbf..00000000 --- a/new/unix/uipriv_unix.h +++ /dev/null @@ -1,14 +0,0 @@ -// 6 april 2015 -#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_32 -#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_32 -#define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_4 -#define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_4 -#include -#include "../uipriv.h" -#include "../ui_unix.h" - -#define gtkXMargin 12 -#define gtkYMargin 12 - -#define widget(c) uiControlHandle(uiControl(c)) -#define WIDGET(c) GTK_WIDGET(widget(c)) diff --git a/new/unix/util.c b/new/unix/util.c deleted file mode 100644 index 72b71dfa..00000000 --- a/new/unix/util.c +++ /dev/null @@ -1,7 +0,0 @@ -// 9 april 2015 -#include "uipriv_unix.h" - -void uiFreeText(char *t) -{ - g_free(t); -} diff --git a/new/unix/window.c b/new/unix/window.c deleted file mode 100644 index 039feb7e..00000000 --- a/new/unix/window.c +++ /dev/null @@ -1,137 +0,0 @@ -// 6 april 2015 -#include "uipriv_unix.h" - -struct window { - uiWindow w; - GtkWidget *widget; - uiParent *content; - int (*onClosing)(uiWindow *, void *); - void *onClosingData; - int margined; -}; - -static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data) -{ - struct window *w = (struct window *) data; - - // return exact values just in case - if ((*(w->onClosing))(uiWindow(w), w->onClosingData)) - return FALSE; - return TRUE; -} - -static int defaultOnClosing(uiWindow *w, void *data) -{ - return 1; -} - -static void onDestroy(GtkWidget *widget, gpointer data) -{ - struct window *w = (struct window *) data; - - uiFree(w); -} - -static void windowDestroy(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - gtk_widget_destroy(w->widget); -} - -static uintptr_t handle(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - return (uintptr_t) (w->widget); -} - -static char *getTitle(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - return g_strdup(gtk_window_get_title(GTK_WINDOW(w->widget))); -} - -static void setTitle(uiWindow *ww, const char *title) -{ - struct window *w = (struct window *) ww; - - gtk_window_set_title(GTK_WINDOW(w->widget), title); -} - -static void show(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - // don't use gtk_widget_show_all(); that will override user hidden settings - gtk_widget_show(w->widget); -} - -static void hide(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - gtk_widget_hide(w->widget); -} - -static void setOnClosing(uiWindow *ww, int (*f)(uiWindow *, void *), void *data) -{ - struct window *w = (struct window *) ww; - - w->onClosing = f; - w->onClosingData = data; -} - -static void setChild(uiWindow *ww, uiControl *c) -{ - struct window *w = (struct window *) ww; - - uiParentSetChild(w->content, c); - uiParentUpdate(w->content); -} - -static int margined(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - return w->margined; -} - -static void setMargined(uiWindow *ww, int margined) -{ - struct window *w = (struct window *) ww; - - w->margined = margined; - if (w->margined) - uiParentSetMargins(w->content, gtkXMargin, gtkYMargin, gtkXMargin, gtkYMargin); - else - uiParentSetMargins(w->content, 0, 0, 0, 0); - uiParentUpdate(w->content); -} - -uiWindow *uiNewWindow(const char *title, int width, int height) -{ - struct window *w; - - w = uiNew(struct window); - w->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(w->widget), title); - gtk_window_resize(GTK_WINDOW(w->widget), width, height); - g_signal_connect(w->widget, "delete-event", G_CALLBACK(onClosing), w); - g_signal_connect(w->widget, "destroy", G_CALLBACK(onDestroy), w); - w->content = uiNewParent((uintptr_t) (w->widget)); - w->onClosing = defaultOnClosing; - - uiWindow(w)->Destroy = windowDestroy; - uiWindow(w)->Handle = handle; - uiWindow(w)->Title = getTitle; - uiWindow(w)->SetTitle = setTitle; - uiWindow(w)->Show = show; - uiWindow(w)->Hide = hide; - uiWindow(w)->OnClosing = setOnClosing; - uiWindow(w)->SetChild = setChild; - uiWindow(w)->Margined = margined; - uiWindow(w)->SetMargined = setMargined; - - return uiWindow(w); -} diff --git a/new/windows/GNUmakeinc.mk b/new/windows/GNUmakeinc.mk deleted file mode 100644 index 494b8e37..00000000 --- a/new/windows/GNUmakeinc.mk +++ /dev/null @@ -1,33 +0,0 @@ -OSCFILES = \ - alloc.c \ - button.c \ - checkbox.c \ - comctl32.c \ - debug.c \ - entry.c \ - init.c \ - label.c \ - main.c \ - newcontrol.c \ - parent.c \ - tab.c \ - text.c \ - util.c \ - window.c - -xLDFLAGS += \ - -luser32 -lkernel32 -lgdi32 -luxtheme -lmsimg32 -lcomdlg32 -lole32 -loleaut32 -loleacc -luuid - -OUT = new.exe - -ifeq ($(ARCH),64) - CC = x86_64-w64-mingw32-gcc - RC = x86_64-w64-mingw32-windres - xCFLAGS += -m64 - xLDFLAGS += -m64 -else - CC = i686-w64-mingw32-gcc - RC = i686-w64-mingw32-windres - xCFLAGS += -m32 - xLDFLAGS += -m32 -endif diff --git a/new/windows/alloc.c b/new/windows/alloc.c deleted file mode 100644 index 147c90d2..00000000 --- a/new/windows/alloc.c +++ /dev/null @@ -1,49 +0,0 @@ -// 4 december 2014 -#include "uipriv_windows.h" - -// wrappers for allocator of choice -// panics on memory exhausted, undefined on heap corruption or other unreliably-detected malady (see http://stackoverflow.com/questions/28761680/is-there-a-windows-api-memory-allocator-deallocator-i-can-use-that-will-just-giv) -// new memory is set to zero -// passing NULL to tableRealloc() acts like tableAlloc() -// passing NULL to tableFree() is a no-op - -void *uiAlloc(size_t size, const char *type) -{ - void *out; - - out = malloc(size); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiAlloc() allocating %s\n", type); - abort(); - } - ZeroMemory(out, size); - if (options.debugLogAllocations) - fprintf(stderr, "%p alloc %s\n", out, type); - return out; -} - -void *uiRealloc(void *p, size_t size, const char *type) -{ - void *out; - - if (p == NULL) - return uiAlloc(size, type); - out = realloc(p, size); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiRealloc() reallocating %s\n", type); - abort(); - } - // TODO zero the extra memory - if (options.debugLogAllocations) - fprintf(stderr, "%p realloc %p\n", p, out); - return out; -} - -void uiFree(void *p) -{ - if (p == NULL) - return; - free(p); - if (options.debugLogAllocations) - fprintf(stderr, "%p free\n", p); -} diff --git a/new/windows/button.c b/new/windows/button.c deleted file mode 100644 index fd7afa3d..00000000 --- a/new/windows/button.c +++ /dev/null @@ -1,112 +0,0 @@ -// 7 april 2015 -#include "uipriv_windows.h" - -struct button { - uiButton b; - void (*onClicked)(uiButton *, void *); - void *onClickedData; -}; - -static BOOL onWM_COMMAND(uiControl *c, WORD code, LRESULT *lResult) -{ - struct button *b = (struct button *) c; - - if (code != BN_CLICKED) - return FALSE; - (*(b->onClicked))(uiButton(b), b->onClickedData); - *lResult = 0; - return TRUE; -} - -static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) -{ - return FALSE; -} - -static void onWM_DESTROY(uiControl *c) -{ - struct button *b = (struct button *) c; - - uiFree(b); -} - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define buttonHeight 14 - -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - HWND hwnd; - SIZE size; - - hwnd = uiControlHWND(c); - - // try the comctl32 version 6 way - size.cx = 0; // explicitly ask for ideal size - size.cy = 0; - if (SendMessageW(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM) (&size)) != FALSE) { - *width = size.cx; - *height = size.cy; - return; - } - - // that didn't work; fall back to using Microsoft's metrics - // Microsoft says to use a fixed width for all buttons; this isn't good enough - // use the text width instead, with some edge padding - *width = uiWindowsWindowTextWidth(hwnd) + (2 * GetSystemMetrics(SM_CXEDGE)); - *height = uiDlgUnitsToY(buttonHeight, d->sys->baseY); -} - -static void defaultOnClicked(uiButton *b, void *data) -{ - // do nothing -} - -static char *getText(uiButton *b) -{ - return uiWindowsControlText(uiControl(b)); -} - -static void setText(uiButton *b, const char *text) -{ - uiWindowsControlSetText(uiControl(b), text); -} - -static void setOnClicked(uiButton *bb, void (*f)(uiButton *, void *), void *data) -{ - struct button *b = (struct button *) bb; - - b->onClicked = f; - b->onClickedData = data; -} - -uiButton *uiNewButton(const char *text) -{ - struct button *b; - uiWindowsNewControlParams p; - WCHAR *wtext; - - b = uiNew(struct button); - - p.dwExStyle = 0; - p.lpClassName = L"button"; - wtext = toUTF16(text); - p.lpWindowName = wtext; - p.dwStyle = BS_PUSHBUTTON | WS_TABSTOP; - p.hInstance = hInstance; - p.useStandardControlFont = TRUE; - p.onWM_COMMAND = onWM_COMMAND; - p.onWM_NOTIFY = onWM_NOTIFY; - p.onWM_DESTROY = onWM_DESTROY; - uiWindowsNewControl(uiControl(b), &p); - uiFree(wtext); - - b->onClicked = defaultOnClicked; - - uiControl(b)->PreferredSize = preferredSize; - - uiButton(b)->Text = getText; - uiButton(b)->SetText = setText; - uiButton(b)->OnClicked = setOnClicked; - - return uiButton(b); -} diff --git a/new/windows/checkbox.c b/new/windows/checkbox.c deleted file mode 100644 index c1d5a6f5..00000000 --- a/new/windows/checkbox.c +++ /dev/null @@ -1,129 +0,0 @@ -// 7 april 2015 -#include "uipriv_windows.h" - -struct checkbox { - uiCheckbox c; - void (*onToggled)(uiCheckbox *, void *); - void *onToggledData; -}; - -static BOOL onWM_COMMAND(uiControl *cc, WORD code, LRESULT *lResult) -{ - struct checkbox *c = (struct checkbox *) cc; - HWND hwnd; - WPARAM check; - - if (code != BN_CLICKED) - return FALSE; - - // we didn't use BS_AUTOCHECKBOX (see controls_windows.go) so we have to manage the check state ourselves - hwnd = uiControlHWND(uiControl(c)); - check = BST_CHECKED; - if (SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) - check = BST_UNCHECKED; - SendMessage(hwnd, BM_SETCHECK, check, 0); - - (*(c->onToggled))(uiCheckbox(c), c->onToggledData); - *lResult = 0; - return TRUE; -} - -static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) -{ - return FALSE; -} - -static void onWM_DESTROY(uiControl *cc) -{ - struct checkbox *c = (struct checkbox *) cc; - - uiFree(c); -} - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define checkboxHeight 10 -// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx -#define checkboxXFromLeftOfBoxToLeftOfLabel 12 - -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - *width = uiDlgUnitsToX(checkboxXFromLeftOfBoxToLeftOfLabel, d->sys->baseX) + uiWindowsWindowTextWidth(uiControlHWND(c)); - *height = uiDlgUnitsToY(checkboxHeight, d->sys->baseY); -} - -static void defaultOnToggled(uiCheckbox *c, void *data) -{ - // do nothing -} - -static char *getText(uiCheckbox *c) -{ - return uiWindowsControlText(uiControl(c)); -} - -static void setText(uiCheckbox *c, const char *text) -{ - uiWindowsControlSetText(uiControl(c), text); -} - -static void setOnToggled(uiCheckbox *cc, void (*f)(uiCheckbox *, void *), void *data) -{ - struct checkbox *c = (struct checkbox *) cc; - - c->onToggled = f; - c->onToggledData = data; -} - -static int getChecked(uiCheckbox *c) -{ - HWND hwnd; - - hwnd = uiControlHWND(uiControl(c)); - return SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED; -} - -static void setChecked(uiCheckbox *c, int checked) -{ - HWND hwnd; - WPARAM check; - - hwnd = uiControlHWND(uiControl(c)); - check = BST_CHECKED; - if (!checked) - check = BST_UNCHECKED; - SendMessage(hwnd, BM_SETCHECK, check, 0); -} - -uiCheckbox *uiNewCheckbox(const char *text) -{ - struct checkbox *c; - uiWindowsNewControlParams p; - WCHAR *wtext; - - c = uiNew(struct checkbox); - - p.dwExStyle = 0; - p.lpClassName = L"button"; - wtext = toUTF16(text); - p.lpWindowName = wtext; - p.dwStyle = BS_CHECKBOX | WS_TABSTOP; - p.hInstance = hInstance; - p.useStandardControlFont = TRUE; - p.onWM_COMMAND = onWM_COMMAND; - p.onWM_NOTIFY = onWM_NOTIFY; - p.onWM_DESTROY = onWM_DESTROY; - uiWindowsNewControl(uiControl(c), &p); - uiFree(wtext); - - c->onToggled = defaultOnToggled; - - uiControl(c)->PreferredSize = preferredSize; - - uiCheckbox(c)->Text = getText; - uiCheckbox(c)->SetText = setText; - uiCheckbox(c)->OnToggled = setOnToggled; - uiCheckbox(c)->Checked = getChecked; - uiCheckbox(c)->SetChecked = setChecked; - - return uiCheckbox(c); -} diff --git a/new/windows/comctl32.c b/new/windows/comctl32.c deleted file mode 100644 index 93b3a271..00000000 --- a/new/windows/comctl32.c +++ /dev/null @@ -1,105 +0,0 @@ -// 17 july 2014 -#include "uipriv_windows.h" - -static ULONG_PTR comctlManifestCookie; -static HMODULE comctl32; - -// these are listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason -BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); -BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR); -LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM); - -#define wantedICCClasses ( \ - ICC_STANDARD_CLASSES | /* user32.dll controls */ \ - ICC_PROGRESS_CLASS | /* progress bars */ \ - ICC_TAB_CLASSES | /* tabs */ \ - ICC_LISTVIEW_CLASSES | /* table headers */ \ - ICC_UPDOWN_CLASS | /* spinboxes */ \ - 0) - -// note that this is an 8-bit character string we're writing; see the encoding clause -static const char manifest[] = "\n\n\nYour application description here.\n\n \n \n \n\n\n"; - -/* -Windows requires a manifest file to enable Common Controls version 6. -The only way to not require an external manifest is to synthesize the manifest ourselves. -We can use the activation context API to load it at runtime. -References: -- http://stackoverflow.com/questions/4308503/how-to-enable-visual-styles-without-a-manifest -- http://support.microsoft.com/kb/830033 -Because neither Go nor MinGW have ways to compile in resources like this (as far as I know), we have to do the work ourselves. -*/ -const char *initCommonControls(void) -{ - WCHAR temppath[MAX_PATH + 1]; - WCHAR filename[MAX_PATH + 1]; - HANDLE file; - DWORD nExpected, nGot; - ACTCTX actctx; - HANDLE ac; - INITCOMMONCONTROLSEX icc; - FARPROC f; - // this is listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason - BOOL (*WINAPI ficc)(const LPINITCOMMONCONTROLSEX); - - if (GetTempPathW(MAX_PATH + 1, temppath) == 0) - return "getting temporary path for writing manifest file in initCommonControls()"; - if (GetTempFileNameW(temppath, L"manifest", 0, filename) == 0) - return "getting temporary filename for writing manifest file in initCommonControls()"; - file = CreateFileW(filename, GENERIC_WRITE, - 0, // don't share while writing - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (file == NULL) - return "creating manifest file in initCommonControls()"; - nExpected = (sizeof manifest / sizeof manifest[0]) - 1; // - 1 to omit the terminating null character) - SetLastError(0); // catch errorless short writes - if (WriteFile(file, manifest, nExpected, &nGot, NULL) == 0) - return "writing manifest file in initCommonControls()"; - if (nGot != nExpected) { - DWORD lasterr; - - lasterr = GetLastError(); - if (lasterr == 0) - return "writing entire manifest file (short write) without error code in initCommonControls()"; - return "writing entire manifest file (short write) in initCommonControls()"; - } - if (CloseHandle(file) == 0) - return "closing manifest file (this IS an error here because not doing so will prevent Windows from being able to use the manifest file in an activation context) in initCommonControls()"; - - ZeroMemory(&actctx, sizeof (ACTCTX)); - actctx.cbSize = sizeof (ACTCTX); - actctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT; - actctx.lpSource = filename; - ac = CreateActCtx(&actctx); - if (ac == INVALID_HANDLE_VALUE) - return "creating activation context for synthesized manifest file in initCommonControls()"; - if (ActivateActCtx(ac, &comctlManifestCookie) == FALSE) - return "activating activation context for synthesized manifest file in initCommonControls()"; - - ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX)); - icc.dwSize = sizeof (INITCOMMONCONTROLSEX); - icc.dwICC = wantedICCClasses; - - comctl32 = LoadLibraryW(L"comctl32.dll"); - if (comctl32 == NULL) - return "loading comctl32.dll in initCommonControls()"; - - // GetProcAddress() only takes a multibyte string -#define LOAD(fn) f = GetProcAddress(comctl32, fn); \ - if (f == NULL) \ - return "loading " fn "() in initCommonControls()"; - - LOAD("InitCommonControlsEx"); - ficc = (BOOL (*WINAPI)(const LPINITCOMMONCONTROLSEX)) f; - LOAD("SetWindowSubclass"); - fv_SetWindowSubclass = (BOOL (*WINAPI)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR)) f; - LOAD("RemoveWindowSubclass"); - fv_RemoveWindowSubclass = (BOOL (*WINAPI)(HWND, SUBCLASSPROC, UINT_PTR)) f; - LOAD("DefSubclassProc"); - fv_DefSubclassProc = (LRESULT (*WINAPI)(HWND, UINT, WPARAM, LPARAM)) f; - - if ((*ficc)(&icc) == FALSE) - return "initializing Common Controls (comctl32.dll) in initCommonControls()"; - - return NULL; -} diff --git a/new/windows/debug.c b/new/windows/debug.c deleted file mode 100644 index bc84b639..00000000 --- a/new/windows/debug.c +++ /dev/null @@ -1,111 +0,0 @@ -// 25 february 2015 -#include "uipriv_windows.h" - -// uncomment the following line to enable debug messages -#define tableDebug -// uncomment the following line to halt on a debug message -#define tableDebugStop - -#ifdef tableDebug - -#include - -HRESULT logLastError(const char *context) -{ - DWORD le; - WCHAR *msg; - BOOL parenthesize = FALSE; - BOOL localFreeFailed = FALSE; - DWORD localFreeLastError; - - le = GetLastError(); - fprintf(stderr, "%s: ", context); - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, le, 0, (LPWSTR) (&msg), 0, NULL) != 0) { - fprintf(stderr, "%S (", msg); - if (LocalFree(msg) != NULL) { - localFreeFailed = TRUE; - localFreeLastError = GetLastError(); - } - parenthesize = TRUE; - } - fprintf(stderr, "GetLastError() == %I32u", le); - if (parenthesize) - fprintf(stderr, ")"); - if (localFreeFailed) - fprintf(stderr, "; local free of system message failed with last error %I32u", localFreeLastError); - fprintf(stderr, "\n"); -#ifdef tableDebugStop - DebugBreak(); -#endif - SetLastError(le); - // a function does not have to set a last error - // if the last error we get is actually 0, then HRESULT_FROM_WIN32(0) will return S_OK (0 cast to an HRESULT, since 0 <= 0), which we don't want - // prevent this by returning E_FAIL, so the rest of the Table code doesn't barge onward - if (le == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(le); -} - -HRESULT logHRESULT(const char *context, HRESULT hr) -{ - WCHAR *msg; - BOOL parenthesize = FALSE; - BOOL localFreeFailed = FALSE; - DWORD localFreeLastError; - - fprintf(stderr, "%s: ", context); - // this isn't technically documented, but everyone does it, including Microsoft (see the implementation of _com_error::ErrorMessage() in a copy of comdef.h that comes with the Windows DDK) - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) hr, 0, (LPWSTR) (&msg), 0, NULL) != 0) { - fprintf(stderr, "%S (", msg); - if (LocalFree(msg) != NULL) { - localFreeFailed = TRUE; - localFreeLastError = GetLastError(); - } - parenthesize = TRUE; - } - fprintf(stderr, "HRESULT == 0x%I32X", hr); - if (parenthesize) - fprintf(stderr, ")"); - if (localFreeFailed) - fprintf(stderr, "; local free of system message failed with last error %I32u", localFreeLastError); - fprintf(stderr, "\n"); -#ifdef tableDebugStop - DebugBreak(); -#endif - return hr; -} - -HRESULT logMemoryExhausted(const char *reason) -{ - fprintf(stderr, "memory exhausted %s\n", reason); -#ifdef tableDebugStop - DebugBreak(); -#endif - return E_OUTOFMEMORY; -} - -#else - -HRESULT logLastError(const char *reason) -{ - DWORD le; - - le = GetLastError(); - // we shouldn't need to do this, but let's do this anyway just to be safe - SetLastError(le); - if (le == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(le); -} - -HRESULT logHRESULT(const char *reason, HRESULT hr) -{ - return hr; -} - -HRESULT logMemoryExhausted(const char *reason) -{ - return E_OUTOFMEMORY; -} - -#endif diff --git a/new/windows/entry.c b/new/windows/entry.c deleted file mode 100644 index 22c108a3..00000000 --- a/new/windows/entry.c +++ /dev/null @@ -1,69 +0,0 @@ -// 8 april 2015 -#include "uipriv_windows.h" - -struct entry { - uiEntry e; -}; - -static BOOL onWM_COMMAND(uiControl *c, WORD code, LRESULT *lResult) -{ - return FALSE; -} - -static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) -{ - return FALSE; -} - -static void onWM_DESTROY(uiControl *c) -{ - struct entry *e = (struct entry *) c; - - uiFree(e); -} - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define entryWidth 107 /* this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary */ -#define entryHeight 14 - -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - *width = uiDlgUnitsToX(entryWidth, d->sys->baseX); - *height = uiDlgUnitsToY(entryHeight, d->sys->baseY); -} - -static char *getText(uiEntry *e) -{ - return uiWindowsControlText(uiControl(e)); -} - -static void setText(uiEntry *e, const char *text) -{ - uiWindowsControlSetText(uiControl(e), text); -} - -uiEntry *uiNewEntry(void) -{ - struct entry *e; - uiWindowsNewControlParams p; - - e = uiNew(struct entry); - - p.dwExStyle = WS_EX_CLIENTEDGE; - p.lpClassName = L"edit"; - p.lpWindowName = L""; - p.dwStyle = ES_AUTOHSCROLL | ES_LEFT | ES_NOHIDESEL | WS_TABSTOP; - p.hInstance = hInstance; - p.useStandardControlFont = TRUE; - p.onWM_COMMAND = onWM_COMMAND; - p.onWM_NOTIFY = onWM_NOTIFY; - p.onWM_DESTROY = onWM_DESTROY; - uiWindowsNewControl(uiControl(e), &p); - - uiControl(e)->PreferredSize = preferredSize; - - uiEntry(e)->Text = getText; - uiEntry(e)->SetText = setText; - - return uiEntry(e); -} diff --git a/new/windows/init.c b/new/windows/init.c deleted file mode 100644 index 99039345..00000000 --- a/new/windows/init.c +++ /dev/null @@ -1,112 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -HINSTANCE hInstance; -int nCmdShow; - -HFONT hMessageFont; - -HBRUSH hollowBrush; - -struct uiInitError { - char *msg; - char failbuf[256]; -}; - -#define initErrorFormat L"error %s: %s%sGetLastError() == %I32u%s" -#define initErrorArgs wmessage, sysmsg, beforele, le, afterle - -static const char *loadLastError(const char *message) -{ - WCHAR *sysmsg; - BOOL hassysmsg; - WCHAR *beforele; - WCHAR *afterle; - int n; - WCHAR *wmessage; - WCHAR *wstr; - const char *str; - DWORD le; - - le = GetLastError(); - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, le, 0, (LPWSTR) (&sysmsg), 0, NULL) != 0) { - hassysmsg = TRUE; - beforele = L" ("; - afterle = L")"; - } else { - hassysmsg = FALSE; - sysmsg = L""; - beforele = L""; - afterle = L""; - } - wmessage = toUTF16(message); - n = _scwprintf(initErrorFormat, initErrorArgs); - wstr = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]"); - snwprintf(wstr, n + 1, initErrorFormat, initErrorArgs); - str = toUTF8(wstr); - uiFree(wstr); - if (hassysmsg) - if (LocalFree(sysmsg) != NULL) - logLastError("error freeing system message in loadLastError()"); - uiFree(wmessage); - return str; -} - -uiInitOptions options; - -const char *uiInit(uiInitOptions *o) -{ - STARTUPINFOW si; - const char *ce; - HICON hDefaultIcon; - HCURSOR hDefaultCursor; - NONCLIENTMETRICSW ncm; - - options = *o; - - hInstance = GetModuleHandle(NULL); - if (hInstance == NULL) - return loadLastError("getting program HINSTANCE"); - - nCmdShow = SW_SHOWDEFAULT; - GetStartupInfoW(&si); - if ((si.dwFlags & STARTF_USESHOWWINDOW) != 0) - nCmdShow = si.wShowWindow; - - ce = initCommonControls(); - if (ce != NULL) - return loadLastError(ce); - - hDefaultIcon = LoadIconW(NULL, IDI_APPLICATION); - if (hDefaultIcon == NULL) - return loadLastError("loading default icon for window classes"); - hDefaultCursor = LoadCursorW(NULL, IDC_ARROW); - if (hDefaultCursor == NULL) - return loadLastError("loading default cursor for window classes"); - - if (registerWindowClass(hDefaultIcon, hDefaultCursor) == 0) - return loadLastError("registering uiWindow window class"); - - ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW)); - ncm.cbSize = sizeof (NONCLIENTMETRICSW); - if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0) - return loadLastError("getting default fonts"); - hMessageFont = CreateFontIndirectW(&(ncm.lfMessageFont)); - if (hMessageFont == NULL) - return loadLastError("loading default messagebox font; this is the default UI font"); - - ce = initParent(hDefaultIcon, hDefaultCursor); - if (ce != NULL) - return loadLastError(ce); - - hollowBrush = (HBRUSH) GetStockObject(HOLLOW_BRUSH); - if (hollowBrush == NULL) - return loadLastError("getting hollow brush"); - - return NULL; -} - -void uiFreeInitError(const char *err) -{ - uiFree((void *) err); -} diff --git a/new/windows/label.c b/new/windows/label.c deleted file mode 100644 index 29c03f77..00000000 --- a/new/windows/label.c +++ /dev/null @@ -1,73 +0,0 @@ -// 11 april 2015 -#include "uipriv_windows.h" - -struct label { - uiLabel l; -}; - -static BOOL onWM_COMMAND(uiControl *c, WORD code, LRESULT *lResult) -{ - return FALSE; -} - -static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) -{ - return FALSE; -} - -static void onWM_DESTROY(uiControl *c) -{ - struct label *l = (struct label *) c; - - uiFree(l); -} - -// via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define labelHeight 8 - -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - *width = uiWindowsWindowTextWidth(uiControlHWND(c)); - *height = uiDlgUnitsToY(labelHeight, d->sys->baseY); -} - -static char *getText(uiLabel *l) -{ - return uiWindowsControlText(uiControl(l)); -} - -static void setText(uiLabel *l, const char *text) -{ - uiWindowsControlSetText(uiControl(l), text); -} - -uiLabel *uiNewLabel(const char *text) -{ - struct label *l; - uiWindowsNewControlParams p; - WCHAR *wtext; - - l = uiNew(struct label); - - p.dwExStyle = 0; - p.lpClassName = L"static"; - wtext = toUTF16(text); - p.lpWindowName = wtext; - // SS_LEFTNOWORDWRAP clips text past the end; SS_NOPREFIX avoids accelerator translation - // controls are vertically aligned to the top by default (thanks Xeek in irc.freenode.net/#winapi) - p.dwStyle = SS_LEFTNOWORDWRAP | SS_NOPREFIX; - p.hInstance = hInstance; - p.useStandardControlFont = TRUE; - p.onWM_COMMAND = onWM_COMMAND; - p.onWM_NOTIFY = onWM_NOTIFY; - p.onWM_DESTROY = onWM_DESTROY; - uiWindowsNewControl(uiControl(l), &p); - uiFree(wtext); - - uiControl(l)->PreferredSize = preferredSize; - - uiLabel(l)->Text = getText; - uiLabel(l)->SetText = setText; - - return uiLabel(l); -} diff --git a/new/windows/main.c b/new/windows/main.c deleted file mode 100644 index bd973b72..00000000 --- a/new/windows/main.c +++ /dev/null @@ -1,56 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -// #qo LDFLAGS: -luser32 -lkernel32 -lgdi32 -luxtheme -lmsimg32 -lcomdlg32 -lole32 -loleaut32 -loleacc -luuid - -static void uimsgloop_else(MSG *msg) -{ - TranslateMessage(msg); - DispatchMessage(msg); -} - -void uiMain(void) -{ - MSG msg; - int res; - HWND active, focus; - - for (;;) { - SetLastError(0); - res = GetMessageW(&msg, NULL, 0, 0); - if (res < 0) - logLastError("error calling GetMessage() in uiMain()"); - if (res == 0) // WM_QUIT - break; - active = GetActiveWindow(); - if (active == NULL) { - uimsgloop_else(&msg); - continue; - } - - // 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 - focus = GetFocus(); - if (focus != NULL) { -/*TODO switch (windowClassOf(focus, areaWindowClass, WC_TABCONTROLW, NULL)) { - case 0: // areaWindowClass - uimsgloop_area(active, focus, &msg); - continue; - case 1: // WC_TABCONTROLW - uimsgloop_tab(active, focus, &msg); - continue; - } - // else fall through -*/ } - - if (IsDialogMessage(active, &msg) != 0) - continue; - uimsgloop_else(&msg); - } -} - -void uiQuit(void) -{ - PostQuitMessage(0); -} diff --git a/new/windows/newcontrol.c b/new/windows/newcontrol.c deleted file mode 100644 index 565ec052..00000000 --- a/new/windows/newcontrol.c +++ /dev/null @@ -1,237 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -typedef struct singleHWND singleHWND; - -struct singleHWND { - HWND hwnd; - BOOL (*onWM_COMMAND)(uiControl *, WORD, LRESULT *); - BOOL (*onWM_NOTIFY)(uiControl *, NMHDR *, LRESULT *); - void (*onWM_DESTROY)(uiControl *); - uiParent *parent; - BOOL userHid; - BOOL containerHid; - BOOL userDisabled; - BOOL containerDisabled; -}; - -static void singleDestroy(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - if (DestroyWindow(s->hwnd) == 0) - logLastError("error destroying control in singleDestroy()"); - // the data structures are destroyed in the subclass procedure -} - -static uintptr_t singleHandle(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - return (uintptr_t) (s->hwnd); -} - -static void singleSetParent(uiControl *c, uiParent *parent) -{ - singleHWND *s = (singleHWND *) (c->Internal); - uiParent *oldparent; - HWND newParentHWND; - - oldparent = s->parent; - s->parent = parent; - newParentHWND = initialParent; - if (s->parent != NULL) - newParentHWND = uiParentHWND(s->parent); - if (SetParent(s->hwnd, newParentHWND) == NULL) - logLastError("error setting control parent in singleSetParent()"); - if (oldparent != NULL) - uiParentUpdate(oldparent); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void singleResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - if (MoveWindow(s->hwnd, x, y, width, height, TRUE) == 0) - logLastError("error moving control in singleResize()"); -} - -static int singleVisible(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - if (s->userHid) - return 0; - return 1; -} - -static void singleShow(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->userHid = FALSE; - if (!s->containerHid) { - ShowWindow(s->hwnd, SW_SHOW); - if (s->parent != NULL) - uiParentUpdate(s->parent); - } -} - -static void singleHide(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->userHid = TRUE; - ShowWindow(s->hwnd, SW_HIDE); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void singleContainerShow(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->containerHid = FALSE; - if (!s->userHid) { - ShowWindow(s->hwnd, SW_SHOW); - if (s->parent != NULL) - uiParentUpdate(s->parent); - } -} - -static void singleContainerHide(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->containerHid = TRUE; - ShowWindow(s->hwnd, SW_HIDE); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void singleEnable(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->userDisabled = FALSE; - if (!s->containerDisabled) - EnableWindow(s->hwnd, TRUE); -} - -static void singleDisable(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->userDisabled = TRUE; - EnableWindow(s->hwnd, FALSE); -} - -static void singleContainerEnable(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->containerDisabled = FALSE; - if (!s->userDisabled) - EnableWindow(s->hwnd, TRUE); -} - -static void singleContainerDisable(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->containerDisabled = TRUE; - EnableWindow(s->hwnd, FALSE); -} - -static LRESULT CALLBACK singleSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - uiControl *c = (uiControl *) dwRefData; - singleHWND *s = (singleHWND *) (c->Internal); - LRESULT lResult; - - switch (uMsg) { - case msgCOMMAND: - if ((*(s->onWM_COMMAND))(c, HIWORD(wParam), &lResult) != FALSE) - return lResult; - break; - case msgNOTIFY: - if ((*(s->onWM_NOTIFY))(c, (NMHDR *) lParam, &lResult) != FALSE) - return lResult; - break; - case WM_DESTROY: - (*(s->onWM_DESTROY))(c); - uiFree(s); - break; - case WM_NCDESTROY: - if ((*fv_RemoveWindowSubclass)(hwnd, singleSubclassProc, uIdSubclass) == FALSE) - logLastError("error removing Windows control subclass in singleSubclassProc()"); - break; - } - return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); -} - -void uiWindowsNewControl(uiControl *c, uiWindowsNewControlParams *p) -{ - singleHWND *s; - - s = uiNew(singleHWND); - s->hwnd = CreateWindowExW(p->dwExStyle, - p->lpClassName, p->lpWindowName, - p->dwStyle | WS_CHILD | WS_VISIBLE, - 0, 0, - // use a nonzero initial size just in case some control breaks with a zero initial size - 100, 100, - initialParent, NULL, p->hInstance, NULL); - if (s->hwnd == NULL) - logLastError("error creating control in uiWindowsNewControl()"); - s->onWM_COMMAND = p->onWM_COMMAND; - s->onWM_NOTIFY = p->onWM_NOTIFY; - s->onWM_DESTROY = p->onWM_DESTROY; - - c->Destroy = singleDestroy; - c->Handle = singleHandle; - c->SetParent = singleSetParent; - c->Resize = singleResize; - c->Visible = singleVisible; - c->Show = singleShow; - c->Hide = singleHide; - c->ContainerShow = singleContainerShow; - c->ContainerHide = singleContainerHide; - c->Enable = singleEnable; - c->Disable = singleDisable; - c->ContainerEnable = singleContainerEnable; - c->ContainerDisable = singleContainerDisable; - - if (p->useStandardControlFont) - SendMessageW(s->hwnd, WM_SETFONT, (WPARAM) hMessageFont, (LPARAM) TRUE); - - if ((*fv_SetWindowSubclass)(s->hwnd, singleSubclassProc, 0, (DWORD_PTR) c) == FALSE) - logLastError("error subclassing Windows control in uiWindowsNewControl()"); - - c->Internal = s; -} - -char *uiWindowsControlText(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - WCHAR *wtext; - char *text; - - wtext = windowText(s->hwnd); - text = toUTF8(wtext); - uiFree(wtext); - return text; -} - -void uiWindowsControlSetText(uiControl *c, const char *text) -{ - singleHWND *s = (singleHWND *) (c->Internal); - WCHAR *wtext; - - wtext = toUTF16(text); - if (SetWindowTextW(s->hwnd, wtext) == 0) - logLastError("error setting control text in uiWindowsControlSetText()"); - uiFree(wtext); -} diff --git a/new/windows/parent.c b/new/windows/parent.c deleted file mode 100644 index b3606d1f..00000000 --- a/new/windows/parent.c +++ /dev/null @@ -1,268 +0,0 @@ -// 10 april 2015 -#include "uipriv_windows.h" - -// All controls in package ui are children of a window of this class. -// This keeps everything together, makes hiding controls en masse (tab page switching, for instance) easy, and makes the overall design cleaner. -// In addition, controls that are first created or don't have a parent are considered children of the "initial parent", which is also of this class. -// This parent is invisible, disabled, and should not be interacted with. - -// TODOs -// - wiith CTLCOLOR handler: [12:24] There's flickering between tabs -// - with CTLCOLOR handler: [12:24] And setting the button text blanked out the entire GUI until I ran my mouse over the elements / [12:25] https://dl.dropboxusercontent.com/u/15144168/GUI%20stuff.png / [12:41] https://dl.dropboxusercontent.com/u/15144168/stack.png here have another screenshot -// - I get this too - -#define uiParentClass L"uiParentClass" - -HWND initialParent; - -static void paintControlBackground(HWND hwnd, HDC dc) -{ - HWND parent; - RECT r; - POINT pOrig; - DWORD le; - - parent = hwnd; - for (;;) { - parent = GetParent(parent); - if (parent == NULL) - logLastError("error getting parent control of control in paintControlBackground()"); - // wine sends these messages early, yay... - if (parent == initialParent) - return; - // skip groupboxes; they're (supposed to be) transparent - if (windowClassOf(parent, L"button", NULL) != 0) - break; - } - if (GetWindowRect(hwnd, &r) == 0) - logLastError("error getting control's window rect in paintControlBackground()"); - // the above is a window rect in screen coordinates; convert to parent coordinates - SetLastError(0); - if (MapWindowRect(NULL, parent, &r) == 0) { - le = GetLastError(); - SetLastError(le); // just to be safe - if (le != 0) - logLastError("error getting client origin of control in paintControlBackground()"); - } - if (SetWindowOrgEx(dc, r.left, r.top, &pOrig) == 0) - logLastError("error moving window origin in paintControlBackground()"); - SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) dc, PRF_CLIENT); - if (SetWindowOrgEx(dc, pOrig.x, pOrig.y, NULL) == 0) - logLastError("error resetting window origin in paintControlBackground()"); -} - -// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing and https://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx -// this X value is really only for buttons but I don't see a better one :/ -#define winXPadding 4 -#define winYPadding 4 - -static void resize(uiControl *control, HWND parent, RECT r, RECT margin) -{ - uiSizing d; - uiSizingSys sys; - HDC dc; - HFONT prevfont; - TEXTMETRICW tm; - SIZE size; - - size.cx = 0; - size.cy = 0; - ZeroMemory(&tm, sizeof (TEXTMETRICW)); - dc = GetDC(parent); - if (dc == NULL) - logLastError("error getting DC in resize()"); - prevfont = (HFONT) SelectObject(dc, hMessageFont); - if (prevfont == NULL) - logLastError("error loading control font into device context in resize()"); - if (GetTextMetricsW(dc, &tm) == 0) - logLastError("error getting text metrics in resize()"); - if (GetTextExtentPoint32W(dc, L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size) == 0) - logLastError("error getting text extent point in resize()"); - sys.baseX = (int) ((size.cx / 26 + 1) / 2); - sys.baseY = (int) tm.tmHeight; - sys.internalLeading = tm.tmInternalLeading; - if (SelectObject(dc, prevfont) != hMessageFont) - logLastError("error restoring previous font into device context in resize()"); - if (ReleaseDC(parent, dc) == 0) - logLastError("error releasing DC in resize()"); - r.left += uiDlgUnitsToX(margin.left, sys.baseX); - r.top += uiDlgUnitsToY(margin.top, sys.baseY); - r.right -= uiDlgUnitsToX(margin.right, sys.baseX); - r.bottom -= uiDlgUnitsToY(margin.bottom, sys.baseY); - d.xPadding = uiDlgUnitsToX(winXPadding, sys.baseX); - d.yPadding = uiDlgUnitsToY(winYPadding, sys.baseY); - d.sys = &sys; - uiControlResize(control, r.left, r.top, r.right - r.left, r.bottom - r.top, &d); -} - -struct parent { - HWND hwnd; - uiControl *child; - intmax_t marginLeft; - intmax_t marginTop; - intmax_t marginRight; - intmax_t marginBottom; -}; - -static LRESULT CALLBACK parentWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - uiParent *p; - struct parent *pp; - CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; - HWND control; - NMHDR *nm = (NMHDR *) lParam; - WINDOWPOS *wp = (WINDOWPOS *) lParam; - RECT r, margin; - - // these must always be executed, even on the initial parent - // why? http://blogs.msdn.com/b/oldnewthing/archive/2010/03/16/9979112.aspx - switch (uMsg) { - case WM_COMMAND: - // bounce back to the control in question - // except if to the initial parent, in which case act as if the message was ignored - control = (HWND) lParam; - if (control != NULL && IsChild(initialParent, control) == 0) - return SendMessageW(control, msgCOMMAND, wParam, lParam); - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - case WM_NOTIFY: - // same as WM_COMMAND - control = nm->hwndFrom; - if (control != NULL && IsChild(initialParent, control) == 0) - return SendMessageW(control, msgNOTIFY, wParam, lParam); - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - case WM_CTLCOLORSTATIC: - case WM_CTLCOLORBTN: -/*TODO // read-only TextFields and Textboxes are exempt - // this is because read-only edit controls count under WM_CTLCOLORSTATIC - if (windowClassOf((HWND) lParam, L"edit", NULL) == 0) - if (textfieldReadOnly((HWND) lParam)) - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -*/ if (SetBkMode((HDC) wParam, TRANSPARENT) == 0) - logLastError("error setting transparent background mode to controls in parentWndProc()"); - paintControlBackground((HWND) lParam, (HDC) wParam); - return (LRESULT) hollowBrush; - } - - // these are only executed on actual parents - p = (uiParent *) GetWindowLongPtrW(hwnd, GWLP_USERDATA); - if (p == NULL) { - if (uMsg == WM_NCCREATE) { - p = (uiParent *) (cs->lpCreateParams); - // this will be NULL for the initial parent; that's what we want - SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) p); - // fall through to DefWindowProcW() - } - // this is the return the initial parent will always use - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } - pp = (struct parent *) (p->Internal); - switch (uMsg) { - case WM_NCDESTROY: - // no need to explicitly destroy children; they're already gone by this point (and so are their data structures; they clean up after themselves) - uiFree(p->Internal); - uiFree(p); - break; // fall through to DefWindowPocW() - case WM_WINDOWPOSCHANGED: - if ((wp->flags & SWP_NOSIZE) != 0) - break; - // fall through - case msgUpdateChild: - if (pp->child == NULL) - break; - if (GetClientRect(pp->hwnd, &r) == 0) - logLastError("error getting client rect for resize in parentWndProc()"); - margin.left = pp->marginLeft; - margin.top = pp->marginTop; - margin.right = pp->marginRight; - margin.bottom = pp->marginBottom; - resize(pp->child, pp->hwnd, r, margin); - return 0; - } - - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - -const char *initParent(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = uiParentClass; - wc.lpfnWndProc = parentWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - if (RegisterClassW(&wc) == 0) - return "registering parent window class"; - - initialParent = CreateWindowExW(0, - uiParentClass, L"", - WS_OVERLAPPEDWINDOW, - 0, 0, - 100, 100, - NULL, NULL, hInstance, NULL); - if (initialParent == NULL) - return "creating initial parent window"; - - // just to be safe, disable the initial parent so it can't be interacted with accidentally - // if this causes issues for our controls, we can remove it - EnableWindow(initialParent, FALSE); - return NULL; -} - -static uintptr_t parentHandle(uiParent *p) -{ - struct parent *pp = (struct parent *) (p->Internal); - - return (uintptr_t) (pp->hwnd); -} - -static void parentSetChild(uiParent *p, uiControl *child) -{ - struct parent *pp = (struct parent *) (p->Internal); - - pp->child = child; - if (pp->child != NULL) - uiControlSetParent(child, p); -} - -static void parentSetMargins(uiParent *p, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom) -{ - struct parent *pp = (struct parent *) (p->Internal); - - pp->marginLeft = left; - pp->marginTop = top; - pp->marginRight = right; - pp->marginBottom = bottom; -} - -static void parentUpdate(uiParent *p) -{ - struct parent *pp = (struct parent *) (p->Internal); - - SendMessageW(pp->hwnd, msgUpdateChild, 0, 0); -} - -uiParent *uiNewParent(uintptr_t osParent) -{ - uiParent *p; - struct parent *pp; - - p = uiNew(uiParent); - p->Internal = uiNew(struct parent); // set now in case the parent class window procedure uses it - pp = (struct parent *) (p->Internal); - pp->hwnd = CreateWindowExW(0, - uiParentClass, L"", - WS_CHILD | WS_VISIBLE, - 0, 0, - 0, 0, - (HWND) osParent, NULL, hInstance, p); - if (pp->hwnd == NULL) - logLastError("error creating uiParent window in uiNewParent()"); - p->Handle = parentHandle; - p->SetChild = parentSetChild; - p->SetMargins = parentSetMargins; - p->Update = parentUpdate; - return p; -} diff --git a/new/windows/tab.c b/new/windows/tab.c deleted file mode 100644 index d2cbd62f..00000000 --- a/new/windows/tab.c +++ /dev/null @@ -1,190 +0,0 @@ -// 12 april 2015 -#include "uipriv_windows.h" - -// TODO -// - tab change notifications aren't being sent on wine (anymore...? TODO) -// - tell wine developers that tab controls do respond to parent changes on real windows (at least comctl6 tab controls do) - -struct tab { - uiTab t; - uiParent **pages; - uintmax_t len; - uintmax_t cap; -}; - -static BOOL onWM_COMMAND(uiControl *c, WORD code, LRESULT *lResult) -{ - return FALSE; -} - -// we have to handle hiding and showing of tab pages ourselves -static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) -{ - struct tab *t = (struct tab *) c; - LRESULT n; - - switch (nm->code) { - case TCN_SELCHANGING: - n = SendMessageW(uiControlHWND(c), TCM_GETCURSEL, 0, 0); - if (n != (LRESULT) (-1)) // if we're changing to a real tab - ShowWindow(uiParentHWND(t->pages[n]), SW_HIDE); - *lResult = FALSE; // and allow the change - return TRUE; - case TCN_SELCHANGE: - n = SendMessageW(uiControlHWND(c), TCM_GETCURSEL, 0, 0); - if (n != (LRESULT) (-1)) { // if we're changing to a real tab - ShowWindow(uiParentHWND(t->pages[n]), SW_SHOW); - // because we only resize the current child on resize, we'll need to trigger an update here - // don't call uiParentUpdate(); doing that won't size the content area (so we'll still have a 0x0 content area, for instance) - SendMessageW(uiControlHWND(c), msgUpdateChild, 0, 0); - } - *lResult = 0; - return TRUE; - } - return FALSE; -} - -static void onWM_DESTROY(uiControl *c) -{ - struct tab *t = (struct tab *) c; - - // no need to worry about freeing the pages themselves; they'll destroy themselves after we return - uiFree(t->pages); - uiFree(t); -} - -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - // TODO -} - -// common code for resizes -static void resizeTab(uiControl *c, LONG width, LONG height) -{ - struct tab *t = (struct tab *) c; - HWND hwnd; - LRESULT n; - RECT r; - - hwnd = uiControlHWND(c); - - n = SendMessageW(hwnd, TCM_GETCURSEL, 0, 0); - if (n == (LRESULT) (-1)) // no child selected; do nothing - return; - - // make a rect at (0, 0) of the given window size - // this should give us the correct client coordinates - r.left = 0; - r.top = 0; - r.right = width; - r.bottom = height; - // convert to the display rectangle - SendMessageW(hwnd, TCM_ADJUSTRECT, FALSE, (LPARAM) (&r)); - - if (MoveWindow(uiParentHWND(t->pages[n]), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE) == 0) - logLastError("error resizing current tab page in resizeTab()"); -} - -// and finally, because we have to resize parents, we have to handle resizes and updates -static LRESULT CALLBACK tabSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - uiControl *c = (uiControl *) dwRefData; - WINDOWPOS *wp = (WINDOWPOS *) lParam; - LRESULT lResult; - RECT r; - - switch (uMsg) { - case WM_WINDOWPOSCHANGED: - if ((wp->flags & SWP_NOSIZE) != 0) - break; - // first, let the tab control handle it - lResult = (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); - // we have the window rect width as part of the WINDOWPOS; resize - resizeTab(c, wp->cx, wp->cy); - return lResult; - case msgUpdateChild: - if (GetWindowRect(uiControlHWND(c), &r) == 0) - logLastError("error getting Tab window rect for synthesized resize message in tabSubProc()"); - // these are in screen coordinates, which match what WM_WINDOWPOSCHANGED gave us (thanks TODOTODOTODOTODOTODOTODOTODO) - resizeTab(c, r.right - r.left, r.bottom - r.top); - return 0; - case WM_NCDESTROY: - if ((*fv_RemoveWindowSubclass)(hwnd, tabSubProc, uIdSubclass) == FALSE) - logLastError("error removing Tab resize handling subclass in tabSubProc()"); - break; - } - return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); -} - -#define tabCapGrow 32 - -void addPage(uiTab *tt, const char *name, uiControl *child) -{ - struct tab *t = (struct tab *) tt; - HWND hwnd; - TCITEMW item; - LRESULT n; - uiParent *parent; - WCHAR *wname; - - if (t->len >= t->cap) { - t->cap += tabCapGrow; - t->pages = (uiParent **) uiRealloc(t->pages, t->cap * sizeof (uiParent *), "uiParent *[]"); - } - - hwnd = uiControlHWND(uiControl(t)); - n = SendMessageW(hwnd, TCM_GETITEMCOUNT, 0, 0); - - parent = uiNewParent((uintptr_t) hwnd); - uiParentSetChild(parent, child); - uiParentUpdate(parent); - if (n != 0) // if this isn't the first page, we have to hide the other controls - ShowWindow(uiParentHWND(parent), SW_HIDE); - t->pages[t->len] = parent; - t->len++; - - ZeroMemory(&item, sizeof (TCITEMW)); - item.mask = TCIF_TEXT; - wname = toUTF16(name); - item.pszText = wname; - // MSDN's example code uses the first invalid index directly for this - if (SendMessageW(hwnd, TCM_INSERTITEM, (WPARAM) n, (LPARAM) (&item)) == (LRESULT) -1) - logLastError("error adding tab to Tab in uiTabAddPage()"); - uiFree(wname); - - // if this is the first tab, Windows will automatically show it /without/ sending a TCN_SELCHANGE notification - // (TODO verify that) - // so we need to manually resize the tab ourselves - // don't use uiUpdateParent() for the same reason as in the TCN_SELCHANGE handler - SendMessageW(hwnd, msgUpdateChild, 0, 0); -} - -uiTab *uiNewTab(void) -{ - struct tab *t; - uiWindowsNewControlParams p; - HWND hwnd; - - t = uiNew(struct tab); - - p.dwExStyle = 0; // don't set WS_EX_CONTROLPARENT yet; we do that dynamically in the message loop (see main_windows.c) - p.lpClassName = WC_TABCONTROLW; - p.lpWindowName = L""; - p.dwStyle = TCS_TOOLTIPS | WS_TABSTOP; - p.hInstance = hInstance; - p.useStandardControlFont = TRUE; - p.onWM_COMMAND = onWM_COMMAND; - p.onWM_NOTIFY = onWM_NOTIFY; - p.onWM_DESTROY = onWM_DESTROY; - uiWindowsNewControl(uiControl(t), &p); - - hwnd = uiControlHWND(uiControl(t)); - if ((*fv_SetWindowSubclass)(hwnd, tabSubProc, 0, (DWORD_PTR) t) == FALSE) - logLastError("error subclassing Tab to give it its own resize handler in uiNewTab()"); - - uiControl(t)->PreferredSize = preferredSize; - - uiTab(t)->AddPage = addPage; - - return uiTab(t); -} diff --git a/new/windows/text.c b/new/windows/text.c deleted file mode 100644 index 8d6d0b0a..00000000 --- a/new/windows/text.c +++ /dev/null @@ -1,55 +0,0 @@ -// 9 april 2015 -#include "uipriv_windows.h" - -// see http://stackoverflow.com/a/29556509/3408572 - -#define MBTWC(str, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, bufsiz) - -WCHAR *toUTF16(const char *str) -{ - WCHAR *wstr; - int n; - - n = MBTWC(str, NULL, 0); - if (n == 0) - logLastError("error figuring out number of characters to convert to in toUTF16()"); - wstr = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]"); - if (MBTWC(str, wstr, n) != n) - logLastError("error converting from UTF-8 to UTF-16 in toUTF16()"); - return wstr; -} - -#define WCTMB(wstr, str, bufsiz) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, bufsiz, NULL, NULL) - -char *toUTF8(const WCHAR *wstr) -{ - char *str; - int n; - - n = WCTMB(wstr, NULL, 0); - if (n == 0) - logLastError("error figuring out number of characters to convert to in toUTF8()"); - str = (char *) uiAlloc(n * sizeof (char), "char[]"); - if (WCTMB(wstr, str, n) != n) - logLastError("error converting from UTF-16 to UTF-8 in toUTFF8()"); - return str; -} - -WCHAR *windowText(HWND hwnd) -{ - LRESULT n; - WCHAR *text; - - n = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); - // WM_GETTEXTLENGTH does not include the null terminator - text = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]"); - // note the comparison: the size includes the null terminator, but the return does not - if (GetWindowTextW(hwnd, text, n + 1) != n) - logLastError("error getting window text in windowText()"); - return text; -} - -void uiFreeText(char *text) -{ - uiFree(text); -} diff --git a/new/windows/uipriv_windows.h b/new/windows/uipriv_windows.h deleted file mode 100644 index 4ba0f5af..00000000 --- a/new/windows/uipriv_windows.h +++ /dev/null @@ -1,69 +0,0 @@ -// 6 january 2015 -#define UNICODE -#define _UNICODE -#define STRICT -#define STRICT_TYPED_ITEMIDS -#define CINTERFACE -#define COBJMACROS -// see https://github.com/golang/go/issues/9916#issuecomment-74812211 -#define INITGUID -// get Windows version right; right now Windows XP -#define WINVER 0x0501 -#define _WIN32_WINNT 0x0501 -#define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */ -#define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */ -#define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../uipriv.h" -#include "../ui_windows.h" - -// ui internal window messages -enum { - // redirected WM_COMMAND and WM_NOTIFY - msgCOMMAND = WM_APP + 0x40, // start offset just to be safe - msgNOTIFY, - msgUpdateChild, // fake because Windows seems to SWP_NOSIZE MoveWindow()s and SetWindowPos()s that don't change the window size (even if SWP_NOSIZE isn't specified) -}; - -// debug_windows.c -extern HRESULT logLastError(const char *); -extern HRESULT logHRESULT(const char *, HRESULT); -extern HRESULT logMemoryExhausted(const char *); - -// init_windows.c -extern HINSTANCE hInstance; -extern int nCmdShow; -extern HFONT hMessageFont; -extern HBRUSH hollowBrush; - -// util_windows.c -extern int windowClassOf(HWND, ...); - -// text_windows.c -extern WCHAR *toUTF16(const char *); -extern char *toUTF8(const WCHAR *); -extern WCHAR *windowText(HWND); - -// comctl32_windows.c -extern BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); -extern BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR); -extern LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM); -extern const char *initCommonControls(void); - -// window_windows.c -extern ATOM registerWindowClass(HICON, HCURSOR); - -// parent_windows.c -extern HWND initialParent; -extern const char *initParent(HICON, HCURSOR); diff --git a/new/windows/util.c b/new/windows/util.c deleted file mode 100644 index 93b32d8f..00000000 --- a/new/windows/util.c +++ /dev/null @@ -1,73 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -intmax_t uiWindowsWindowTextWidth(HWND hwnd) -{ - LRESULT len; - WCHAR *text; - HDC dc; - HFONT prevfont; - SIZE size; - - size.cx = 0; - size.cy = 0; - - // first we need the window text - len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); - if (len == 0) // no text; nothing to do - return 0; - text = (WCHAR *) uiAlloc((len + 1) * sizeof (WCHAR), "WCHAR[]"); - // note the comparison: the size includes the null terminator, but the return does not - if (GetWindowText(hwnd, text, len + 1) != len) - logLastError("error getting window text in uiWindowsWindowTextWidth()"); - - // now we can do the calculations - dc = GetDC(hwnd); - if (dc == NULL) - logLastError("error getting DC in uiWindowsWindowTextWidth()"); - prevfont = (HFONT) SelectObject(dc, hMessageFont); - if (prevfont == NULL) - logLastError("error loading control font into device context in uiWindowsWindowTextWidth()"); - if (GetTextExtentPoint32W(dc, text, len, &size) == 0) - logLastError("error getting text extent point in uiWindowsWindowTextWidth()"); - if (SelectObject(dc, prevfont) != hMessageFont) - logLastError("error restoring previous font into device context in uiWindowsWindowTextWidth()"); - if (ReleaseDC(hwnd, dc) == 0) - logLastError("error releasing DC in uiWindowsWindowTextWidth()"); - uiFree(text); - - return size.cx; -} - -// this is a helper function that takes the logic of determining window classes and puts it all in one place -// 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) -// usage: windowClassOf(hwnd, L"class 1", L"class 2", ..., NULL) -int windowClassOf(HWND hwnd, ...) -{ -// 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) -#define maxClassName 260 - WCHAR classname[maxClassName + 1]; - va_list ap; - WCHAR *curname; - int i; - - if (GetClassNameW(hwnd, classname, maxClassName) == 0) - logLastError("error getting name of window class in windowClassOf()"); - va_start(ap, hwnd); - i = 0; - for (;;) { - curname = va_arg(ap, WCHAR *); - if (curname == NULL) - break; - if (_wcsicmp(classname, curname) == 0) { - va_end(ap); - return i; - } - i++; - } - // no match - va_end(ap); - return -1; -} diff --git a/new/windows/window.c b/new/windows/window.c deleted file mode 100644 index e9360eb7..00000000 --- a/new/windows/window.c +++ /dev/null @@ -1,216 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -struct window { - uiWindow w; - HWND hwnd; - uiParent *content; - BOOL shownOnce; - int (*onClosing)(uiWindow *, void *); - void *onClosingData; - int margined; -}; - -#define uiWindowClass L"uiWindowClass" - -static LRESULT CALLBACK uiWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - struct window *w; - CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; - WINDOWPOS *wp = (WINDOWPOS *) lParam; - RECT r; - HWND contenthwnd; - - w = (struct window *) GetWindowLongPtrW(hwnd, GWLP_USERDATA); - if (w == NULL) { - if (uMsg == WM_CREATE) - SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) (cs->lpCreateParams)); - // fall through to DefWindowProc() anyway - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } - switch (uMsg) { - case WM_WINDOWPOSCHANGED: - if ((wp->flags & SWP_NOSIZE) != 0) - break; - // fall through - case msgUpdateChild: - if (GetClientRect(w->hwnd, &r) == 0) - logLastError("error getting window client rect for resize in uiWindowWndProc()"); - contenthwnd = uiParentHWND(w->content); - if (MoveWindow(contenthwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE) == 0) - logLastError("error resizing window content parent in uiWindowWndProc()"); - return 0; - case WM_CLOSE: - if (!(*(w->onClosing))(uiWindow(w), w->onClosingData)) - return 0; - break; // fall through to DefWindowProcW() - case WM_DESTROY: - // no need to free the child ourselves; it'll destroy itself after we leave this handler - uiFree(w); - break; // fall through to DefWindowProcW() - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - -ATOM registerWindowClass(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = uiWindowClass; - wc.lpfnWndProc = uiWindowWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - return RegisterClassW(&wc); -} - -#define exstyle 0 -#define style WS_OVERLAPPEDWINDOW - -static int defaultOnClosing(uiWindow *w, void *data) -{ - return 1; -} - -static void windowDestroy(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - DestroyWindow(w->hwnd); -} - -static uintptr_t windowHandle(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - return (uintptr_t) (w->hwnd); -} - -static char *windowTitle(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - WCHAR *wtext; - char *text; - - wtext = windowText(w->hwnd); - text = toUTF8(wtext); - uiFree(wtext); - return text; -} - -static void windowSetTitle(uiWindow *ww, const char *text) -{ - struct window *w = (struct window *) ww; - WCHAR *wtext; - - wtext = toUTF16(text); - if (SetWindowTextW(w->hwnd, wtext) == 0) - logLastError("error setting window title in uiWindowSetTitle()"); - uiFree(wtext); -} - -static void windowShow(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - if (w->shownOnce) { - ShowWindow(w->hwnd, SW_SHOW); - return; - } - w->shownOnce = TRUE; - ShowWindow(w->hwnd, nCmdShow); - if (UpdateWindow(w->hwnd) == 0) - logLastError("error calling UpdateWindow() after showing uiWindow for the first time"); -} - -static void windowHide(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - ShowWindow(w->hwnd, SW_HIDE); -} - -static void windowOnClosing(uiWindow *ww, int (*f)(uiWindow *, void *), void *data) -{ - struct window *w = (struct window *) ww; - - w->onClosing = f; - w->onClosingData = data; -} - -static void windowSetChild(uiWindow *ww, uiControl *c) -{ - struct window *w = (struct window *) ww; - - uiParentSetChild(w->content, c); - // don't call uiParentUpdate(); instead, synthesize a resize - // otherwise, we'll have a 0x0 content area at first - SendMessageW(w->hwnd, msgUpdateChild, 0, 0); -} - -static int windowMargined(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - return w->margined; -} - -// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define windowMargin 7 - -static void windowSetMargined(uiWindow *ww, int margined) -{ - struct window *w = (struct window *) ww; - - w->margined = margined; - if (w->margined) - uiParentSetMargins(w->content, windowMargin, windowMargin, windowMargin, windowMargin); - else - uiParentSetMargins(w->content, 0, 0, 0, 0); - uiParentUpdate(w->content); -} - -uiWindow *uiNewWindow(const char *title, int width, int height) -{ - struct window *w; - RECT adjust; - WCHAR *wtitle; - - w = uiNew(struct window); - w->onClosing = defaultOnClosing; - - adjust.left = 0; - adjust.top = 0; - adjust.right = width; - adjust.bottom = height; - if (AdjustWindowRectEx(&adjust, style, FALSE, exstyle) == 0) - logLastError("error getting real window coordinates in uiWindow()"); - - wtitle = toUTF16(title); - w->hwnd = CreateWindowExW(exstyle, - uiWindowClass, wtitle, - style, - CW_USEDEFAULT, CW_USEDEFAULT, - adjust.right - adjust.left, adjust.bottom - adjust.top, - NULL, NULL, hInstance, w); - if (w->hwnd == NULL) - logLastError("error creating window in uiWindow()"); - uiFree(wtitle); - - w->content = uiNewParent((uintptr_t) (w->hwnd)); - - uiWindow(w)->Destroy = windowDestroy; - uiWindow(w)->Handle = windowHandle; - uiWindow(w)->Title = windowTitle; - uiWindow(w)->SetTitle = windowSetTitle; - uiWindow(w)->Show = windowShow; - uiWindow(w)->Hide = windowHide; - uiWindow(w)->OnClosing = windowOnClosing; - uiWindow(w)->SetChild = windowSetChild; - uiWindow(w)->Margined = windowMargined; - uiWindow(w)->SetMargined = windowSetMargined; - - return uiWindow(w); -}