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