How to make NSOpenPanel accept keyboard and mouse events in objective-c? - c++

I have C++ console application getting written in XCode, and I need to open a file selector dialog. To do this I'm using Cocoa with objective-c. I'm trying to open an NSOpenPanel to use it for this purpose. I'm using the following code currently:
const char* openDialog()
{
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
[openDlg setCanChooseFiles:YES];
[openDlg setFloatingPanel:YES];
if ( [openDlg runModal] == NSOKButton )
{
for( NSURL* URL in [openDlg URLs] )
{
NSLog( #"%#", [URL path] );
return [URL.path UTF8String];
}
}
return NULL;
}
This works, however the created file selector doesnt accept mouse and keyboard events properly. It's hard to explain, but for example when I run the code from XCode when hovering above the window the mouse still behaves as if were in XCode, showing the caret symbol. When i run the application from the terminal whenever I type something it sends the input to the terminal, even though the file selector is "in front". Command clicking gives the mouse events properly to the file selector though.
I looked through NSOpenPanel's documentation and googled the problem extensively but I couldn't find an answer to this.

/*
To run in Terminal: clang openpanel.m -fobjc-arc -framework Cocoa -o openpanel && ./openpanel
*/
#import <Cocoa/Cocoa.h>
int main() {
NSApplication *application = [NSApplication sharedApplication];
[application setActivationPolicy:NSApplicationActivationPolicyAccessory];
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
[openDlg setCanChooseFiles:YES];
[openDlg setFloatingPanel:YES];
if ( [openDlg runModal] == NSModalResponseOK ) {
for( NSURL* URL in [openDlg URLs] ) {
NSLog( #"%#", [URL path] );
}
}
return 0;
}
Thanks to #Willeke.

Related

how can I synchronize a gtk::label with the creation or suppression of a file in a directory?

I have a program who lists all files in the working directory (I use glib for doing this), then I screen this list in a GtkWindow trough a Gtk::Label. I screen the window by using run(),
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "Zombie-Shadowchaser SixSixSix");
app->run(*pMainWindow);
I know how to change the label with set_label() I can synchronize the list of files in the directory with the list screened trough the click of a button. So if I delete or create a file, it will remove or add to the label the file. But how can I make my program to synchronize every second without clicking ?
here a full example, is also good to study if you are looking to understand how to use g_signal_connect()
#include <gtkmm.h>
Gtk::Label *plabel; // because I"m lazzy...
/**
** everytime a file is created in the current directory, toCallbackFunction()
** will be called. The paramaters are the same of signal see signal here :
** http://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/gio/GFileMonitor.html#GFileMonitor-changed
**/
void
toCallbackFunction(GFileMonitor *monitor
,GFile *file
,GFile *other_file
,GFileMonitorEvent event_type
,gpointer user_data
)
{
plabel->set_label( g_file_get_path(file) );
}
int
main(int argc
,char *argv[]
)
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
Gtk::Window window;
Gtk::Label label;
window.set_default_size(800, 200);
label.set_label("test");
window.add(label);
label.show();
plabel = &label;
/*
* g_file_monitor() requires a file, not a path. So we use g_file_new_for_path()
* to convert the directory (this is for demonstration)
*/
GFile *file = g_file_new_for_path(".");
GFileMonitor *monitor;
/*
* http://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/gio/GFile.html#g-file-monitor
*/
monitor = g_file_monitor_directory(file, G_FILE_MONITOR_NONE, nullptr, nullptr);
/*
* the next line, is how to connect the monitor to a callback function when
* the signal changed has been triggered.
*/
g_signal_connect(monitor, "changed", G_CALLBACK (toCallbackFunction), nullptr);
return app->run(window);
}
compile on linux :
g++ main.cc -o simple `pkg-config gtkmm-3.0 --cflags --libs` -std=c++11
for MS Windows users, I'm not racist, but I don't know how to compile on windows. Any comment would be apreciate, I made this piece of code by my own. Thx to report any error.
How to use it :
when you start the program, go with your console in the same directory and create a new file, for example,
$ echo "stack" > overflow
you should get something like :
Thx to nemequ

Create alert / message box in command line OSX app

I'm trying to create a simple app that just opens an alert. So imagine this
int main(int argc, const char * argv[]) {
int result = SomeMagicAlertFunction("Hello World", "Yes", "No");
printf("User picked: %d¥n", result);
}
I've found some info about NSAlert but all the examples are for full OSX Apps, the kind with an app package as in
+-MyApp.app
|
+-Contents
|
+-MacOS
|
+-MyApp
etc, but I just want an alert in a command line app. One file, not an app package. Is that possible in OSX in either C/C++ or Objective C? I saw something about NSRunAlertPanel but that's been removed in Yosemite and says to use NSAlert.
Found an answer moments later
#import <Cocoa/Cocoa.h>
void SomeMagicAlertFunction(void) {
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:#"OK"];
[alert addButtonWithTitle:#"Cancel"];
[alert setMessageText:#"Delete the record?"];
[alert setInformativeText:#"Deleted records cannot be restored."];
[alert setAlertStyle:NSWarningAlertStyle];
if ([alert runModal] == NSAlertFirstButtonReturn) {
}
//[alert release];
}

How to quit QApplication gracefully on logout?

I have an application with notification area icon, so the main window may ignore close event. I am trying to save preferences and history on application quit. I also want to handle logout when the application is running. While the application is cross-platform, it is most convenient/useful in GNU/Linux, so Windows logout behavior is of much less concern.
This is a minimal compilable example that was used for testing behavior of different desktop environments/window managers:
// main.cpp
# include <QApplication>
# include <QMainWindow>
# include <QCloseEvent>
# include <QTimer>
# include <iostream>
class M : public QMainWindow
{
Q_OBJECT
public:
~M();
public slots:
void onAboutToQuit();
private:
void closeEvent(QCloseEvent *);
};
M::~M()
{
std::cout << "M::~M()" << std::endl;
}
void M::onAboutToQuit()
{
std::cout << "onAboutToQuit()" << std::endl;
}
void M::closeEvent(QCloseEvent * e)
{
std::cout << "closeEvent()" << std::endl;
hide();
QTimer::singleShot(5000, this, SLOT(show()));
e->ignore();
}
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
M m;
m.setWindowModality(Qt::NonModal);
m.connect(& app, SIGNAL(aboutToQuit()),
SLOT(onAboutToQuit()));
m.show();
return app.exec();
}
# include "main.moc"
// CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(closeeventbug)
option(QT5 "Use Qt5" OFF)
if(QT5)
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
else()
find_package(Qt4 REQUIRED)
include_directories(${QT_INCLUDES})
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_AUTOMOC ON)
add_executable(closeeventbug main.cpp)
if(QT5)
qt5_use_modules(closeeventbug Core Widgets)
else()
target_link_libraries(closeeventbug ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
endif()
Most full-blown desktop environments on logout attempt to close visible window. But since the test app does not exit when closed, logging out is interrupted/cancelled. If logging out is performed while the window is invisible, it quits gracefully (just like I want it to). Less feature-full desktop environments/window managers ignore the still-running application and exit. Most of them don't even warn the application about logging out, so there is neither "closeEvent()", nor "onAboutToQuit()", nor "M::~M()" in the file, to which the program output is redirected.
The detailed results (all non-Windows results are from Manjaro GNU/Linux):
Full-blown desktop environments that cancel logging out if the visible window refuses to exit, finish invisible application gracefully:
closeEvent()
onAboutToQuit()
M::~M()
{ KDE, XFCE, Mate, GNOME, Cinnamon }
All others don't cancel quit, but some of them try to warn the application.
I have no idea why onAboutToQuit() is present in the log, but M::~M() is not in this case...
closeEvent()
onAboutToQuit()
{ Windows7 }
3.
closeEvent()
{ icewm, E17 }
4.
<nothing in the log>
{ RazorQt, LxDE, LxQt, i3, budgie, fluxbox, awesome, openbox,
wmii, E16, pekWM, uwm, fvwm, xmonad, spectrwm, windowmaker,
herbstluftwm, WindowsXP }
The behaviour is exactly the same for any combination of (GCC 4.9.1 OR Clang 3.4.2) AND (Qt 4.8.6 OR Qt 5.3.1). However when I tried Qt 4.8 and Qt 5.2 on Xubuntu, the results were somewhat different: there was no blocking with Qt 5.2 in XFCE - the application finished gracefully regardless of main window visibility. But blocking was present with Qt 4.8 (just the same as in Manjaro).
I know that it is possible to handle logout properly (without blocking) because there are several applications that do that just fine. All of them have notification area icon, are closed to notification area, but don't block logging out.
Qt-based: GoldenDict, Transmission-Qt, Kopete;
GTK-based: Audacious, Pidgin.
I have examined the source code of Qt-based ones and found nothing special in handling closeEvent:
https://github.com/goldendict/goldendict/blob/master/mainwindow.cc
void MainWindow::closeEvent( QCloseEvent * ev )
{
if ( cfg.preferences.enableTrayIcon && cfg.preferences.closeToTray )
{
ev->ignore();
hide();
}
else
{
ev->accept();
qApp->quit();
}
}
https://github.com/bfleischer/transmission/blob/master/qt/mainwin.cc
void
TrMainWindow :: closeEvent( QCloseEvent * event )
{
// if they're using a tray icon, close to the tray
// instead of exiting
if( !myPrefs.getBool( Prefs :: SHOW_TRAY_ICON ) )
event->accept( );
else {
toggleWindows( false );
event->ignore( );
}
}
void
TrMainWindow :: toggleWindows( bool doShow )
{
if( !doShow )
{
hide( );
}
else
{
if ( !isVisible( ) ) show( );
if ( isMinimized( ) ) showNormal( );
//activateWindow( );
raise( );
QApplication::setActiveWindow( this );
}
}
git clone git://anongit.kde.org/kopete
void KopeteWindow::closeEvent ( QCloseEvent *e )
{
// if we are not ok to exit on close and we are not shutting down then just do what needs to be done if a
// window is closed.
KopeteApplication *app = static_cast<KopeteApplication *> ( kapp );
if ( !shouldExitOnClose() && !app->isShuttingDown() && !app->sessionSaving() ) {
// BEGIN of code borrowed from KMainWindow::closeEvent
// Save settings if auto-save is enabled, and settings have changed
if ( settingsDirty() && autoSaveSettings() )
saveAutoSaveSettings();
if ( queryClose() ) {
e->accept();
}
// END of code borrowed from KMainWindow::closeEvent
kDebug ( 14000 ) << "just closing because we have a system tray icon";
}
else
{
kDebug ( 14000 ) << "delegating to KXmlGuiWindow::closeEvent()";
KXmlGuiWindow::closeEvent ( e );
}
}
So the questions:
How to ensure that my application does not block logging out even if the main window is visible?
How to ensure that onAboutToQuit() and ~M() are called on logout in as many desktop environments/window managers as possible?
I suspect that some system signals should be listened to, but I have no idea which exactly...
QApplication has signal related to OS session actions - you can easily handle it. For more details take a look at Qt docs Session Management page

Using SDL2 with wxWidgets 3.0

My goal is to build a Game Boy emulator. In order to do this, I would like to embed an SDL2 surface into a wxWidgets window.
I found this tutorial: http://code.technoplaza.net/wx-sdl/part1/, but my program crashes as soon as I run it. However I suspect this was intended for SDL1.2. Part of the program is shown below.
It seems that if I call SDL_Init() and also attempt to show a wxFrame (which, in this case, is MainWindow), it shows the window for a second and then the program crashes. I commented all other calls to SDL in my program so far, so it seems the problem lies with calling Show() on a wxFrame and initing SDL2 in the same program.
So the question is: can SDL2 and wxWidgets 3 work together? If not, could you guys suggest to me good alternatives a GUI of a Game Boy emulator? Does wxWidgets have its own graphics frame like Qt does (I'd rather avoid Qt)?
Thanks very much!
#include "MainApp.h"
#include "MainWindow.h"
#include <stdexcept>
namespace GBEmu {
static void initSDL() {
//This and SDL_Quit() are the only calls to the SDL library in my code
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
throw std::runtime_error("Fatal Error: Could not init SDL");
}
}
bool MainApp::OnInit()
{
try {
//If I comment out this line, the MainWindow wxFrame shows up fine.
//If I leave both uncommented, the window shows up quickly and then
//crashes.
initSDL();
//If I comment out this line and leave initSDL() uncommented,
//the program will not crash, but just run forever.
(new MainWindow("GBEmu", {50,50}, {640,480}))->Show();
} catch(std::exception &e) {
wxLogMessage(_("Fatal Error: " + std::string(e.what())));
}
return true;
}
int MainApp::OnExit() {
SDL_Quit();
return wxApp::OnExit();
}
}
wxIMPLEMENT_APP(GBEmu::MainApp);
EDIT: Here is more information on how it crashes: It crashes with a Segfault in what seems to be the pthread_mutex_lock disassembly file. This is the output in the console with stack trace:
Starting /home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx...
The program has unexpectedly finished.
/home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx crashed
Stack trace:
Error: signal 11:
/home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx(_ZN5GBEmu7handlerEi+0x1c)[0x414805]
/lib/x86_64-linux-gnu/libc.so.6(+0x36ff0)[0x7fb88e136ff0]
/lib/x86_64-linux-gnu/libpthread.so.0(pthread_mutex_lock+0x30)[0x7fb88c12ffa0]
/usr/lib/x86_64-linux-gnu/libX11.so.6(XrmQGetResource+0x3c)[0x7fb88d1ca15c]
/usr/lib/x86_64-linux-gnu/libX11.so.6(XGetDefault+0xc2)[0x7fb88d1a7a92]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x94dcf)[0x7fb88af8edcf]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x97110)[0x7fb88af91110]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(cairo_surface_get_font_options+0x87)[0x7fb88af63e07]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x2b61f)[0x7fb88af2561f]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x2ef95)[0x7fb88af28f95]
This is a screenshot of where it seems to fail (line 7):
Update: In my MainWindow class, I attach a menu bar to the window. However, it seems when I comment out the setting of the menu bar, the window will show up fine even with initing of SDL. The menu bar will show up fine if I have initSDL() commented out but not the setting of the menu bar. Here is where I set the menu bar:
MainWindow::MainWindow(const wxString &title, const wxPoint &pos, const wxSize &size)
:wxFrame(nullptr, wxIDs::MainWindow, title, pos, size){
wxMenu *fileMenu = new wxMenu;
fileMenu->Append(wxID_EXIT);
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append(fileMenu, "&File");
//commenting this line out will allow the window to showup
//and not crash the program
SetMenuBar(menuBar);
}
You are experiencing an old heisenbug.
The workaround is simple: you have to initialize SDL before wxWidgets (basically, before GTK). To achieve this, you have to change
wxIMPLEMENT_APP(GBEmu::MainApp);
to
wxIMPLEMENT_APP_NO_MAIN(GBEmu::MainApp);
so that wxWidgets doesn't hijack your main().
Then you have to create main() manually. In it, initialize SDL, then call wxEntry():
int main(int argc, char** argv)
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cerr << "Could not initialize SDL.\n";
return 1;
}
return wxEntry(argc, argv);
}
More about the bug:
I have googled around a bit and found that this bug has come up in a few places over the years. There are open reports in many bug trackers that have stack traces very similar to the one you get here (with debug symbols).
The oldest report I could find is from 2005 (!!) from the cairo bug tracker (https://bugs.freedesktop.org/show_bug.cgi?id=4373).
My best guess is that the real hiding place of this bug in either in GTK, cairo, or X. Unfortunately I do not currently have the time to look into it more in depth.

Parsing terminal arguments Qt Mac OS X

I have a simple text editor in which I would like to open a file when it's double-clicked from the system file manager.
I managed to do that without any problems under Ubuntu Linux (13.04), but in Mac OS X my code did not work.
After researching a bit, I found out that you need to add the --args argument in terminal in order to parse the arguments to main().
I fixed my code and now my application bundle can open files from the terminal, but when I double click a file in Finder (and select my app), my application launches as if did not receive any terminal arguments (creates a new file).
Here is the code of the main() function:
int main(int argc, char *argv[])
{
QApplication MyApp(argc, argv);
Textpad.setApplicationName("MyApp");
Textpad.setApplicationVersion("0.7.2");
Textpad.setWindowIcon(QIcon(":/app-icon/48x48/icon.png"));
MainWindow *Window = new MainWindow();
QString Arguments;
QString FileLocation;
if (argc != 1) {
int i;
for (i = 0; i < argc; i++)
Arguments = argv[i];
// Check if the OS is Mac OS X (Mac OS X is 3)
if (Window->CheckOS() == 3)
// Remove the "--args" so that we don't confuse it with the file location
Arguments.replace("--args", "");
if (Arguments == "--help") {
// Show help
}
// Create a new file when Textpad is launched normally (under Linux)
if (Arguments == "%U") {
FileLocation.clear();
// Load settings and create UI
Window->Initialize();
// Open the requested file
Window->LoadFile(FileLocation);
}
else {
FileLocation = Arguments;
// Load settings and create UI
Window->Initialize();
// Open the requested file
Window->LoadFile(FileLocation);
}
}
else {
// Create new file
FileLocation.clear();
// Load settings and create UI
Window->Initialize();
// Open the requested file
Window->LoadFile(FileLocation);
}
return MyApp.exec();
}
As I said before my application opens files without probles from the terminal when I write the following:
open MyApp.app --args <location of my file>
But fails when I try to open a file from Finder.
What I am missing?
Thank you in advance.
First of all, you will have to link against the OX-X Framework. OSX works with Events similar to signal slots. The filename will also be given by an apple event. I`ve had this quite some time ago with another language, but i still found a reference:
Edit doc now in Qt archive:
https://doc.qt.io/archives/qq/qq12-mac-events.html