handmade.network » Wiki » GUI Program Skeleton

Windows

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <windows.h>

LRESULT CALLBACK WindowProcedure(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
    if (message == WM_DESTROY) {
        // If we receive the destroy message, then quit the program.
        PostQuitMessage(0);
        return 0;
    } else {
        // We don't handle this message. Use the default handler.
        return DefWindowProc(window, message, wParam, lParam);
    }
}

int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, 
        LPSTR commandLine, int commandShow) {
    // Create the window class.
    WNDCLASS windowClass = {};
    windowClass.style = CS_HREDRAW | CS_VREDRAW;
    windowClass.lpfnWndProc = WindowProcedure;
    windowClass.hInstance = instance;
    windowClass.lpszClassName = "MyWindowClass";
    windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    windowClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    RegisterClass(&windowClass);

    // Create and show the actual window.
    HWND window = CreateWindow("MyWindowClass", "Hello, GUI!", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, instance, NULL);
    ShowWindow(window, commandShow);
    UpdateWindow(window);

    // Process window messages.
    MSG message;
    while (GetMessage(&message, NULL, 0, 0) > 0) {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }

    return message.wParam;
}

Link with user32.lib.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <windows.h>
static bool Running;

...
while(Running) {
    while ( PeekMessage( &message, 0, 0, 0, PM_REMOVE ) ) {
        if ( message.message == WM_QUIT) {
            Running = false;
        }
        TranslateMessage(&message);
        DispatchMessage(&message); 
    }
    // Do your stuff here
}
...

With DPI Scaling

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <windows.h>
#include <ShellScalingAPI.h>

LRESULT CALLBACK WindowProcedure(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
    if (message == WM_DESTROY) {
        // If we receive the destroy message, then quit the program.
        PostQuitMessage(0);
        return 0;
    } else if (message == WM_DPICHANGED) {
        RECT *newBounds = (RECT *) lParam;
        MoveWindow(window, newBounds->left, newBounds->top, 
            newBounds->right - newBounds->left, newBounds->bottom - newBounds->top,
            TRUE);
    } else {
        // We don't handle this message. Use the default handler.
        return DefWindowProc(window, message, wParam, lParam);
    }
}

int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, 
        LPSTR commandLine, int commandShow) {
    SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);

    // Create the window class.
    WNDCLASS windowClass = {};
    windowClass.style = CS_HREDRAW | CS_VREDRAW;
    windowClass.lpfnWndProc = WindowProcedure;
    windowClass.hInstance = instance;
    windowClass.lpszClassName = "MyWindowClass";
    windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    windowClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    RegisterClass(&windowClass);

    // Create and show the actual window.
    HWND window = CreateWindow("MyWindowClass", "Hello, GUI!", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, instance, NULL);
    ShowWindow(window, commandShow);
    UpdateWindow(window);

    // Process window messages.
    MSG message;
    while (GetMessage(&message, NULL, 0, 0) > 0) {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }

    return message.wParam;
}

Additionally link with Shcore.lib.

Linux / X11

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Compile with gcc this_file.c -lX11
#include <X11/Xlib.h>

int main(void){

    // Create connection to the X Server.
    Display* dpy = XOpenDisplay(NULL);

    // Create window.
    Window   win = XCreateSimpleWindow(
        dpy,
        DefaultRootWindow(dpy), // Parent
        0, 0,                   // X/Y, often overridden by window manager
        400, 200,               // Width/Height
        0, 0,                   // Border
        WhitePixel(dpy, 0)      // Background
    );

    char msg[] = "Hello, GUI!";

    // Set window title.
    XStoreName(dpy, win, msg);

    // Choose which events we want.
    XSelectInput(dpy, win,
                 SubstructureNotifyMask // Window size changes (ConfigureNotify)
                 | ExposureMask         // Window needs to be repainted (Expose)
                 | PointerMotionMask    // Mouse moves (MotionNotify)
                 | ButtonPressMask
                 | ButtonReleaseMask
                 | KeyPressMask);

    // Make window visible and give it focus.
    XMapRaised(dpy, win);

    // For window manager close button event.
    Atom win_closed_id = XInternAtom(dpy, "WM_DELETE_WINDOW", 0);
    XSetWMProtocols(dpy, win, &win_closed_id, 1);

    for (;;) {
        XEvent ev;
        XNextEvent(dpy, &ev);

        // WM close button pushed, exit.
        if (ev.type == ClientMessage && ev.xclient.data.l[0] == win_closed_id) {
            return 0;
        }

        // Expose event tells us to repaint (some of) the window.
        if (ev.type == Expose) {
            XDrawString(dpy, win, DefaultGC(dpy, 0), 30, 30, msg, sizeof(msg)-1);
        }
    }
}

Gtk

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <gtk/gtk.h>

static void ActivateApplication(GtkApplication* application, void *data) {
    GtkWidget *window = gtk_application_window_new(application);
    gtk_window_set_title(GTK_WINDOW(window), "Hello, GUI!");
    gtk_window_set_default_size(GTK_WINDOW(window), 400, 200);
    gtk_widget_show_all(window);
}

int main(int argc, char **argv) {
    GtkApplication *application = gtk_application_new("my.app.id", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(application, "activate", G_CALLBACK(ActivateApplication), NULL);
    return g_application_run(G_APPLICATION(application), argc, argv);
}

Compile with:

gcc `pkg-config --cflags gtk+-3.0` -o gtk-test gtk-test.c `pkg-config --libs gtk+-3.0