Thursday, November 10, 2011

Create Button Using Pure XCB Code on Mac OS X

First create two images sing GIMP or any other image editor of your favorite, but it must be saved as C code.
The images are only 1 x 36 pixels each (yes, that's correct, only 1 pixel width). It will be repeated automatically.

Here's my example on the button, modify it according to your needs:


I write the above code my self, but pasted into PasteBin just to get the syntax highlighting style, it's easier to read the code this way.

The following is the output of the program:

XCB Button Test


NOTE:
Mac OS X Snow Leopard is using version of libxcb which is located at different location (as compared to Linux), so you must add -I/usr/X11/include -L/usr/X11/lib -lxcb -lxcb-atom to compile the code.

The complete compilation command should be:

gcc -I/usr/X11/include -L/usr/X11/lib -lxcb -lxcb-atom -o MacButton-Test MacButton.c

Further more, libxcb itself is a work on progress, if using the newer version (X11R7.6) you don't even need to include xcb_atom.h, and there's no WM_NAME, it's defined as XCB_ATOM_WM_NAME and XCB_ATOM_STRING. These items are actually just a typedef of uint32_t (integer 32 bit).

You can try it now!

Friday, September 23, 2011

CFUserNotification With 3 Buttons

Here's a sample to display a MessageBox with more than 1 button, and how to get the user response.


/***
 * test4.c
 * CFUserNotification Dialog with 3 buttons
 * 
 * Compile with the following commands:
 *   gcc -framework CoreFoundation -o Test4 test4.c
 *   mkdir -pv Test4.app/Contents/MacOS && mv -v Test4 Test4.app/Contents/MacOS
 *
 */


#include <CoreFoundation/CoreFoundation.h>

int main(int argc, const char** argv)
{
CFOptionFlags cfRes;
CFStringRef strTest = CFSTR("Test Button");
CFUserNotificationDisplayAlert(5, kCFUserNotificationNoteAlertLevel
NULL, NULL, NULL
CFSTR("Testing"), 
CFSTR("Click on any button..."), 
CFSTR("OK"), 
CFSTR("Cancel"), 
CFSTR("Test Button"), 
&cfRes);
switch (cfRes)
{
case kCFUserNotificationDefaultResponse:
strTest = CFSTR("Default response");
break;
case kCFUserNotificationAlternateResponse:
strTest = CFSTR("Alternate response");
break;
case kCFUserNotificationOtherResponse:
strTest = CFSTR("Other response");
break;
default:
strTest = CFSTR("Cancel response");
break;
}
CFUserNotificationDisplayNotice(0, kCFUserNotificationPlainAlertLevel
NULL, NULL, NULL, CFSTR("Result"),
                                        strTest, CFSTR("OK"));
return 0;
}

I intentionally used 5 seconds timeout for parameter 1 (argument 0) to call CFUserNotificationDisplayAlert(), so that we can see more differences than previous examples. If we pass 0 for this parameter, then the Dialog Box will never be dismissed automatically, unless the user click one of the buttons.

The 3 NULL parameters above are for the address of iconFileURL, soundFileURL, and localizedStringURL. We don't use iconFileURL because we use the icon from system through the second parameter kCFUserNotificationNoteAlertLevel, which display a balloon with 'I'. The other ones are 'Stop', 'Caution', and 'Plain' --- AlertLevel. Try to change it yourself and recompile you code.

Check out Mac OS X official documentations for this.


Thursday, September 22, 2011

Simplified Version of CoreFoundation MessageBox

My previous example of using CoreFoundation demonstrating a rather complicated code for just showing a MessageBox, but actually we can do it very straightforward by just making a single call like the following example:

/*
test3.c
Mac OS X Message Box using only CoreFoundation framework.
This code doesn't use Objective-C or Cocoa, just plain C.
Build using commands:
gcc -framework CoreFoundation -o Test3 test3.c
mkdir -pv Test2.app/Contents/MacOS && mv -v Test3 Test3.app/Contents/MacOS
Run the resulting by double-clicking Test3 from the Finder or by issuing
command:
open Test3.app
from the Terminal.
*/

#include <CoreFoundation/CoreFoundation.h>

int main(int argc, const char** argv)
{
CFOptionFlags nRet;
SInt32 nRes = CFUserNotificationDisplayAlert(0, kCFUserNotificationPlainAlertLevel,
NULL, NULL, NULL,
CFSTR("Testing"),
CFSTR("This is a test for direct dialog."),
CFSTR("OK"), NULL, NULL, &nRet);
return 0;
}

Compile the code using the above command lines, you will get the same result as before.

Now, if you don't even care about any user response hold by nRet variable (just like most Information MessageBox), you can simply replace the content of function main() above with these lines:

return CFUserNotificationDisplayNotice(0, kCFUserNotificationPlainAlertLevel,
NULL, NULL, NULL,         CFSTR("Testing"),
                        CFSTR("This is a test for direct dialog"),
CFSTR("OK"));

And of course, if you want, you can make a simple function just to be able to make a call like the following:

MessageBox(CFSTR("Testing"), CFSTR("This is a test"), CFSTR("OK"));

But I don't think that's necessary :-)


Wednesday, September 21, 2011

Message Box Using CoreFoundation Framework

My previous example was created using Cocoa framework, but actually the same MessageBox can be displayed just by linking against CoreFoundation framework (not using Cocoa and/or Objective-C API).

This approach is useful when you're developing a minimalist GUI applications (maybe some Command-Line application, or a core utilities that doesn't require heavy load of GUI), but still want to use MessageBox for the purpose of information like error messages to the users.

Most user would prefer a simple but clear MessageBox message, rather than a plain text from the command line, which sometimes rather difficult to read and understand.


/* 
 test2.c 
 Mac OS X Message Box using only CoreFoundation framework.
 This code doesn't use Objective-C or Cocoa, just plain C.
 Build using commands:

gcc -framework CoreFoundation -o Test2 test2.c
mkdir -pv Test2.app/Contents/MacOS && mv -v Test2 Test2.app/Contents/MacOS

 Run the resulting by double-clicking Test2 from the Finder or by issuing
 command:
open Test2.app
 from the Terminal.

 */

#include <CoreFoundation/CoreFoundation.h>

int main(int argc, const char** argv)
{
SInt32 nRes = 0;
CFUserNotificationRef pDlg = NULL;
const void* keys[] = { kCFUserNotificationAlertHeaderKey,
kCFUserNotificationAlertMessageKey };
const void* vals[] = {
CFSTR("Test Foundation Message Box"),
CFSTR("Hello, World!")
};
CFDictionaryRef dict = CFDictionaryCreate(0, keys, vals,
                sizeof(keys)/sizeof(*keys), 
                &kCFTypeDictionaryKeyCallBacks
                &kCFTypeDictionaryValueCallBacks);
pDlg = CFUserNotificationCreate(kCFAllocatorDefault0
                     kCFUserNotificationPlainAlertLevel
                     &nRes, dict);
return 0;
}


The resulting application should look like the following:

Test2.app running.

Now you've learned how to display MessageBox without using Cocoa on Mac OS X.


Simple GUI Hello World Using Cocoa

First of all, you must install Xcode --- if you haven't do that already, so that you'll be able to compile the following codes.

After you have everything about the tools ready, then you can create a new plain text file using any text editor (preferably the one with Syntax Highlighting capability for C/C++ language and their variants, including Objective-C/C++). In this case I'm using Xcode editor, but for now we're not using any other Xcode's features other than just editing text with fancy highlighting and of course the GCC compiler for Mac OS X, which already attached to the system after the installation of Xcode.

Open a terminal (that's from /Applications/Utilities/Terminal.app), then change directory into your preferred place for this test --- any place will do, maybe some new folder on your Desktop. Type ' cd ~/Desktop ', then 'touch test1.m' to create this new file.

Actually you can use Xcode's menu File->New File... for this, but I don't want you to be confused by the next options following the menu.

Either way, open that new test1.m by just double-clicking the icon from the Finder, then type the following lines of codes.  

/*
 test1.m
 Compile using gcc -framework Cocoa -o Test1 test1.m
 Then execute these lines of commands:
   mkdir -pv Test1.app/Contents/MacOS
   mv -v Test1 Test1.app/Contents/MacOS
 You can then double-click the icon of Test1.app from Finder window, or just
 from Terminal using ' open Test1.app '
 */

#include <Cocoa/Cocoa.h>

int main(int argc, const char** argv)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
[NSApplication sharedApplication];
NSRunAlertPanel(@"Testing Message Box",
@"Hello, World!",
@"OK", NULL, NULL);
[pool release];
return 0;
}

You can also copy-paste the text if you like, but I recommend you to type them yourself, because that way you will be forced to memorize each lines, which is a good practice.

You can then execute the above command lines (just 3 lines including the compilations and packaging your new application) --- that's the one I commented out on the top of this sample text codes.

If there's no mistyping or any other mistakes, the application should run nicely, showing a MessageBox similar to the following picture:

Test1.app running.

Congratulation, and welcome to the Mac OS X's GUI programming!

Examine your first application codes, and try to change the strings for parameters sent to NSRunAlertPanel().