diff --git a/box.c b/box.c deleted file mode 100644 index 129a9a62..00000000 --- a/box.c +++ /dev/null @@ -1,397 +0,0 @@ -// 7 april 2015 -#include "uipriv.h" - -typedef struct box box; -typedef struct boxControl boxControl; - -struct box { - uiBox s; - boxControl *controls; - uintmax_t len; - uintmax_t cap; - int vertical; - uiParent *parent; - int padded; - int userHid; - int containerHid; - int userDisabled; - int containerDisabled; -}; - -struct boxControl { - 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 boxDestroy(uiControl *c) -{ - box *b = (box *) c; - uintmax_t i; - - if (b->parent != NULL) - complain("attempt to destroy a uiControl at %p while it still has a parent %p", c, b->parent); - for (i = 0; i < b->len; i++) - uiControlDestroy(b->controls[i].c); - uiFree(b->controls); - uiFree(b); -} - -static uintptr_t boxHandle(uiControl *c) -{ - return 0; -} - -static void boxSetParent(uiControl *c, uiParent *parent) -{ - box *b = (box *) c; - uintmax_t i; - uiParent *oldparent; - - oldparent = b->parent; - b->parent = parent; - for (i = 0; i < b->len; i++) - uiControlSetParent(b->controls[i].c, b->parent); - if (oldparent != NULL) - uiParentUpdate(oldparent); - if (b->parent != NULL) - uiParentUpdate(b->parent); -} - -static void boxPreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - box *b = (box *) c; - int xpadding, ypadding; - uintmax_t nStretchy; - // these two contain the largest preferred width and height of all stretchy controls in the box - // 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 (b->len == 0) - return; - - // 0) get this Box's padding - xpadding = 0; - ypadding = 0; - if (b->padded) { - xpadding = d->xPadding; - ypadding = d->yPadding; - } - - // 1) initialize the desired rect with the needed padding - if (b->vertical) - *height = (b->len - 1) * ypadding; - else - *width = (b->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 < b->len; i++) { - if (!uiControlVisible(b->controls[i].c)) - continue; - uiControlPreferredSize(b->controls[i].c, d, &preferredWidth, &preferredHeight); - if (b->controls[i].stretchy) { - nStretchy++; - if (maxStretchyWidth < preferredWidth) - maxStretchyWidth = preferredWidth; - if (maxStretchyHeight < preferredHeight) - maxStretchyHeight = preferredHeight; - } - if (b->vertical) { - if (*width < preferredWidth) - *width = preferredWidth; - if (!b->controls[i].stretchy) - *height += preferredHeight; - } else { - if (!b->controls[i].stretchy) - *width += preferredWidth; - if (*height < preferredHeight) - *height = preferredHeight; - } - } - - // 3) and now we can add in stretchy controls - if (b->vertical) - *height += nStretchy * maxStretchyHeight; - else - *width += nStretchy * maxStretchyWidth; -} - -static void boxResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) -{ - box *b = (box *) c; - int xpadding, ypadding; - uintmax_t nStretchy; - intmax_t stretchywid, stretchyht; - uintmax_t i; - intmax_t preferredWidth, preferredHeight; - - if (b->len == 0) - return; - - // -1) get this Box's padding - xpadding = 0; - ypadding = 0; - if (b->padded) { - xpadding = d->xPadding; - ypadding = d->yPadding; - } - - // 0) inset the available rect by the needed padding - if (b->vertical) - height -= (b->len - 1) * ypadding; - else - width -= (b->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 < b->len; i++) { - if (!uiControlVisible(b->controls[i].c)) - continue; - if (b->controls[i].stretchy) { - nStretchy++; - continue; - } - uiControlPreferredSize(b->controls[i].c, d, &preferredWidth, &preferredHeight); - if (b->vertical) { // all controls have same width - b->controls[i].width = width; - b->controls[i].height = preferredHeight; - stretchyht -= preferredHeight; - } else { // all controls have same height - b->controls[i].width = preferredWidth; - b->controls[i].height = height; - stretchywid -= preferredWidth; - } - } - - // 2) now get the size of stretchy controls - if (nStretchy != 0) - if (b->vertical) - stretchyht /= nStretchy; - else - stretchywid /= nStretchy; - for (i = 0; i < b->len; i++) { - if (!uiControlVisible(b->controls[i].c)) - continue; - if (b->controls[i].stretchy) { - b->controls[i].width = stretchywid; - b->controls[i].height = stretchyht; - } - } - - // 3) now we can position controls - for (i = 0; i < b->len; i++) { - if (!uiControlVisible(b->controls[i].c)) - continue; - uiControlResize(b->controls[i].c, x, y, b->controls[i].width, b->controls[i].height, d); - if (b->vertical) - y += b->controls[i].height + ypadding; - else - x += b->controls[i].width + xpadding; - } -} - -static int boxVisible(uiControl *c) -{ - box *b = (box *) c; - - return !(b->userHid); -} - -static void boxShow(uiControl *c) -{ - box *b = (box *) c; - uintmax_t i; - - b->userHid = 0; - if (!b->containerHid) { - for (i = 0; i < b->len; i++) - uiControlContainerShow(b->controls[i].c); - if (b->parent != NULL) - uiParentUpdate(b->parent); - } -} - -static void boxHide(uiControl *c) -{ - box *b = (box *) c; - uintmax_t i; - - b->userHid = 1; - for (i = 0; i < b->len; i++) - uiControlContainerHide(b->controls[i].c); - if (b->parent != NULL) - uiParentUpdate(b->parent); -} - -static void boxContainerShow(uiControl *c) -{ - box *b = (box *) c; - uintmax_t i; - - b->containerHid = 0; - if (!b->userHid) { - for (i = 0; i < b->len; i++) - uiControlContainerShow(b->controls[i].c); - if (b->parent != NULL) - uiParentUpdate(b->parent); - } -} - -static void boxContainerHide(uiControl *c) -{ - box *b = (box *) c; - uintmax_t i; - - b->containerHid = 1; - for (i = 0; i < b->len; i++) - uiControlContainerHide(b->controls[i].c); - if (b->parent != NULL) - uiParentUpdate(b->parent); -} - -static void boxEnable(uiControl *c) -{ - box *b = (box *) c; - uintmax_t i; - - b->userDisabled = 0; - if (!b->containerDisabled) - for (i = 0; i < b->len; i++) - uiControlContainerEnable(b->controls[i].c); -} - -static void boxDisable(uiControl *c) -{ - box *b = (box *) c; - uintmax_t i; - - b->userDisabled = 1; - for (i = 0; i < b->len; i++) - uiControlContainerDisable(b->controls[i].c); -} - -static void boxContainerEnable(uiControl *c) -{ - box *b = (box *) c; - uintmax_t i; - - b->containerDisabled = 0; - if (!b->userDisabled) - for (i = 0; i < b->len; i++) - uiControlContainerEnable(b->controls[i].c); -} - -static void boxContainerDisable(uiControl *c) -{ - box *b = (box *) c; - uintmax_t i; - - b->containerDisabled = 1; - for (i = 0; i < b->len; i++) - uiControlContainerDisable(b->controls[i].c); -} - -#define boxCapGrow 32 - -static void boxAppend(uiBox *ss, uiControl *c, int stretchy) -{ - box *b = (box *) ss; - - if (b->len >= b->cap) { - b->cap += boxCapGrow; - b->controls = (boxControl *) uiRealloc(b->controls, b->cap * sizeof (boxControl), "boxControl[]"); - } - b->controls[b->len].c = c; - b->controls[b->len].stretchy = stretchy; - b->len++; // must be here for parent updates to work - if (b->parent != NULL) { - uiControlSetParent(b->controls[b->len - 1].c, b->parent); - uiParentUpdate(b->parent); - } -} - -static void boxDelete(uiBox *ss, uintmax_t index) -{ - box *b = (box *) ss; - uiControl *removed; - uintmax_t i; - - removed = b->controls[index].c; - // TODO switch to memmove? - for (i = index; i < b->len - 1; i++) - b->controls[i] = b->controls[i + 1]; - // TODO memset the last one to NULL - b->len--; - if (b->parent != NULL) { - uiControlSetParent(removed, NULL); - uiParentUpdate(b->parent); - } -} - -static int boxPadded(uiBox *ss) -{ - box *b = (box *) ss; - - return b->padded; -} - -static void boxSetPadded(uiBox *ss, int padded) -{ - box *b = (box *) ss; - - b->padded = padded; - if (b->parent != NULL) - uiParentUpdate(b->parent); -} - -uiBox *uiNewHorizontalBox(void) -{ - box *b; - - b = uiNew(box); - - uiControl(b)->Destroy = boxDestroy; - uiControl(b)->Handle = boxHandle; - uiControl(b)->SetParent = boxSetParent; - uiControl(b)->PreferredSize = boxPreferredSize; - uiControl(b)->Resize = boxResize; - uiControl(b)->Visible = boxVisible; - uiControl(b)->Show = boxShow; - uiControl(b)->Hide = boxHide; - uiControl(b)->ContainerShow = boxContainerShow; - uiControl(b)->ContainerHide = boxContainerHide; - uiControl(b)->Enable = boxEnable; - uiControl(b)->Disable = boxDisable; - uiControl(b)->ContainerEnable = boxContainerEnable; - uiControl(b)->ContainerDisable = boxContainerDisable; - - uiBox(b)->Append = boxAppend; - uiBox(b)->Delete = boxDelete; - uiBox(b)->Padded = boxPadded; - uiBox(b)->SetPadded = boxSetPadded; - - return uiBox(b); -} - -uiBox *uiNewVerticalBox(void) -{ - uiBox *ss; - box *b; - - ss = uiNewHorizontalBox(); - b = (box *) ss; - b->vertical = 1; - return ss; -} diff --git a/darwin/alloc.m b/darwin/alloc.m deleted file mode 100644 index 8f539af7..00000000 --- a/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/darwin/text.m b/darwin/text.m deleted file mode 100644 index f0d3dab6..00000000 --- a/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/darwin/util.m b/darwin/util.m deleted file mode 100644 index 6861147e..00000000 --- a/darwin/util.m +++ /dev/null @@ -1,25 +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]; -} - -void complain(const char *fmt, ...) -{ - // TODO -} diff --git a/darwin/window.m b/darwin/window.m deleted file mode 100644 index 850ce61b..00000000 --- a/darwin/window.m +++ /dev/null @@ -1,163 +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 - - // just to be safe - [self.w setContentView:[[NSView alloc] initWithFrame:NSZeroRect]]; - uiParentDestroy(self.content); - - // now we need to release the window too - [self.w release]; - - // and clean up - 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) -{ - uiParentSetMainControl(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, int hasMenubar) -{ - 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]); - - // don't release on close; we'll do it ourselves (see above) - [d.w setReleasedWhenClosed:NO]; - - 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/ui.idl b/ui.idl deleted file mode 100644 index 7c98b71e..00000000 --- a/ui.idl +++ /dev/null @@ -1,149 +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; -}; - -func Init(options *InitOptions) *const char; -func FreeInitError(err *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 SetHasParent(hasParent int); - func SetOSContainer(c *OSContainer); - 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); -}; - -interface OSContainer { - field Internal *void; - func Destroy(void); - func Handle(void) uintptr_t; - func SetMainControl(c *Control); - func SetMargins(left intmax_t, top intmax_t, right intmax_t, bottom intmax_t); - func Update(void); -}; -func NewOSContainer(osParent uintptr_t) *OSContainer; - -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, hasMenubar 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 Box from Control { - func Append(c *Control, stretchy int); - func Delete(index uintmax_t); - func Padded(void) int; - func SetPadded(padded int); -}; -func NewHorizontalBox(void) *Box; -func NewVerticalBox(void) *Box; - -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 { - // TODO rename to AppendPage() - func AddPage(name *const char, c *Control); - func DeletePage(index uintmax_t); -}; -func NewTab(void) *Tab; - -interface Menu { - func AddItem(name string) *MenuItem; - func AddCheckItem(name string) *MenuItem; - func AddQuitItem(void) *MenuItem; - func AddPreferencesItem(void) *MenuItem; - func AddAboutItem(void) *MenuItem; - func AddSeparator(void); -}; -func NewMenu(name string) *Menu; - -interface MenuItem { - func Enable(void); - func Disable(void); - func OnClicked(f *func(sender *void, data *void), data *void); - func Checked(void) int; - func SetChecked(checked int); -}; - -raw "#endif"; - -}; diff --git a/unix/alloc.c b/unix/alloc.c deleted file mode 100644 index 33482b25..00000000 --- a/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/unix/text.c b/unix/text.c deleted file mode 100644 index 72b71dfa..00000000 --- a/unix/text.c +++ /dev/null @@ -1,7 +0,0 @@ -// 9 april 2015 -#include "uipriv_unix.h" - -void uiFreeText(char *t) -{ - g_free(t); -} diff --git a/unix/util.c b/unix/util.c deleted file mode 100644 index f02f4380..00000000 --- a/unix/util.c +++ /dev/null @@ -1,13 +0,0 @@ -// 18 april 2015 -#include "uipriv_unix.h" - -void complain(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - // there's no g_errorv() in glib 2.32, so do it manually instead - g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, fmt, ap); - va_end(ap); - abort(); // just in case -} diff --git a/unix/window.c b/unix/window.c deleted file mode 100644 index ec42ab91..00000000 --- a/unix/window.c +++ /dev/null @@ -1,172 +0,0 @@ -// 6 april 2015 -#include "uipriv_unix.h" - -struct window { - uiWindow w; - GtkWidget *widget; - GtkContainer *container; - GtkWindow *window; - uiParent *content; - int (*onClosing)(uiWindow *, void *); - void *onClosingData; - int margined; - gulong destroyBlocker; -}; - -static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data) -{ - struct window *w = (struct window *) data; - - // manually destroy the window ourselves; don't let the delete-event handler do it - if ((*(w->onClosing))(uiWindow(w), w->onClosingData)) - uiWindowDestroy(uiWindow(w)); - return TRUE; // don't continue to the default delete-event handler; we destroyed the window by now -} - -static int defaultOnClosing(uiWindow *w, void *data) -{ - return 1; -} - -static void destroyBlocker(GtkWidget *widget, gpointer data) -{ - complain("attempt to dispose uiWindow at %p before uiWindowDestroy()", data); -} - -// TODO should we change the GtkWindow's child first? -static void windowDestroy(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - // first, hide the window to prevent our cleanup from being noticed - gtk_widget_hide(w->widget); - // next, destroy the content uiParent - uiParentDestroy(w->content); - // now that we cleaned up properly, we can mark our window as ready to be destroyed - g_signal_handler_disconnect(w->widget, w->destroyBlocker); - // finally, destroy the window - gtk_widget_destroy(w->widget); - // and free ourselves - uiFree(w); -} - -static uintptr_t windowHandle(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - return (uintptr_t) (w->widget); -} - -static char *windowTitle(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - return g_strdup(gtk_window_get_title(w->window)); -} - -static void windowSetTitle(uiWindow *ww, const char *title) -{ - struct window *w = (struct window *) ww; - - gtk_window_set_title(w->window, title); -} - -static void windowShow(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 windowHide(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - gtk_widget_hide(w->widget); -} - -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; - - uiParentSetMainControl(w->content, c); - uiParentUpdate(w->content); -} - -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(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, int hasMenubar) -{ - struct window *w; - GtkWidget *vbox; - GtkWidget *contentWidget; - - w = uiNew(struct window); - - w->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); - w->container = GTK_CONTAINER(w->widget); - w->window = GTK_WINDOW(w->widget); - - gtk_window_set_title(w->window, title); - // TODO this does not take menus or CSD into account - gtk_window_resize(w->window, width, height); - - g_signal_connect(w->widget, "delete-event", G_CALLBACK(onClosing), w); - w->destroyBlocker = g_signal_connect(w->widget, "destroy", G_CALLBACK(destroyBlocker), w); - - if (hasMenubar) { - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_show_all(vbox); - gtk_container_add(w->container, vbox); - - gtk_container_add(GTK_CONTAINER(vbox), makeMenubar()); - - w->content = uiNewParent((uintptr_t) GTK_CONTAINER(vbox)); - contentWidget = GTK_WIDGET(uiParentHandle(w->content)); - gtk_widget_set_hexpand(contentWidget, TRUE); - gtk_widget_set_halign(contentWidget, GTK_ALIGN_FILL); - gtk_widget_set_vexpand(contentWidget, TRUE); - gtk_widget_set_valign(contentWidget, GTK_ALIGN_FILL); - } else - w->content = uiNewParent((uintptr_t) (w->container)); - - w->onClosing = defaultOnClosing; - - 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); -} diff --git a/windows/alloc.c b/windows/alloc.c deleted file mode 100644 index 147c90d2..00000000 --- a/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/windows/text.c b/windows/text.c deleted file mode 100644 index 8d6d0b0a..00000000 --- a/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/windows/util.c b/windows/util.c deleted file mode 100644 index 63529e59..00000000 --- a/windows/util.c +++ /dev/null @@ -1,83 +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; -} - -void complain(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - abort(); -} diff --git a/windows/window.c b/windows/window.c deleted file mode 100644 index 354aba4b..00000000 --- a/windows/window.c +++ /dev/null @@ -1,251 +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; - BOOL canDestroy; -}; - -#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; - const uiMenuItem *item; - - 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_COMMAND: - // not a menu - if (lParam != 0) - break; - if (HIWORD(wParam) != 0) - break; - item = menuIDToItem(LOWORD(wParam)); - printf("%d", item->Type); - if (item->Type == uiMenuItemTypeCommand) - printf(" %s", item->Name); - printf("\n"); - return 0; - 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)) - uiWindowDestroy(uiWindow(w)); - return 0; // we destroyed it already - case WM_DESTROY: - if (!w->canDestroy) - complain("attempt to destroy uiWindow at %p before uiWindowDestroy()", w); - 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; - - // first destroy the content - uiParentDestroy(w->content); - // then mark that we're ready to destroy - w->canDestroy = TRUE; - // and finally destroy - // TODO check for errors - DestroyWindow(w->hwnd); - // no need to explicitly destroy the menubar, if any; that's done automatically during window destruction -} - -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; - - uiParentSetMainControl(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, int hasMenubar) -{ - struct window *w; - RECT adjust; - WCHAR *wtitle; - BOOL hasMenubarBOOL; - HMENU hmenu; - - w = uiNew(struct window); - w->onClosing = defaultOnClosing; - - hasMenubarBOOL = FALSE; - if (hasMenubar) - hasMenubarBOOL = TRUE; - - adjust.left = 0; - adjust.top = 0; - adjust.right = width; - adjust.bottom = height; - // TODO does not handle menu wrapping; see http://blogs.msdn.com/b/oldnewthing/archive/2003/09/11/54885.aspx - if (AdjustWindowRectEx(&adjust, style, hasMenubarBOOL, 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)); - - if (hasMenubar) { - hmenu = makeMenubar(); - if (SetMenu(w->hwnd, hmenu) == 0) - logLastError("error giving menu to window in uiNewWindow()"); - } - - 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); -}