App Management

Registering the Main Window

See the C++ MFC example on GitHub.

The main window of your app is automatically registered and announced as an io.Connect app when you register it as an io.Connect Window using glue_register_main_window() or glue_register_window():

// Here `my_app` is a previously defined MFC object from which you can extract the window handle.
const HWND handle = my_app->m_pMainWnd->m_hWnd;

// Callback for handling io.Connect app events.
void app_event_callback (glue_app_command command, const void* callback, const glue_payload* payload, COOKIE cookie) {
    std::cout << "App event for main window: " << command << std::endl;
}

// Callback for handling io.Connect Window events.
void window_event_callback (glue_window_command command, const char* context_name, COOKIE cookie) {
    std::cout << "Window event for main window: " << command << std::endl;
}

// The main window of your app will be registered as an io.Connect Window and as an io.Connect app.
glue_register_main_window(handle, &app_event_calback, &window_event_callback, "Main Window");

The app_event_callback passed as a second argument is an app_callback_function which allows you to handle app events for the main window.

For more details on registering app windows as io.Connect Windows, see the Window Management section.

App Factories

Registering an app factory allows you to register the child windows of your app as io.Connect apps, announce their instances in the io.Connect environment and handle app events for them. To register an app factory, use glue_app_register_factory(). It accepts as arguments the name of the app to be created, an app event handler as an app_callback_function, an optional JSON representation of the app definition, and an optional callback cookie. The app event handler will be invoked with the create glue_app_command when an instance of the child app is created.

To announce the created app instance in the io.Connect environment, use glue_app_announce_instance() within the app_callback_function. The glue_app_announce_instance() method accepts as arguments a correlational callback (the same one that is passed as an argument to the app_callback_function), the window handle, an app event handler as an app_callback_function, a window event handler as a glue_window_callback_function, and an optional cookie.

The following example demonstrates how to register an app factory and announce the child instances in the io.Connect environment:

// Callback for handling app events for each announced child instance. Registered when announcing the child.
void child_app_event_callback(const glue_app_command command, const void* callback, const glue_payload* payload, COOKIE cookie) {
    std::cout << "App event for child window: " << command << std::endl;
}

// Callback for handling window events for each announced child instance. Registered when announcing the child.
void child_window_event_callback (glue_window_command command, const char* context_name, COOKIE cookie) {
    std::cout << "Window event for child window: " << command << std::endl;
}

// Callback that will be invoked with the `create` command when a child instance is created by the app factory.
void app_factory_callback (glue_app_command command, const void* callback, const ::glue_payload* payload, COOKIE cookie) {
    switch (command) {
        case glue_app_command::create: {
            // Here `my_child_window` is a previously defined MFC object from which you can extract the window handle.
            const HWND handle = my_child_window->m_hWnd;

            // Announce the child instance passing the same correlational callback received from the `app_factory_callback`
            // the child window handle, and the app and window event handlers.
            glue_app_announce_instance(callback, handle, &child_app_event_callback, &child_window_event_callback);

            // Alternatively, factories can deny creating instances by pushing failure:
            // glue_push_failure(callback, "Can't create a child instance.")
            break;
        }
        default:
            break;
    }
}

// Register the app factory.
const void* my_app_factory = glue_app_register_factory("Child App", &app_factory_callback);

Registering an app factory returns a reference to the created app factory. Use glue_destroy_resource() to destroy it:

glue_destroy_resource(my_app_factory);

App State

You can save a state for the main and child windows of your app, as well as restore an initial or previously saved state. The initial state of an app can be passed through app definition.

Main Window

To save and restore a state for your main window, use the app_callback_function passed to glue_register_main_window() when registering your main window. When the app_callback_function is invoked with the save glue_app_command, push a state to be saved, and when it's invoked with the init command, restore the saved state using the passed payload:

// Here `my_app` is a previously defined MFC object from which you can extract the window handle.
const HWND handle = my_app->m_pMainWnd->m_hWnd;

// Callback for handling io.Connect app events.
void app_event_callback (glue_app_command command, const void* callback, const glue_payload* payload, COOKIE cookie) {
    // Check the command with which the app event handler was invoked.
    switch (command) {
        case glue_app_command::save:
            // Use the io.Connect methods prefixed with `glue_push_` to push a save state.
            glue_push_json_payload(callback, "{io: {a: 42, b: \"forty-two\"}}");
            break;
        case glue_app_command::init: {
            // Use the io.Connect methods prefixed with `glue_read_` to extract the initial or restored state.
            const auto restore_state = glue_read_json(payload->reader, nullptr);
            std::cout << "Restored state: " << restore_state << std::endl;
            break;
        }
        default:
            break;
    }
}

// Callback for handling io.Connect Window events.
void window_event_callback (glue_window_command command, const char* context_name, COOKIE cookie) {
    std::cout << "Window event for main window: " << command << std::endl;
}

glue_register_main_window(handle, &app_event_calback, &window_event_callback, "Main Window");

If you have registered your main window via glue_register_window(), which doesn't accept a callback for handling app events, you can use glue_set_save_state() to save you app state. It accepts an invocation_callback_function as an argument which you can use to push a state to be saved. The state can then be restored by extracting it from the io.Connect Desktop starting context with glue_get_starting_context_reader(). Before attempting to extract a saved state from the starting context, you must check whether your app has been started by io.Connect Desktop using glue_is_launched_by_gd():

void save_state_callback (const char* endpoint_name, COOKIE cookie, const ::glue_payload* payload, const void* endpoint) {
    glue_push_json_payload(endpoint, "{my_saved_state: {a: 42, b: \"io\"}}");
}

// Set a callback that will be invoked whenever user-specific data
// for this instance is to be persisted by the platform.
glue_set_save_state(&save_state_callback);

// Check whether your app has been started by the platform.
if (glue_is_launched_by_gd()) {
    // Get the starting context reader and extract the initial or restored state.
    const auto starting_context_reader = glue_get_starting_context_reader();
    const auto val = glue_read_glue_value(starting_context_reader, "state");
}

// Here `my_app` is a previously defined MFC object from which you can extract the window handle.
const HWND handle = my_app->m_pMainWnd->m_hWnd;

// Callback for handling io.Connect Window events.
void window_event_callback (glue_window_command command, const char* context_name, COOKIE cookie) {
    std::cout << "Window event for main window: " << command << std::endl;
}

// Register the main window.
glue_register_window(handle, &window_event_callback, "Main Window", nullptr, true);

Child Windows

The save and restore state of child windows is handled in the app_callback_function passed to glue_app_announce_instance() when announcing a child app instance created by an app factory. When the app_callback_function is invoked with the save glue_app_command, push a state to be saved, and when it's invoked with the init command, restore the saved state using the passed payload:

// Callback for handling app events for each announced child instance.
// Passed as an argument to `glue_app_announce_instance()`.
void child_app_event_callback(const glue_app_command command, const void* callback, const glue_payload* payload, COOKIE cookie) {
    // Check the command with which the app event handler was invoked.
    switch (command) {
        case glue_app_command::save:
            // Use the io.Connect methods prefixed with `glue_push_` to push a save state.
            glue_push_json_payload(callback, "{io: {a: 42, b: \"forty-two\"}}");
            break;
        case glue_app_command::init: {
            // Use the io.Connect methods prefixed with `glue_read_` to extract the initial or restored state.
            const auto restore_state = glue_read_json(payload->reader, nullptr);
            std::cout << "Restored state: " << restore_state << std::endl;
            break;
        }
        default:
            break;
    }
}

For a full example of registering an app factory for child windows, see the App Factories section.

Events

To handle io.Connect app events (creating a child instance, saving and restoring state, shutdown), use the app_callback_function passed to glue_register_main_window(), glue_app_register_factory() or glue_app_announce_instance(). It will be invoked with an app command as a glue_app_command indicating the io.Connect app event, a correlational callback that can be passed to other io.Connect methods (e.g., glue_app_announce_instance() when announcing a newly created app instance, or to glue_push_payload() when saving the app state), a glue_payload value holding the initial or restored state, and an optional callback cookie.

The create glue_app_command is used only when creating child app instances and therefore this event can be handled only when registering an app factory:

// Callback that will be invoked with the `create` command when a child instance is created by the app factory.
void app_factory_callback (glue_app_command command, const void* callback, const ::glue_payload* payload, COOKIE cookie) {
    switch (command) {
        case glue_app_command::create: {
            // Create and announce a child app instance.
            // Handle the app events related to that instance.
            break;
        }
        default:
            break;
    }
}

// Register the app factory.
const void* my_app_factory = glue_app_register_factory("Child App", &app_factory_callback);

All other app events can be handled in the app_callback_function when registering a main window or announcing a child instance:

// Callback for handling io.Connect app events.
void app_event_callback (glue_app_command command, const void* callback, const glue_payload* payload, COOKIE cookie) {
    // Check the command with which the app event handler was invoked.
    switch (command) {
        case glue_app_command::save:
            // Use the io.Connect methods prefixed with `glue_push_` to push a save state.
            glue_push_json_payload(callback, "{io: {a: 42, b: \"forty-two\"}}");
            break;
        case glue_app_command::init: {
            // Use the io.Connect methods prefixed with `glue_read_` to extract the initial or restored state.
            const auto restore_state = glue_read_json(payload->reader, nullptr);
            std::cout << "Restored state: " << restore_state << std::endl;
            break;
        }
        case glue_app_command::shutdown:
            std::cout << "The app will shutdown." << std::endl;
            // Close the window and free resources.
            break;
        default:
            break;
    }
}