// C++ Headers
#include <ctime>
// Windows Headers
#ifdef _WIN32
#define Rectangle WinRectangle
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#undef Rectangle
#endif
// Project Headers
#include "Application.h"
#include "Window.h"
#include "Common.h"
BEGIN_NAMESPACE
struct ApplicationData
{
bool started;
int screenW, screenH;
clock_t lastTick;
Window* mainWindow;
};
#ifdef _WIN32
extern LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Application::Application()
{
m_data = new ApplicationData;
m_data->screenW = GetSystemMetrics(SM_CXSCREEN);
m_data->screenH= GetSystemMetrics(SM_CYSCREEN);
WNDCLASSEXW wcx = { sizeof(WNDCLASSEXA), CS_OWNDC | CS_HREDRAW | CS_VREDRAW, MainWndProc,
0, 0, GetModuleHandle(0), NULL, NULL, NULL, NULL, L"MainWClass", NULL };
RegisterClassExW(&wcx);
//m_data->mainWindow = new Window("Test", a_fullscreen);
//ShowCursor(FALSE);
}
Application::~Application()
{
//delete m_data->mainWindow;
delete m_data;
}
int Application::exec()
{
normalLoop();
return 0;
}
void Application::normalLoop()
{
MSG msg;
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
void Application::gameLoop()
{
MSG msg;
while (true)
{
// Remove all messages off the queue ... makes it look like we are responding
while ( GetQueueStatus(QS_ALLEVENTS) )
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
clock_t tick = clock();
m_data->lastTick = tick;
SHORT escape = GetAsyncKeyState(VK_ESCAPE);
if ( escape )
break;
m_data->mainWindow->repaint();
}
}
#else
END_NAMESPACE
// C/C++ API for Mac OS X Windowing - windowing.cpp
// Created by John Ryland (jryland@xiaofrog.com), 29/10/2017
// Copyright (c) 2017 InvertedLogic
// All rights reserved.
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include "ObjectiveC.h"
#include <ApplicationServices/ApplicationServices.h>
//#include <OpenGL/gl.h>
extern id NSApp;
class NSString;
typedef NSString* NSRunLoopMode;
typedef unsigned long long NSEventMask;
const NSEventMask NSAnyEventMask = UINT64_MAX;
typedef unsigned long NSApplicationActivationPolicy;
const NSApplicationActivationPolicy NSApplicationActivationPolicyRegular = 0;
extern "C" NSRunLoopMode NSDefaultRunLoopMode;
BEGIN_NAMESPACE
#define OBJC_BEGIN_CLASS(name, base) \
void Register##name##Class() { \
Class newClass; \
newClass = objc_allocateClassPair((Class)objc_getClass(#base), #name, 0);
#define OBJC_METHOD(func, impl...) \
BOOL (*func##Impl)(id, SEL, id) = [](id _self, SEL _cmd, id _notification)->BOOL \
{ \
ObjectiveC::Object _this = ObjectiveC::Object(_self); \
impl \
}; \
class_addMethod(newClass, sel_getUid(#func ":"), (IMP)func##Impl, "i@:@");
#define OBJC_MEMBER(typ, name) \
class_addIvar(newClass, #name, sizeof(typ), sizeof(typ), #typ);
#define OBJC_END_CLASS() \
objc_registerClassPair(newClass); \
}
void RegisterWindowClass();
/*
void RegisterApplicationClass();
BOOL AppDidFinishLaunching(id self, SEL _cmd, id notification)
{
Application* appPtr = 0;
object_getInstanceVariable(self, "m_applicationPtr", (void**)&appPtr);
// printf("AppDidFinishLaunching %i\n", __LINE__);
s_started = true;
// printf("AppDidFinishLaunching %i\n", __LINE__);
return YES;
}
void RegisterApplicationClass()
{
Class AppDelClass;
AppDelClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "AppDelegate", 0);
class_addMethod(AppDelClass, sel_getUid("applicationDidFinishLaunching:"), (IMP)AppDidFinishLaunching, "i@:@");
class_addIvar(AppDelClass, "m_applicationPtr", sizeof(Application*), sizeof(Application*), "Application*");
objc_registerClassPair(AppDelClass);
}
*/
class ShimApplication : public Application
{
public:
void start2() { start(); }
};
void Application::start()
{
m_data->started = true;
}
// AppDelegate
OBJC_BEGIN_CLASS(AppDelegate, NSObject)
// Methods
OBJC_METHOD(applicationDidFinishLaunching,
{
auto appPtr = _this.get<ShimApplication*>("m_applicationPtr");
appPtr->start2();
//return true;
return YES;
})
// Members
OBJC_MEMBER(Application*, m_applicationPtr);
OBJC_END_CLASS()
extern "C" bool NSApplicationLoad(void);
Application::Application()
{
// bool res =
NSApplicationLoad();
//printf("result of NSApplicationLoad() = %i\n", res);
m_data = new ApplicationData;
m_data->started = false;
//m_data->screenW = xx;
//m_data->screenH = xx;
//auto pool = ObjectiveC::Object("NSAutoreleasePool")["alloc"]()["init"]();
// TODO: convert to ObjectiveC wrapper code
ObjectiveC::Object app = ObjectiveC::Object("NSApplication")["sharedApplication"]();
// ObjectiveC::Object app(NSApp);
app["setActivationPolicy:"](NSApplicationActivationPolicyRegular);
RegisterAppDelegateClass();
// RegisterApplicationClass();
RegisterWindowClass();
ObjectiveC::Object appDelObj = ObjectiveC::Object("AppDelegate")["alloc"]()["init"]();
appDelObj.set("m_applicationPtr", (void*)this);
app["setDelegate:"](appDelObj.m_object);
printf("waiting for AppDidFinishLaunching\n");
app["finishLaunching"]();
while (!m_data->started)
{
// printf("waiting for event\n");
//CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, YES);
auto event = app["nextEventMatchingMask:untilDate:inMode:dequeue:"](NSAnyEventMask, nil, NSDefaultRunLoopMode, YES);
app["sendEvent:"](event.m_object);
app["updateWindows"]();
event["release"]();
// printf("got event\n");
}
ObjectiveC::Object s = ObjectiveC::Object("NSString")["stringWithUTF8String:"]("");
ObjectiveC::Object q = ObjectiveC::Object("NSString")["stringWithUTF8String:"]("q");
ObjectiveC::Object appS = ObjectiveC::Object("NSString")["stringWithUTF8String:"]("Application");
ObjectiveC::Object aboutS = ObjectiveC::Object("NSString")["stringWithUTF8String:"]("About...");
ObjectiveC::Object quitS = ObjectiveC::Object("NSString")["stringWithUTF8String:"]("Quit");
ObjectiveC::Object mainMenu = ObjectiveC::Object("NSMenu")["alloc"]()["init"]();
ObjectiveC::Object mainAppMenuItem = ObjectiveC::Object("NSMenuItem")["alloc"]()["initWithTitle:action:keyEquivalent:"](appS.m_object, nil, s.m_object);
mainMenu["addItem:"](mainAppMenuItem.m_object);
ObjectiveC::Object appMenu = ObjectiveC::Object("NSMenu")["alloc"]()["init"]();
mainAppMenuItem["setSubmenu:"](appMenu.m_object);
appMenu["addItemWithTitle:action:keyEquivalent:"](aboutS.m_object, nil, s.m_object);
ObjectiveC::Object menuItem = appMenu["addItemWithTitle:action:keyEquivalent:"](quitS.m_object, sel_getUid("terminate:"), q.m_object);
menuItem["setTag:"](10);
app["setMainMenu:"](mainMenu);
//mainMenu["setAutoenablesItems:"](YES);
/*
//[theMenu setAutoenablesItems:NO];
//[tItem setKeyEquivalentModifierMask:NSCommandKeyMask];
*/
//app["activateIgnoringOtherApps:"](NO);
// appDelObj["release"]();
// appDelObj["autorelease"]();
printf("finished waiting for AppDidFinishLaunching\n");
//pool["release"]();
}
Application::~Application()
{
// any shut down code needed
delete m_data;
}
int Application::exec()
{
/*
ObjectiveC::Object app(NSApp);
while (true)
{
auto event = app["nextEventMatchingMask:untilDate:inMode:dequeue:"](NSAnyEventMask, nil, NSDefaultRunLoopMode, YES);
app["sendEvent:"](event.m_object);
app["updateWindows"]();
event["release"]();
}
*/
/*
// Objective-C version that emulates what "run" does internally
- (void)run
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self finishLaunching];
shouldKeepRunning = YES;
do
{
[pool release];
pool = [[NSAutoreleasePool alloc] init];
NSEvent *event =
[self
nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:YES];
[self sendEvent:event];
[self updateWindows];
} while (shouldKeepRunning);
[pool release];
}
- (void)terminate:(id)sender
{
shouldKeepRunning = NO;
}
*/
printf("run loop\n");
auto pool = ObjectiveC::Object("NSAutoreleasePool")["alloc"]()["init"]();
ObjectiveC::Object((id)NSApp)["run"]();
pool["release"]();
return 0;
}
void Application::normalLoop()
{
}
void Application::gameLoop()
{
}
#endif
END_NAMESPACE