Here we will create a window with 2 buttons. One button will write to stdout (if program is started from the terminal), and the second button will display a "messagebox". Compared to creating a window in Windows, this seems a bit more involved, but you have more options.
libgtk-3-0 is required for the sample to link correctly.
Code first:
%include "gtkenums.inc" %include "equates.inc" global main ;GTK extern gtk_init, gtk_window_new, gtk_button_new_with_label extern gtk_container_add, gtk_widget_show, gtk_main, gtk_main_quit extern gtk_container_set_border_width, gtk_widget_destroy extern gtk_window_set_position, gtk_window_set_default_size extern gtk_window_set_title, gtk_fixed_new, gtk_widget_set_size_request extern gtk_fixed_put, gtk_widget_show_all, gtk_message_dialog_new extern gtk_dialog_run, gtk_widget_destroy ;GLib extern g_signal_connect_data, g_print SECTION .data szPushMe db "Push Me!", 0 szItWorks db "Your first GTK window, it works!!!!!", 10 ,0 szSad db "Really? I am sad that you are leaving me!", 10, 0 szPoof db "Go POOF!", 0 szTitle db "GTK using NASM!", 0 szevent_delete db "delete-event", 0 szevent_destroy db "destroy", 0 szevent_clicked db "clicked", 0 SECTION .bss lpBuffer resb 12 hMain resd 1 hButton resd 1 hExit resd 1 hFrame resd 1 SECTION .text ;~ int main( int argc, ;~ char *argv[] ) main: push ebp mov ebp, esp lea eax, [ebp + 12] lea ecx, [ebp + 8] push eax push ecx call gtk_init add esp, 4 * 2 push GTK_WINDOW_TOPLEVEL call gtk_window_new add esp, 4 * 1 mov [hMain], eax push 150 push 300 push eax call gtk_window_set_default_size add esp, 4 * 3 push GTK_WIN_POS_CENTER push dword [hMain] call gtk_window_set_position add esp, 4 * 2 push szTitle push dword [hMain] call gtk_window_set_title add esp, 4 * 2 call gtk_fixed_new mov [hFrame], eax push eax push dword [hMain] call gtk_container_add add esp, 4 * 2 ; Push me button push szPushMe call gtk_button_new_with_label add esp, 4 * 1 mov [hButton], eax push 35 push 80 push eax call gtk_widget_set_size_request add esp, 4 * 3 push 20 push 100 push dword [hButton] push dword [hFrame] call gtk_fixed_put add esp, 4 * 4 ; Exit button push szPoof call gtk_button_new_with_label add esp, 4 * 1 mov [hExit], eax push 35 push 80 push eax call gtk_widget_set_size_request add esp, 4 * 3 push 90 push 100 push dword [hExit] push dword [hFrame] call gtk_fixed_put add esp, 4 * 4 ; Signals push NULL push NULL push NULL push event_delete push szevent_delete push dword [hMain] call g_signal_connect_data add esp, 4 * 6 push NULL push NULL push NULL push event_destroy push szevent_destroy push dword [hMain] call g_signal_connect_data add esp, 4 * 6 push NULL push NULL push NULL push event_clicked push szevent_clicked push dword [hButton] call g_signal_connect_data add esp, 4 * 6 push NULL push NULL push NULL push event_delete push szevent_clicked push dword [hExit] call g_signal_connect_data add esp, 4 * 6 push dword [hMain] call gtk_widget_show_all add esp, 4 * 1 call gtk_main mov esp, ebp pop ebp ret ;~ gboolean event_delete( GtkWidget *widget, ;~ GdkEvent *event, ;~ gpointer data ) event_delete: push dword [hMain] call show_dialog cmp eax, GTK_RESPONSE_NO jne .bye mov eax, TRUE ret .bye: call gtk_main_quit mov eax, FALSE ret ;~ void event_destroy( GtkWidget *widget, ;~ gpointer data ) event_destroy: call gtk_main_quit ret ;~ void event_clicked( GtkWidget *widget, ;~ gpointer data ) event_clicked: push szItWorks call g_print add esp, 4 * 1 ret ;~ void show_dialog(gpointer window) show_dialog: push ebp mov ebp, esp push esi push szSad push GTK_BUTTONS_YES_NO push GTK_MESSAGE_QUESTION push GTK_DIALOG_DESTROY_WITH_PARENT push dword [ebp + 8] call gtk_message_dialog_new add esp, 4 * 5 xchg eax, esi push esi call gtk_dialog_run add esp, 4 * 1 push eax push esi call gtk_widget_destroy add esp, 4 * 1 pop eax pop esi mov esp, ebp pop ebp ret 4 * 1
Info on GTK+ can be found at the GNOME Dev Center
main: push ebp mov ebp, esp lea eax, [ebp + 12] lea ecx, [ebp + 8] push eax push ecx call gtk_init add esp, 4 * 2
The first thing we must do is initialize the GTK+ Toolkit, and let it parse the command line. We do this with gtk_init. ALL GTK+ applications support some command line options as to how GTK+ should run for the app. gtk_init will look for these options, and remove them from argv, and pass any remaining options on to your program. Some options (X11 and Windows GDK have a few others) you can pass to GTK are:
- --gtk-module module
- --g-fatal-warnings
- --gtk-debug options
- --gtk-no-debug options
The following are not GTK+ per say, but GDK:
- --class class
- --name name
- --gdk-debug options
- --gdk-no-debug options
Being GTK+ is written in C, most code (that I have found so far) uses the cdecl calling convention, which means we must adjust the stack pointer (ESP) after ever call.
gtk_init has no return value, so if GTK+ was not able to initialize the windowing system, your application just terminates. If you want to fall back to a text interface if errors are encountered, use gtk_init_check instead. Both functions are the same, except the latter returns FALSE on error.
Now that everything is initialized properly and there were no errors, we can set up our window and widgets.
push GTK_WINDOW_TOPLEVEL call gtk_window_new add esp, 4 * 1 mov [hMain], eax push 150 push 300 push eax call gtk_window_set_default_size add esp, 4 * 3 push GTK_WIN_POS_CENTER push dword [hMain] call gtk_window_set_position add esp, 4 * 2 push szTitle push dword [hMain] call gtk_window_set_title add esp, 4 * 2
Our "window" is a GtkWindow Object which can contain other widgets. What kind of Widgets? Take a look at the Widget Gallery. First thing we need to do is create a new GtkWindow with gtk_window_new This returns a pointer to a new GtkWindow, we pass this anywhere it expects GtkWindow *window Next we set the Height and Width of the window with gtk_window_set_default_size. We set the initial position of the window with gtk_window_set_position The values that can be used here are:
typedef enum { GTK_WIN_POS_NONE, GTK_WIN_POS_CENTER, GTK_WIN_POS_MOUSE, GTK_WIN_POS_CENTER_ALWAYS, GTK_WIN_POS_CENTER_ON_PARENT } GtkWindowPosition;
It is usually a BAD idea to use GTK_WIN_POS_CENTER_ALWAYS as it won't work well with all window managers or windowing systems. Use at your own risk.
If you want to set the text to be displayed in the title bar, you set it with gtk_window_set_title. If for some reason you want the caption to be different for certain cases (maybe display one thing from a script file, another thing if run from another program etc...) You would pass NULL for *title, and pass the option --name with the text you want for the caption. If you pass NULL and don't pass the --name option, GTK+ uses the exe name as the caption.
Now we need a container to place our buttons on. We will use a GtkFixed for simplicity. This container allows us to place other widgets at fixed positions with fixed sizes. We would not normally use this container since it can create display bugs since the position and sizes of widgets place on it are fixed.
call gtk_fixed_new mov [hFrame], eax push eax push dword [hMain] call gtk_container_add add esp, 4 * 2
Once we create our fixed widget with gtk_fixed_new we must add it to a container. This container is our GTKWindow and we add it with gtk_container_add
Now that we have a widget to add other widgets to, we can create our GTKButton Widgets.
push szPushMe call gtk_button_new_with_label add esp, 4 * 1 mov [hButton], eax push 35 push 80 push eax call gtk_widget_set_size_request add esp, 4 * 3 push 20 push 100 push dword [hButton] push dword [hFrame] call gtk_fixed_put add esp, 4 * 4
This code is repeated to create our second button.
Want text on your button? We use gtk_button_new_with_label with a pointer to the text to use.
Next we set the minimum height and width with gtk_widget_set_size_request After we create the button and set the sizes, we need to add it to the fixed widget, that is done with gtk_fixed_put.
Now that we have our window and buttons set up, they do nothing except sit there. We need to associate signals to them. So to have a button perform something when clicked, we set up a signal handler to catch these signals and call the appropriate function.
So, for one of our buttons we set up a handler for the "clicked" signal:
push NULL push NULL push NULL push event_clicked push szevent_clicked push dword [hButton] call g_signal_connect_data add esp, 4 * 6
A little note on g_signal_connect_data. The functions I wanted to use were, g_signal_connect and g_signal_connect_swapped but alas, there weren't exports for them. Why? They are macros that resolve to g_signal_connect_data
So, now anytime you click on that button, the following code gets called:
event_clicked: push szItWorks call g_print add esp, 4 * 1 ret
How do we show a message box anytime someone tries to close our app with the close menu or x? We setup an event handler for the delete event
push NULL push NULL push NULL push event_delete push szevent_delete push dword [hMain] call g_signal_connect_data add esp, 4 * 6
And the callback:
event_delete: push dword [hMain] call show_dialog cmp eax, GTK_RESPONSE_NO jne .bye mov eax, TRUE ret .bye: call gtk_main_quit mov eax, FALSE ret
To prevent the app from closing, we return TRUE.
show_dialog: push ebp mov ebp, esp push esi push szSad push GTK_BUTTONS_YES_NO push GTK_MESSAGE_QUESTION push GTK_DIALOG_DESTROY_WITH_PARENT push dword [ebp + 8] call gtk_message_dialog_new add esp, 4 * 5 xchg eax, esi push szReally push esi call gtk_window_set_title add esp, 4 * 2 push esi call gtk_dialog_run add esp, 4 * 1 push eax push esi call gtk_widget_destroy add esp, 4 * 1

gtk-firstwin source