aboutsummaryrefslogtreecommitdiffstats
path: root/app_manager.cpp
blob: 2926921f49083a9953fbd32174815e4521277408 (plain)
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include "app_manager.hpp"
#include "api.hpp"
#include "apps/main_clock.hpp"
#include "apps/home_menu.hpp"
#include "apps/settings/main.hpp"

#define NUMBER_OF_APPS 3
// From pico-watch.c:
extern Api app_api;

std::vector<BaseApp*> open_apps;
int APPS_DESTROY_ON_EXIT[NUMBER_OF_APPS] = {0, 1, 1};
int APPS_IS_INIT[NUMBER_OF_APPS] = {0}; // Only run in background if init

// Called by app_init to create the app object.
int app_create(int app_id) {
    switch (app_id) {
        case 0: open_apps.push_back(new app_home_menu(&app_api)); break;
        default: __breakpoint();
    }
}

// Init a new app, that is not running.
int app_init(int app_id) {
    app_api.display_fill(0,1); // Clear OLED
    app_api.performance_render_interval_set(500); // Reset interval

    if (app_id > NUMBER_OF_APPS-1 or app_id < 0) {
        printf("Tried to init app %d", app_id);
        return app_init(0);
    }

    if (!APPS_IS_INIT[app_id]) {
        app_create(app_id);
        /* int status = (*APPS_FUNC_INIT[app_id])(&app_api);

        switch (status) {
            case Api::app_init_return_status::MALLOC_FAILED:
                printf("App init failed (alloc), ");
                for (int i=0; i<10; i++) {
                    if ((*APPS_FUNC_INIT[app_id])(&app_api) != Api::app_init_return_status::MALLOC_FAILED) {
                        printf("worked after %d tries\n", i);
                        APPS_IS_INIT[app_id] = 1;
                        return app_id;
                    }
                }
                // Instead, the current app could continue running: return current_app
                printf("gave up, launching app 0\n");
                return app_init(0); // Note: this has to work (and should)
            
            default: // OK and unhandled status codes
                printf("App init, status: %d\n", status);
                break;
        } */
        APPS_IS_INIT[app_id] = 1;
    }
    return app_id;
}

// Allow the running app, referenced by app_id, to invoke its render routine.
int app_render(int app_id) {
    for (auto app : open_apps) {
        if (app_id == app->app_id)
            return app->render(&app_api);
    }
}

// Delta is in ms, from time_since_button_press()
int app_btnpressed(int app_id, uint gpio, unsigned long delta) {
    for (auto app : open_apps) {
        if (app_id == app->app_id)
            return app->btnpressed(&app_api, gpio, delta);
    }
}

// Quit the app referenced by the app_id.
int app_destroy(int app_id) {
    BaseApp* to_destroy;

    // FIXME: Does not work if the app is not open. An invalid item tries to get freed.
    int to_delete_id = 0;
    for (auto app : open_apps) {
        if (app_id == app->app_id) {
            to_destroy = app;
            break;
        }
        to_delete_id++;
    }
    delete to_destroy;
    open_apps.erase(open_apps.begin() + to_delete_id);

    APPS_IS_INIT[app_id] = 0;
    return 0;
}

// Requests the current app to be replaced by an other one. The replacement will be done at the right moment.
void app_switch_request(int to_appid) {
    if (!g_s.app_switch_requested)
        g_s.app_switch_to_app = to_appid;
    g_s.app_switch_requested = true;
    app_api.performance_render_interval_set(0); // This will be reset on new app init
}

void app_switch(int old_appid, int new_appid) {
    g_s.app_ready = false;
    if (APPS_DESTROY_ON_EXIT[old_appid])
        app_destroy(old_appid);
    g_s.current_app = app_init(new_appid);
    g_s.app_ready = true;
}