I have an open source MS-DOS emulator for iOS here:
https://github.com/MattAndrzejczuk/MSDOS-for-iOS
This app runs well when using my older iOS devices such as the old iPhone 5S. but right after iOS 13.0 was released, the app delegate has trouble rendering SDL due to NOT calling UIKit methods on the main thread, but I'm not quite sure if this crash is due to OpenGL being completely deprecated, or, if maybe the newer SceneDelegate and AppDelegate changes which seemed to have been overhauled in iOS 13 are the cause of this issue. Just for some context, I've noticed that I cannot create a new Xcode project with a basic hello world label and build it directly for iOS 12 devices without doing this:
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
// ADD THIS TO DEFAULT APPDELEGATE.H:
#property (strong, nonatomic) UIWindow *window;
#end
This solution below, only somewhat fixed the problem:
Sources/dospad/Shared/DosEmuThread.m
#import "DosEmuThread.h"
extern int SDL_main(int argc, char *argv[]);
#implementation DosEmuThread
#synthesize started;
- (void)start
{
if (started) {
NSLog(#"DosEmuThread %p already started", self);
return;
}
NSLog(#"Start dosbox in new thread");
started = YES;
[NSThread detachNewThreadSelector:#selector(run) toTarget:self withObject:nil];
}
- (void) run {
#autoreleasepool {
/// UNCOMMENTING THIS SOMEWHAT FIXES THE ISSUE:
//dispatch_async(dispatch_get_main_queue(), ^{
char *argv[1] = {"dosbox"};
SDL_main(1, argv);
self.started = NO;
//});
}
}
#end
This fixes the app, in that I can reach the DOS prompt, but once I try to open something like this:
C:\ cd WAR2A
C:\ WAR2.EXE
I just get stuck at a blank screen, so obviously the quick fix of putting the dos thread on the main thread will break once SDL tries to run a full screen EXE app.
I'd really like to have the ability to emulate an x86 machine to run classic DOS games and even support Windows 95 for iOS, if there are alternative git repos out there that can do something similar, please let me know.
Related
I'm working on a Qt project on Windows that heavily uses OpenGL. It was originally configured to use OpenGL version 2.1, and everything worked fine. Recently, I upgraded the OpenGL version in the code to 3.0. Now, the project crashes very early during initialization with the following error:
QML debugging is enabled. Only use this in a safe environment.
ASSERT: "qGuiApp" in file kernel\qopenglcontext.cpp, line 1238
Debug Error!
Program: C:\Qt\5.7\msvc2015_64\bin\Qt5Cored.dll
Module: 5.7.0
File: global\qglobal.cpp
Line: 3063
ASSERT: "qGuiApp" in file kernel\qopenglcontext.cpp, line 1238
... and this is the line that the debugger stops on:
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
In global.cpp, it's failing at the end of this block. Specifically, the line number given in the error message corresponds to the #endif line:
#ifndef QT_NO_EXCEPTIONS
/*
\internal
Allows you to call std::terminate() without including <exception>.
Called internally from QT_TERMINATE_ON_EXCEPTION
*/
Q_NORETURN void qTerminate() Q_DECL_NOTHROW
{
std::terminate();
}
#endif
Looking at qopenglcontext.cpp, line 1238 is actually within a large comment block. Here is the code that directly follows, which is almost certainly the right place based on the error message above (the Q_ASSERT(qGuiApp) line):
QOpenGLContext::OpenGLModuleType QOpenGLContext::openGLModuleType()
{
#if defined(QT_OPENGL_DYNAMIC)
Q_ASSERT(qGuiApp);
return QGuiApplicationPrivate::instance()->platformIntegration()->openGLModuleType();
#elif defined(QT_OPENGL_ES_2)
return LibGLES;
#else
return LibGL;
#endif
}
Keep in mind these are standard Qt files and this is code I have never touched.
Here is a summary of what I've tried so far. Of course, none of these worked:
Tried setting my environment variables like the following page suggests: http://doc.qt.io/qt-5/windows-requirements.html. Specifically, I set my QT_OPENGL var to desktop, angle, and then software, and nothing worked.
As the same page suggested, I tried adding the following lines to my .pro file: "LIBS += opengl32.lib" and "LIBS += -lopengl32" (I added one line, tested it, removed it, then added the second line.)
Tried un-setting the QT_OPENGL_DYNAMIC variable.
Downloaded and ran OpenGL Extensions Viewer 4.1 and confirmed that my OpenGL exists and is setup just fine. The Render Test functionality proves that OpenGL is otherwise working on my system.
Also successfully ran the HelloWorld OpenGL example that's built-in to Qt. This ran fine, confirming that Qt is otherwise able to run OpenGL.
I'm out of ideas here. Any suggestions or knowledge would be welcome. Also, if you need more information please ask and I will respond promptly.
EDIT : Here is the beginning of main:
int main(int argc, char* argv[])
{
// setup OpenGL before application initialization
GLFunctions::setupOpenGL();
QApplication app(argc, argv);
....
}
And here is the setup function:
static void setupOpenGL()
{
QSurfaceFormat fmt;
fmt.setDepthBufferSize( 24 );
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
{
fmt.setVersion(3, 3);
fmt.setProfile(QSurfaceFormat::CoreProfile);
//fmt.setRenderableType(QSurfaceFormat::OpenGL);
}
else
{
fmt.setVersion(3, 0);
}
}
From the documentation of QOpenGLContext::openGLModuleType():
Note: This function requires that the QGuiApplication instance is already created.
You may set your desired version regardless of the openGLModuleType (remove the check) and check later if you got your requested version or not.
Upon login the initial display of my UI worked fine in iOS 9 with the UITabBarController showing all icons appropriately but in iOS 10 there is a noticeable delay of up to 5 - 10 seconds without any error in the log.
I've posted a bug to Apple ID- 29127274
The fix is below...
-J
Here is the code that cause the problem:
#implementation MyTabBarController
//...
- (void)viewDidLoad
{
[super viewDidLoad];
//the code below was causing the delay ... this worked find in iOS9
//tried legacy #define style
//[self setSelectedIndex:int(SelectedLandingToTab)];
//tried extern style .... both fail
//[self setSelectedIndex:SELECTEDLANDINGTAB];
}
//...
#end
If you comment out the setSelectedIndex then the UITabBar shows properly without delay.
-J
Having read through various posts and threads that lead me nowhere I need your help.
I do have a Qt Application for Mac OS X that at some point of use will be in the background and not active. When this is the case I want to add a global hotkey so that the user can easily turn certain features on or off by clicking pre-defined hotkeys.
The following isn't working while the app is in the background and not focused.
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_F12), parent);
shortcut->setContext(Qt::ApplicationShortcut);
So far I found Qxt which happens to be outdated for Qt 5.5.
Then there is DDHotkey which requires a certain compiler which we can not use for various reasons.
Lastly, I found the solution of adding a global AppleScript which registers an event, again, not what I am looking for.
tell application "System Events" to tell process "myApp"
click menu item "myButton" of menu 1 of menu bar item "Menu" of menu bar 1
end tell
Is there a way to use objective-c or cocoa to accomplish exactly what I am looking for?
Please lead me in the right direction if I may have missed something.
Thanks in advance!
To those who seek a more Qt way, check the following repository:
https://github.com/ddqd/qxtglobalshortcut5
It makes use of the outdated qxt library but gets it working again.
The person tested it until Qt 5.4, we use it successfully under Qt 5.5.
This might be what you're looking for
https://github.com/jaz303/JFHotkeyManager
You could also look at this example from Apple, using the RegisterEventHotKey API call which I think will point you in the right direction.
https://developer.apple.com/library/prerelease/mac/samplecode/FunkyOverlayWindow/Listings/FunkyOverlayWindow_OverlayWindow_m.html#//apple_ref/doc/uid/DTS10000391-FunkyOverlayWindow_OverlayWindow_m-DontLinkElementID_8
Or you could try this code
#import <Carbon/Carbon.h>
EventHandlerUPP hotKeyFunction;
pascal OSStatus hotKeyHandler(EventHandlerCallRef nextHandler,EventRef theEvent, void *userData)
{
Notify *obj = userData;
[obj foo];
return noErr;
}
#implementation Notify
- (id)init
{
self = [super init];
if (self) {
//handler
hotKeyFunction = NewEventHandlerUPP(hotKeyHandler);
EventTypeSpec eventType;
eventType.eventClass = kEventClassKeyboard;
eventType.eventKind = kEventHotKeyReleased;
InstallApplicationEventHandler(hotKeyFunction,1,&eventType,self,NULL);
//hotkey
UInt32 keyCode = 80; //F19
EventHotKeyRef theRef = NULL;
EventHotKeyID keyID;
keyID.signature = 'FOO '; //arbitrary string
keyID.id = 1;
RegisterEventHotKey(keyCode,0,keyID,GetApplicationEventTarget(),0,&theRef);
}
return self;
}
- (void)foo
{
}
#end
And the header
#include "notify.mm"
#interface Notify
- (id)init;
- (void)foo;
#end
Simply this is just a object with a method and a constructor, in objective-c this is called init, or initialize, and variants. Calling it should be straight forward with "new".
E.x
#include "notify.h"
int main(){
Notify* object = new Notify();
}
However, some basic understanding of Objective-C is needed. It's mostly syntax differences in my opinion. But I'm no Objective-C expert myself. Anyway, there is a lot of ways to solve it, this might not be the best idea. You can also call Objective-C code from inside of a C++ class of yours. Take a look at the links bellow for a great example of how that's done.
https://el-tramo.be/blog/mixing-cocoa-and-qt/
https://github.com/remko/mixing-cocoa-and-qt/
http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++
I've tried in 2 forums, but I had no luck so far.
So, I am using Qt IDE in order to build my application so as to participate to the Ubuntu Showdown contest. In my application, I've done the following:
void show_app(MainWindow *data)
{
//this works fine:
app_indicator_set_status(appindicator, APP_INDICATOR_STATUS_PASSIVE);
//this crashes the application:
data->show();
}
void MainWindow::make_indicator()
{
if(appindicator){
//appindicator has already been created
return;
}
appindicator = app_indicator_new("Format Junkie Indicator", "formatjunkie", APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
GtkWidget* showapp_option;
GtkWidget* indicatormenu = gtk_menu_new();
GtkWidget* item = gtk_menu_item_new_with_label("Format Junkie main menu");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), indicatormenu);
showapp_option = gtk_menu_item_new_with_label("Show App!");
g_signal_connect(showapp_option, "activate", G_CALLBACK(show_app), this);
gtk_menu_shell_append(GTK_MENU_SHELL(indicatormenu), showapp_option);
gtk_widget_show_all(indicatormenu);
app_indicator_set_status(appindicator, APP_INDICATOR_STATUS_ACTIVE);
app_indicator_set_attention_icon(appindicator, "dialog-warning");
app_indicator_set_menu(appindicator, GTK_MENU (indicatormenu));
}
So, basically I am trying to make a simple indicator entry, which, on click, it will hide the indicator and display the application. The indicator can be successfully hidden using the PASSIVE thingy over there, but, during the call data->show();, the application crashes.
Any help on what I am doing wrong would be appreciated! Also, please help me to correct this problem I'm facing (alternatively, I will migrate to the old and good tray icon (it works fine in Ubuntu 12.04, anyway) which I can handle very easily and efficiently)
The callback for the activate signal needs to have the following type:
void callback(GtkMenuItem *, gpointer)
So show_app should be defined like this
void show_app(GtkMenuItem *showapp_option, MainWindow *data)
That should solve your problem.
I am developing a C++ app and I need to display a NSWindow with a WebKit WebView inside it. I've coded up the Objective-C class which will manage creating and displaying the window but the WebView contained inside it does not display. Here is my code. Any idea on what is wrong and how I can fix it?
I'm compiling the below code with
$g++ -x objective-c++ -framework Cocoa -framework WebKit Foo.m main.m -o test
Foo.h
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
#interface Foo :NSObject {
NSWindow *window;
WebView *view;
}
- (void)displayWindow;
#end
Foo.m
#import "Foo.h"
#implementation Foo
- (id)init {
self = [super init];
// Window Container
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(500.0f,500.0f,250.0f,250.0f)
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreNonretained
defer:NO];
// WebView
view = [[WebView alloc] initWithFrame:NSMakeRect(0, 0, 250.0f, 250.0f)
frameName:#"Frame"
groupName:nil];
[[view mainFrame] loadHTMLString:#"<html><head></head><body><h1>Hello</h1></body></html>"
baseURL:nil];
return self;
}
- (void)displayWindow {
NSLog(#"In Display window");
[window setContentView:view];
[window setLevel:NSStatusWindowLevel];
[window orderFrontRegardless];
sleep(5); // leave it up for 5 seconds
}
- (void)dealloc {
[window release];
[super dealloc];
}
#end
main.m
#import "Foo.h"
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSApplication sharedApplication];
Foo *foo = [[Foo alloc] init];
[foo displayWindow];
[foo release];
[pool release];
return 0;
}
You need to run the run loop. If you just order the window in and then exit, that's exactly what will happen: The window will appear, and then (five seconds later) your program will exit. You can run the run loop by telling the application (which you create but don't otherwise use) to run.
On the main thread of a Cocoa app, sleep is always the wrong answer. The same goes for its Cocoa cousins, +[NSThread sleepUntilDate:] and +[NSThread sleepForTimeInterval:]. The run loop will let you tell it to run for a fixed amount of time, but that won't get the application running; you do need to send the application the run message, which provides no opportunity to exit after a fixed interval.
The solution there is to first create an NSTimer object whose target is the application and whose selector is #selector(terminate:). Create it scheduled and non-repeating, with the interval set to five seconds. (Creating it scheduled means you don't need to schedule it separately—it is already ready to go from the moment you create it.) Then, send the application the run message. Five seconds later, the run loop will fire the timer, which will tell the application to terminate itself. This is assuming that you actually have a good reason to make your application quit after five seconds.
As noted by Yuji, every window in modern Cocoa should use NSBackingStoreBuffered.
And don't forget to release what you have created; you currently are forgetting that in the case of the view. See the Memory Management Programming Guide for Cocoa.
Once you have this working, I suggest moving toward a more typical architecture for this application:
Create a subclass of NSObject, and make an instance of that class your application's delegate.
Put the window and its WebView into a nib, and have the app delegate create a window controller to load and own the contents of that nib.
The app delegate should also be responsible for loading the page into the WebView and for setting up the self-termination timer.
Finally, create a nib to hold your application's main menu (the contents of the menu bar) and the application delegate. Interface Builder has a template for the first part; you create the app delegate object by dragging a blank Object in from the Library, setting its class on the ⌘6 Inspector, and dragging the connection from the application to the object. Then, you can reduce main to the single line that Xcode's project templates put in it: return NSApplicationMain(argc, argv);.
Doing all this will help your understanding of Cocoa, as well as your maintenance of the application—cramming everything into main will not scale.
You should also read the Cocoa Fundamentals Guide, if you haven't already.
Don't make it sleep. It stops the execution of the main thread, in which the GUI is dealt with. Instead, you need to run the run loop. Also, Cocoa needs to set itself up. So, call [[NSApplication sharedApplication] run] to set it up correctly and run the event loop.
Also, don't use backing mode other than buffered mode. Other modes are remnants from the time immemorial, and only NSBackingStoreBuffered should be used. As discussed in this Apple document, the non-retained mode is a remnant to support Classic Blue Box (OS 9 virtualizer), and newer classes like WebKit just can't operate within it.
So, what you need to do is practically:
change NSBackingStoreNonretained to NSBackingStoreBuffered.
Remove the line
sleep(5);
add a line
[[NSApplication sharedApplication] run];
after
[foo displayWindow];
Also, in order for an app to receive events from the window server correctly, you need to pack it into an app bundle. Compile it into a binary called foo, and create the following structure:
foo.app/
foo.app/Contents/
foo.app/Contents/MacOS/
foo.app/Contents/MacOS/foo <--- this is the executable
Then you can double-click foo.app from the Finder, or just call ./foo from the command line.