Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Paprikachu

macrumors newbie
Original poster
May 24, 2012
6
0
Hi there,

I want to create my own little GUI library in C++. I wondered if it was possible to create windows and other elements without using Objective-C(++). I couldn't find anything with Google. Is there a way?

/pap
 
Last edited:
No.

The GUI components of Carbon, the non-Objective-C part of the API are essentially deprecated and may be unusable. Carbon (look up "Core Services") is the transitional interface between Classic Mac OS and OS X, comprising legacy calls some of which go all the way back to Lisa. As such, it is designed for a 32-bit system and will not work on 64-bit. If you want a library that you can continue to use, you will simply have to glue C++ onto some Cocoa – once the library is compiled, you will never know the difference.

Of course, you could employ XWindows, gaining the benefit of broader Unixy compatibility, but that might be a can of worms.
 
I write my own Library because they both suck. There is no good GUI Framework/Library out there that emphasizes modern C++ style.

Then write a library that glues into Cocoa. Obscure the objective-C within your library and it will look just like C++ to the app code, though you may also have to write methods that handle other objects (like NSStrings and NSArrays). Basically, to make your own C++ guilib, you would have to glue onto huge sections of AppKit and Foundation frameworks.
 
I just started to create a simple, empty window (Ofc i know that it won't show up because there is no message loop yet). However, the linker claims that some symbols are missing.

The applications consists of 4 files: main.cpp, window.hpp/cpp and window_impl.mm.

main.cpp:
Code:
#include "window.hpp"

int main()
{
	gui::window wnd("foobar");
}

window.hpp:
Code:
#ifndef WINDOW_HPP
#define WINDOW_HPP

#include <string>

namespace detail
{
	typedef void* window_handle;

	extern window_handle create_window(std::string const& title);
	extern void destroy_window(window_handle handle);
}

namespace gui
{
	struct window
	{
		typedef detail::window_handle native_handle;

		window(std::string const& title);
		~window();

		native_handle handle();

	private:
		native_handle handle_;
	};
}

#endif // WINDOW_HPP

window.cpp:
Code:
#include "window.hpp"

namespace gui
{
	window::window(std::string const& title)
		: handle_(detail::create_window(title))
	{}

	window::~window()
	{
		detail::destroy_window(handle_);
	}

	detail::window_handle window::handle()
	{
		return handle_;
	}
}

window_impl.mm:
Code:
#include <string>
#import <Cocoa/Cocoa.h>

namespace detail
{
    NSWindow* create_window(std::string const& title)
    {
        NSWindow* window = [[NSWindow alloc] init];
        NSString* objc_title = [NSString stringWithCString:title.c_str() encoding:NSASCIIStringEncoding];
        [window setTitle:objc_title];
        return window;
    }
    
    void destroy_window(NSWindow* window)
    {
        [window release];
    }
}

I compiled all cpp/mm files with
gcc -c -o <filename>.o <filename>.cpp/.mm
and it worked. Then i tried to link with
gcc -o windowlib main.o window.o window_impl.o
but the linker says:
Undefined symbols for architecture x86_64:
"std::allocator<char>::allocator()", referenced from:
_main in main.o
"std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)", referenced from:
_main in main.o
"std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()", referenced from:
_main in main.o
"std::allocator<char>::~allocator()", referenced from:
_main in main.o
"std::ios_base::Init::Init()", referenced from:
__static_initialization_and_destruction_0(int, int) in main.o
"std::ios_base::Init::~Init()", referenced from:
__static_initialization_and_destruction_0(int, int) in main.o
"___gxx_personality_v0", referenced from:
Dwarf Exception Unwind Info (__eh_frame) in main.o
"detail::destroy_window(void*)", referenced from:
gui::window::~window() in window.o
gui::window::~window() in window.o
"std::basic_string<char, std::char_traits<char>, std::allocator<char> >::c_str() const", referenced from:
detail::create_window(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) in window_impl.o
"_objc_msgSend_fixup", referenced from:
anon in window_impl.o
"_OBJC_CLASS_$_NSWindow", referenced from:
objc-class-ref in window_impl.o
"_OBJC_CLASS_$_NSString", referenced from:
objc-class-ref in window_impl.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
What am I doing wrong?
 
What am I doing wrong?
You use probably the wrong linker options. I used:
gcc -o windowlib.dylib -dylib window_impl.o window.o main.o -lobjc -lstdc++ -framework Foundation -framework AppKit

which reduced the error output to:

Undefined symbols:
"detail::destroy_window(void*)", referenced from:
gui::window::~window()in window.o
gui::window::~window()in window.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

This is probably a problem between Objective-C and C++ (i.e. the linker can not see your defined symbols).
 
Thanks a lot! I could solve the last problem by declaring the functions as extern "C". However, when i run the application (For now i built a normal program, not a .dylib) i get an NSException with the following trace:
2012-05-28 12:45:50.464 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x10021b510 of class NSMutableParagraphStyle autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.466 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x100606860 of class NSCFDictionary autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.466 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x100209510 of class NSCFNumber autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.466 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x100209510 of class NSCFNumber autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.467 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x1006089a0 of class NSCFArray autoreleased with no pool in place - just leaking
Mon May 28 12:45:50 <my name>'s-MacBook-Pro.local windowlib[19422] <Error>: kCGErrorInvalidConnection: CGSGetCurrentCursorLocation: Invalid connection
Mon May 28 12:45:50 <my name>'s-MacBook-Pro.local windowlib[19422] <Error>: kCGErrorFailure: Set a breakpoint @ CGErrorBreakpoint() to catch errors as they are logged.
Mon May 28 12:45:50 <my name>'s-MacBook-Pro.local windowlib[19422] <Error>: kCGErrorInvalidConnection: CGSNewWindowWithOpaqueShape: Invalid connection
2012-05-28 12:45:50.468 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x113100ae0 of class NSCFString autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.468 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x113100560 of class NSException autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.468 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x113100150 of class _NSCallStackArray autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.469 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x1131001b0 of class _NSCallStackArray autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.469 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x1131003c0 of class NSCFString autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.602 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x101804600 of class NSCFString autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.602 windowlib[19422:903] *** __NSAutoreleaseNoPool(): Object 0x113100dc0 of class NSConcreteMutableData autoreleased with no pool in place - just leaking
2012-05-28 12:45:50.602 windowlib[19422:903] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error (1002) creating CGSWindow'
*** Call stack at first throw:
(
0 CoreFoundation 0x00007fff8334e784 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00007fff85e56f03 objc_exception_throw + 45
2 CoreFoundation 0x00007fff8334e5a7 +[NSException raise:format:arguments:] + 103
3 CoreFoundation 0x00007fff8334e534 +[NSException raise:format:] + 148
4 AppKit 0x00007fff87577f52 _NSCreateWindowWithOpaqueShape2 + 473
5 AppKit 0x00007fff8750c691 -[NSWindow _commonAwake] + 1214
6 AppKit 0x00007fff87509376 -[NSWindow _commonInitFrame:styleMask:backing:defer:] + 1501
7 AppKit 0x00007fff87508002 -[NSWindow _initContent:styleMask:backing:defer:contentView:] + 1396
8 AppKit 0x00007fff87507a8b -[NSWindow initWithContentRect:styleMask:backing:defer:] + 42
9 AppKit 0x00007fff87b0fa74 -[NSWindow init] + 94
10 windowlib 0x0000000100000c82 create_window + 69
11 windowlib 0x0000000100000be4 _ZN3gui6windowC1ERKSs + 28
12 windowlib 0x0000000100000b2f main + 63
13 windowlib 0x0000000100000ae8 start + 52
14 ??? 0x0000000000000001 0x0 + 1
)
terminate called after throwing an instance of 'NSException'
Abort trap

Any ideas what i could've done wrong? I'm totally new to Objective-C++.
 
Last edited:
Any ideas what i could've done wrong? I'm totally new to Objective-C++.

What do the error messages say? They say there's no autorelease pool in place. So that's what you did wrong.

If you don't know what autorelease is, or why it needs a pool, then you need to study the fundamentals more thoroughly. Without a solid understanding of the Cocoa Foundation classes, you can't possibly achieve your goal.

Autorelease, and release/retain should be covered very early in any decent tutorial. If you haven't studied this before, see the Advanced Memory Management Guide.


One of the error messages also said:
Code:
Set a breakpoint @ CGErrorBreakpoint() to catch errors as they are logged.
So you'll have to learn to do that using the debugger. Using the debugger is another fundamental and essential skill.


The Mac Developer Library has a lot of resources for learning fundamentals.
https://developer.apple.com/library/mac/navigation/
See the "Getting Started" and "Guides" resource types.
 
Thanks a lot! I could solve the last problem by declaring the functions as extern "C". However, when i run the application (For now i built a normal program, not a .dylib) i get an NSException with the following trace:
Any ideas what i could've done wrong?
Your window initialization is probably not the correct way.

See Tasks -> Creating Windows
https://developer.apple.com/library...ple_ref/doc/uid/20000013-DontLinkElementID_11

And which functions are now "extern "C""?

Btw, Window Programming Guide for Cocoa:
https://developer.apple.com/library...l/WinPanel.html#//apple_ref/doc/uid/10000031i

I'm totally new to Objective-C++.
Me too. I find your work interesting. ;-)
 
Wow. I'm really impressed how ****ed up the Cocoa API is. Seriously, I've never seen such a bad API. Forcing someone to use some particular kind of memory management (here: reference counting) is the worst thing that an API ever can do.

The problem is: For various reasons i have to do the reference counting on the C++ side. This means that i have pointers to reference counted pointers to reference counted objects. Inefficient. Also, i don't need intrusive reference counting (because it's again, inefficient, but also because i need week references), but also exception-save RC. (which Cocoa's RC is clearly not)

Or, in short: The Cocoa way of managing objects is conceptually bu****it and not suited for any kind of application.

Anyway, thanks again for all the links you provided me with.

And which functions are now "extern "C""?
The functions that my GUI library uses internally, window_create and window_destroy. (I renamed them to have the name of the class at the front so i can get all functions related to windows with autocompletion by typing "window".)
 
Yes, yes and yes.

Pick your poison, then deal with it.

You're making a Facade. At some point, every instance of the Facade pattern must deal with the imperfections of the underlying subsystem. Logically, this is required. If the underlying subsystem already had the perfect interface, no Facade would be needed at all.

So pick one of the available "sucky" things (Qt, WxWidgets, Cocoa, whatever) and deal with it. That will mean understanding it completely, and working with it on its own terms, regardless of what you perceive as the amount of suckiness therein.

You could start by building your Facade on top of something like Qt or WxWidgets, which may be closer to what you want to deal with. This adds another layer, but it's a starting point. If you factor things well enough, you may be able to replace that underlying subsystem with something else later.
 
One of who?

One of the folks who claim anything they didn't create themselves is crap. I've worked with folks with that attitude. With that type either they are not nearly as brilliant as they think they are, or even if they are brilliant, their attitude keeps them from working effectively in a team, or they waste a hell of a lot of time reinventing the wheel because they think they can do it better.

Not wanting to start a war with you or anything .. I'm just sayin' ....
 
If Cocoa is so intolerable, Qt sucks, WxWidgets is a PITA and nothing else is suitable, it seems to me the best choice would be Xlib. Just go right to the bottom and build the who UI design from the most portable windowing API there is. It would be a whole lot of work, but the result would be a sense of accomplishment – and probably major burn-out with a desire to embark on a different line of work.
 
Or, in short: The Cocoa way of managing objects is conceptually bu****it and not suited for any kind of application...

... except for making money developing mobile applications. None of the ivory tower, theoretically more "beautiful", development scheme's come anywhere close to producing the same magnitude of total mobile market revenue. I wonder why?
 
If Cocoa is so intolerable, Qt sucks, WxWidgets is a PITA and nothing else is suitable, it seems to me the best choice would be Xlib. Just go right to the bottom and build the who UI design from the most portable windowing API there is. It would be a whole lot of work, but the result would be a sense of accomplishment – and probably major burn-out with a desire to embark on a different line of work.

Either that or he could design a robot arm that would key-in the Objective-C and design the GUI for him via a custom language the OP architects, that way he wouldn't have to code in such an "intolerable" environment.
 
If Cocoa is so intolerable, Qt sucks, WxWidgets is a PITA and nothing else is suitable, it seems to me the best choice would be Xlib. Just go right to the bottom and build the who UI design from the most portable windowing API there is. It would be a whole lot of work, but the result would be a sense of accomplishment – and probably major burn-out with a desire to embark on a different line of work.

XCB is a better choice than Xlib in my opinion as it has several advantages over Xlib.

http://en.wikipedia.org/wiki/XCB
 
Reminds me of

standards.png


Good luck.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.