Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ third_party/*/patches/.applied_*
__pycache__/
libs/libfreetype/include/
utils/.cached/*
.vscode
17 changes: 16 additions & 1 deletion build/userland/prepare_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import os
import json
import subprocess
from distutils.dir_util import copy_tree

fs_app_name = sys.argv[1]
app_name = sys.argv[2]
Expand All @@ -31,7 +32,16 @@ def write_config(config, outpath):

config['name'] = app_name
config['exec_rel_path'] = fs_app_name
config['icon_path'] = "/res/icons/apps/" + fs_app_name + ".icon"

# Resolve app icon
if 'assets' in config:
if 'AppIcon' in os.listdir(outpath + '/' + config['assets']):
config['icon_path'] = outpath[4:] + '/' + config['assets'] + '/AppIcon'
else:
raise Exception("An \"AppIcon\" folder is required within the assets folder \"" + config['assets'] + "\"")
else:
config['icon_path'] = '/res/icons/apps/missing.icon'

config['bundle_id'] = "com.opuntia.{0}".format(fs_app_name)

print_json(config_file, config)
Expand All @@ -45,6 +55,11 @@ def write_config(config, outpath):
for fname in os.listdir(src_dir):
if fname == "info.json":
config = read_config(src_dir + "/info.json")

if 'resources' in config:
for resource_dir in config['resources']:
copy_tree(src_dir + "/" + resource_dir, outpath + '/' + resource_dir)

break

write_config(config, outpath)
29 changes: 29 additions & 0 deletions libs/libfoundation/include/libfoundation/AssetManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2020-2022 The opuntiaOS Project Authors.
* + Contributed by Mainasara Tsowa <tsowamainasara@gmail.com>
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/

// Begining of possible AssetManager to locate/read/write to files and folders in the app directory
Comment thread
nimelehin marked this conversation as resolved.
namespace LFoundation {

class AssetManager {
public:
AssetManager(const std::string& name)
:m_app_root(std::string() + "/Applications/" + name + ".app/Content")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better if we could look for Content folder getting the binary path. I would to implement this similar to Apple's Bundle. They have the similar to what you have implemented. bundle.main could be initialised with a binary path (see ProcessInfo::parse_info_file) during the startup of UI Apps (again as a ProcessInfo).

Both UI and Foundation libs I try to make as close as possible to Apple's versions (as I have plans on launching recompiled iOS apps one day). So it would be great that all APIs have the similar behaviour to Apple's.

{
}

~AssetManager() = default;

std::string find(std::string path)
{
return m_app_root + path;
}
private:
std::string m_app_root;
};

}
7 changes: 6 additions & 1 deletion userland/applications/about/AppDelegate.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
#include "ViewController.h"
#include <libui/AppDelegate.h>
#include <libui/MenuBar.h>
#include <libfoundation/AssetManager.h>

class AppDelegate : public UI::AppDelegate {
public:
AppDelegate() = default;
virtual ~AppDelegate() = default;

LG::Size preferred_desktop_window_size() const override { return LG::Size(200, 210); }
const char* icon_path() const override { return "/res/icons/apps/about.icon"; }
const char* icon_path() const override
{
LFoundation::AssetManager assets = LFoundation::AssetManager("about");
return assets.find("Resources/Assets/AppIcon").c_str();
}

virtual bool application() override
{
Expand Down
4 changes: 4 additions & 0 deletions userland/applications/about/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"assets": "Resources/Assets/",
"resources": ["Resources"]
}
7 changes: 6 additions & 1 deletion userland/applications/activity_monitor/AppDelegate.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
#include "ViewController.h"
#include <libui/AppDelegate.h>
#include <libfoundation/AssetManager.h>

class AppDelegate : public UI::AppDelegate {
public:
AppDelegate() = default;
virtual ~AppDelegate() = default;

LG::Size preferred_desktop_window_size() const override { return LG::Size(220, 210); }
const char* icon_path() const override { return "/res/icons/apps/activity_monitor.icon"; }
const char* icon_path() const override

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it's fine to keep for now, but it would be good to get rid of these icon_path() functions somehow. I didn't think on how to implement this, may be you can think of something.

{
LFoundation::AssetManager assets = LFoundation::AssetManager("activity_monitor");
return assets.find("Resources/Assets/AppIcon").c_str();;
}

virtual bool application() override
{
Expand Down
4 changes: 4 additions & 0 deletions userland/applications/activity_monitor/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"assets": "Resources/Assets",
"resources": ["Resources"]
}
7 changes: 6 additions & 1 deletion userland/applications/calculator/AppDelegate.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
#include "ViewController.h"
#include <libui/AppDelegate.h>
#include <libfoundation/AssetManager.h>

class AppDelegate : public UI::AppDelegate {
public:
AppDelegate() = default;
virtual ~AppDelegate() = default;

LG::Size preferred_desktop_window_size() const override { return LG::Size(240, 340); }
const char* icon_path() const override { return "/res/icons/apps/calculator.icon"; }
const char* icon_path() const override
{
LFoundation::AssetManager assets = LFoundation::AssetManager("calculator");
return assets.find("Resources/Assets/AppIcon").c_str();
}

virtual bool application() override
{
Expand Down
4 changes: 4 additions & 0 deletions userland/applications/calculator/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"assets": "Resources/Assets",
"resources": ["Resources"]
}
7 changes: 6 additions & 1 deletion userland/applications/terminal/AppDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "TerminalViewController.h"
#include <csignal>
#include <libui/AppDelegate.h>
#include <libfoundation/AssetManager.h>

static int shell_pid = 0;

Expand Down Expand Up @@ -38,7 +39,11 @@ class AppDelegate : public UI::AppDelegate {
virtual ~AppDelegate() = default;

LG::Size preferred_desktop_window_size() const override { return LG::Size(400, 300); }
const char* icon_path() const override { return "/res/icons/apps/terminal.icon"; }
const char* icon_path() const override
{
LFoundation::AssetManager assets = LFoundation::AssetManager("terminal");
return assets.find("Resources/Assets/AppIcon").c_str();
}

bool application() override
{
Expand Down
4 changes: 4 additions & 0 deletions userland/applications/terminal/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"assets": "Resources/Assets",
"resources": ["Resources"]
}
6 changes: 6 additions & 0 deletions userland/system/applist/AppListViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ class AppListViewController : public UI::ViewController<AppListView> {
LG::PNG::PNGLoader loader;

std::string icon_path = jdict_root->data()["icon_path"]->cast_to<LFoundation::Json::StringObject>()->data();
std::string icon_rel_path = jdict_root->data()["icon_rel_path"]->cast_to<LFoundation::Json::StringObject>()->data();

if (!icon_rel_path.empty()) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding an "empty" icon if icon_rel_path is not set. (here they are: https://github.com/opuntiaOS-Project/opuntiaOS/tree/master/base/res/icons/apps/missing.icon)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so that means icon_path generated by prepare_app.py should be completely omitted? Or is there any plan for it? Maybe always setting it to the missing icon path

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should unify icon_path and icon_rel_path for sure, so yeah we should omit one of them. But also in case if there is no such field in info.json which describes location of an icon, we should set a "missing icon".

As an alternative to this icon_path and icon_rel_path we could provide path to asset folder in the info.json. And to require have a "special" folder which contains icons inside the asset folder. In other words to have a provided path to an asset folder and look there for a "AppIcon" folder to get all of the icons.

icon_path = content_dir + icon_rel_path;
}

new_ent.set_icon(loader.load_from_file(icon_path + "/32x32.png"));

std::string rel_exec_path = jdict_root->data()["exec_rel_path"]->cast_to<LFoundation::Json::StringObject>()->data();
Expand Down
34 changes: 30 additions & 4 deletions userland/system/dock/DockViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,50 @@
#include <libui/Window.h>
#include <memory>
#include <sys/types.h>
#include <libfoundation/json/Parser.h>

class DockViewController : public UI::ViewController<DockView> {
public:
DockViewController(DockView& view)
: UI::ViewController<DockView>(view)
{
m_dock_apps.push_back("about");
m_dock_apps.push_back("terminal");
m_dock_apps.push_back("calculator");
m_dock_apps.push_back("activity_monitor");
}
virtual ~DockViewController() = default;

virtual void view_did_load() override
{
view().set_background_color(LG::Color::LightSystemOpaque);
view().new_dock_entity("/Applications/about.app/Content/about", "/res/icons/apps/about.icon", "com.opuntia.about");
view().new_dock_entity("/Applications/terminal.app/Content/terminal", "/res/icons/apps/terminal.icon", "com.opuntia.terminal");
view().new_dock_entity("/Applications/activity_monitor.app/Content/activity_monitor", "/res/icons/apps/activity_monitor.icon", "com.opuntia.activity_monitor");
view().new_dock_entity("/Applications/calculator.app/Content/calculator", "/res/icons/apps/calculator.icon", "com.opuntia.calculator");
for (auto& app : m_dock_apps) {
std::string app_content_dir = "/Applications/";
app_content_dir += app;
app_content_dir += ".app/Content/";
auto json_parser = LFoundation::Json::Parser(app_content_dir + "info.json");
LFoundation::Json::Object* jobj_root = json_parser.object();

if (jobj_root->invalid()) {
return;
}

auto* jdict_root = jobj_root->cast_to<LFoundation::Json::DictObject>();

std::string icon_path = jdict_root->data()["icon_path"]->cast_to<LFoundation::Json::StringObject>()->data();
std::string icon_rel_path = jdict_root->data()["icon_rel_path"]->cast_to<LFoundation::Json::StringObject>()->data();

if (!icon_rel_path.empty()) {
icon_path = app_content_dir + icon_rel_path;
}

std::string bundle_id = jdict_root->data()["bundle_id"]->cast_to<LFoundation::Json::StringObject>()->data();
view().new_dock_entity(app_content_dir + app, icon_path, bundle_id);
}

view().set_needs_display();
}

private:
std::vector<std::string> m_dock_apps;
};
69 changes: 62 additions & 7 deletions userland/system/homescreen/HomeScreenViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,72 @@
#include <libui/Window.h>
#include <memory>
#include <sys/types.h>
#include <libfoundation/json/Parser.h>

class HomeScreenViewController : public UI::ViewController<HomeScreenView> {
public:
HomeScreenViewController(HomeScreenView& view)
: UI::ViewController<HomeScreenView>(view)
{
m_apps.push_back({
.name = "about",
.fast_launch = true,
.home_screen = true,
});

m_apps.push_back({
.name = "terminal",
.fast_launch = true,
.home_screen = true,
});

m_apps.push_back({
.name = "activity_monitor",
.fast_launch = false,
.home_screen = true,
});

m_apps.push_back({
.name = "calculator",
.fast_launch = true,
.home_screen = true,
});
}
virtual ~HomeScreenViewController() = default;

void init_data()
{
view().new_fast_launch_entity("About", "/res/icons/apps/about.icon", "/Applications/about.app/Content/about"); // FIXME: Parse some init file
view().new_fast_launch_entity("Terminal", "/res/icons/apps/terminal.icon", "/Applications/terminal.app/Content/terminal");
view().new_fast_launch_entity("Calculator", "/res/icons/apps/calculator.icon", "/Applications/calculator.app/Content/calculator");
view().new_grid_entity("About", "/res/icons/apps/about.icon", "/Applications/about.app/Content/about"); // FIXME: Parse some init file
view().new_grid_entity("Terminal", "/res/icons/apps/terminal.icon", "/Applications/terminal.app/Content/terminal");
view().new_grid_entity("Monitor", "/res/icons/apps/activity_monitor.icon", "/Applications/activity_monitor.app/Content/activity_monitor");
view().new_grid_entity("Calculator", "/res/icons/apps/calculator.icon", "/Applications/calculator.app/Content/calculator");
for (auto& app : m_apps) {
std::string app_content_dir = "/Applications/";
app_content_dir += app.name;
app_content_dir += ".app/Content/";
auto json_parser = LFoundation::Json::Parser(app_content_dir + "info.json");
LFoundation::Json::Object* jobj_root = json_parser.object();

if (jobj_root->invalid()) {
return;
}

auto* jdict_root = jobj_root->cast_to<LFoundation::Json::DictObject>();

std::string icon_path = jdict_root->data()["icon_path"]->cast_to<LFoundation::Json::StringObject>()->data();
std::string icon_rel_path = jdict_root->data()["icon_rel_path"]->cast_to<LFoundation::Json::StringObject>()->data();

if (!icon_rel_path.empty()) {
icon_path = app_content_dir + icon_rel_path;
}

std::string exec_rel_path = jdict_root->data()["exec_rel_path"]->cast_to<LFoundation::Json::StringObject>()->data();
std::string name = jdict_root->data()["name"]->cast_to<LFoundation::Json::StringObject>()->data();

if (app.fast_launch) {
view().new_fast_launch_entity(name, icon_path, app_content_dir + exec_rel_path);
}

if (app.home_screen) {
view().new_grid_entity(name, icon_path, app_content_dir + exec_rel_path);
}
}
}

virtual void view_did_load() override
Expand All @@ -45,4 +93,11 @@ class HomeScreenViewController : public UI::ViewController<HomeScreenView> {
}

private:
struct app_launcher {
std::string name;
bool fast_launch;
bool home_screen;
};
typedef struct app_launcher app_launcher_t;
std::vector<app_launcher_t> m_apps;
};