summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile488
-rw-r--r--Makefile.macros249
-rw-r--r--content/handlers/css/hints.c47
-rw-r--r--content/handlers/html/box.h4
-rw-r--r--content/handlers/html/box_construct.c67
-rw-r--r--content/handlers/html/box_manipulate.c1
-rw-r--r--content/handlers/html/layout.c418
-rw-r--r--desktop/netsurf.c6
-rw-r--r--docs/integration-testing.md9
-rw-r--r--frontends/Makefile.hts122
-rw-r--r--frontends/amiga/Makefile.tools21
-rw-r--r--frontends/amiga/iff_dr2d.c4
-rw-r--r--frontends/atari/Makefile.tools19
-rw-r--r--frontends/beos/Makefile.tools14
-rw-r--r--frontends/framebuffer/Makefile.tools15
-rw-r--r--frontends/gtk/Makefile10
-rw-r--r--frontends/gtk/Makefile.tools16
-rw-r--r--frontends/gtk/corewindow.c1
-rw-r--r--frontends/gtk/gui.c1347
-rw-r--r--frontends/gtk/misc.c190
-rw-r--r--frontends/gtk/misc.h24
-rw-r--r--frontends/gtk/window.c17
-rw-r--r--frontends/monkey/Makefile.tools15
-rw-r--r--frontends/monkey/main.c17
-rw-r--r--frontends/riscos/Makefile.tools52
-rw-r--r--frontends/riscos/filetype.c2
-rw-r--r--frontends/riscos/filetype.h3
-rw-r--r--frontends/riscos/gui.c4
-rw-r--r--frontends/windows/Makefile.tools19
-rw-r--r--include/netsurf/bitmap.h4
-rw-r--r--include/netsurf/fetch.h8
-rw-r--r--resources/default.css4
-rw-r--r--test/corestrings.c2
-rwxr-xr-xtest/monkey_driver.py15
-rw-r--r--tools/convert_font.c6
-rw-r--r--utils/corestringlist.h2
36 files changed, 1940 insertions, 1302 deletions
diff --git a/Makefile b/Makefile
index d8e3b1664..ac38b50ea 100644
--- a/Makefile
+++ b/Makefile
@@ -12,8 +12,7 @@
#
# Look at Makefile.config for configuration options.
#
-# Tested on unix platforms (building for GTK and cross-compiling for RO) and
-# on RO (building for RO).
+# Best results obtained building on unix platforms cross compiling for others
#
# To clean, invoke as above, with the 'clean' target
#
@@ -26,100 +25,8 @@
all: all-program
-# Determine host type
-# NOTE: HOST determination on RISC OS could fail because of missing bug fixes
-# in UnixLib which only got addressed in UnixLib 5 / GCCSDK 4.
-# When you don't have 'uname' available, you will see:
-# File 'uname' not found
-# When you do and using a 'uname' compiled with a buggy UnixLib, you
-# will see the following printed on screen:
-# RISC OS
-# In both cases HOST make variable is empty and we recover from that by
-# assuming we're building on RISC OS.
-# In case you don't see anything printed (including the warning), you
-# have an up-to-date RISC OS build system. ;-)
-HOST := $(shell uname -s)
-
-# Sanitise host
-# TODO: Ideally, we want the equivalent of s/[^A-Za-z0-9]/_/g here
-HOST := $(subst .,_,$(subst -,_,$(subst /,_,$(HOST))))
-
-ifeq ($(HOST),)
- HOST := riscos
- $(warning Build platform determination failed but that's a known problem for RISC OS so we're assuming a native RISC OS build.)
-else
- ifeq ($(HOST),RISC OS)
- # Fixup uname -s returning "RISC OS"
- HOST := riscos
- endif
-endif
-ifeq ($(HOST),riscos)
- # Build happening on RO platform, default target is RO backend
- ifeq ($(TARGET),)
- TARGET := riscos
- endif
-endif
-
-ifeq ($(HOST),BeOS)
- HOST := beos
-endif
-ifeq ($(HOST),Haiku)
- # Haiku implements the BeOS API
- HOST := beos
-endif
-ifeq ($(HOST),beos)
- # Build happening on BeOS platform, default target is BeOS backend
- ifeq ($(TARGET),)
- TARGET := beos
- endif
- ifeq ($(TARGET),haiku)
- override TARGET := beos
- endif
-endif
-
-ifeq ($(HOST),AmigaOS)
- HOST := amiga
- ifeq ($(TARGET),)
- TARGET := amiga
- endif
-endif
-
-ifeq ($(HOST),FreeMiNT)
- HOST := mint
-endif
-ifeq ($(HOST),mint)
- ifeq ($(TARGET),)
- TARGET := atari
- endif
-endif
-
-ifeq ($(findstring MINGW,$(HOST)),MINGW)
- # MSYS' uname reports the likes of "MINGW32_NT-6.0"
- HOST := windows
-endif
-ifeq ($(HOST),windows)
- ifeq ($(TARGET),)
- TARGET := windows
- endif
-endif
-
-# Default target is GTK backend
-ifeq ($(TARGET),)
- TARGET := gtk3
-endif
-
-# valid values for the TARGET
-VLDTARGET := riscos gtk2 gtk3 beos amiga amigaos3 framebuffer windows atari monkey
+# default values for base variables
-# Check for valid TARGET
-ifeq ($(filter $(VLDTARGET),$(TARGET)),)
- $(error Unknown TARGET "$(TARGET)", Must be one of $(VLDTARGET))
-endif
-
-# ensure empty values for base variables
-
-# Sub target for build
-SUBTARGET=
# Resources executable target depends upon
RESOURCES=
# Messages executable target depends on
@@ -153,169 +60,11 @@ BUILD_CFLAGS = -g -W -Wall -Wundef -Wpointer-arith -Wcast-align \
-Wwrite-strings -Wmissing-declarations -Wuninitialized \
-Wno-unused-parameter
-ifeq ($(TARGET),riscos)
- ifeq ($(HOST),riscos)
- # Build for RO on RO
- GCCSDK_INSTALL_ENV := <NSLibs$$Dir>
- CCRES := ccres
- TPLEXT :=
- MAKERUN := makerun
- SQUEEZE := squeeze
- RUNEXT :=
- CC := gcc
- CXX := g++
- EXEEXT :=
- PKG_CONFIG :=
- else
- # Cross-build for RO (either using GCCSDK 3.4.6 - AOF,
- # either using GCCSDK 4 - ELF)
- ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
- ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/env),)
- GCCSDK_INSTALL_ENV := /opt/netsurf/arm-unknown-riscos/env
- else
- GCCSDK_INSTALL_ENV := /home/riscos/env
- endif
- endif
-
- ifeq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
- ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/cross/bin),)
- GCCSDK_INSTALL_CROSSBIN := /opt/netsurf/arm-unknown-riscos/cross/bin
- else
- GCCSDK_INSTALL_CROSSBIN := /home/riscos/cross/bin
- endif
- endif
-
- CCRES := $(GCCSDK_INSTALL_CROSSBIN)/ccres
- TPLEXT := ,fec
- MAKERUN := $(GCCSDK_INSTALL_CROSSBIN)/makerun
- SQUEEZE := $(GCCSDK_INSTALL_CROSSBIN)/squeeze
- RUNEXT := ,feb
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
- ifneq (,$(findstring arm-unknown-riscos-gcc,$(CC)))
- SUBTARGET := -elf
- EXEEXT := ,e1f
- ELF2AIF := $(GCCSDK_INSTALL_CROSSBIN)/elf2aif
- else
- SUBTARGET := -aof
- EXEEXT := ,ff8
- endif
- CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
- PKG_CONFIG := $(GCCSDK_INSTALL_ENV)/ro-pkg-config
- endif
-else
- ifeq ($(TARGET),beos)
- # Building for BeOS/Haiku
- #ifeq ($(HOST),beos)
- # Build for BeOS on BeOS
- GCCSDK_INSTALL_ENV := /boot/develop
- CC := gcc
- CXX := g++
- EXEEXT :=
- PKG_CONFIG := pkg-config
- #endif
- else
- ifeq ($(TARGET),windows)
- ifneq ($(HOST),windows)
- # Set Mingw defaults
- GCCSDK_INSTALL_ENV ?= /opt/netsurf/i686-w64-mingw32/env
- GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/i686-w64-mingw32/cross/bin
-
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
- WINDRES := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*windres)
-
- PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
- else
- # Building on Windows
- CC := gcc
- PKG_CONFIG :=
- endif
- else
- ifeq ($(findstring amiga,$(TARGET)),amiga)
- ifeq ($(findstring amiga,$(HOST)),amiga)
- PKG_CONFIG := pkg-config
- else
- ifeq ($(TARGET),amigaos3)
- GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-unknown-amigaos/env
- GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-unknown-amigaos/cross/bin
-
- SUBTARGET = os3
- else
- GCCSDK_INSTALL_ENV ?= /opt/netsurf/ppc-amigaos/env
- GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/ppc-amigaos/cross/bin
- endif
-
- override TARGET := amiga
-
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
-
- PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
- endif
- else
- ifeq ($(TARGET),atari)
- ifeq ($(HOST),atari)
- PKG_CONFIG := pkg-config
- else
- ifeq ($(HOST),mint)
- PKG_CONFIG := pkg-config
- else
- GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-atari-mint/env
- GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-atari-mint/cross/bin
-
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
-
- PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
- endif
- endif
- else
- ifeq ($(TARGET),monkey)
- ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
- PKG_CONFIG := pkg-config
- else
- PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
- endif
-
- ifneq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
- CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
- endif
- else
- ifeq ($(TARGET),framebuffer)
- ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
- PKG_CONFIG := pkg-config
- else
- PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
- endif
-
- ifneq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
- CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
- endif
-
- else
- # All native targets
-
- # use native package config
- PKG_CONFIG := pkg-config
-
- # gtk target processing
- ifeq ($(TARGET),gtk3)
- override TARGET := gtk
- override NETSURF_GTK_MAJOR := 3
- SUBTARGET = $(NETSURF_GTK_MAJOR)
- else
- ifeq ($(TARGET),gtk2)
- override TARGET := gtk
- override NETSURF_GTK_MAJOR := 2
- SUBTARGET = $(NETSURF_GTK_MAJOR)
- endif
- endif
- endif
- endif
- endif
- endif
- endif
- endif
-endif
+# compute HOST, TARGET and SUBTARGET
+include frontends/Makefile.hts
+
+# target specific tool overrides
+include frontends/$(TARGET)/Makefile.tools
# compiler versioning to adjust warning flags
CC_VERSION := $(shell $(CC) -dumpfullversion -dumpversion)
@@ -340,138 +89,8 @@ TOOLROOT := $(OBJROOT)/tools
CFLAGS_ENV := $(CFLAGS)
CXXFLAGS_ENV := $(CXXFLAGS)
-# A macro that conditionaly adds flags to the build when a feature is enabled.
-#
-# 1: Feature name (ie, NETSURF_USE_BMP -> BMP)
-# 2: Parameters to add to CFLAGS
-# 3: Parameters to add to LDFLAGS
-# 4: Human-readable name for the feature
-define feature_enabled
- ifeq ($$(NETSURF_USE_$(1)),YES)
- CFLAGS += $(2)
- CXXFLAGS += $(2)
- LDFLAGS += $(3)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(4) enabled (NETSURF_USE_$(1) := YES))
- endif
- else ifeq ($$(NETSURF_USE_$(1)),NO)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(4) disabled (NETSURF_USE_$(1) := NO))
- endif
- else
- $$(info M.CONFIG: $(4) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
- $$(error NETSURF_USE_$(1) must be YES or NO)
- endif
-endef
-
-# A macro that conditionaly adds flags to the build with a uniform display.
-#
-# 1: Feature name (ie, NETSURF_USE_BMP -> BMP)
-# 2: Human-readable name for the feature
-# 3: Parameters to add to CFLAGS when enabled
-# 4: Parameters to add to LDFLAGS when enabled
-# 5: Parameters to add to CFLAGS when disabled
-# 6: Parameters to add to LDFLAGS when disabled
-define feature_switch
- ifeq ($$(NETSURF_USE_$(1)),YES)
- CFLAGS += $(3)
- CXXFLAGS += $(3)
- LDFLAGS += $(4)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(2) enabled (NETSURF_USE_$(1) := YES))
- endif
- else ifeq ($$(NETSURF_USE_$(1)),NO)
- CFLAGS += $(5)
- CXXFLAGS += $(5)
- LDFLAGS += $(6)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(2) disabled (NETSURF_USE_$(1) := NO))
- endif
- else
- $$(info M.CONFIG: $(4) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
- $$(error NETSURF_USE_$(1) must be YES or NO)
- endif
-endef
-
-# Extend flags with appropriate values from pkg-config for enabled features
-#
-# 1: pkg-config required modules for feature
-# 2: Human-readable name for the feature
-define pkg_config_find_and_add
- ifeq ($$(PKG_CONFIG),)
- $$(error pkg-config is required to auto-detect feature availability)
- endif
-
- PKG_CONFIG_$(1)_EXISTS := $$(shell $$(PKG_CONFIG) --exists $(1) && echo yes)
-
- ifeq ($$(PKG_CONFIG_$(1)_EXISTS),yes)
- CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(1))
- CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(1))
- LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(1))
- ifneq ($(MAKECMDGOALS),clean)
- $$(info PKG.CNFG: $(2) ($(1)) enabled)
- endif
- else
- ifneq ($(MAKECMDGOALS),clean)
- $$(info PKG.CNFG: $(2) ($(1)) failed)
- $$(error Unable to find library for: $(2) ($(1)))
- endif
- endif
-endef
-
-# Extend flags with appropriate values from pkg-config for enabled features
-#
-# 1: Feature name (ie, NETSURF_USE_RSVG -> RSVG)
-# 2: pkg-config required modules for feature
-# 3: Human-readable name for the feature
-define pkg_config_find_and_add_enabled
- ifeq ($$(PKG_CONFIG),)
- $$(error pkg-config is required to auto-detect feature availability)
- endif
-
- NETSURF_FEATURE_$(1)_AVAILABLE := $$(shell $$(PKG_CONFIG) --exists $(2) && echo yes)
- NETSURF_FEATURE_$(1)_CFLAGS ?= -DWITH_$(1)
-
- ifeq ($$(NETSURF_USE_$(1)),YES)
- ifeq ($$(NETSURF_FEATURE_$(1)_AVAILABLE),yes)
- CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
- CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
- LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(2)) $$(NETSURF_FEATURE_$(1)_LDFLAGS)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) enabled (NETSURF_USE_$(1) := YES))
- endif
- else
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) failed (NETSURF_USE_$(1) := YES))
- $$(error Unable to find library for: $(3) ($(2)))
- endif
- endif
- else ifeq ($$(NETSURF_USE_$(1)),AUTO)
- ifeq ($$(NETSURF_FEATURE_$(1)_AVAILABLE),yes)
- CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
- CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
- LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(2)) $$(NETSURF_FEATURE_$(1)_LDFLAGS)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) auto-enabled (NETSURF_USE_$(1) := AUTO))
- NETSURF_USE_$(1) := YES
- endif
- else
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) auto-disabled (NETSURF_USE_$(1) := AUTO))
- NETSURF_USE_$(1) := NO
- endif
- endif
- else ifeq ($$(NETSURF_USE_$(1)),NO)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) disabled (NETSURF_USE_$(1) := NO))
- endif
- else
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
- $$(error NETSURF_USE_$(1) must be YES, NO, or AUTO)
- endif
- endif
-endef
+# library and feature building macros
+include Makefile.macros
# ----------------------------------------------------------------------------
# General flag setup
@@ -681,20 +300,6 @@ S_COMMON := \
# Message targets
# ----------------------------------------------------------------------------
-# Message splitting rule generation macro
-# 1 = Language
-define split_messages
-
-$$(MESSAGES_TARGET)/$(1)/Messages: resources/FatMessages $$(TOOLROOT)/split-messages
- $$(VQ)echo "MSGSPLIT: Language: $(1) Filter: $$(MESSAGES_FILTER)"
- $$(Q)$$(MKDIR) -p $$(MESSAGES_TARGET)/$(1)
- $$(Q)$$(RM) $$@
- $$(Q)$$(TOOLROOT)/split-messages -l $(1) -p $$(MESSAGES_FILTER) -f messages -o $$@ -z $$<
-
-CLEAN_MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
-MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
-
-endef
# generate the message file rules
$(eval $(foreach LANG,$(MESSAGES_LANGUAGES), \
@@ -745,7 +350,7 @@ ifeq ($(TARGET),beos)
$(Q)$(BEOS_SETVER) $(EXETARGET) \
-app $(VERSION_MAJ) $(VERSION_MIN) 0 d 0 \
-short "NetSurf $(VERSION_FULL)" \
- -long "NetSurf $(VERSION_FULL) © 2003 - 2016 The NetSurf Developers"
+ -long "NetSurf $(VERSION_FULL) © 2003 - 2021 The NetSurf Developers"
$(VQ)echo " MIMESET: $(EXETARGET)"
$(Q)$(BEOS_MIMESET) $(EXETARGET)
endif
@@ -769,79 +374,6 @@ all-program: $(EXETARGET) $(POSTEXES)
.SUFFIXES:
DEPFILES :=
-# Now some macros which build the make system
-
-# 1 = Source file
-# 2 = dep filename, no prefix
-# 3 = obj filename, no prefix
-define dependency_generate_c
-DEPFILES += $(2)
-
-endef
-
-# 1 = Source file
-# 2 = dep filename, no prefix
-# 3 = obj filename, no prefix
-define dependency_generate_s
-DEPFILES += $(2)
-
-endef
-
-# 1 = Source file
-# 2 = obj filename, no prefix
-# 3 = dep filename, no prefix
-ifeq ($(CC_MAJOR),2)
-# simpler deps tracking for gcc2...
-define compile_target_c
-$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
- $$(VQ)echo " DEP: $(1)"
- $$(Q)$$(RM) $$(DEPROOT)/$(3)
- $$(Q)$$(CC) $$(IFLAGS) $$(CFLAGS) -MM \
- $(1) | sed 's,^.*:,$$(DEPROOT)/$(3) $$(OBJROOT)/$(2):,' \
- > $$(DEPROOT)/$(3)
- $$(VQ)echo " COMPILE: $(1)"
- $$(Q)$$(RM) $$(OBJROOT)/$(2)
- $$(Q)$$(CC) $$(COMMON_WARNFLAGS) $$(CWARNFLAGS) $$(IFLAGS) $$(CFLAGS) $(CFLAGS_ENV) -o $$(OBJROOT)/$(2) -c $(1)
-
-endef
-else
-define compile_target_c
-$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
- $$(VQ)echo " COMPILE: $(1)"
- $$(Q)$$(RM) $$(DEPROOT)/$(3)
- $$(Q)$$(RM) $$(OBJROOT)/$(2)
- $$(Q)$$(CC) $$(COMMON_WARNFLAGS) $$(CWARNFLAGS) $$(IFLAGS) $$(CFLAGS) $(CFLAGS_ENV) \
- -MMD -MT '$$(DEPROOT)/$(3) $$(OBJROOT)/$(2)' \
- -MF $$(DEPROOT)/$(3) -o $$(OBJROOT)/$(2) -c $(1)
-
-endef
-endif
-
-define compile_target_cpp
-$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
- $$(VQ)echo " DEP: $(1)"
- $$(Q)$$(RM) $$(DEPROOT)/$(3)
- $$(Q)$$(CC) $$(IFLAGS) $$(CXXFLAGS) $$(COMMON_WARNFLAGS) $$(CXXWARNFLAGS) -MM \
- $(1) | sed 's,^.*:,$$(DEPROOT)/$(3) $$(OBJROOT)/$(2):,' \
- > $$(DEPROOT)/$(3)
- $$(VQ)echo " COMPILE: $(1)"
- $$(Q)$$(RM) $$(OBJROOT)/$(2)
- $$(Q)$$(CXX) $$(COMMON_WARNFLAGS) $$(CXXWARNFLAGS) $$(IFLAGS) $$(CXXFLAGS) $(CXXFLAGS_ENV) -o $$(OBJROOT)/$(2) -c $(1)
-
-endef
-
-# 1 = Source file
-# 2 = obj filename, no prefix
-# 3 = dep filename, no prefix
-define compile_target_s
-$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
- $$(VQ)echo "ASSEMBLE: $(1)"
- $$(Q)$$(RM) $$(DEPROOT)/$(3)
- $$(Q)$$(RM) $$(OBJROOT)/$(2)
- $$(Q)$$(CC) $$(ASFLAGS) -MMD -MT '$$(DEPROOT)/$(3) $$(OBJROOT)/$(2)' \
- -MF $$(DEPROOT)/$(3) -o $$(OBJROOT)/$(2) -c $(1)
-
-endef
# Rules to construct dep lines for each object...
$(eval $(foreach SOURCE,$(filter %.c,$(SOURCES)), \
diff --git a/Makefile.macros b/Makefile.macros
new file mode 100644
index 000000000..d8468b41e
--- /dev/null
+++ b/Makefile.macros
@@ -0,0 +1,249 @@
+# -*- mode: makefile-gmake -*-
+##
+## Netsurf library and feature macros
+##
+
+# A macro that conditionaly adds flags to the build when a feature is enabled.
+#
+# 1: Feature name (ie, NETSURF_USE_BMP -> BMP)
+# 2: Parameters to add to CFLAGS
+# 3: Parameters to add to LDFLAGS
+# 4: Human-readable name for the feature
+define feature_enabled
+ ifeq ($$(NETSURF_USE_$(1)),YES)
+ CFLAGS += $(2)
+ CXXFLAGS += $(2)
+ LDFLAGS += $(3)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(4) enabled (NETSURF_USE_$(1) := YES))
+ endif
+ else ifeq ($$(NETSURF_USE_$(1)),NO)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(4) disabled (NETSURF_USE_$(1) := NO))
+ endif
+ else
+ $$(info M.CONFIG: $(4) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
+ $$(error NETSURF_USE_$(1) must be YES or NO)
+ endif
+endef
+
+
+# A macro that conditionaly adds flags to the build with a uniform display.
+#
+# 1: Feature name (ie, NETSURF_USE_BMP -> BMP)
+# 2: Human-readable name for the feature
+# 3: Parameters to add to CFLAGS when enabled
+# 4: Parameters to add to LDFLAGS when enabled
+# 5: Parameters to add to CFLAGS when disabled
+# 6: Parameters to add to LDFLAGS when disabled
+define feature_switch
+ ifeq ($$(NETSURF_USE_$(1)),YES)
+ CFLAGS += $(3)
+ CXXFLAGS += $(3)
+ LDFLAGS += $(4)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(2) enabled (NETSURF_USE_$(1) := YES))
+ endif
+ else ifeq ($$(NETSURF_USE_$(1)),NO)
+ CFLAGS += $(5)
+ CXXFLAGS += $(5)
+ LDFLAGS += $(6)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(2) disabled (NETSURF_USE_$(1) := NO))
+ endif
+ else
+ $$(info M.CONFIG: $(4) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
+ $$(error NETSURF_USE_$(1) must be YES or NO)
+ endif
+endef
+
+
+# Extend flags with appropriate values from pkg-config for enabled features
+#
+# 1: pkg-config required modules for feature
+# 2: Human-readable name for the feature
+define pkg_config_find_and_add
+ ifeq ($$(PKG_CONFIG),)
+ $$(error pkg-config is required to auto-detect feature availability)
+ endif
+
+ PKG_CONFIG_$(1)_EXISTS := $$(shell $$(PKG_CONFIG) --exists $(1) && echo yes)
+
+ ifeq ($$(PKG_CONFIG_$(1)_EXISTS),yes)
+ CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(1))
+ CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(1))
+ LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(1))
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info PKG.CNFG: $(2) ($(1)) enabled)
+ endif
+ else
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info PKG.CNFG: $(2) ($(1)) failed)
+ $$(error Unable to find library for: $(2) ($(1)))
+ endif
+ endif
+endef
+
+
+# Extend flags with appropriate values from pkg-config for enabled features
+#
+# 1: Feature name (ie, NETSURF_USE_RSVG -> RSVG)
+# 2: pkg-config required modules for feature
+# 3: Human-readable name for the feature
+define pkg_config_find_and_add_enabled
+ ifeq ($$(PKG_CONFIG),)
+ $$(error pkg-config is required to auto-detect feature availability)
+ endif
+
+ NETSURF_FEATURE_$(1)_AVAILABLE := $$(shell $$(PKG_CONFIG) --exists $(2) && echo yes)
+ NETSURF_FEATURE_$(1)_CFLAGS ?= -DWITH_$(1)
+
+ ifeq ($$(NETSURF_USE_$(1)),YES)
+ ifeq ($$(NETSURF_FEATURE_$(1)_AVAILABLE),yes)
+ CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
+ CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
+ LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(2)) $$(NETSURF_FEATURE_$(1)_LDFLAGS)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) enabled (NETSURF_USE_$(1) := YES))
+ endif
+ else
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) failed (NETSURF_USE_$(1) := YES))
+ $$(error Unable to find library for: $(3) ($(2)))
+ endif
+ endif
+ else ifeq ($$(NETSURF_USE_$(1)),AUTO)
+ ifeq ($$(NETSURF_FEATURE_$(1)_AVAILABLE),yes)
+ CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
+ CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
+ LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(2)) $$(NETSURF_FEATURE_$(1)_LDFLAGS)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) auto-enabled (NETSURF_USE_$(1) := AUTO))
+ NETSURF_USE_$(1) := YES
+ endif
+ else
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) auto-disabled (NETSURF_USE_$(1) := AUTO))
+ NETSURF_USE_$(1) := NO
+ endif
+ endif
+ else ifeq ($$(NETSURF_USE_$(1)),NO)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) disabled (NETSURF_USE_$(1) := NO))
+ endif
+ else
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
+ $$(error NETSURF_USE_$(1) must be YES, NO, or AUTO)
+ endif
+ endif
+endef
+
+
+# Message splitting rule generation macro
+#
+# 1 = Language
+define split_messages
+
+$$(MESSAGES_TARGET)/$(1)/Messages: resources/FatMessages $$(TOOLROOT)/split-messages
+ $$(VQ)echo "MSGSPLIT: Language: $(1) Filter: $$(MESSAGES_FILTER)"
+ $$(Q)$$(MKDIR) -p $$(MESSAGES_TARGET)/$(1)
+ $$(Q)$$(RM) $$@
+ $$(Q)$$(TOOLROOT)/split-messages -l $(1) -p $$(MESSAGES_FILTER) -f messages -o $$@ -z $$<
+
+CLEAN_MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
+MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
+
+endef
+
+
+# Now some macros which build the make system
+
+# Extend dependancy files for c source files
+#
+# 1 = Source file
+# 2 = dep filename, no prefix
+# 3 = obj filename, no prefix
+define dependency_generate_c
+DEPFILES += $(2)
+
+endef
+
+
+# Extend dependancy files for s source files
+#
+# 1 = Source file
+# 2 = dep filename, no prefix
+# 3 = obj filename, no prefix
+define dependency_generate_s
+DEPFILES += $(2)
+
+endef
+
+
+# Rule generator to compile c files
+#
+# 1 = Source file
+# 2 = obj filename, no prefix
+# 3 = dep filename, no prefix
+ifeq ($(CC_MAJOR),2)
+# simpler deps tracking for gcc2...
+define compile_target_c
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
+ $$(VQ)echo " DEP: $(1)"
+ $$(Q)$$(RM) $$(DEPROOT)/$(3)
+ $$(Q)$$(CC) $$(IFLAGS) $$(CFLAGS) -MM \
+ $(1) | sed 's,^.*:,$$(DEPROOT)/$(3) $$(OBJROOT)/$(2):,' \
+ > $$(DEPROOT)/$(3)
+ $$(VQ)echo " COMPILE: $(1)"
+ $$(Q)$$(RM) $$(OBJROOT)/$(2)
+ $$(Q)$$(CC) $$(COMMON_WARNFLAGS) $$(CWARNFLAGS) $$(IFLAGS) $$(CFLAGS) $(CFLAGS_ENV) -o $$(OBJROOT)/$(2) -c $(1)
+
+endef
+else
+define compile_target_c
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
+ $$(VQ)echo " COMPILE: $(1)"
+ $$(Q)$$(RM) $$(DEPROOT)/$(3)
+ $$(Q)$$(RM) $$(OBJROOT)/$(2)
+ $$(Q)$$(CC) $$(COMMON_WARNFLAGS) $$(CWARNFLAGS) $$(IFLAGS) $$(CFLAGS) $(CFLAGS_ENV) \
+ -MMD -MT '$$(DEPROOT)/$(3) $$(OBJROOT)/$(2)' \
+ -MF $$(DEPROOT)/$(3) -o $$(OBJROOT)/$(2) -c $(1)
+
+endef
+endif
+
+
+# Rule generator to compile cpp files
+#
+# 1 = Source file
+# 2 = obj filename, no prefix
+# 3 = dep filename, no prefix
+define compile_target_cpp
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
+ $$(VQ)echo " DEP: $(1)"
+ $$(Q)$$(RM) $$(DEPROOT)/$(3)
+ $$(Q)$$(CC) $$(IFLAGS) $$(CXXFLAGS) $$(COMMON_WARNFLAGS) $$(CXXWARNFLAGS) -MM \
+ $(1) | sed 's,^.*:,$$(DEPROOT)/$(3) $$(OBJROOT)/$(2):,' \
+ > $$(DEPROOT)/$(3)
+ $$(VQ)echo " COMPILE: $(1)"
+ $$(Q)$$(RM) $$(OBJROOT)/$(2)
+ $$(Q)$$(CXX) $$(COMMON_WARNFLAGS) $$(CXXWARNFLAGS) $$(IFLAGS) $$(CXXFLAGS) $(CXXFLAGS_ENV) -o $$(OBJROOT)/$(2) -c $(1)
+
+endef
+
+
+# Rule generator to compile s files
+#
+# 1 = Source file
+# 2 = obj filename, no prefix
+# 3 = dep filename, no prefix
+define compile_target_s
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
+ $$(VQ)echo "ASSEMBLE: $(1)"
+ $$(Q)$$(RM) $$(DEPROOT)/$(3)
+ $$(Q)$$(RM) $$(OBJROOT)/$(2)
+ $$(Q)$$(CC) $$(ASFLAGS) -MMD -MT '$$(DEPROOT)/$(3) $$(OBJROOT)/$(2)' \
+ -MF $$(DEPROOT)/$(3) -o $$(OBJROOT)/$(2) -c $(1)
+
+endef
diff --git a/content/handlers/css/hints.c b/content/handlers/css/hints.c
index 9748030b7..defeae10a 100644
--- a/content/handlers/css/hints.c
+++ b/content/handlers/css/hints.c
@@ -1579,6 +1579,50 @@ static void css_hint_white_space_nowrap(
}
}
+static void css_hint_list(
+ nscss_select_ctx *ctx,
+ dom_node *node)
+{
+ struct css_hint *hint = &(hint_ctx.hints[hint_ctx.len]);
+ dom_exception err;
+ dom_string *attr;
+
+ err = dom_element_get_attribute(node, corestring_dom_type, &attr);
+ if (err == DOM_NO_ERR && attr != NULL) {
+ const char *attr_str = dom_string_data(attr);
+ size_t attr_len = dom_string_byte_length(attr);
+ enum css_list_style_type_e type = CSS_LIST_STYLE_TYPE_INHERIT;
+
+ if (attr_len == 1) {
+ switch (attr_str[0]) {
+ case 'a':
+ type = CSS_LIST_STYLE_TYPE_LOWER_ALPHA;
+ break;
+ case 'A':
+ type = CSS_LIST_STYLE_TYPE_UPPER_ALPHA;
+ break;
+ case 'i':
+ type = CSS_LIST_STYLE_TYPE_LOWER_ROMAN;
+ break;
+ case 'I':
+ type = CSS_LIST_STYLE_TYPE_UPPER_ROMAN;
+ break;
+ case '1':
+ type = CSS_LIST_STYLE_TYPE_DECIMAL;
+ break;
+ }
+ }
+
+ if (type != CSS_LIST_STYLE_TYPE_INHERIT) {
+ hint->prop = CSS_PROP_LIST_STYLE_TYPE;
+ hint->status = type;
+ css_hint_advance(&hint);
+ }
+
+ dom_string_unref(attr);
+ }
+}
+
/* Exported function, documeted in css/hints.h */
css_error node_presentational_hint(void *pw, void *node,
@@ -1671,6 +1715,9 @@ css_error node_presentational_hint(void *pw, void *node,
case DOM_HTML_ELEMENT_TYPE_CANVAS:
css_hint_height_width_canvas(pw, node);
break;
+ case DOM_HTML_ELEMENT_TYPE_OL:
+ css_hint_list(pw, node);
+ break;
default:
break;
}
diff --git a/content/handlers/html/box.h b/content/handlers/html/box.h
index d0df73568..1059556e6 100644
--- a/content/handlers/html/box.h
+++ b/content/handlers/html/box.h
@@ -404,6 +404,10 @@ struct box {
*/
struct column *col;
+ /**
+ * List item value.
+ */
+ int list_value;
/**
* List marker box if this is a list-item, or NULL.
diff --git a/content/handlers/html/box_construct.c b/content/handlers/html/box_construct.c
index e2eaf8ca6..7bfc35e44 100644
--- a/content/handlers/html/box_construct.c
+++ b/content/handlers/html/box_construct.c
@@ -366,6 +366,7 @@ box_construct_marker(struct box *box,
{
lwc_string *image_uri;
struct box *marker;
+ enum css_list_style_type_e list_style_type;
marker = box_create(NULL, box->style, false, NULL, NULL, title,
NULL, ctx->bctx);
@@ -374,81 +375,33 @@ box_construct_marker(struct box *box,
marker->type = BOX_BLOCK;
+ list_style_type = css_computed_list_style_type(box->style);
+
/** \todo marker content (list-style-type) */
- switch (css_computed_list_style_type(box->style)) {
+ switch (list_style_type) {
case CSS_LIST_STYLE_TYPE_DISC:
/* 2022 BULLET */
marker->text = (char *) "\342\200\242";
marker->length = 3;
break;
+
case CSS_LIST_STYLE_TYPE_CIRCLE:
/* 25CB WHITE CIRCLE */
marker->text = (char *) "\342\227\213";
marker->length = 3;
break;
+
case CSS_LIST_STYLE_TYPE_SQUARE:
/* 25AA BLACK SMALL SQUARE */
marker->text = (char *) "\342\226\252";
marker->length = 3;
break;
- case CSS_LIST_STYLE_TYPE_DECIMAL:
- case CSS_LIST_STYLE_TYPE_LOWER_ALPHA:
- case CSS_LIST_STYLE_TYPE_LOWER_ROMAN:
- case CSS_LIST_STYLE_TYPE_UPPER_ALPHA:
- case CSS_LIST_STYLE_TYPE_UPPER_ROMAN:
- default:
- if (parent->last) {
- struct box *last = parent->last;
-
- /* Drill down into last child of parent
- * to find the list marker (if any)
- *
- * Floated list boxes end up as:
- *
- * parent
- * BOX_INLINE_CONTAINER
- * BOX_FLOAT_{LEFT,RIGHT}
- * BOX_BLOCK <-- list box
- * ...
- */
- while (last != NULL && last->list_marker == NULL) {
- struct box *last_inner = last;
-
- while (last_inner != NULL) {
- if (last_inner->list_marker != NULL)
- break;
- if (last_inner->type ==
- BOX_INLINE_CONTAINER ||
- last_inner->type ==
- BOX_FLOAT_LEFT ||
- last_inner->type ==
- BOX_FLOAT_RIGHT) {
- last_inner = last_inner->last;
- } else {
- last_inner = NULL;
- }
- }
- if (last_inner != NULL) {
- last = last_inner;
- } else {
- last = last->prev;
- }
- }
- if (last && last->list_marker) {
- marker->rows = last->list_marker->rows + 1;
- }
- }
-
- marker->text = talloc_array(ctx->bctx, char, 20);
- if (marker->text == NULL)
- return false;
-
- snprintf(marker->text, 20, "%u.", marker->rows);
- marker->length = strlen(marker->text);
- break;
+ default:
+ /* Numerical list counters get handled in layout. */
+ /* Fall through. */
case CSS_LIST_STYLE_TYPE_NONE:
- marker->text = 0;
+ marker->text = NULL;
marker->length = 0;
break;
}
diff --git a/content/handlers/html/box_manipulate.c b/content/handlers/html/box_manipulate.c
index d23091b7c..8073a7fd1 100644
--- a/content/handlers/html/box_manipulate.c
+++ b/content/handlers/html/box_manipulate.c
@@ -143,6 +143,7 @@ box_create(css_select_results *styles,
box->float_container = NULL;
box->next_float = NULL;
box->cached_place_below_level = 0;
+ box->list_value = 1;
box->list_marker = NULL;
box->col = NULL;
box->gadget = NULL;
diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index ddf1d1632..c8c0127ad 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -47,6 +47,7 @@
#include "utils/talloc.h"
#include "utils/utils.h"
#include "utils/nsoption.h"
+#include "utils/corestrings.h"
#include "utils/nsurl.h"
#include "netsurf/inttypes.h"
#include "netsurf/content.h"
@@ -4410,36 +4411,426 @@ layout_block_context(struct box *block,
return true;
}
+/**
+ * Get a dom node's element tag type.
+ *
+ * \param[in] node Node to get tag type of.
+ * \param[in] type Returns element tag type on success.
+ * \return true if on success, false otherwise.
+ */
+static bool
+layout__get_element_tag(
+ const dom_node *node,
+ dom_html_element_type *type)
+{
+ dom_html_element_type element_type;
+ dom_node_type node_type;
+ dom_exception exc;
+
+ exc = dom_node_get_node_type(node, &node_type);
+ if (exc != DOM_NO_ERR ||
+ node_type != DOM_ELEMENT_NODE) {
+ return false;
+ }
+
+ exc = dom_html_element_get_tag_type(node, &element_type);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ *type = element_type;
+ return true;
+}
+
+
+/**
+ * Check a node's tag type.
+ *
+ * \param[in] node Node to check tag type of.
+ * \param[in] type Tag type to test for.
+ * \return true if if node has given type, false otherwise.
+ */
+static inline bool
+layout__check_element_type(
+ const dom_node *node,
+ dom_html_element_type type)
+{
+ dom_html_element_type element_type;
+
+ if (!layout__get_element_tag(node, &element_type)) {
+ return false;
+ }
+
+ return element_type == type;
+}
+
+
+/**
+ * Helper to get attribute value from a LI node.
+ *
+ * \param[in] li_node DOM node for the LI element;
+ * \param[out] value_out Returns the value on success.
+ * \return true if node has value, otherwise false.
+ */
+static bool
+layout__get_li_value(dom_node *li_node, dom_long *value_out)
+{
+ dom_exception exc;
+ dom_long value;
+ bool has_value;
+
+ /** \todo
+ * dom_html_li_element_get_value() is rubbish and we can't tell
+ * a lack of value attribute or invalid value from a perfectly
+ * valid '-1'.
+ *
+ * This helps for the common case of no value. However we should
+ * fix libdom to have some kind of sane interface to get numerical
+ * attributes.
+ */
+ exc = dom_element_has_attribute(li_node,
+ corestring_dom_value,
+ &has_value);
+ if (exc != DOM_NO_ERR || has_value == false) {
+ return false;
+ }
+
+ exc = dom_html_li_element_get_value(
+ (dom_html_li_element *)li_node,
+ &value);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ *value_out = value;
+ return true;
+}
+
+
+/**
+ * Helper to get start attribute value from a OL node.
+ *
+ * \param[in] ol_node DOM node for the OL element;
+ * \param[out] start_out Returns the value on success.
+ * \return true if node has value, otherwise false.
+ */
+static bool
+layout__get_ol_start(dom_node *ol_node, dom_long *start_out)
+{
+ dom_exception exc;
+ dom_long start;
+ bool has_start;
+
+ /** \todo
+ * see layout__get_li_value().
+ */
+ exc = dom_element_has_attribute(ol_node,
+ corestring_dom_start,
+ &has_start);
+ if (exc != DOM_NO_ERR || has_start == false) {
+ return false;
+ }
+
+ exc = dom_html_olist_element_get_start(
+ (dom_html_olist_element *)ol_node,
+ &start);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ *start_out = start;
+ return true;
+}
+
+
+/**
+ * Helper to get reversed attribute value from a OL node.
+ *
+ * \param[in] ol_node DOM node for the OL element;
+ * \return true if node has reversed, otherwise false.
+ */
+static bool
+layout__get_ol_reversed(dom_node *ol_node)
+{
+ dom_exception exc;
+ bool has_reversed;
+
+ exc = dom_element_has_attribute(ol_node,
+ corestring_dom_reversed,
+ &has_reversed);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ return has_reversed;
+}
+
+
+/**
+ * Get the number of list items for a list owner.
+ *
+ * \param[in] list_owner DOM node to count list items for.
+ * \param[in] count_out Returns list item count on success.
+ * \return true on success, otherwise false.
+ */
+static bool
+layout__get_list_item_count(
+ dom_node *list_owner, int *count_out)
+{
+ dom_html_element_type tag_type;
+ dom_exception exc;
+ dom_node *child;
+ int count;
+
+ if (list_owner == NULL) {
+ return false;
+ }
+
+ if (!layout__get_element_tag(list_owner, &tag_type)) {
+ return false;
+ }
+
+ if (tag_type != DOM_HTML_ELEMENT_TYPE_OL &&
+ tag_type != DOM_HTML_ELEMENT_TYPE_UL) {
+ return false;
+ }
+
+ exc = dom_node_get_first_child(list_owner, &child);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ count = 0;
+ while (child != NULL) {
+ dom_node *temp_node;
+
+ if (layout__check_element_type(child,
+ DOM_HTML_ELEMENT_TYPE_LI)) {
+ struct box *child_box;
+ if (dom_node_get_user_data(child,
+ corestring_dom___ns_key_box_node_data,
+ &child_box) != DOM_NO_ERR) {
+ dom_node_unref(child);
+ return false;
+ }
+
+ if (child_box != NULL &&
+ child_box->list_marker != NULL) {
+ count++;
+ }
+ }
+
+ exc = dom_node_get_next_sibling(child, &temp_node);
+ dom_node_unref(child);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ child = temp_node;
+ }
+
+ *count_out = count;
+ return true;
+}
+
+
+/**
+ * Handle list item counting, if this is a list owner box.
+ *
+ * \param[in] box Box to do list item counting for.
+ */
+static void
+layout__ordered_list_count(
+ struct box *box)
+{
+ dom_html_element_type tag_type;
+ dom_exception exc;
+ dom_node *child;
+ int step = 1;
+ int next;
+
+ if (box->node == NULL) {
+ return;
+ }
+
+ if (!layout__get_element_tag(box->node, &tag_type)) {
+ return;
+ }
+
+ if (tag_type != DOM_HTML_ELEMENT_TYPE_OL &&
+ tag_type != DOM_HTML_ELEMENT_TYPE_UL) {
+ return;
+ }
+
+ next = 1;
+ if (tag_type == DOM_HTML_ELEMENT_TYPE_OL) {
+ bool have_start = layout__get_ol_start(box->node, &next);
+ bool have_reversed = layout__get_ol_reversed(box->node);
+
+ if (have_reversed) {
+ step = -1;
+ }
+
+ if (!have_start && have_reversed) {
+ layout__get_list_item_count(box->node, &next);
+ }
+ }
+
+ exc = dom_node_get_first_child(box->node, &child);
+ if (exc != DOM_NO_ERR) {
+ return;
+ }
+
+ while (child != NULL) {
+ dom_node *temp_node;
+
+ if (layout__check_element_type(child,
+ DOM_HTML_ELEMENT_TYPE_LI)) {
+ struct box *child_box;
+
+ if (dom_node_get_user_data(child,
+ corestring_dom___ns_key_box_node_data,
+ &child_box) != DOM_NO_ERR) {
+ dom_node_unref(child);
+ return;
+ }
+
+ if (child_box != NULL &&
+ child_box->list_marker != NULL) {
+ dom_long value;
+ struct box *marker = child_box->list_marker;
+ if (layout__get_li_value(child, &value)) {
+ marker->list_value = value;
+ next = marker->list_value;
+ } else {
+ marker->list_value = next;
+ }
+ next += step;
+ }
+ }
+
+ exc = dom_node_get_next_sibling(child, &temp_node);
+ dom_node_unref(child);
+ if (exc != DOM_NO_ERR) {
+ return;
+ }
+
+ child = temp_node;
+ }
+}
+
+/**
+ * Set up the marker text for a numerical list item.
+ *
+ * \param[in] content The HTML content.
+ * \param[in] box The list item's main box.
+ */
+static void
+layout__set_numerical_marker_text(
+ const html_content *content,
+ struct box *box)
+{
+ struct box *marker = box->list_marker;
+ size_t counter_len;
+ css_error css_res;
+ enum {
+ /**
+ * initial length of a list marker buffer
+ *
+ * enough for 9,999,999,999,999,999,999 in decimal
+ * or five characters for 4-byte UTF-8.
+ */
+ LIST_MARKER_SIZE = 20,
+ };
+
+ marker->text = talloc_array(content->bctx, char, LIST_MARKER_SIZE);
+ if (marker->text == NULL) {
+ return;
+ }
+
+ css_res = css_computed_format_list_style(box->style, marker->list_value,
+ marker->text, LIST_MARKER_SIZE, &counter_len);
+ if (css_res == CSS_OK) {
+ if (counter_len > LIST_MARKER_SIZE) {
+ /* Use computed size as marker did not fit in
+ * default allocation. */
+ marker->text = talloc_realloc(content->bctx,
+ marker->text,
+ char,
+ counter_len);
+ if (marker->text == NULL) {
+ return;
+ }
+ css_computed_format_list_style(box->style,
+ marker->list_value, marker->text,
+ counter_len, &counter_len);
+ }
+ marker->length = counter_len;
+ }
+}
+
+/**
+ * Find out if box's style represents a numerical list style type.
+ *
+ * \param[in] b Box with style to test.
+ * \return true if box has numerical list style type, false otherwise.
+ */
+static bool
+layout__list_item_is_numerical(
+ const struct box *b)
+{
+ enum css_list_style_type_e t = css_computed_list_style_type(b->style);
+
+ switch (t) {
+ case CSS_LIST_STYLE_TYPE_DISC: /* Fall through. */
+ case CSS_LIST_STYLE_TYPE_CIRCLE: /* Fall through. */
+ case CSS_LIST_STYLE_TYPE_SQUARE: /* Fall through. */
+ case CSS_LIST_STYLE_TYPE_NONE:
+ return false;
+
+ default:
+ return true;
+ }
+}
/**
* Layout list markers.
*/
static void
-layout_lists(struct box *box,
- const struct gui_layout_table *font_func,
- const nscss_len_ctx *len_ctx)
+layout_lists(const html_content *content, struct box *box)
{
struct box *child;
- struct box *marker;
- plot_font_style_t fstyle;
+
+ layout__ordered_list_count(box);
for (child = box->children; child; child = child->next) {
if (child->list_marker) {
- marker = child->list_marker;
+ struct box *marker = child->list_marker;
+
+ if (layout__list_item_is_numerical(child)) {
+ if (marker->text == NULL) {
+ layout__set_numerical_marker_text(
+ content, child);
+ }
+ }
if (marker->object) {
marker->width =
content_get_width(marker->object);
marker->x = -marker->width;
marker->height =
content_get_height(marker->object);
- marker->y = (line_height(len_ctx,
+ marker->y = (line_height(
+ &content->len_ctx,
marker->style) -
marker->height) / 2;
} else if (marker->text) {
if (marker->width == UNKNOWN_WIDTH) {
- font_plot_style_from_css(len_ctx,
- marker->style, &fstyle);
- font_func->width(&fstyle,
+ plot_font_style_t fstyle;
+ font_plot_style_from_css(
+ &content->len_ctx,
+ marker->style,
+ &fstyle);
+ content->font_func->width(&fstyle,
marker->text,
marker->length,
&marker->width);
@@ -4447,7 +4838,8 @@ layout_lists(struct box *box,
}
marker->x = -marker->width;
marker->y = 0;
- marker->height = line_height(len_ctx,
+ marker->height = line_height(
+ &content->len_ctx,
marker->style);
} else {
marker->x = 0;
@@ -4458,7 +4850,7 @@ layout_lists(struct box *box,
/* Gap between marker and content */
marker->x -= 4;
}
- layout_lists(child, font_func, len_ctx);
+ layout_lists(content, child);
}
}
@@ -5436,7 +5828,7 @@ bool layout_document(html_content *content, int width, int height)
doc->children->margin[BOTTOM]);
}
- layout_lists(doc, font_func, &content->len_ctx);
+ layout_lists(content, doc);
layout_position_absolute(doc, doc, 0, 0, content);
layout_position_relative(&content->len_ctx, doc, doc, 0, 0);
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 6cc3a118f..fd838b80b 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -155,10 +155,10 @@ nserror netsurf_init(const char *store_path)
hlcache_parameters.llcache.fetch_attempts = nsoption_uint(max_retried_fetches);
/* image cache is 25% of total memory cache size */
- image_cache_parameters.limit = (hlcache_parameters.llcache.limit * 25) / 100;
+ image_cache_parameters.limit = hlcache_parameters.llcache.limit / 4;
/* image cache hysteresis is 20% of the image cache size */
- image_cache_parameters.hysteresis = (image_cache_parameters.limit * 20) / 100;
+ image_cache_parameters.hysteresis = image_cache_parameters.limit / 5;
/* account for image cache use from total */
hlcache_parameters.llcache.limit -= image_cache_parameters.limit;
@@ -167,7 +167,7 @@ nserror netsurf_init(const char *store_path)
hlcache_parameters.llcache.store.limit = nsoption_uint(disc_cache_size);
/* set backing store hysterissi to 20% */
- hlcache_parameters.llcache.store.hysteresis = (hlcache_parameters.llcache.store.limit * 20) / 100;;
+ hlcache_parameters.llcache.store.hysteresis = hlcache_parameters.llcache.store.limit / 5;
/* set the path to the backing store */
hlcache_parameters.llcache.store.path =
diff --git a/docs/integration-testing.md b/docs/integration-testing.md
index da93343d2..03b41308a 100644
--- a/docs/integration-testing.md
+++ b/docs/integration-testing.md
@@ -400,9 +400,14 @@ The window to be rendered is identified with the `window` key, the
value of this must be a previously created window identifier or an
assert will occur.
+The `area` key allows control of the area to be redraw. The parameters are on two forms:
+
+ * A sequence of four numbers in the form `x0 y0 x1 y1`
+ * The keyword extent which attempt to plot the entire extent of the canvas
+
An optional list of checks may be specified with the `checks` key. If
any check is not satisfied an assert will occur and the test will
-fail.
+fail. Multiple checks can be specified and all most pass successfully.
The checks available are:
@@ -416,8 +421,10 @@ The checks available are:
- action: plot-check
window: win1
+ area: extent
checks:
- text-contains: NetSurf
+ - text-contains: Browser
- text-not-contains: Chrome
- bitmap-count: 1
diff --git a/frontends/Makefile.hts b/frontends/Makefile.hts
new file mode 100644
index 000000000..b5af240f1
--- /dev/null
+++ b/frontends/Makefile.hts
@@ -0,0 +1,122 @@
+# -*- mode: makefile-gmake -*-
+##
+## determine the HOST TARGET and SUBTARGET
+##
+
+# Determine host type
+# NOTE: HOST determination on RISC OS could fail because of missing bug fixes
+# in UnixLib which only got addressed in UnixLib 5 / GCCSDK 4.
+# When you don't have 'uname' available, you will see:
+# File 'uname' not found
+# When you do and using a 'uname' compiled with a buggy UnixLib, you
+# will see the following printed on screen:
+# RISC OS
+# In both cases HOST make variable is empty and we recover from that by
+# assuming we're building on RISC OS.
+# In case you don't see anything printed (including the warning), you
+# have an up-to-date RISC OS build system. ;-)
+HOST := $(shell uname -s)
+
+# Sanitise host
+# TODO: Ideally, we want the equivalent of s/[^A-Za-z0-9]/_/g here
+HOST := $(subst .,_,$(subst -,_,$(subst /,_,$(HOST))))
+
+ifeq ($(HOST),)
+ HOST := riscos
+ $(warning Build platform determination failed but that's a known problem for RISC OS so we're assuming a native RISC OS build.)
+else
+ ifeq ($(HOST),RISC OS)
+ # Fixup uname -s returning "RISC OS"
+ HOST := riscos
+ endif
+endif
+ifeq ($(HOST),riscos)
+ # Build happening on RO platform, default target is RO backend
+ ifeq ($(TARGET),)
+ TARGET := riscos
+ endif
+endif
+
+ifeq ($(HOST),BeOS)
+ HOST := beos
+endif
+ifeq ($(HOST),Haiku)
+ # Haiku implements the BeOS API
+ HOST := beos
+endif
+ifeq ($(HOST),beos)
+ # Build happening on BeOS platform, default target is BeOS backend
+ ifeq ($(TARGET),)
+ TARGET := beos
+ endif
+ ifeq ($(TARGET),haiku)
+ override TARGET := beos
+ endif
+endif
+
+ifeq ($(HOST),AmigaOS)
+ HOST := amiga
+ ifeq ($(TARGET),)
+ TARGET := amiga
+ endif
+endif
+
+ifeq ($(HOST),FreeMiNT)
+ HOST := mint
+endif
+ifeq ($(HOST),mint)
+ ifeq ($(TARGET),)
+ TARGET := atari
+ endif
+endif
+
+ifeq ($(findstring MINGW,$(HOST)),MINGW)
+ # MSYS' uname reports the likes of "MINGW32_NT-6.0"
+ HOST := windows
+endif
+ifeq ($(HOST),windows)
+ ifeq ($(TARGET),)
+ TARGET := windows
+ endif
+endif
+
+# Setup (sub)targets
+
+# empty default sub target
+SUBTARGET=
+
+# Default target is GTK 3 backend
+ifeq ($(TARGET),)
+ override TARGET := gtk
+ SUBTARGET = 3
+else
+ ifeq ($(TARGET),gtk)
+ # unspecified gtk is gtk3
+ SUBTARGET = 3
+ else
+ ifeq ($(TARGET),gtk3)
+ # gtk3 is gtk target with subtarget of 3
+ override TARGET := gtk
+ SUBTARGET = 3
+ else
+ ifeq ($(TARGET),gtk2)
+ # gtk2 is gtk target with subtarget of 2
+ override TARGET := gtk
+ SUBTARGET = 2
+ else
+ ifeq ($(TARGET),amigaos3)
+ override TARGET := amiga
+ SUBTARGET = os3
+ endif
+ endif
+ endif
+ endif
+endif
+
+# valid values for the TARGET
+VLDTARGET := amiga atari beos framebuffer gtk monkey riscos windows
+
+# Check for valid TARGET
+ifeq ($(filter $(VLDTARGET),$(TARGET)),)
+ $(error Unknown TARGET "$(TARGET)", Must be one of $(VLDTARGET))
+endif
diff --git a/frontends/amiga/Makefile.tools b/frontends/amiga/Makefile.tools
new file mode 100644
index 000000000..c16928783
--- /dev/null
+++ b/frontends/amiga/Makefile.tools
@@ -0,0 +1,21 @@
+# -*- mode: makefile-gmake -*-
+##
+## amiga target tool setup
+##
+
+ifeq ($(findstring amiga,$(HOST)),amiga)
+ # building for amiga on amiga
+ PKG_CONFIG := pkg-config
+else
+ ifeq ($(SUBTARGET),os3)
+ GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-unknown-amigaos/env
+ GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-unknown-amigaos/cross/bin
+ else
+ GCCSDK_INSTALL_ENV ?= /opt/netsurf/ppc-amigaos/env
+ GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/ppc-amigaos/cross/bin
+ endif
+
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+
+ PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
+endif
diff --git a/frontends/amiga/iff_dr2d.c b/frontends/amiga/iff_dr2d.c
index 5de1463f0..624b501ff 100644
--- a/frontends/amiga/iff_dr2d.c
+++ b/frontends/amiga/iff_dr2d.c
@@ -120,6 +120,7 @@ bool ami_svg_to_dr2d(struct IFFHandle *iffh, const char *buffer,
if(!(PushChunk(iffh,0,ID_NAME,IFFSIZE_UNKNOWN)))
{
WriteChunkBytes(iffh,url,strlen(url));
+ WriteChunkBytes(iffh,"\0",1);
PopChunk(iffh);
}
@@ -185,6 +186,7 @@ bool ami_svg_to_dr2d(struct IFFHandle *iffh, const char *buffer,
attr->DashPattern = 1;
attr->EdgeValue = findcolour(diagram->shape[i].stroke);
}
+
attr->EdgeThick = (float) diagram->shape[i].stroke_width;
if(!(PushChunk(iffh,0,ID_ATTR,IFFSIZE_UNKNOWN)))
@@ -281,7 +283,7 @@ bool ami_svg_to_dr2d(struct IFFHandle *iffh, const char *buffer,
if(!(PushChunk(iffh, 0, ID_FONS, IFFSIZE_UNKNOWN)))
{
WriteChunkBytes(iffh, fons, sizeof(struct fons_struct));
- WriteChunkBytes(iffh, "Topaz\0", 6);
+ WriteChunkBytes(iffh, "Helvetica\0", 10);
PopChunk(iffh);
}
free(fons);
diff --git a/frontends/atari/Makefile.tools b/frontends/atari/Makefile.tools
new file mode 100644
index 000000000..971ab21be
--- /dev/null
+++ b/frontends/atari/Makefile.tools
@@ -0,0 +1,19 @@
+# -*- mode: makefile-gmake -*-
+##
+## atari target tool setup
+##
+
+ifeq ($(HOST),atari)
+ PKG_CONFIG := pkg-config
+else
+ ifeq ($(HOST),mint)
+ PKG_CONFIG := pkg-config
+ else
+ GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-atari-mint/env
+ GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-atari-mint/cross/bin
+
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+
+ PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
+ endif
+endif \ No newline at end of file
diff --git a/frontends/beos/Makefile.tools b/frontends/beos/Makefile.tools
new file mode 100644
index 000000000..0324a2825
--- /dev/null
+++ b/frontends/beos/Makefile.tools
@@ -0,0 +1,14 @@
+# -*- mode: makefile-gmake -*-
+##
+## BeOS target tool setup
+##
+
+# Building for BeOS/Haiku
+#ifeq ($(HOST),beos)
+ # Build for BeOS on BeOS
+ GCCSDK_INSTALL_ENV := /boot/develop
+ CC := gcc
+ CXX := g++
+ EXEEXT :=
+ PKG_CONFIG := pkg-config
+#endif
diff --git a/frontends/framebuffer/Makefile.tools b/frontends/framebuffer/Makefile.tools
new file mode 100644
index 000000000..80623b164
--- /dev/null
+++ b/frontends/framebuffer/Makefile.tools
@@ -0,0 +1,15 @@
+# -*- mode: makefile-gmake -*-
+##
+## tool setup for the framebuffer target
+##
+
+ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
+ PKG_CONFIG := pkg-config
+else
+ PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
+endif
+
+ifneq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+ CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
+endif
diff --git a/frontends/gtk/Makefile b/frontends/gtk/Makefile
index 3bf3ea063..4f3fd5f52 100644
--- a/frontends/gtk/Makefile
+++ b/frontends/gtk/Makefile
@@ -166,11 +166,11 @@ endif
# ----------------------------------------------------------------------------
# S_FRONTEND are sources purely for the GTK frontend
-S_FRONTEND := gui.c schedule.c layout_pango.c bitmap.c plotters.c \
- scaffolding.c gdk.c completion.c throbber.c accelerator.c \
- selection.c window.c fetch.c download.c menu.c print.c \
- search.c tabs.c toolbar.c gettext.c compat.c viewdata.c \
- viewsource.c preferences.c about.c resources.c corewindow.c \
+S_FRONTEND := gui.c misc.c schedule.c layout_pango.c bitmap.c plotters.c \
+ scaffolding.c gdk.c completion.c throbber.c accelerator.c \
+ selection.c window.c fetch.c download.c menu.c print.c \
+ search.c tabs.c toolbar.c gettext.c compat.c viewdata.c \
+ viewsource.c preferences.c about.c resources.c corewindow.c \
local_history.c global_history.c cookies.c hotlist.c page_info.c
# This is the final source build list
diff --git a/frontends/gtk/Makefile.tools b/frontends/gtk/Makefile.tools
new file mode 100644
index 000000000..5331dcc71
--- /dev/null
+++ b/frontends/gtk/Makefile.tools
@@ -0,0 +1,16 @@
+# -*- mode: makefile-gmake -*-
+##
+## tool setup for the gtk target
+##
+
+# use native package config
+PKG_CONFIG := pkg-config
+
+# gtk target processing
+ifeq ($(SUBTARGET),3)
+ override NETSURF_GTK_MAJOR := 3
+endif
+
+ifeq ($(SUBTARGET),2)
+ override NETSURF_GTK_MAJOR := 2
+endif
diff --git a/frontends/gtk/corewindow.c b/frontends/gtk/corewindow.c
index b3568c602..baa4cf155 100644
--- a/frontends/gtk/corewindow.c
+++ b/frontends/gtk/corewindow.c
@@ -87,6 +87,7 @@ static browser_mouse_state nsgtk_cw_gdkbutton_to_nsstate(GdkEventButton *event)
}
if (event->state & GDK_MOD1_MASK) {
+ /* usually alt */
ms |= BROWSER_MOUSE_MOD_3;
}
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index e5006d954..a826b053a 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -43,12 +43,10 @@
#include "netsurf/cookie_db.h"
#include "netsurf/browser.h"
#include "netsurf/browser_window.h"
-#include "netsurf/misc.h"
#include "netsurf/netsurf.h"
#include "content/fetch.h"
#include "content/backing_store.h"
#include "desktop/save_complete.h"
-#include "desktop/save_pdf.h"
#include "desktop/searchweb.h"
#include "desktop/hotlist.h"
@@ -70,34 +68,183 @@
#include "gtk/selection.h"
#include "gtk/search.h"
#include "gtk/bitmap.h"
+#include "gtk/misc.h"
#include "gtk/resources.h"
#include "gtk/layout_pango.h"
#include "gtk/accelerator.h"
bool nsgtk_complete = false;
-char *nsgtk_config_home; /* exported global defined in gtk/gui.h */
+/* exported global defined in gtk/gui.h */
+char *nsgtk_config_home;
-GdkPixbuf *favicon_pixbuf; /** favicon default pixbuf */
-GdkPixbuf *win_default_icon_pixbuf; /** default window icon pixbuf */
+/** favicon default pixbuf */
+GdkPixbuf *favicon_pixbuf;
+
+/** default window icon pixbuf */
+GdkPixbuf *win_default_icon_pixbuf;
GtkBuilder *warning_builder;
-char **respaths; /** resource search path vector */
+/** resource search path vector */
+char **respaths;
-/**
- * Cause an abnormal program termination.
- *
- * \note This never returns and is intended to terminate without any cleanup.
- *
- * \param error The message to display to the user.
- */
-static void die(const char * const error)
+
+/* exported function documented in gtk/warn.h */
+nserror nsgtk_warning(const char *warning, const char *detail)
{
- fprintf(stderr, "%s", error);
- exit(EXIT_FAILURE);
+ char buf[300]; /* 300 is the size the RISC OS GUI uses */
+ static GtkWindow *nsgtk_warning_window;
+ GtkLabel *WarningLabel;
+
+ NSLOG(netsurf, INFO, "%s %s", warning, detail ? detail : "");
+ fflush(stdout);
+
+ nsgtk_warning_window = GTK_WINDOW(gtk_builder_get_object(warning_builder, "wndWarning"));
+ WarningLabel = GTK_LABEL(gtk_builder_get_object(warning_builder,
+ "labelWarning"));
+
+ snprintf(buf, sizeof(buf), "%s %s", messages_get(warning),
+ detail ? detail : "");
+ buf[sizeof(buf) - 1] = 0;
+
+ gtk_label_set_text(WarningLabel, buf);
+
+ gtk_widget_show_all(GTK_WIDGET(nsgtk_warning_window));
+
+ return NSERROR_OK;
}
+
+/* exported interface documented in gtk/gui.h */
+uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
+{
+ /* this function will need to become much more complex to support
+ * everything that the RISC OS version does. But this will do for
+ * now. I hope.
+ */
+ switch (key->keyval) {
+
+ case GDK_KEY(Tab):
+ return NS_KEY_TAB;
+
+ case GDK_KEY(BackSpace):
+ if (key->state & GDK_SHIFT_MASK)
+ return NS_KEY_DELETE_LINE_START;
+ else
+ return NS_KEY_DELETE_LEFT;
+
+ case GDK_KEY(Delete):
+ if (key->state & GDK_SHIFT_MASK)
+ return NS_KEY_DELETE_LINE_END;
+ else
+ return NS_KEY_DELETE_RIGHT;
+
+ case GDK_KEY(Linefeed):
+ return 13;
+
+ case GDK_KEY(Return):
+ return 10;
+
+ case GDK_KEY(Left):
+ case GDK_KEY(KP_Left):
+ return NS_KEY_LEFT;
+
+ case GDK_KEY(Right):
+ case GDK_KEY(KP_Right):
+ return NS_KEY_RIGHT;
+
+ case GDK_KEY(Up):
+ case GDK_KEY(KP_Up):
+ return NS_KEY_UP;
+
+ case GDK_KEY(Down):
+ case GDK_KEY(KP_Down):
+ return NS_KEY_DOWN;
+
+ case GDK_KEY(Home):
+ case GDK_KEY(KP_Home):
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_LINE_START;
+ else
+ return NS_KEY_TEXT_START;
+
+ case GDK_KEY(End):
+ case GDK_KEY(KP_End):
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_LINE_END;
+ else
+ return NS_KEY_TEXT_END;
+
+ case GDK_KEY(Page_Up):
+ case GDK_KEY(KP_Page_Up):
+ return NS_KEY_PAGE_UP;
+
+ case GDK_KEY(Page_Down):
+ case GDK_KEY(KP_Page_Down):
+ return NS_KEY_PAGE_DOWN;
+
+ case 'a':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_SELECT_ALL;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'u':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_DELETE_LINE;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'c':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_COPY_SELECTION;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'v':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_PASTE;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'x':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_CUT_SELECTION;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'Z':
+ case 'y':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_REDO;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'z':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_UNDO;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case GDK_KEY(Escape):
+ return NS_KEY_ESCAPE;
+
+ /* Modifiers - do nothing for now */
+ case GDK_KEY(Shift_L):
+ case GDK_KEY(Shift_R):
+ case GDK_KEY(Control_L):
+ case GDK_KEY(Control_R):
+ case GDK_KEY(Caps_Lock):
+ case GDK_KEY(Shift_Lock):
+ case GDK_KEY(Meta_L):
+ case GDK_KEY(Meta_R):
+ case GDK_KEY(Alt_L):
+ case GDK_KEY(Alt_R):
+ case GDK_KEY(Super_L):
+ case GDK_KEY(Super_R):
+ case GDK_KEY(Hyper_L):
+ case GDK_KEY(Hyper_R):
+ return 0;
+
+ }
+ return gdk_keyval_to_unicode(key->keyval);
+}
+
+
/**
* Create an array of valid paths to search for resources.
*
@@ -156,6 +303,176 @@ nsgtk_init_resource_path(const char *config_home)
/**
+ * create directory name and check it is acessible and a directory.
+ */
+static nserror
+check_dirname(const char *path, const char *leaf, char **dirname_out)
+{
+ nserror ret;
+ char *dirname = NULL;
+ struct stat dirname_stat;
+
+ ret = netsurf_mkpath(&dirname, NULL, 2, path, leaf);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* ensure access is possible and the entry is actualy
+ * a directory.
+ */
+ if (stat(dirname, &dirname_stat) == 0) {
+ if (S_ISDIR(dirname_stat.st_mode)) {
+ if (access(dirname, R_OK | W_OK) == 0) {
+ *dirname_out = dirname;
+ return NSERROR_OK;
+ } else {
+ ret = NSERROR_PERMISSION;
+ }
+ } else {
+ ret = NSERROR_NOT_DIRECTORY;
+ }
+ } else {
+ ret = NSERROR_NOT_FOUND;
+ }
+
+ free(dirname);
+
+ return ret;
+}
+
+
+/**
+ * Get the path to the config directory.
+ *
+ * @param config_home_out Path to configuration directory.
+ * @return NSERROR_OK on sucess and \a config_home_out updated else error code.
+ */
+static nserror get_config_home(char **config_home_out)
+{
+ nserror ret;
+ char *home_dir;
+ char *xdg_config_dir;
+ char *config_home;
+
+ home_dir = getenv("HOME");
+
+ /* The old $HOME/.netsurf/ directory should be used if it
+ * exists and is accessible.
+ */
+ if (home_dir != NULL) {
+ ret = check_dirname(home_dir, ".netsurf", &config_home);
+ if (ret == NSERROR_OK) {
+ NSLOG(netsurf, INFO, "\"%s\"", config_home);
+ *config_home_out = config_home;
+ return ret;
+ }
+ }
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ /* If $XDG_CONFIG_HOME is either not set or empty, a
+ * default equal to $HOME/.config should be used.
+ */
+
+ /** @todo the meaning of empty is never defined so I
+ * am assuming it is a zero length string but is it
+ * supposed to mean "whitespace" and if so what counts
+ * as whitespace? (are tabs etc. counted or should
+ * isspace() be used)
+ */
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".config/netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_config_dir, "netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ NSLOG(netsurf, INFO, "\"%s\"", config_home);
+
+ *config_home_out = config_home;
+ return NSERROR_OK;
+}
+
+
+static nserror create_config_home(char **config_home_out)
+{
+ char *config_home = NULL;
+ char *home_dir;
+ char *xdg_config_dir;
+ nserror ret;
+
+ NSLOG(netsurf, INFO, "Attempting to create configuration directory");
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = netsurf_mkpath(&config_home, NULL, 4, home_dir, ".config","netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = netsurf_mkpath(&config_home, NULL, 3, xdg_config_dir, "netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = netsurf_mkdir_all(config_home);
+ if (ret != NSERROR_OK) {
+ free(config_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ config_home[strlen(config_home) - 1] = 0;
+
+ NSLOG(netsurf, INFO, "\"%s\"", config_home);
+
+ *config_home_out = config_home;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Ensures output logging stream is correctly configured
+ */
+static bool nslog_stream_configure(FILE *fptr)
+{
+ /* set log stream to be non-buffering */
+ setbuf(fptr, NULL);
+
+ return true;
+}
+
+
+/**
* Set option defaults for gtk frontend.
*
* \param defaults The option table to update.
@@ -250,7 +567,7 @@ static nserror set_defaults(struct nsoption_s *defaults)
/* set default items in toolbar */
nsoption_set_charp(toolbar_items,
- strdup("back/history/forward/reloadstop/url_bar/websearch/openmenu"));
+ strdup("back/history/forward/reloadstop/url_bar/websearch/openmenu"));
/* set default for menu and tool bar visibility */
nsoption_set_charp(bar_show, strdup("tool"));
@@ -258,6 +575,253 @@ static nserror set_defaults(struct nsoption_s *defaults)
return NSERROR_OK;
}
+
+/**
+ * Initialise user options
+ *
+ * Initialise the browser configuration options. These are set by:
+ * - set generic defaults suitable for the gtk frontend
+ * - user choices loaded from Choices file
+ * - command line parameters
+ */
+static nserror nsgtk_option_init(int *pargc, char** argv)
+{
+ nserror ret;
+ char *choices = NULL;
+
+ /* user options setup */
+ ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* Attempt to load the user choices */
+ ret = netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
+ if (ret == NSERROR_OK) {
+ nsoption_read(choices, nsoptions);
+ free(choices);
+ }
+
+ /* overide loaded options with those from commandline */
+ nsoption_commandline(pargc, argv, nsoptions);
+
+ /* ensure all options fall within sensible bounds */
+
+ /* Attempt to handle nonsense status bar widths. These may exist
+ * in people's Choices as the GTK front end used to abuse the
+ * status bar width option by using it for an absolute value in px.
+ * The GTK front end now correctly uses it as a proportion of window
+ * width. Here we assume that a value of less than 15% is wrong
+ * and set to the default two thirds. */
+ if (nsoption_int(toolbar_status_size) < 1500) {
+ nsoption_set_int(toolbar_status_size, 6667);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * initialise message translation
+ */
+static nserror nsgtk_messages_init(char **respaths)
+{
+ const char *messages;
+ nserror ret;
+ const uint8_t *data;
+ size_t data_size;
+
+ ret = nsgtk_data_from_resname("Messages", &data, &data_size);
+ if (ret == NSERROR_OK) {
+ ret = messages_add_from_inline(data, data_size);
+ } else {
+ /* Obtain path to messages */
+ ret = nsgtk_path_from_resname("Messages", &messages);
+ if (ret == NSERROR_OK) {
+ ret = messages_add_from_file(messages);
+ }
+ }
+ return ret;
+}
+
+
+/**
+ * Get the path to the cache directory.
+ *
+ * @param cache_home_out Path to cache directory.
+ * @return NSERROR_OK on sucess and \a cache_home_out updated else error code.
+ */
+static nserror get_cache_home(char **cache_home_out)
+{
+ nserror ret;
+ char *xdg_cache_dir;
+ char *cache_home;
+ char *home_dir;
+
+ /* $XDG_CACHE_HOME defines the base directory relative to
+ * which user specific non-essential data files should be
+ * stored.
+ */
+ xdg_cache_dir = getenv("XDG_CACHE_HOME");
+
+ if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
+ /* If $XDG_CACHE_HOME is either not set or empty, a
+ * default equal to $HOME/.cache should be used.
+ */
+
+ home_dir = getenv("HOME");
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".cache/netsurf", &cache_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_cache_dir, "netsurf", &cache_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ NSLOG(netsurf, INFO, "\"%s\"", cache_home);
+
+ *cache_home_out = cache_home;
+ return NSERROR_OK;
+}
+
+
+/**
+ * create a cache directory
+ */
+static nserror create_cache_home(char **cache_home_out)
+{
+ char *cache_home = NULL;
+ char *home_dir;
+ char *xdg_cache_dir;
+ nserror ret;
+
+ NSLOG(netsurf, INFO, "Attempting to create cache directory");
+
+ /* $XDG_CACHE_HOME defines the base directory
+ * relative to which user specific cache files
+ * should be stored.
+ */
+ xdg_cache_dir = getenv("XDG_CACHE_HOME");
+
+ if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = netsurf_mkpath(&cache_home, NULL, 4, home_dir, ".cache", "netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = netsurf_mkpath(&cache_home, NULL, 3, xdg_cache_dir, "netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = netsurf_mkdir_all(cache_home);
+ if (ret != NSERROR_OK) {
+ free(cache_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ cache_home[strlen(cache_home) - 1] = 0;
+
+ NSLOG(netsurf, INFO, "\"%s\"", cache_home);
+
+ *cache_home_out = cache_home;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * GTK specific initialisation
+ */
+static nserror nsgtk_init(int *pargc, char ***pargv, char **cache_home)
+{
+ nserror ret;
+
+ /* Locate the correct user configuration directory path */
+ ret = get_config_home(&nsgtk_config_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no config directory exists yet so try to create one */
+ ret = create_config_home(&nsgtk_config_home);
+ }
+ if (ret != NSERROR_OK) {
+ NSLOG(netsurf, INFO,
+ "Unable to locate a configuration directory.");
+ nsgtk_config_home = NULL;
+ }
+
+ /* Initialise gtk */
+ gtk_init(pargc, pargv);
+
+ /* initialise logging. Not fatal if it fails but not much we
+ * can do about it either.
+ */
+ nslog_init(nslog_stream_configure, pargc, *pargv);
+
+ /* build the common resource path list */
+ respaths = nsgtk_init_resource_path(nsgtk_config_home);
+ if (respaths == NULL) {
+ fprintf(stderr, "Unable to locate resources\n");
+ return 1;
+ }
+
+ /* initialise the gtk resource handling */
+ ret = nsgtk_init_resources(respaths);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "GTK resources failed to initialise (%s)\n",
+ messages_get_errorcode(ret));
+ return ret;
+ }
+
+ /* Initialise user options */
+ ret = nsgtk_option_init(pargc, *pargv);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "Options failed to initialise (%s)\n",
+ messages_get_errorcode(ret));
+ return ret;
+ }
+
+ /* Initialise translated messages */
+ ret = nsgtk_messages_init(respaths);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "Unable to load translated messages (%s)\n",
+ messages_get_errorcode(ret));
+ NSLOG(netsurf, INFO, "Unable to load translated messages");
+ /** \todo decide if message load faliure should be fatal */
+ }
+
+ /* Locate the correct user cache directory path */
+ ret = get_cache_home(cache_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no cache directory exists yet so try to create one */
+ ret = create_cache_home(cache_home);
+ }
+ if (ret != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Unable to locate a cache directory.");
+ }
+
+
+ return NSERROR_OK;
+}
+
+
#if GTK_CHECK_VERSION(3,14,0)
/**
@@ -266,7 +830,7 @@ static nserror set_defaults(struct nsoption_s *defaults)
static nserror nsgtk_add_named_icons_to_theme(void)
{
gtk_icon_theme_add_resource_path(gtk_icon_theme_get_default(),
- "/org/netsurf/icons");
+ "/org/netsurf/icons");
return NSERROR_OK;
}
@@ -280,7 +844,7 @@ add_builtin_icon(const char *prefix, const char *name, int x, int y)
char *resname;
int resnamelen;
- /* resource name string length allowing for / .png and termination */
+ /* resource name string length allowing for / .png and termination */
resnamelen = strlen(prefix) + strlen(name) + 5 + 1 + 4 + 1;
resname = malloc(resnamelen);
if (resname == NULL) {
@@ -299,13 +863,14 @@ add_builtin_icon(const char *prefix, const char *name, int x, int y)
return NSERROR_OK;
}
+
/**
* adds named icons into gtk theme
*/
static nserror nsgtk_add_named_icons_to_theme(void)
{
/* these must also be in gtk/resources.c pixbuf_resource *and*
- * gtk/res/netsurf.gresource.xml
+ * gtk/res/netsurf.gresource.xml
*/
add_builtin_icon("", "local-history", 8, 32);
add_builtin_icon("", "show-cookie", 24, 24);
@@ -327,13 +892,13 @@ static nserror nsgtk_add_named_icons_to_theme(void)
/**
- * Initialize GTK specific parts of the browser.
+ * setup GTK specific parts of the browser.
*
* \param argc The number of arguments on the command line
* \param argv A string vector of command line arguments.
* \respath A string vector of the path elements of resources
*/
-static nserror nsgtk_init(int argc, char** argv, char **respath)
+static nserror nsgtk_setup(int argc, char** argv, char **respath)
{
char buf[PATH_MAX];
char *resource_filename;
@@ -467,19 +1032,6 @@ static nserror nsgtk_init(int argc, char** argv, char **respath)
}
-
-/**
- * Ensures output logging stream is correctly configured
- */
-static bool nslog_stream_configure(FILE *fptr)
-{
- /* set log stream to be non-buffering */
- setbuf(fptr, NULL);
-
- return true;
-}
-
-
/**
* Run the gtk event loop.
*
@@ -540,7 +1092,10 @@ static void nsgtk_main(void)
}
-static void gui_quit(void)
+/**
+ * finalise the browser
+ */
+static void nsgtk_finalise(void)
{
nserror res;
@@ -592,630 +1147,28 @@ static void gui_quit(void)
free(nsgtk_config_home);
gtk_fetch_filetype_fin();
-}
-
-static nserror gui_launch_url(struct nsurl *url)
-{
- gboolean ok;
- GError *error = NULL;
- ok = nsgtk_show_uri(NULL, nsurl_access(url), GDK_CURRENT_TIME, &error);
- if (ok == TRUE) {
- return NSERROR_OK;
- }
-
- if (error) {
- nsgtk_warning(messages_get("URIOpenError"), error->message);
- g_error_free(error);
- }
- return NSERROR_NO_FETCH_HANDLER;
-}
-
-/* exported function documented in gtk/warn.h */
-nserror nsgtk_warning(const char *warning, const char *detail)
-{
- char buf[300]; /* 300 is the size the RISC OS GUI uses */
- static GtkWindow *nsgtk_warning_window;
- GtkLabel *WarningLabel;
-
- NSLOG(netsurf, INFO, "%s %s", warning, detail ? detail : "");
- fflush(stdout);
-
- nsgtk_warning_window = GTK_WINDOW(gtk_builder_get_object(warning_builder, "wndWarning"));
- WarningLabel = GTK_LABEL(gtk_builder_get_object(warning_builder,
- "labelWarning"));
-
- snprintf(buf, sizeof(buf), "%s %s", messages_get(warning),
- detail ? detail : "");
- buf[sizeof(buf) - 1] = 0;
-
- gtk_label_set_text(WarningLabel, buf);
-
- gtk_widget_show_all(GTK_WIDGET(nsgtk_warning_window));
-
- return NSERROR_OK;
-}
-
-
-static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data)
-{
- char **owner_pass = ((void **)data)[0];
- char **user_pass = ((void **)data)[1];
- GtkWindow *wnd = ((void **)data)[2];
- GtkBuilder *password_builder = ((void **)data)[3];
- char *path = ((void **)data)[4];
-
- char *op, *op1;
- char *up, *up1;
-
- op = strdup(gtk_entry_get_text(
- GTK_ENTRY(gtk_builder_get_object(password_builder,
- "entryPDFOwnerPassword"))));
- op1 = strdup(gtk_entry_get_text(
- GTK_ENTRY(gtk_builder_get_object(password_builder,
- "entryPDFOwnerPassword1"))));
- up = strdup(gtk_entry_get_text(
- GTK_ENTRY(gtk_builder_get_object(password_builder,
- "entryPDFUserPassword"))));
- up1 = strdup(gtk_entry_get_text(
- GTK_ENTRY(gtk_builder_get_object(password_builder,
- "entryPDFUserPassword1"))));
-
-
- if (op[0] == '\0') {
- gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
- "labelInfo")),
- "Owner password must be at least 1 character long:");
- free(op);
- free(up);
- } else if (!strcmp(op, up)) {
- gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
- "labelInfo")),
- "User and owner passwords must be different:");
- free(op);
- free(up);
- } else if (!strcmp(op, op1) && !strcmp(up, up1)) {
-
- *owner_pass = op;
- if (up[0] == '\0')
- free(up);
- else
- *user_pass = up;
-
- free(data);
- gtk_widget_destroy(GTK_WIDGET(wnd));
- g_object_unref(G_OBJECT(password_builder));
-
- save_pdf(path);
-
- free(path);
- } else {
- gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
- "labelInfo")), "Passwords not confirmed:");
- free(op);
- free(up);
- }
-
- free(op1);
- free(up1);
-}
-
-static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data)
-{
- GtkWindow *wnd = ((void **)data)[2];
- GtkBuilder *password_builder = ((void **)data)[3];
- char *path = ((void **)data)[4];
-
- free(data);
-
- gtk_widget_destroy(GTK_WIDGET(wnd));
- g_object_unref(G_OBJECT(password_builder));
-
- save_pdf(path);
-
- free(path);
-}
-
-static void nsgtk_pdf_password(char **owner_pass, char **user_pass, char *path)
-{
- GtkButton *ok, *no;
- GtkWindow *wnd;
- void **data;
- GtkBuilder *password_builder;
- nserror res;
-
- res = nsgtk_builder_new_from_resname("password", &password_builder);
- if (res != NSERROR_OK) {
- NSLOG(netsurf, INFO, "Password UI builder init failed");
- return;
- }
-
- gtk_builder_connect_signals(password_builder, NULL);
-
- wnd = GTK_WINDOW(gtk_builder_get_object(password_builder,
- "wndPDFPassword"));
-
- data = malloc(5 * sizeof(void *));
-
- *owner_pass = NULL;
- *user_pass = NULL;
-
- data[0] = owner_pass;
- data[1] = user_pass;
- data[2] = wnd;
- data[3] = password_builder;
- data[4] = path;
-
- ok = GTK_BUTTON(gtk_builder_get_object(password_builder,
- "buttonPDFSetPassword"));
- no = GTK_BUTTON(gtk_builder_get_object(password_builder,
- "buttonPDFNoPassword"));
-
- g_signal_connect(G_OBJECT(ok), "clicked",
- G_CALLBACK(nsgtk_PDF_set_pass), (gpointer)data);
- g_signal_connect(G_OBJECT(no), "clicked",
- G_CALLBACK(nsgtk_PDF_no_pass), (gpointer)data);
-
- gtk_widget_show(GTK_WIDGET(wnd));
-}
-
-
-uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
-{
- /* this function will need to become much more complex to support
- * everything that the RISC OS version does. But this will do for
- * now. I hope.
- */
- switch (key->keyval) {
-
- case GDK_KEY(Tab):
- return NS_KEY_TAB;
-
- case GDK_KEY(BackSpace):
- if (key->state & GDK_SHIFT_MASK)
- return NS_KEY_DELETE_LINE_START;
- else
- return NS_KEY_DELETE_LEFT;
-
- case GDK_KEY(Delete):
- if (key->state & GDK_SHIFT_MASK)
- return NS_KEY_DELETE_LINE_END;
- else
- return NS_KEY_DELETE_RIGHT;
-
- case GDK_KEY(Linefeed):
- return 13;
-
- case GDK_KEY(Return):
- return 10;
-
- case GDK_KEY(Left):
- case GDK_KEY(KP_Left):
- return NS_KEY_LEFT;
-
- case GDK_KEY(Right):
- case GDK_KEY(KP_Right):
- return NS_KEY_RIGHT;
-
- case GDK_KEY(Up):
- case GDK_KEY(KP_Up):
- return NS_KEY_UP;
-
- case GDK_KEY(Down):
- case GDK_KEY(KP_Down):
- return NS_KEY_DOWN;
-
- case GDK_KEY(Home):
- case GDK_KEY(KP_Home):
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_LINE_START;
- else
- return NS_KEY_TEXT_START;
-
- case GDK_KEY(End):
- case GDK_KEY(KP_End):
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_LINE_END;
- else
- return NS_KEY_TEXT_END;
-
- case GDK_KEY(Page_Up):
- case GDK_KEY(KP_Page_Up):
- return NS_KEY_PAGE_UP;
-
- case GDK_KEY(Page_Down):
- case GDK_KEY(KP_Page_Down):
- return NS_KEY_PAGE_DOWN;
-
- case 'a':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_SELECT_ALL;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'u':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_DELETE_LINE;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'c':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_COPY_SELECTION;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'v':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_PASTE;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'x':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_CUT_SELECTION;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'Z':
- case 'y':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_REDO;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'z':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_UNDO;
- return gdk_keyval_to_unicode(key->keyval);
-
- case GDK_KEY(Escape):
- return NS_KEY_ESCAPE;
-
- /* Modifiers - do nothing for now */
- case GDK_KEY(Shift_L):
- case GDK_KEY(Shift_R):
- case GDK_KEY(Control_L):
- case GDK_KEY(Control_R):
- case GDK_KEY(Caps_Lock):
- case GDK_KEY(Shift_Lock):
- case GDK_KEY(Meta_L):
- case GDK_KEY(Meta_R):
- case GDK_KEY(Alt_L):
- case GDK_KEY(Alt_R):
- case GDK_KEY(Super_L):
- case GDK_KEY(Super_R):
- case GDK_KEY(Hyper_L):
- case GDK_KEY(Hyper_R):
- return 0;
-
- }
- return gdk_keyval_to_unicode(key->keyval);
-}
-
-
-/**
- * create directory name and check it is acessible and a directory.
- */
-static nserror
-check_dirname(const char *path, const char *leaf, char **dirname_out)
-{
- nserror ret;
- char *dirname = NULL;
- struct stat dirname_stat;
-
- ret = netsurf_mkpath(&dirname, NULL, 2, path, leaf);
- if (ret != NSERROR_OK) {
- return ret;
- }
-
- /* ensure access is possible and the entry is actualy
- * a directory.
- */
- if (stat(dirname, &dirname_stat) == 0) {
- if (S_ISDIR(dirname_stat.st_mode)) {
- if (access(dirname, R_OK | W_OK) == 0) {
- *dirname_out = dirname;
- return NSERROR_OK;
- } else {
- ret = NSERROR_PERMISSION;
- }
- } else {
- ret = NSERROR_NOT_DIRECTORY;
- }
- } else {
- ret = NSERROR_NOT_FOUND;
- }
-
- free(dirname);
-
- return ret;
-}
-
-/**
- * Get the path to the config directory.
- *
- * @param config_home_out Path to configuration directory.
- * @return NSERROR_OK on sucess and \a config_home_out updated else error code.
- */
-static nserror get_config_home(char **config_home_out)
-{
- nserror ret;
- char *home_dir;
- char *xdg_config_dir;
- char *config_home;
-
- home_dir = getenv("HOME");
-
- /* The old $HOME/.netsurf/ directory should be used if it
- * exists and is accessible.
- */
- if (home_dir != NULL) {
- ret = check_dirname(home_dir, ".netsurf", &config_home);
- if (ret == NSERROR_OK) {
- NSLOG(netsurf, INFO, "\"%s\"", config_home);
- *config_home_out = config_home;
- return ret;
- }
- }
-
- /* $XDG_CONFIG_HOME defines the base directory
- * relative to which user specific configuration files
- * should be stored.
- */
- xdg_config_dir = getenv("XDG_CONFIG_HOME");
-
- if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
- /* If $XDG_CONFIG_HOME is either not set or empty, a
- * default equal to $HOME/.config should be used.
- */
-
- /** @todo the meaning of empty is never defined so I
- * am assuming it is a zero length string but is it
- * supposed to mean "whitespace" and if so what counts
- * as whitespace? (are tabs etc. counted or should
- * isspace() be used)
- */
-
- /* the HOME envvar is required */
- if (home_dir == NULL) {
- return NSERROR_NOT_DIRECTORY;
- }
-
- ret = check_dirname(home_dir, ".config/netsurf", &config_home);
- if (ret != NSERROR_OK) {
- return ret;
- }
- } else {
- ret = check_dirname(xdg_config_dir, "netsurf", &config_home);
- if (ret != NSERROR_OK) {
- return ret;
- }
- }
-
- NSLOG(netsurf, INFO, "\"%s\"", config_home);
-
- *config_home_out = config_home;
- return NSERROR_OK;
-}
-
-static nserror create_config_home(char **config_home_out)
-{
- char *config_home = NULL;
- char *home_dir;
- char *xdg_config_dir;
- nserror ret;
-
- NSLOG(netsurf, INFO, "Attempting to create configuration directory");
-
- /* $XDG_CONFIG_HOME defines the base directory
- * relative to which user specific configuration files
- * should be stored.
- */
- xdg_config_dir = getenv("XDG_CONFIG_HOME");
-
- if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
- home_dir = getenv("HOME");
-
- if ((home_dir == NULL) || (*home_dir == 0)) {
- return NSERROR_NOT_DIRECTORY;
- }
-
- ret = netsurf_mkpath(&config_home, NULL, 4, home_dir, ".config","netsurf", "/");
- if (ret != NSERROR_OK) {
- return ret;
- }
- } else {
- ret = netsurf_mkpath(&config_home, NULL, 3, xdg_config_dir, "netsurf", "/");
- if (ret != NSERROR_OK) {
- return ret;
- }
- }
-
- /* ensure all elements of path exist (the trailing / is required) */
- ret = netsurf_mkdir_all(config_home);
- if (ret != NSERROR_OK) {
- free(config_home);
- return ret;
- }
-
- /* strip the trailing separator */
- config_home[strlen(config_home) - 1] = 0;
-
- NSLOG(netsurf, INFO, "\"%s\"", config_home);
-
- *config_home_out = config_home;
-
- return NSERROR_OK;
-}
-
-/**
- * Get the path to the cache directory.
- *
- * @param cache_home_out Path to cache directory.
- * @return NSERROR_OK on sucess and \a cache_home_out updated else error code.
- */
-static nserror get_cache_home(char **cache_home_out)
-{
- nserror ret;
- char *xdg_cache_dir;
- char *cache_home;
- char *home_dir;
-
- /* $XDG_CACHE_HOME defines the base directory relative to
- * which user specific non-essential data files should be
- * stored.
- */
- xdg_cache_dir = getenv("XDG_CACHE_HOME");
-
- if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
- /* If $XDG_CACHE_HOME is either not set or empty, a
- * default equal to $HOME/.cache should be used.
- */
-
- home_dir = getenv("HOME");
-
- /* the HOME envvar is required */
- if (home_dir == NULL) {
- return NSERROR_NOT_DIRECTORY;
- }
-
- ret = check_dirname(home_dir, ".cache/netsurf", &cache_home);
- if (ret != NSERROR_OK) {
- return ret;
- }
- } else {
- ret = check_dirname(xdg_cache_dir, "netsurf", &cache_home);
- if (ret != NSERROR_OK) {
- return ret;
- }
- }
-
- NSLOG(netsurf, INFO, "\"%s\"", cache_home);
-
- *cache_home_out = cache_home;
- return NSERROR_OK;
-}
-
-static nserror create_cache_home(char **cache_home_out)
-{
- char *cache_home = NULL;
- char *home_dir;
- char *xdg_cache_dir;
- nserror ret;
-
- NSLOG(netsurf, INFO, "Attempting to create configuration directory");
-
- /* $XDG_CACHE_HOME defines the base directory
- * relative to which user specific cache files
- * should be stored.
- */
- xdg_cache_dir = getenv("XDG_CACHE_HOME");
-
- if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
- home_dir = getenv("HOME");
-
- if ((home_dir == NULL) || (*home_dir == 0)) {
- return NSERROR_NOT_DIRECTORY;
- }
-
- ret = netsurf_mkpath(&cache_home, NULL, 4, home_dir, ".cache", "netsurf", "/");
- if (ret != NSERROR_OK) {
- return ret;
- }
- } else {
- ret = netsurf_mkpath(&cache_home, NULL, 3, xdg_cache_dir, "netsurf", "/");
- if (ret != NSERROR_OK) {
- return ret;
- }
- }
-
- /* ensure all elements of path exist (the trailing / is required) */
- ret = netsurf_mkdir_all(cache_home);
- if (ret != NSERROR_OK) {
- free(cache_home);
- return ret;
- }
-
- /* strip the trailing separator */
- cache_home[strlen(cache_home) - 1] = 0;
-
- NSLOG(netsurf, INFO, "\"%s\"", cache_home);
-
- *cache_home_out = cache_home;
-
- return NSERROR_OK;
-}
-
-static nserror nsgtk_option_init(int *pargc, char** argv)
-{
- nserror ret;
- char *choices = NULL;
-
- /* user options setup */
- ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
- if (ret != NSERROR_OK) {
- return ret;
- }
-
- /* Attempt to load the user choices */
- ret = netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
- if (ret == NSERROR_OK) {
- nsoption_read(choices, nsoptions);
- free(choices);
- }
-
- /* overide loaded options with those from commandline */
- nsoption_commandline(pargc, argv, nsoptions);
+ /* common finalisation */
+ netsurf_exit();
- /* ensure all options fall within sensible bounds */
+ /* finalise options */
+ nsoption_finalise(nsoptions, nsoptions_default);
- /* Attempt to handle nonsense status bar widths. These may exist
- * in people's Choices as the GTK front end used to abuse the
- * status bar width option by using it for an absolute value in px.
- * The GTK front end now correctly uses it as a proportion of window
- * width. Here we assume that a value of less than 15% is wrong
- * and set to the default two thirds. */
- if (nsoption_int(toolbar_status_size) < 1500) {
- nsoption_set_int(toolbar_status_size, 6667);
- }
+ /* finalise logging */
+ nslog_finalise();
- return NSERROR_OK;
}
-static struct gui_misc_table nsgtk_misc_table = {
- .schedule = nsgtk_schedule,
-
- .quit = gui_quit,
- .launch_url = gui_launch_url,
- .pdf_password = nsgtk_pdf_password,
- .present_cookies = nsgtk_cookies_present,
-};
-
-
-static nserror nsgtk_messages_init(char **respaths)
-{
- const char *messages;
- nserror ret;
- const uint8_t *data;
- size_t data_size;
-
- ret = nsgtk_data_from_resname("Messages", &data, &data_size);
- if (ret == NSERROR_OK) {
- ret = messages_add_from_inline(data, data_size);
- } else {
- /* Obtain path to messages */
- ret = nsgtk_path_from_resname("Messages", &messages);
- if (ret == NSERROR_OK) {
- ret = messages_add_from_file(messages);
- }
- }
- return ret;
-}
/**
* Main entry point from OS.
*/
int main(int argc, char** argv)
{
+ nserror res;
char *cache_home = NULL;
- nserror ret;
struct netsurf_table nsgtk_table = {
- .misc = &nsgtk_misc_table,
+ .misc = nsgtk_misc_table,
.window = nsgtk_window_table,
.clipboard = nsgtk_clipboard_table,
.download = nsgtk_download_table,
@@ -1227,99 +1180,43 @@ int main(int argc, char** argv)
.layout = nsgtk_layout_table,
};
- ret = netsurf_register(&nsgtk_table);
- if (ret != NSERROR_OK) {
- die("NetSurf operation table failed registration\n");
- }
-
- /* Locate the correct user configuration directory path */
- ret = get_config_home(&nsgtk_config_home);
- if (ret == NSERROR_NOT_FOUND) {
- /* no config directory exists yet so try to create one */
- ret = create_config_home(&nsgtk_config_home);
- }
- if (ret != NSERROR_OK) {
- NSLOG(netsurf, INFO,
- "Unable to locate a configuration directory.");
- nsgtk_config_home = NULL;
- }
-
- /* Initialise gtk */
- gtk_init(&argc, &argv);
-
- /* initialise logging. Not fatal if it fails but not much we
- * can do about it either.
- */
- nslog_init(nslog_stream_configure, &argc, argv);
-
- /* build the common resource path list */
- respaths = nsgtk_init_resource_path(nsgtk_config_home);
- if (respaths == NULL) {
- fprintf(stderr, "Unable to locate resources\n");
- return 1;
- }
-
- /* initialise the gtk resource handling */
- ret = nsgtk_init_resources(respaths);
- if (ret != NSERROR_OK) {
- fprintf(stderr, "GTK resources failed to initialise (%s)\n",
- messages_get_errorcode(ret));
- return 1;
- }
-
- /* Initialise user options */
- ret = nsgtk_option_init(&argc, argv);
- if (ret != NSERROR_OK) {
- fprintf(stderr, "Options failed to initialise (%s)\n",
- messages_get_errorcode(ret));
+ res = netsurf_register(&nsgtk_table);
+ if (res != NSERROR_OK) {
+ fprintf(stderr,
+ "NetSurf operation table failed registration (%s)\n",
+ messages_get_errorcode(res));
return 1;
}
- /* Initialise translated messages */
- ret = nsgtk_messages_init(respaths);
- if (ret != NSERROR_OK) {
- fprintf(stderr, "Unable to load translated messages (%s)\n",
- messages_get_errorcode(ret));
- NSLOG(netsurf, INFO, "Unable to load translated messages");
- /** \todo decide if message load faliure should be fatal */
- }
-
- /* Locate the correct user cache directory path */
- ret = get_cache_home(&cache_home);
- if (ret == NSERROR_NOT_FOUND) {
- /* no cache directory exists yet so try to create one */
- ret = create_cache_home(&cache_home);
- }
- if (ret != NSERROR_OK) {
- NSLOG(netsurf, INFO, "Unable to locate a cache directory.");
+ /* gtk specific initialisation */
+ res = nsgtk_init(&argc, &argv, &cache_home);
+ if (res != NSERROR_OK) {
+ fprintf(stderr, "NetSurf gtk failed to initialise (%s)\n",
+ messages_get_errorcode(res));
+ return 2;
}
/* core initialisation */
- ret = netsurf_init(cache_home);
+ res = netsurf_init(cache_home);
free(cache_home);
- if (ret != NSERROR_OK) {
+ if (res != NSERROR_OK) {
fprintf(stderr, "NetSurf core failed to initialise (%s)\n",
- messages_get_errorcode(ret));
- return 1;
+ messages_get_errorcode(res));
+ return 3;
}
/* gtk specific initalisation and main run loop */
- ret = nsgtk_init(argc, argv, respaths);
- if (ret != NSERROR_OK) {
- fprintf(stderr, "NetSurf gtk initialise failed (%s)\n",
- messages_get_errorcode(ret));
- } else {
- nsgtk_main();
+ res = nsgtk_setup(argc, argv, respaths);
+ if (res != NSERROR_OK) {
+ nsgtk_finalise();
+ fprintf(stderr, "NetSurf gtk setup failed (%s)\n",
+ messages_get_errorcode(res));
+ return 4;
}
- /* common finalisation */
- netsurf_exit();
+ nsgtk_main();
- /* finalise options */
- nsoption_finalise(nsoptions, nsoptions_default);
-
- /* finalise logging */
- nslog_finalise();
+ nsgtk_finalise();
return 0;
}
diff --git a/frontends/gtk/misc.c b/frontends/gtk/misc.c
new file mode 100644
index 000000000..bda0dd688
--- /dev/null
+++ b/frontends/gtk/misc.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2021 Vincemt Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Implementation of netsurf miscellaneous operations table
+ */
+
+#include <stdbool.h>
+#include <gtk/gtk.h>
+
+#include "utils/errors.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/nsurl.h"
+#include "netsurf/misc.h"
+#include "desktop/save_pdf.h"
+
+#include "gtk/compat.h"
+#include "gtk/warn.h"
+#include "gtk/schedule.h"
+#include "gtk/resources.h"
+#include "gtk/cookies.h"
+#include "gtk/misc.h"
+
+
+static nserror gui_launch_url(struct nsurl *url)
+{
+ gboolean ok;
+ GError *error = NULL;
+
+ ok = nsgtk_show_uri(NULL, nsurl_access(url), GDK_CURRENT_TIME, &error);
+ if (ok == TRUE) {
+ return NSERROR_OK;
+ }
+
+ if (error) {
+ nsgtk_warning(messages_get("URIOpenError"), error->message);
+ g_error_free(error);
+ }
+ return NSERROR_NO_FETCH_HANDLER;
+}
+
+static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data)
+{
+ char **owner_pass = ((void **)data)[0];
+ char **user_pass = ((void **)data)[1];
+ GtkWindow *wnd = ((void **)data)[2];
+ GtkBuilder *password_builder = ((void **)data)[3];
+ char *path = ((void **)data)[4];
+
+ char *op, *op1;
+ char *up, *up1;
+
+ op = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFOwnerPassword"))));
+ op1 = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFOwnerPassword1"))));
+ up = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFUserPassword"))));
+ up1 = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFUserPassword1"))));
+
+
+ if (op[0] == '\0') {
+ gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
+ "labelInfo")),
+ "Owner password must be at least 1 character long:");
+ free(op);
+ free(up);
+ } else if (!strcmp(op, up)) {
+ gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
+ "labelInfo")),
+ "User and owner passwords must be different:");
+ free(op);
+ free(up);
+ } else if (!strcmp(op, op1) && !strcmp(up, up1)) {
+
+ *owner_pass = op;
+ if (up[0] == '\0')
+ free(up);
+ else
+ *user_pass = up;
+
+ free(data);
+ gtk_widget_destroy(GTK_WIDGET(wnd));
+ g_object_unref(G_OBJECT(password_builder));
+
+ save_pdf(path);
+
+ free(path);
+ } else {
+ gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
+ "labelInfo")), "Passwords not confirmed:");
+ free(op);
+ free(up);
+ }
+
+ free(op1);
+ free(up1);
+}
+
+static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data)
+{
+ GtkWindow *wnd = ((void **)data)[2];
+ GtkBuilder *password_builder = ((void **)data)[3];
+ char *path = ((void **)data)[4];
+
+ free(data);
+
+ gtk_widget_destroy(GTK_WIDGET(wnd));
+ g_object_unref(G_OBJECT(password_builder));
+
+ save_pdf(path);
+
+ free(path);
+}
+
+static void nsgtk_pdf_password(char **owner_pass, char **user_pass, char *path)
+{
+ GtkButton *ok, *no;
+ GtkWindow *wnd;
+ void **data;
+ GtkBuilder *password_builder;
+ nserror res;
+
+ res = nsgtk_builder_new_from_resname("password", &password_builder);
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Password UI builder init failed");
+ return;
+ }
+
+ gtk_builder_connect_signals(password_builder, NULL);
+
+ wnd = GTK_WINDOW(gtk_builder_get_object(password_builder,
+ "wndPDFPassword"));
+
+ data = malloc(5 * sizeof(void *));
+
+ *owner_pass = NULL;
+ *user_pass = NULL;
+
+ data[0] = owner_pass;
+ data[1] = user_pass;
+ data[2] = wnd;
+ data[3] = password_builder;
+ data[4] = path;
+
+ ok = GTK_BUTTON(gtk_builder_get_object(password_builder,
+ "buttonPDFSetPassword"));
+ no = GTK_BUTTON(gtk_builder_get_object(password_builder,
+ "buttonPDFNoPassword"));
+
+ g_signal_connect(G_OBJECT(ok), "clicked",
+ G_CALLBACK(nsgtk_PDF_set_pass), (gpointer)data);
+ g_signal_connect(G_OBJECT(no), "clicked",
+ G_CALLBACK(nsgtk_PDF_no_pass), (gpointer)data);
+
+ gtk_widget_show(GTK_WIDGET(wnd));
+}
+
+
+static struct gui_misc_table misc_table = {
+ .schedule = nsgtk_schedule,
+
+ .launch_url = gui_launch_url,
+ .pdf_password = nsgtk_pdf_password,
+ .present_cookies = nsgtk_cookies_present,
+};
+
+struct gui_misc_table *nsgtk_misc_table = &misc_table;
diff --git a/frontends/gtk/misc.h b/frontends/gtk/misc.h
new file mode 100644
index 000000000..3a02c2254
--- /dev/null
+++ b/frontends/gtk/misc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021 Vincemt Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_GTK_MISC_H
+#define NETSURF_GTK_MISC_H 1
+
+extern struct gui_misc_table *nsgtk_misc_table;
+
+#endif
diff --git a/frontends/gtk/window.c b/frontends/gtk/window.c
index f0a53a66f..f5c87ef87 100644
--- a/frontends/gtk/window.c
+++ b/frontends/gtk/window.c
@@ -391,12 +391,25 @@ nsgtk_window_button_release_event(GtkWidget *widget,
bool shift = event->state & GDK_SHIFT_MASK;
bool ctrl = event->state & GDK_CONTROL_MASK;
+ switch (event->button) {
+ case 8:
+ nsgtk_toolbar_item_activate(g->toolbar, BACK_BUTTON);
+ break;
+ case 9:
+ nsgtk_toolbar_item_activate(g->toolbar, FORWARD_BUTTON);
+ break;
+ default:
+ NSLOG(netsurf, DEBUG, "event button %d", event->button);
+ break;
+ }
+
/* If the mouse state is PRESS then we are waiting for a release to emit
* a click event, otherwise just reset the state to nothing */
- if (g->mouse.state & BROWSER_MOUSE_PRESS_1)
+ if (g->mouse.state & BROWSER_MOUSE_PRESS_1) {
g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1);
- else if (g->mouse.state & BROWSER_MOUSE_PRESS_2)
+ } else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) {
g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2);
+ }
/* Handle modifiers being removed */
if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift)
diff --git a/frontends/monkey/Makefile.tools b/frontends/monkey/Makefile.tools
new file mode 100644
index 000000000..7546506ff
--- /dev/null
+++ b/frontends/monkey/Makefile.tools
@@ -0,0 +1,15 @@
+# -*- mode: makefile-gmake -*-
+##
+## monkey target tool setup
+##
+
+ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
+ PKG_CONFIG := pkg-config
+else
+ PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
+endif
+
+ifneq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+ CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
+endif
diff --git a/frontends/monkey/main.c b/frontends/monkey/main.c
index bae815056..463f0bea6 100644
--- a/frontends/monkey/main.c
+++ b/frontends/monkey/main.c
@@ -73,7 +73,8 @@ static void die(const char * const error)
exit(EXIT_FAILURE);
}
-/** obtain language from environment
+/**
+ * obtain language from environment
*
* start with GNU extension LANGUAGE environment variable and then try
* POSIX variables LC_ALL, LC_MESSAGES and LANG
@@ -107,7 +108,8 @@ static const char *get_language(void)
}
-/** provide a string vector of languages in preference order
+/**
+ * provide a string vector of languages in preference order
*
* environment variables are processed to aquire a colon separated
* list of languages which are converted into a string vector. The
@@ -174,7 +176,16 @@ static const char * const *get_languagev(void)
return &langv[0];
}
-/* Stolen from gtk/gui.c */
+/**
+ * Create an array of valid paths to search for resources.
+ *
+ * The idea is that all the complex path computation to find resources
+ * is performed here, once, rather than every time a resource is
+ * searched for.
+ *
+ * \param resource_path A shell style colon separated path list
+ * \return A string vector of valid paths where resources can be found
+ */
static char **
nsmonkey_init_resource(const char *resource_path)
{
diff --git a/frontends/riscos/Makefile.tools b/frontends/riscos/Makefile.tools
new file mode 100644
index 000000000..9ea5c29f2
--- /dev/null
+++ b/frontends/riscos/Makefile.tools
@@ -0,0 +1,52 @@
+# -*- mode: makefile-gmake -*-
+##
+## RISC OS target tool setup
+##
+
+ifeq ($(HOST),riscos)
+ # Build for RO on RO
+ GCCSDK_INSTALL_ENV := <NSLibs$$Dir>
+ CCRES := ccres
+ TPLEXT :=
+ MAKERUN := makerun
+ SQUEEZE := squeeze
+ RUNEXT :=
+ CC := gcc
+ CXX := g++
+ EXEEXT :=
+ PKG_CONFIG :=
+else
+ # Cross-build for RO (either using GCCSDK 3.4.6 - AOF,
+ # either using GCCSDK 4 - ELF)
+ ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
+ ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/env),)
+ GCCSDK_INSTALL_ENV := /opt/netsurf/arm-unknown-riscos/env
+ else
+ GCCSDK_INSTALL_ENV := /home/riscos/env
+ endif
+ endif
+ ifeq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
+ ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/cross/bin),)
+ GCCSDK_INSTALL_CROSSBIN := /opt/netsurf/arm-unknown-riscos/cross/bin
+ else
+ GCCSDK_INSTALL_CROSSBIN := /home/riscos/cross/bin
+ endif
+ endif
+
+ CCRES := $(GCCSDK_INSTALL_CROSSBIN)/ccres
+ TPLEXT := ,fec
+ MAKERUN := $(GCCSDK_INSTALL_CROSSBIN)/makerun
+ SQUEEZE := $(GCCSDK_INSTALL_CROSSBIN)/squeeze
+ RUNEXT := ,feb
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+ ifneq (,$(findstring arm-unknown-riscos-gcc,$(CC)))
+ SUBTARGET := -elf
+ EXEEXT := ,e1f
+ ELF2AIF := $(GCCSDK_INSTALL_CROSSBIN)/elf2aif
+ else
+ SUBTARGET := -aof
+ EXEEXT := ,ff8
+ endif
+ CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
+ PKG_CONFIG := $(GCCSDK_INSTALL_ENV)/ro-pkg-config
+endif
diff --git a/frontends/riscos/filetype.c b/frontends/riscos/filetype.c
index 73651cd63..b0dc949f8 100644
--- a/frontends/riscos/filetype.c
+++ b/frontends/riscos/filetype.c
@@ -39,6 +39,7 @@ static const struct type_entry type_map[] = {
{0x188, "application/x-shockwave-flash"},
{0x695, "image/gif"},
{0x69c, "image/x-ms-bmp"},
+ {0xa66, "image/webp"},
{0xaad, "image/svg+xml"},
{0xaff, "image/x-drawfile"},
{0xb60, "image/png"},
@@ -269,6 +270,7 @@ int ro_content_native_type(struct hlcache_handle *c)
case FILETYPE_BMP: /* bmp */
case FILETYPE_ICO: /* ico */
case FILETYPE_PNG: /* png */
+ case FILETYPE_WEBP: /* webp */
case 0xff9: /* sprite */
return osfile_TYPE_SPRITE;
case FILETYPE_SVG: /* svg */
diff --git a/frontends/riscos/filetype.h b/frontends/riscos/filetype.h
index 4c45e7bd0..b9fca4d49 100644
--- a/frontends/riscos/filetype.h
+++ b/frontends/riscos/filetype.h
@@ -67,6 +67,9 @@
#ifndef FILETYPE_SVG
#define FILETYPE_SVG 0xaad
#endif
+#ifndef FILETYPE_WEBP
+#define FILETYPE_WEBP 0xa66
+#endif
/**
* Determine the MIME type of a local file.
diff --git a/frontends/riscos/gui.c b/frontends/riscos/gui.c
index b0eb23256..cc12eaccb 100644
--- a/frontends/riscos/gui.c
+++ b/frontends/riscos/gui.c
@@ -827,6 +827,7 @@ static void ro_msg_dataload(wimp_message *message)
case osfile_TYPE_TEXT:
case FILETYPE_ARTWORKS:
case FILETYPE_SVG:
+ case FILETYPE_WEBP:
/* display the actual file */
error = netsurf_path_to_nsurl(message->data.data_xfer.file_name, &url);
break;
@@ -929,7 +930,8 @@ static void ro_msg_datasave(wimp_message *message)
case osfile_TYPE_SPRITE:
case osfile_TYPE_TEXT:
case FILETYPE_ARTWORKS:
- case FILETYPE_SVG: {
+ case FILETYPE_SVG:
+ case FILETYPE_WEBP: {
os_error *error;
dataxfer->your_ref = dataxfer->my_ref;
diff --git a/frontends/windows/Makefile.tools b/frontends/windows/Makefile.tools
new file mode 100644
index 000000000..dff3dfec3
--- /dev/null
+++ b/frontends/windows/Makefile.tools
@@ -0,0 +1,19 @@
+# -*- mode: makefile-gmake -*-
+##
+## windows (win32) target tool setup
+##
+
+ifneq ($(HOST),windows)
+ # Set Mingw defaults
+ GCCSDK_INSTALL_ENV ?= /opt/netsurf/i686-w64-mingw32/env
+ GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/i686-w64-mingw32/cross/bin
+
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+ WINDRES := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*windres)
+
+ PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
+else
+ # Building on Windows
+ CC := gcc
+ PKG_CONFIG :=
+endif
diff --git a/include/netsurf/bitmap.h b/include/netsurf/bitmap.h
index a85efce99..f5de51423 100644
--- a/include/netsurf/bitmap.h
+++ b/include/netsurf/bitmap.h
@@ -143,14 +143,14 @@ struct gui_bitmap_table {
int (*get_height)(void *bitmap);
/**
- * The the *bytes* per pixel.
+ * Get the *bytes* per pixel.
*
* \param bitmap The bitmap
*/
size_t (*get_bpp)(void *bitmap);
/**
- * Savde a bitmap to disc.
+ * Save a bitmap to disc.
*
* \param bitmap The bitmap to save
* \param path The path to save the bitmap to.
diff --git a/include/netsurf/fetch.h b/include/netsurf/fetch.h
index 6e6d653ee..30b204868 100644
--- a/include/netsurf/fetch.h
+++ b/include/netsurf/fetch.h
@@ -49,15 +49,15 @@ struct gui_fetch_table {
/**
* Translate resource to full url.
*
- * @note Only used in resource fetcher
+ * @note Only used in resource protocol fetcher
*
- * Transforms a resource: path into a full URL. The returned URL
+ * Transforms a resource protocol path into a full URL. The returned URL
* is used as the target for a redirect. The caller takes ownership of
* the returned nsurl including unrefing it when finished with it.
*
* \param path The path of the resource to locate.
- * \return A string containing the full URL of the target object or
- * NULL if no suitable resource can be found.
+ * \return A netsurf url object containing the full URL of the resource
+ * path or NULL if a suitable resource URL can not be generated.
*/
struct nsurl* (*get_resource_url)(const char *path);
diff --git a/resources/default.css b/resources/default.css
index 276bc1554..fa47c76ff 100644
--- a/resources/default.css
+++ b/resources/default.css
@@ -50,9 +50,9 @@ pre { display: block; font-family: monospace; white-space: pre; margin-bottom: 1
ins { color: green; text-decoration: underline; }
del { color: red; text-decoration: line-through; }
-ul { display: block; padding-left: 1.5em; margin: 1.12em 0;
+ul { display: block; padding-left: 40px; margin: 1.12em 0;
list-style-type: disc; }
-ol { display: block; padding-left: 1.5em; margin: 1.12em 0;
+ol { display: block; padding-left: 40px; margin: 1.12em 0;
list-style-type: decimal; }
li { display: list-item; }
diff --git a/test/corestrings.c b/test/corestrings.c
index aaa23e4d0..43eb5130e 100644
--- a/test/corestrings.c
+++ b/test/corestrings.c
@@ -40,7 +40,7 @@
*
* This is used to test all the out of memory paths in initialisation.
*/
-#define CORESTRING_TEST_COUNT 483
+#define CORESTRING_TEST_COUNT 487
START_TEST(corestrings_test)
{
diff --git a/test/monkey_driver.py b/test/monkey_driver.py
index 606530e81..9b810d2a6 100755
--- a/test/monkey_driver.py
+++ b/test/monkey_driver.py
@@ -436,13 +436,26 @@ def run_test_step_action_plot_check(ctx, step):
print(get_indent(ctx) + "Action: " + step["action"])
assert_browser(ctx)
win = ctx['windows'][step['window']]
+
+ if 'area' in step.keys():
+ if step["area"] == "extent":
+ # ought to capture the extent updates and use that, instead use a
+ # big area and have the browser clip it
+ area=["0","0","1000","1000000"]
+ else:
+ area = [step["area"]]
+ else:
+ area = None
+
+ # get the list of checks
if 'checks' in step.keys():
checks = step['checks']
else:
checks = {}
+
all_text_list = []
bitmaps = []
- for plot in win.redraw():
+ for plot in win.redraw(coords=area):
if plot[0] == 'TEXT':
all_text_list.extend(plot[6:])
if plot[0] == 'BITMAP':
diff --git a/tools/convert_font.c b/tools/convert_font.c
index 9f5734b71..d22c85920 100644
--- a/tools/convert_font.c
+++ b/tools/convert_font.c
@@ -290,14 +290,14 @@ static bool generate_font_header(const char *path, struct font_data *data)
for (s = 0; s < 4; s++) {
- fprintf(fp, "const uint8_t *%s_section_table;\n",
+ fprintf(fp, "extern const uint8_t *%s_section_table;\n",
var_lables[s]);
- fprintf(fp, "const uint16_t *%s_sections;\n",
+ fprintf(fp, "extern const uint16_t *%s_sections;\n",
var_lables[s]);
}
- fprintf(fp, "const uint8_t *font_glyph_data;\n");
+ fprintf(fp, "extern const uint8_t *font_glyph_data;\n");
fprintf(fp, "\n\n");
diff --git a/utils/corestringlist.h b/utils/corestringlist.h
index d6be3c4c1..b253b3b56 100644
--- a/utils/corestringlist.h
+++ b/utils/corestringlist.h
@@ -295,6 +295,7 @@ CORESTRING_DOM_STRING(rect);
CORESTRING_DOM_STRING(rel);
CORESTRING_DOM_STRING(reset);
CORESTRING_DOM_STRING(resize);
+CORESTRING_DOM_STRING(reversed);
CORESTRING_DOM_STRING(rows);
CORESTRING_DOM_STRING(rowspan);
CORESTRING_DOM_STRING(scroll);
@@ -309,6 +310,7 @@ CORESTRING_DOM_STRING(size);
CORESTRING_DOM_STRING(sizes);
CORESTRING_DOM_STRING(src);
CORESTRING_DOM_STRING(stalled);
+CORESTRING_DOM_STRING(start);
CORESTRING_DOM_STRING(storage);
CORESTRING_DOM_STRING(style);
CORESTRING_DOM_STRING(submit);