Removed or moved a bunch of stale files from the old source. All that's left now is to re-add the main controls and recreate the test program.
This commit is contained in:
parent
1288624725
commit
4c280ca42c
|
@ -1,20 +0,0 @@
|
|||
OSMFILES = \
|
||||
alloc.m \
|
||||
button.m \
|
||||
checkbox.m \
|
||||
entry.m \
|
||||
init.m \
|
||||
label.m \
|
||||
main.m \
|
||||
menu.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 = $(OUTBASE)
|
|
@ -1,70 +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 <NSApplicationDelegate>
|
||||
@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]];
|
||||
|
||||
// always do this so we always have an application menu
|
||||
[NSApp setMainMenu:makeMenubar()];
|
||||
|
||||
// we can use a stock NSView for this
|
||||
destroyedControlsView = [[NSView alloc] initWithFrame:NSZeroRect];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uiFreeInitError(const char *err)
|
||||
{
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
// 20 april 2015
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
struct menuConfig {
|
||||
BOOL hasQuit;
|
||||
BOOL hasPreferences;
|
||||
BOOL hasAbout;
|
||||
};
|
||||
|
||||
static NSMenuItem *quitItem;
|
||||
static NSMenuItem *preferencesItem;
|
||||
static NSMenuItem *aboutItem;
|
||||
|
||||
void appendMenuItem(NSMenu *menu, const uiMenuItem *item, struct menuConfig *menuConfig)
|
||||
{
|
||||
NSMenuItem *mitem;
|
||||
|
||||
switch (item->Type) {
|
||||
case uiMenuItemTypeCommand:
|
||||
case uiMenuItemTypeCheckbox:
|
||||
mitem = [[NSMenuItem alloc] initWithTitle:toNSString(item->Name) action:NULL keyEquivalent:@""];
|
||||
[menu addItem:mitem];
|
||||
return;
|
||||
case uiMenuItemTypeQuit:
|
||||
// TODO verify name
|
||||
menuConfig->hasQuit = YES;
|
||||
return;
|
||||
case uiMenuItemTypePreferences:
|
||||
// TODO verify name
|
||||
menuConfig->hasPreferences = YES;
|
||||
return;
|
||||
case uiMenuItemTypeAbout:
|
||||
// TODO verify name
|
||||
menuConfig->hasAbout = YES;
|
||||
return;
|
||||
case uiMenuItemTypeSeparator:
|
||||
// TODO verify name
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
return;
|
||||
}
|
||||
// TODO complain
|
||||
}
|
||||
|
||||
NSMenuItem *makeMenu(const char *name, const uiMenuItem *items, struct menuConfig *menuConfig)
|
||||
{
|
||||
NSMenuItem *menubarItem;
|
||||
NSMenu *menu;
|
||||
const uiMenuItem *i;
|
||||
|
||||
menubarItem = [[NSMenuItem alloc] initWithTitle:toNSString(name) action:NULL keyEquivalent:@""];
|
||||
menu = [[NSMenu alloc] initWithTitle:toNSString(name)];
|
||||
for (i = items; i->Type != 0; i++)
|
||||
appendMenuItem(menu, i, menuConfig);
|
||||
[menubarItem setSubmenu:menu];
|
||||
return menubarItem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NSMenu *makeMenubar(void)
|
||||
{
|
||||
NSMenu *menubar;
|
||||
struct menuConfig menuConfig;
|
||||
const uiMenu *m;
|
||||
|
||||
menubar = [[NSMenu alloc] initWithTitle:@""];
|
||||
|
||||
// always build the application menu
|
||||
buildApplicationMenu(menubar);
|
||||
|
||||
memset(&menuConfig, 0, sizeof (struct menuConfig));
|
||||
if (options.Menu != NULL)
|
||||
for (m = options.Menu; m->Name != NULL; m++)
|
||||
[menubar addItem:makeMenu(m->Name, m->Items, &menuConfig)];
|
||||
|
||||
if (menuConfig.hasQuit)
|
||||
[quitItem setEnabled:YES];
|
||||
if (menuConfig.hasPreferences)
|
||||
[preferencesItem setEnabled:YES];
|
||||
if (menuConfig.hasAbout)
|
||||
[aboutItem setEnabled:YES];
|
||||
|
||||
return menubar;
|
||||
}
|
134
darwin/parent.m
134
darwin/parent.m
|
@ -1,134 +0,0 @@
|
|||
// 17 april 2015
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
@interface uipParent : NSView {
|
||||
uiControl *mainControl;
|
||||
intmax_t marginLeft;
|
||||
intmax_t marginTop;
|
||||
intmax_t marginRight;
|
||||
intmax_t marginBottom;
|
||||
}
|
||||
- (void)uipDestroyMainControl;
|
||||
- (void)uipSetMainControl:(uiControl *)mainControl parent:(uiParent *)p;
|
||||
- (void)uipSetMarginLeft:(intmax_t)left top:(intmax_t)top right:(intmax_t)right bottom:(intmax_t)bottom;
|
||||
- (void)uipUpdate;
|
||||
@end
|
||||
|
||||
@implementation uipParent
|
||||
|
||||
uiLogObjCClassAllocations
|
||||
|
||||
- (void)setFrameSize:(NSSize)s
|
||||
{
|
||||
[super setFrameSize:s];
|
||||
[self uipUpdate];
|
||||
}
|
||||
|
||||
- (void)uipDestroyMainControl
|
||||
{
|
||||
if (self->mainControl != NULL) {
|
||||
// we have to do this before we can destroy controls
|
||||
uiControlSetParent(self->mainControl, NULL);
|
||||
uiControlDestroy(self->mainControl);
|
||||
self->mainControl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)uipSetMainControl:(uiControl *)mainControl parent:(uiParent *)p
|
||||
{
|
||||
if (self->mainControl != NULL)
|
||||
uiControlSetParent(self->mainControl, NULL);
|
||||
self->mainControl = mainControl;
|
||||
if (self->mainControl != NULL)
|
||||
uiControlSetParent(self->mainControl, p);
|
||||
}
|
||||
|
||||
- (void)uipSetMarginLeft:(intmax_t)left top:(intmax_t)top right:(intmax_t)right bottom:(intmax_t)bottom
|
||||
{
|
||||
self->marginLeft = left;
|
||||
self->marginTop = top;
|
||||
self->marginRight = right;
|
||||
self->marginBottom = bottom;
|
||||
}
|
||||
|
||||
// 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)uipUpdate
|
||||
{
|
||||
uiSizing d;
|
||||
intmax_t x, y, width, height;
|
||||
|
||||
if (self->mainControl == 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->mainControl, x, y, width, height, &d);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static void parentDestroy(uiParent *pp)
|
||||
{
|
||||
uipParent *p = (uipParent *) (pp->Internal);
|
||||
|
||||
[p retain]; // to avoid destruction upon removing from superview
|
||||
[p uipDestroyMainControl];
|
||||
[p removeFromSuperview];
|
||||
[destroyedControlsView addSubview:p];
|
||||
[p release];
|
||||
}
|
||||
|
||||
static uintptr_t parentHandle(uiParent *p)
|
||||
{
|
||||
return (uintptr_t) (p->Internal);
|
||||
}
|
||||
|
||||
static void parentSetMainControl(uiParent *pp, uiControl *mainControl)
|
||||
{
|
||||
uipParent *p = (uipParent *) (pp->Internal);
|
||||
|
||||
[p uipSetMainControl:mainControl parent:pp];
|
||||
}
|
||||
|
||||
static void parentSetMargins(uiParent *pp, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom)
|
||||
{
|
||||
uipParent *p = (uipParent *) (pp->Internal);
|
||||
|
||||
[p uipSetMarginLeft:left top:top right:right bottom:bottom];
|
||||
}
|
||||
|
||||
static void parentUpdate(uiParent *pp)
|
||||
{
|
||||
uipParent *p = (uipParent *) (pp->Internal);
|
||||
|
||||
[p uipUpdate];
|
||||
}
|
||||
|
||||
uiParent *uiNewParent(uintptr_t osParent)
|
||||
{
|
||||
uiParent *p;
|
||||
uipParent *pp;
|
||||
|
||||
p = uiNew(uiParent);
|
||||
|
||||
pp = [[uipParent alloc] initWithFrame:NSZeroRect];
|
||||
// don't use osParent; we'll need to call specific selectors to set the parent view
|
||||
p->Internal = pp;
|
||||
|
||||
p->Destroy = parentDestroy;
|
||||
p->Handle = parentHandle;
|
||||
p->SetMainControl = parentSetMainControl;
|
||||
p->SetMargins = parentSetMargins;
|
||||
p->Update = parentUpdate;
|
||||
|
||||
return p;
|
||||
}
|
|
@ -1,46 +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 <Cocoa/Cocoa.h>
|
||||
#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); \
|
||||
}
|
||||
|
||||
#define VIEW(c) uiControlHandle(uiControl(c))
|
||||
|
||||
// init.m
|
||||
extern NSView *destroyedControlsView;
|
||||
|
||||
// util.m
|
||||
extern void setStandardControlFont(NSControl *);
|
||||
extern void disableAutocorrect(NSTextView *);
|
||||
|
||||
// parent.m
|
||||
// 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.m
|
||||
extern void finishNewTextField(NSTextField *, BOOL);
|
||||
|
||||
// menu.m
|
||||
extern NSMenu *makeMenubar(void);
|
23
ui_darwin.h
23
ui_darwin.h
|
@ -1,23 +0,0 @@
|
|||
// 7 april 2015
|
||||
|
||||
/*
|
||||
This file assumes that you have imported <Cocoa/Cocoa.h> 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.
|
||||
// The two onDestroy parameters define a function and its parameter to call when the widget is destroyed.
|
||||
extern void uiDarwinNewControl(uiControl *c, Class class, BOOL inScrollView, BOOL scrollViewHasBorder, void (*onDestroy)(void *), void *onDestroyData);
|
||||
|
||||
// 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
|
21
ui_unix.h
21
ui_unix.h
|
@ -1,21 +0,0 @@
|
|||
// 7 april 2015
|
||||
|
||||
/*
|
||||
This file assumes that you have included <gtk/gtk.h> 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 destroy parameters are for a function that should be called when destroying the widget.
|
||||
// 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, void (*destroy)(void *), void *onDestroyData, const char *firstProperty, ...);
|
||||
|
||||
struct uiSizingSys {
|
||||
// this structure currently left blank
|
||||
};
|
||||
|
||||
#endif
|
58
ui_windows.h
58
ui_windows.h
|
@ -1,58 +0,0 @@
|
|||
// 7 april 2015
|
||||
|
||||
/*
|
||||
This file assumes that you have included <windows.h> 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__
|
||||
|
||||
// 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);
|
||||
// TODO set idFrom to 0?
|
||||
BOOL (*onWM_NOTIFY)(uiControl *c, NMHDR *nm, LRESULT *lResult);
|
||||
|
||||
// This is called when the widget is ready to be destroyed.
|
||||
void (*onDestroy)(void *data);
|
||||
void *onDestroyData;
|
||||
};
|
||||
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
|
12
uipriv.h
12
uipriv.h
|
@ -1,12 +0,0 @@
|
|||
// 6 april 2015
|
||||
#include <stdlib.h>
|
||||
#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 *);
|
||||
|
||||
extern void complain(const char *, ...);
|
|
@ -1,21 +0,0 @@
|
|||
OSCFILES = \
|
||||
alloc.c \
|
||||
button.c \
|
||||
checkbox.c \
|
||||
entry.c \
|
||||
init.c \
|
||||
label.c \
|
||||
lifetimes.c \
|
||||
main.c \
|
||||
menu.c \
|
||||
newcontrol.c \
|
||||
parent.c \
|
||||
tab.c \
|
||||
text.c \
|
||||
util.c \
|
||||
window.c
|
||||
|
||||
xCFLAGS += `pkg-config --cflags gtk+-3.0`
|
||||
xLDFLAGS += `pkg-config --libs gtk+-3.0`
|
||||
|
||||
OUT = $(OUTBASE)
|
|
@ -1,21 +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 <gtk/gtk.h>
|
||||
#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))
|
||||
|
||||
// lifetimes.c
|
||||
extern gulong blockDestruction(GtkWidget *, void *);
|
||||
extern void readyToDestroy(GtkWidget *, gulong);
|
||||
|
||||
// menu.c
|
||||
extern GtkWidget *makeMenubar(void);
|
|
@ -1,34 +0,0 @@
|
|||
OSCFILES = \
|
||||
alloc.c \
|
||||
button.c \
|
||||
checkbox.c \
|
||||
comctl32.c \
|
||||
debug.c \
|
||||
entry.c \
|
||||
init.c \
|
||||
label.c \
|
||||
main.c \
|
||||
menu.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 = $(OUTBASE).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
|
|
@ -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[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n<assemblyIdentity\n version=\"1.0.0.0\"\n processorArchitecture=\"*\"\n name=\"CompanyName.ProductName.YourApplication\"\n type=\"win32\"\n/>\n<description>Your application description here.</description>\n<dependency>\n <dependentAssembly>\n <assemblyIdentity\n type=\"win32\"\n name=\"Microsoft.Windows.Common-Controls\"\n version=\"6.0.0.0\"\n processorArchitecture=\"*\"\n publicKeyToken=\"6595b64144ccf1df\"\n language=\"*\"\n />\n </dependentAssembly>\n</dependency>\n</assembly>\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;
|
||||
}
|
111
windows/debug.c
111
windows/debug.c
|
@ -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 <stdio.h>
|
||||
|
||||
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
|
|
@ -1,77 +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 <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <stdint.h>
|
||||
#include <uxtheme.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <windowsx.h>
|
||||
#include <vsstyle.h>
|
||||
#include <vssym32.h>
|
||||
#include <stdarg.h>
|
||||
#include <oleacc.h>
|
||||
#include <stdio.h>
|
||||
#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)
|
||||
msgCanDestroyNow,
|
||||
};
|
||||
|
||||
#define HWND(c) ((HWND) uiControlHandle(uiControl(c)))
|
||||
#define uiParentHWND(p) ((HWND) uiParentHandle(p))
|
||||
|
||||
// debug.c
|
||||
extern HRESULT logLastError(const char *);
|
||||
extern HRESULT logHRESULT(const char *, HRESULT);
|
||||
extern HRESULT logMemoryExhausted(const char *);
|
||||
|
||||
// init.c
|
||||
extern HINSTANCE hInstance;
|
||||
extern int nCmdShow;
|
||||
extern HFONT hMessageFont;
|
||||
extern HBRUSH hollowBrush;
|
||||
|
||||
// util.c
|
||||
extern int windowClassOf(HWND, ...);
|
||||
|
||||
// text.c
|
||||
extern WCHAR *toUTF16(const char *);
|
||||
extern char *toUTF8(const WCHAR *);
|
||||
extern WCHAR *windowText(HWND);
|
||||
|
||||
// comctl32.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.c
|
||||
extern ATOM registerWindowClass(HICON, HCURSOR);
|
||||
|
||||
// parent.c
|
||||
extern HWND initialParent;
|
||||
extern const char *initParent(HICON, HCURSOR);
|
||||
|
||||
// menu.c
|
||||
extern HMENU makeMenubar(void);
|
||||
extern const uiMenuItem *menuIDToItem(UINT_PTR);
|
Loading…
Reference in New Issue