Commit 02978f75 authored by Melroy van den Berg's avatar Melroy van den Berg
Browse files

Merge branch '10-save-restore-window-state' into 'master'

Resolve "Save & restore window state"

Closes #10

See merge request libreweb/browser!9
parents 85b5672a 25cd1287
Pipeline #3156 passed with stages
in 46 seconds
......@@ -8,7 +8,7 @@ What would you do different; if you could **reinvent** The Internet in 21st cent
I was inspired by Douglas Engelbart, Tim Berners-Lee and Ted Nelson as well as projects like IPFS, Jekyll, ARPANET, and more.
*Note:* Project is still in Alpha phase!
*Note:* Project is still in development!
## Download
......@@ -19,6 +19,10 @@ I was inspired by Douglas Engelbart, Tim Berners-Lee and Ted Nelson as well as p
![Browser Screenshot](./misc/browser_screenshot.png)
![Browser Markdown Editor](./misc/browser_screenshot_2.png)
## Documentation
Visit the [dedicated documentation site](https://docs.libreweb.org) for user documentation.
## Ideas/Features
The current success criteria:
......@@ -40,11 +44,11 @@ The current success criteria:
## Developers
Decentralized Browser written in C++20 with C libraries. And using the [cmark-gfm](https://github.com/github/cmark-gfm) library, used for CommonMark (markdown) parsing.
Decentralized Browser is written C++ together with some [libraries](/lib). It's using the [cmark-gfm](https://github.com/github/cmark-gfm) library for example, which is used for CommonMark (markdown) parsing.
Browser is using GTK 3 as UI library including Pango & Cairo for text drawing and manipulation.
We're using markdown as the source-code of the content/site. No HTML and JavaScript anymore, content is king after all.
For now we will use markdown as the source of the site. No HTML and JavaScript anymore, content is king after all.
LibreWeb Browser is using [Gnome GTK3](https://developer.gnome.org/gtk3/stable/) as UI framework.
### Development Environment
......@@ -57,10 +61,10 @@ For the build you need at least:
* GCC 9 or higher (GCC 8 should also work, but not adviced. Package: `build-essential`)
* CMake (Package: `cmake`)
* Ninja build system (Package: `ninja-build`)
* GTK & Cairo & Pango (including C++ bindings):
* GTK & Pango (including C++ bindings):
* Package: `libgtkmm-3.0-dev` under Debian based distros
### Documentation
### Developer Docs
See latest [Developer Docs](https://gitlab.melroy.org/libreweb/browser/-/jobs/artifacts/master/file/build/docs/html/index.html?job=doxygen).
......
# Example: https://github.com/MariaDB/server/tree/10.5/cmake
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "LibreWeb Browser - Decentralized Web-Browser")
set(CPACK_PACKAGE_VENDOR "Melroy van den Berg")
set(CPACK_PACKAGE_CONTACT "Melroy van den Berg <info@libreweb.org>")
set(CPACK_PACKAGE_HOMEPAGE_URL "https://libreweb.org")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/misc/package_desc.txt")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_TARGET}-${CPACK_PACKAGE_VERSION}")
set(CPACK_DEBIAN_PACKAGE_SECTION "web")
set(CPACK_RPM_PACKAGE_GROUP "Applications/Internet")
set(CPACK_RPM_PACKAGE_GROUP "Applications/Internet")
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-v${CPACK_PACKAGE_VERSION}") # Without '-Linux' suffix
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND EXISTS "/etc/os-release")
......
LibreWeb Browser is a fully decentralized free software and open-source Web Browser.
Allowing users to easily browse and host new content on the decentralized web. Build on top of IPFS.
Decentralization comes with many benefits like resilient to censorship and no single point of failure.
I was inspired by Douglas Engelbart, Tim Berners-Lee and Ted Nelson as well as projects like IPFS, Jekyll and ARPANET.
Please read the documentation at https://docs.libreweb.org.
\ No newline at end of file
......@@ -2,10 +2,13 @@
# By: Melroy van den Berg
# Description: Release production build + create Debian package file (.deb),
# RPM [Red Hat] Package Manager (.rpm) and compressed file (.tgz/.tar.gz)
#
# Installs into /usr folder (prefix)
rm -rf build_prod
mkdir build_prod
cd build_prod
cmake -GNinja -DCMAKE_BUILD_TYPE=Release ..
cmake -GNinja -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_BUILD_TYPE=Release ..
ninja &&
echo "INFO: Building packages...";
cpack -G "TGZ;DEB;RPM"
......@@ -18,11 +18,11 @@ set(PROJECT_TARGET libreweb-browser)
set(THREADS_PREFER_PTHREAD_FLAG ON)
# Find required dependencies
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTKMM gtkmm-3.0)
pkg_check_modules(CAIRO cairomm-1.0)
pkg_check_modules(GTKMM REQUIRED gtkmm-3.0)
pkg_check_modules(GLIB REQUIRED glib-2.0)
add_definitions(${GTKMM_CFLAGS_OTHER})
......@@ -39,8 +39,39 @@ if(NOT json_POPULATED)
add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
# Generate Project version header file
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/project_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/project_config.h)
# Find the GLib path for schema installation
execute_process(
COMMAND
${PKG_CONFIG_EXECUTABLE}
glib-2.0
--variable prefix
OUTPUT_VARIABLE
_glib_prefix
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(GSETTINGS_DIR "${_glib_prefix}/share/glib-2.0/schemas/" CACHE INTERNAL "")
# Fetch path for schema compiler from pkg-config
execute_process(
COMMAND
${PKG_CONFIG_EXECUTABLE}
gio-2.0
--variable
glib_compile_schemas
OUTPUT_VARIABLE
_glib_compile_schemas
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Set glib schema compiler command
set(glib_schema_compiler ${_glib_compile_schemas} CACHE INTERNAL "")
set(SCHEMA_FILE ${CMAKE_CURRENT_SOURCE_DIR}/org.libreweb.browser.gschema.xml)
# Source code
set(HEADERS
about.h
file.h
......@@ -51,7 +82,6 @@ set(HEADERS
draw.h
source-code-dialog.h
)
set(SOURCES
main.cc
about.cc
......@@ -67,6 +97,21 @@ set(SOURCES
add_executable(${PROJECT_TARGET} ${SOURCES})
# Copy gschema.xml file to build directory
set(SCHEMA_DIR ${CMAKE_CURRENT_BINARY_DIR}/gsettings)
add_custom_command(
TARGET ${PROJECT_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${SCHEMA_FILE}
${SCHEMA_DIR}/org.libreweb.browser.gschema.xml
)
add_custom_command(
TARGET ${PROJECT_TARGET} POST_BUILD
COMMAND ${glib_schema_compiler} ${SCHEMA_DIR}
COMMENT "Compiling schemas in folder: ${SCHEMA_DIR}"
)
# Add fallback for std filesystem in older GCC versions
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.4)
......@@ -88,15 +133,18 @@ target_include_directories(${PROJECT_TARGET} PRIVATE
${CMAKE_BINARY_DIR}
${CMAKE_EXTENSIONS_BINARY_DIR}
${GTKMM_INCLUDE_DIRS}
${CAIRO_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/lib/ipfs-http-client/include
)
)
target_link_directories(${PROJECT_TARGET} PRIVATE
${GTKMM_LIBRARY_DIRS}
${CAIRO_LIBRARY_DIRS}
)
target_link_libraries(${PROJECT_TARGET} PRIVATE LibCommonMarker LibCommonMarkerExtensions ipfs-http-client Threads::Threads ${CXX_FILESYSTEM_LIBRARIES} ${GTKMM_LIBRARIES} ${CAIRO_LIBRARIES} nlohmann_json::nlohmann_json)
target_link_libraries(${PROJECT_TARGET} PRIVATE LibCommonMarker LibCommonMarkerExtensions ipfs-http-client Threads::Threads ${CXX_FILESYSTEM_LIBRARIES} ${GTKMM_LIBRARIES} nlohmann_json::nlohmann_json)
# Install browser binary
install(TARGETS ${PROJECT_TARGET} RUNTIME DESTINATION bin)
install(TARGETS ${PROJECT_TARGET} RUNTIME DESTINATION "bin" COMPONENT applications)
# Install & compile GTK schema file
install(FILES ${SCHEMA_FILE} DESTINATION ${GSETTINGS_DIR})
install(CODE "execute_process (COMMAND ${glib_schema_compiler} ${GSETTINGS_DIR})")
......@@ -127,12 +127,12 @@ bool IPFS::shouldKillRunningProcess()
std::string path = "/proc/" + std::to_string(pid) + "/exe";
if (readlink(path.c_str(), pathbuf, sizeof(pathbuf) - 1) > 0)
{
// TODO: Compare version or file path location
char beginPath[28] = "/usr/share/libreweb-browser";
char beginPath[] = "/usr/share/libreweb-browser";
// If the begin path does not path (!= 0), return true,
// meaning the process will be killed.
return (strncmp(pathbuf, beginPath, strlen(beginPath)) != 0);
}
// TODO: Compare IPFS version as well, maybe?
}
else
{
......
#include "mainwindow.h"
#include "project_config.h"
#include "md-parser.h"
#include "menu.h"
#include "file.h"
......@@ -10,14 +11,21 @@
#include <glibmm/miscutils.h>
#include <glibmm/main.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glibmm/miscutils.h>
#include <cmark-gfm.h>
#include <pthread.h>
#include <iostream>
#include <nlohmann/json.hpp>
/**
* For info: NDEBUG variable be used for debugging purpose, example:
* #ifdef NDEBUG
* #endif
*/
MainWindow::MainWindow()
: accelGroup(Gtk::AccelGroup::create()),
m_menu(accelGroup),
: m_accelGroup(Gtk::AccelGroup::create()),
m_settings(),
m_menu(m_accelGroup),
m_draw_main(*this),
m_draw_secondary(*this),
m_vbox(Gtk::ORIENTATION_VERTICAL, 0),
......@@ -41,7 +49,20 @@ MainWindow::MainWindow()
set_title(m_appName);
set_default_size(1000, 800);
set_position(Gtk::WIN_POS_CENTER);
add_accel_group(accelGroup);
add_accel_group(m_accelGroup);
// Change schema directory when browser is not installed
if (!this->isInstalled())
{
std::string schemaDir = std::string(BINARY_DIR) + "/gsettings";
std::cout << "INFO: Use settings from: " << schemaDir << std::endl;
Glib::setenv("GSETTINGS_SCHEMA_DIR", schemaDir);
}
// Load schema settings file
m_settings = Gio::Settings::create("org.libreweb.browser");
set_default_size(m_settings->get_int("width"), m_settings->get_int("height"));
if (m_settings->get_boolean("maximized"))
this->maximize();
m_statusPopover.set_position(Gtk::POS_BOTTOM);
m_statusPopover.set_size_request(200, 80);
......@@ -53,7 +74,10 @@ MainWindow::MainWindow()
// Timeouts
this->statusTimerHandler = Glib::signal_timeout().connect(sigc::mem_fun(this, &MainWindow::update_connection_status), 3000);
// Connect signals
// Window signals
this->signal_delete_event().connect(sigc::mem_fun(this, &MainWindow::delete_window));
// Menu & toolbar signals
m_menu.new_doc.connect(sigc::mem_fun(this, &MainWindow::new_doc)); /*!< Menu item for new document */
m_menu.open.connect(sigc::mem_fun(this, &MainWindow::open)); /*!< Menu item for opening existing document */
m_menu.save.connect(sigc::mem_fun(this, &MainWindow::save)); /*!< Menu item for save document */
......@@ -372,13 +396,14 @@ MainWindow::MainWindow()
// timer will do the updates later
this->update_connection_status();
#ifdef NDEBUG
// Show start page by default
go_home();
#else
// Load test.md file in debug
doRequest("file://../../test.md", true);
#endif
// Show homepage if debugging is disabled
#ifdef NDEBUG
go_home();
#else
std::cout << "INFO: Running as Debug mode, opening test.md." << std::endl;
// Load test file when developing
doRequest("file://../../test.md", true);
#endif
}
/**
......@@ -404,6 +429,20 @@ void MainWindow::doRequest(const std::string &path, bool setAddressBar, bool isH
}
}
/**
* \brief Called when Window is closed
*/
bool MainWindow::delete_window(GdkEventAny *any_event __attribute__((unused)))
{
// Save the schema settings
m_settings->set_int("width", this->get_width());
m_settings->set_int("height", this->get_height());
m_settings->set_boolean("maximized", this->is_maximized());
// Fullscreen will be availible with gtkmm-4.0
//m_settings->set_boolean("fullscreen", this->is_fullscreen());
return false;
}
/**
* \brief Timeout slot: Update the IPFS connection status every x seconds
*/
......@@ -428,7 +467,7 @@ bool MainWindow::update_connection_status()
// And also update text
m_statusLabel.set_text("IPFS Network Stats:\n\nConnected peers: " + std::to_string(nrPeers) +
"\nRate in: " + in + " kB/s" +
"\nRate out: " + out + " kB/s");
"\nRate out: " + out + " kB/s");
}
else
{
......@@ -809,6 +848,25 @@ void MainWindow::refresh()
doRequest();
}
/**
* \brief Determing if browser is installed from current binary path, at runtime
* \return true if the current running process is installed (to the installed prefix path)
*/
bool MainWindow::isInstalled()
{
char pathbuf[1024];
memset(pathbuf, 0, sizeof(pathbuf));
if (readlink("/proc/self/exe", pathbuf, sizeof(pathbuf) - 1) > 0)
{
// If current binary path starts with the install prefix, it's installed
return (strncmp(pathbuf, INSTALL_PREFIX, strlen(INSTALL_PREFIX)) == 0);
}
else
{
return true; // fallback; always installed
}
}
void MainWindow::enableEdit()
{
// Inform the Draw class that we are creating a new document
......
......@@ -19,6 +19,7 @@
#include <gtkmm/searchbar.h>
#include <gtkmm/searchentry.h>
#include <gtkmm/paned.h>
#include <giomm/settings.h>
#include <thread>
/**
......@@ -33,6 +34,7 @@ public:
protected:
// Signal handlers
bool delete_window(GdkEventAny* any_event);
bool update_connection_status();
void cut();
void copy();
......@@ -60,7 +62,8 @@ protected:
void show_source_code_dialog();
void get_heading();
Glib::RefPtr<Gtk::AccelGroup> accelGroup; /*!< Accelerator group, used for keyboard shortcut bindings */
Glib::RefPtr<Gtk::AccelGroup> m_accelGroup; /*!< Accelerator group, used for keyboard shortcut bindings */
Glib::RefPtr<Gio::Settings> m_settings; /*!< Settings to store our preferences, even during restarts */
// Child widgets
Menu m_menu;
......@@ -158,6 +161,7 @@ private:
sigc::connection statusTimerHandler;
IPFS ipfs;
bool isInstalled();
void enableEdit();
void disableEdit();
void postDoRequest(const std::string &path, bool setAddressBar, bool isHistoryRequest);
......
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema path="/org/libreweb/browser/" id="org.libreweb.browser">
<key name="width" type="i">
<default>1000</default>
<summary>Window width</summary>
</key>
<key name="height" type="i">
<default>800</default>
<summary>Window height</summary>
</key>
<key name="maximized" type="b">
<default>false</default>
<summary>Is window maximized</summary>
</key>
<key name="fullscreen" type="b">
<default>false</default>
<summary>Is window fullscreen</summary>
</key>
</schema>
</schemalist>
#ifndef INCLUDE_GUARD
#define INCLUDE_GUARD
#ifndef PROJECT_CONFIG_H
#define PROJECT_CONFIG_H
#define PROJECT_NAME "@PROJECT_NAME@"
#define PROJECT_VER "@PROJECT_VERSION@"
#define PROJECT_VER_MAJOR "@PROJECT_VERSION_MAJOR@"
#define PROJECT_VER_MINOR "@PROJECT_VERSION_MINOR@"
#define PTOJECT_VER_PATCH "@PROJECT_VERSION_PATCH@"
#define PROJECT_VER_PATCH "@PROJECT_VERSION_PATCH@"
#endif // INCLUDE_GUARD
\ No newline at end of file
#define INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
#define BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@"
#endif // PROJECT_CONFIG_H
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment