summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Wildemann <gta04@metalstrolche.de>2017-02-23 19:43:25 +0100
committerStefan Wildemann <gta04@metalstrolche.de>2017-02-23 19:43:25 +0100
commitf8bfd1c1ae7f0c2d74ea021baeb8828110b5d657 (patch)
tree0bdd482b55ce4251a3ebd97fb11f46440eeea694
parent867fe129d0dfb9fea7e840317669cc04a1e709a9 (diff)
parent518d1b9b6ea7898926d1a7bccfd27fd4eb35869a (diff)
downloadnavit-f8bfd1c1ae7f0c2d74ea021baeb8828110b5d657.tar.gz
Merge remote-tracking branch 'upstream/trunk' into sailfish_build
-rwxr-xr-xCMakeLists.txt42
-rw-r--r--ci/build_linux.sh2
-rw-r--r--ci/pointer-64.pngbin0 -> 1733 bytes
-rw-r--r--ci/publish.sh4
-rw-r--r--ci/run_linux_tests.sh54
-rw-r--r--ci/xdotools.sh94
-rw-r--r--navit/attr_def.h2
-rw-r--r--navit/graphics/egl/CMakeLists.txt2
-rw-r--r--navit/graphics/egl/graphics_egl.c1458
-rw-r--r--navit/graphics/qt5/CMakeLists.txt9
-rw-r--r--navit/graphics/qt5/QNavitWidget.cpp158
-rw-r--r--navit/graphics/qt5/QNavitWidget.h33
-rw-r--r--navit/graphics/qt5/event_qt5.cpp185
-rw-r--r--navit/graphics/qt5/event_qt5.h18
-rw-r--r--navit/graphics/qt5/graphics_qt5.cpp837
-rw-r--r--navit/graphics/qt5/graphics_qt5.h63
-rw-r--r--navit/vehicle/qt5/CMakeLists.txt6
-rw-r--r--navit/vehicle/qt5/vehicle_qt5.cpp300
-rw-r--r--navit/vehicle/qt5/vehicle_qt5.h58
19 files changed, 3308 insertions, 17 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e2b869203..819e7d450 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -85,7 +85,9 @@ add_module(graphics/gd "FreeType library not found" FALSE)
add_module(graphics/gtk_drawing_area "FreeType library not found" FALSE)
add_module(graphics/opengl "FreeType library not found" FALSE)
add_module(graphics/sdl "Required library not found" FALSE)
+add_module(graphics/egl "Required library not found" FALSE)
add_module(graphics/qt_qpainter "Qt libraries not found" FALSE)
+add_module(graphics/qt5 "Qt5 libraries not found" FALSE)
add_module(gui/qml "Qt Declarative not found" FALSE)
add_module(gui/gtk "GTK libs not found" FALSE)
add_module(vehicle/gpsd "gpsd lib not found" FALSE)
@@ -97,6 +99,7 @@ add_module(binding/python "python libraries not found" FALSE)
add_module(speech/dbus "dbus-glib-1 not found" FALSE)
add_module(speech/cmdline "neither system() nor CreateProcess() found" FALSE)
add_module(vehicle/gpsd_dbus "dbus-glib-1 not found" FALSE)
+add_module(vehicle/qt5 "Qt5 libraries not found" FALSE)
add_module(speech/speech_dispatcher "speech_dispatcher lib not found" FALSE)
add_module(autoload/osso "Default" FALSE)
add_module(map/garmin "Garmin library not found" FALSE)
@@ -136,6 +139,9 @@ find_package(Glib)
find_package(Gmodule)
find_package(ZLIB)
find_package(Freetype)
+find_library(SDL2MAIN SDL2)
+find_library(SDL2IMAGE SDL2_image)
+find_library(GLES2 GLESv2)
find_package(SDL)
find_package(SDL_ttf)
find_package(SDL_image)
@@ -151,11 +157,21 @@ find_package(Threads)
libfind_pkg_check_modules(FONTCONFIG fontconfig)
#Qt detection
if (NOT DISABLE_QT)
- # Unfortunately, CMake seems to ignore the "OPTIONAL_COMPONENTS" flag,
- # and actually requires all components to be installed. Maybe this can
- # be fixed later...
- find_package(Qt4 4.7 COMPONENTS QtCore OPTIONAL_COMPONENTS QtGui QtXml QtDeclarative QtSvg)
+ find_package(Qt5Widgets)
+ find_package(Qt5Svg)
+ find_package(Qt5DBus)
+ find_package(Qt5Positioning)
+ find_package(Qt5Sensors)
+ #find_package(Qt5Declarative)
+ if (Qt5Widgets_FOUND)
+ else (Qt5Widgets_FOUND)
+ # Unfortunately, CMake seems to ignore the "OPTIONAL_COMPONENTS" flag,
+ # and actually requires all components to be installed. Maybe this can
+ # be fixed later...
+ find_package(Qt4 4.7 COMPONENTS QtCore OPTIONAL_COMPONENTS QtGui QtXml QtDeclarative QtSvg)
+ endif (Qt5Widgets_FOUND)
endif (NOT DISABLE_QT)
+
#pkg-config based detection
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
@@ -274,6 +290,7 @@ else(FREETYPE_FOUND)
set_with_reason(graphics/gtk_drawing_area "FreeType library not found" FALSE)
set_with_reason(graphics/opengl "FreeType library not found" FALSE)
set_with_reason(graphics/sdl "FreeType library not found" FALSE)
+ set_with_reason(graphics/egl "FreeType library not found" FALSE)
endif(FREETYPE_FOUND)
if(FONTCONFIG_FOUND)
@@ -296,7 +313,17 @@ if (QT_FOUND)
endif()
endif()
endif(QT_FOUND)
-
+if (Qt5Widgets_FOUND)
+ set_with_reason(graphics/qt5 "Qt5 found" TRUE ${Qt5Widgets_LIBRARIES}
+ ${Qt5Declarative_LIBRARIES}
+ ${Qt5Svg_LIBRARIES}
+ ${Qt5DBus_LIBRARIES})
+endif ()
+if (Qt5Positioning_FOUND)
+ set_with_reason(vehicle/qt5 "Qt5 Positioning found" TRUE
+ ${Qt5Positioning_LIBRARIES}
+ ${Qt5Sensors_LIBRARIES})
+endif ()
if(GTK2_FOUND)
# Include gtk.h with "SYSTEM" to avoid GCC compiler warning for gtkitemfactory.h.
include_directories(SYSTEM ${GTK2_GTK_INCLUDE_DIR})
@@ -346,6 +373,11 @@ if(SDL_FOUND AND SDLIMAGE_FOUND AND FREETYPE_FOUND)
set_with_reason(graphics/sdl "SDL/SDL_image libs found" TRUE ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY})
endif(SDL_FOUND AND SDLIMAGE_FOUND AND FREETYPE_FOUND)
+if(SDL2MAIN AND SDL2IMAGE AND GLES2)
+ set_with_reason(graphics/egl "SDL2/SDL2_image libs found" TRUE ${SDL2MAIN} ${SDL2IMAGE} ${GLES2})
+ message(STATUS "EGL libs found : ${SDL2MAIN} ${SDL2IMAGE} ${GLES2}")
+endif(SDL2_FOUND AND SDL2IMAGE_FOUND AND GLES2)
+
if (LIBGPS_FOUND)
if (LIBGPS_NEW_FOUND)
set(VEHICLE_GPSD_REASON "gpsd lib found")
diff --git a/ci/build_linux.sh b/ci/build_linux.sh
index 3716f47d9..7e26d0685 100644
--- a/ci/build_linux.sh
+++ b/ci/build_linux.sh
@@ -1,4 +1,4 @@
-sudo apt-get install cmake libpng12-dev librsvg2-bin libfreetype6-dev libdbus-glib-1-dev g++ libgtk2.0-dev
+sudo apt-get install cmake libpng12-dev librsvg2-bin libfreetype6-dev libdbus-glib-1-dev g++ libgtk2.0-dev libqt5svg5-dev
cmake_opts="-Dgraphics/qt_qpainter:BOOL=FALSE -Dgui/qml:BOOL=FALSE -DSVG2PNG:BOOL=FALSE -DSAMPLE_MAP=n -Dgraphics/gtk_drawing_area:BOOL=TRUE"
diff --git a/ci/pointer-64.png b/ci/pointer-64.png
new file mode 100644
index 000000000..904f6878d
--- /dev/null
+++ b/ci/pointer-64.png
Binary files differ
diff --git a/ci/publish.sh b/ci/publish.sh
index 06f5b147b..2f880f339 100644
--- a/ci/publish.sh
+++ b/ci/publish.sh
@@ -2,11 +2,11 @@ cd ~/
git clone git@github.com:navit-gps/infrastructure-blackbox.git
cd infrastructure-blackbox/keyrings/
openssl aes-256-cbc -d -in keystore.gpg -k $KEY > ~/.keystore
-openssl aes-256-cbc -d -in client_secrets.gpg -k $KEY > client_secrets.json
+openssl aes-256-cbc -d -in client_secrets.gpg -k $KEY > ~/navit/ci/client_secrets.json
openssl aes-256-cbc -d -in androidpublisher.gpg -k $KEY > androidpublisher.dat
pip install google-api-python-client
-jarsigner -storepass $SP $CIRCLE_ARTIFACTS/navit-$CIRCLE_SHA1-${ARCH}-release-unsigned.apk $key_name
+/usr/lib/jvm/java-8-openjdk-amd64/bin/jarsigner -storepass $SP $CIRCLE_ARTIFACTS/navit-$CIRCLE_SHA1-${ARCH}-release-unsigned.apk $key_name
/usr/local/android-sdk-linux/build-tools/25.0.1/zipalign 4 $CIRCLE_ARTIFACTS/navit-$CIRCLE_SHA1-${ARCH}-release-unsigned.apk $CIRCLE_ARTIFACTS/navit-$CIRCLE_SHA1-${ARCH}-release-signed.apk
python ~/navit/ci/basic_upload_apks.py org.navitproject.navit $CIRCLE_ARTIFACTS/navit-$CIRCLE_SHA1-${ARCH}-release-signed.apk
diff --git a/ci/run_linux_tests.sh b/ci/run_linux_tests.sh
index 0897ec4e4..3f87161ed 100644
--- a/ci/run_linux_tests.sh
+++ b/ci/run_linux_tests.sh
@@ -1,18 +1,56 @@
#!/bin/bash
+linux_test () {
+ # create logs dir
+ mkdir $CIRCLE_ARTIFACTS/logs_${1}
+
+ #run instance of navit and remember pid
+ ./navit >$CIRCLE_ARTIFACTS/logs_${1}/stdout.txt 2>$CIRCLE_ARTIFACTS/logs_${1}/stderr.txt &
+ pid=$!
+
+ # give navit time to come up
+ sleep 5
+
+ # screen shot root window
+ import -window root $CIRCLE_ARTIFACTS/default.png
+
+ # run tests on X11
+ bash ~/navit/ci/xdotools.sh
+
+ # python ~/navit/ci/dbus_tests.py $CIRCLE_TEST_REPORTS/
+ # dbus-send --print-reply --session --dest=org.navit_project.navit /org/navit_project/navit/default_navit org.navit_project.navit.navit.quit
+
+ # kill navit instance
+ kill $pid
+}
+
set -e
pushd ~/linux-bin/navit/
+
+# prepare environment by getting a map of berkley
+cat > maps/berkeley.xml << EOF
+<map type="binfile" data="\$NAVIT_SHAREDIR/maps/berkeley.bin" />
+EOF
+wget http://sd-55475.dedibox.fr/berkeley.bin -O maps/berkeley.bin
+
+# back up config
+cp navit.xml navit.xml.bak
+
+# run gtk test
sed -i -e 's@name="Local GPS" profilename="car" enabled="yes" active="1"@name="Local GPS" profilename="car" enabled="no" active="0"@' navit.xml
-sed -i -e 's@name="Demo" profilename="car" enabled="no" active="yes"@name="Demo" profilename="car" enabled="yes" active="yes" follow="1" refresh="1"@' navit.xml
+sed -i -e 's@name="Demo" profilename="car" enabled="no" @name="Demo" profilename="car" enabled="yes" follow="1" refresh="1"@' navit.xml
sed -i -e 's@type="internal" enabled@type="internal" fullscreen="1" font_size="350" enabled@' navit.xml
sed -i -e 's@libbinding_dbus.so" active="no"@libbinding_dbus.so" active="yes"@' navit.xml
+linux_test gtk_drawing_area
-./navit &
-pid=$!
-
-import -window root $CIRCLE_ARTIFACTS/default.png
+# restore config
+cp navit.xml.bak navit.xml
+# run qt5 test
+sed -i -e 's@graphics type="gtk_drawing_area"@graphics type="qt5" v="792" h="547"@' navit.xml
+sed -i -e 's@name="Local GPS" profilename="car" enabled="yes" active="1"@name="Local GPS" profilename="car" enabled="no" active="0"@' navit.xml
+sed -i -e 's@name="Demo" profilename="car" enabled="no" @name="Demo" profilename="car" enabled="yes" follow="1" refresh="1"@' navit.xml
+sed -i -e 's@type="internal" enabled@type="internal" fullscreen="1" font_size="350" enabled@' navit.xml
+sed -i -e 's@libbinding_dbus.so" active="no"@libbinding_dbus.so" active="yes"@' navit.xml
+linux_test qt5
-# python ~/navit/ci/dbus_tests.py $CIRCLE_TEST_REPORTS/
-#
-# dbus-send --print-reply --session --dest=org.navit_project.navit /org/navit_project/navit/default_navit org.navit_project.navit.navit.quit
diff --git a/ci/xdotools.sh b/ci/xdotools.sh
new file mode 100644
index 000000000..36331fd9b
--- /dev/null
+++ b/ci/xdotools.sh
@@ -0,0 +1,94 @@
+sudo apt-get install xdotool
+# Use xinput test 4 when running x11vnc on the circleci server to find mouse coordinates
+
+[ -d $CIRCLE_ARTIFACTS/frames/ ] || mkdir $CIRCLE_ARTIFACTS/frames/
+
+event=0
+
+send_event (){
+ file=`printf "%05d\n" $event`
+
+ import -window root $CIRCLE_ARTIFACTS/frames/tmp.png
+ if [[ "$1" == "mousemove" ]]; then
+ composite -gravity NorthWest -geometry +$2+$3 ~/navit/ci/pointer-64.png $CIRCLE_ARTIFACTS/frames/tmp.png $CIRCLE_ARTIFACTS/frames/${file}.png
+ else
+ mv $CIRCLE_ARTIFACTS/frames/tmp.png $CIRCLE_ARTIFACTS/frames/${file}.png
+ fi
+ event=$((event+1))
+ xdotool $@
+ sleep 1
+}
+
+
+# Center the view
+send_event key KP_Enter # Open main menu
+send_event key Down # Select 'Actions'
+send_event key KP_Enter # Validate
+send_event key Down # Scroll to 'Bookmarks'
+send_event key Right # Scroll to 'Former destinations'
+send_event key Right # Select 'Town'
+send_event key KP_Enter # Validate
+# Send 'Berk'
+send_event key b
+send_event key e
+send_event key r
+send_event key k
+send_event key Down # Highlight search area
+send_event key Down # Highlight first result
+send_event key KP_Enter # Validate
+
+# Set the position
+send_event mousemove 482 318 click 1 # Open main menu, clicking on a somewhat random position on the map
+send_event key Down # Select 'Actions'
+send_event key KP_Enter # Validate
+send_event key Down # Scroll to 'Bookmarks'
+send_event key Right # Scroll to 'Former destinations'
+send_event key Right # Select current coordinates
+send_event key KP_Enter # Validate
+
+# Set a destination
+send_event key KP_Enter # Open main menu
+send_event key Down # Select 'Actions'
+send_event key KP_Enter # Validate
+send_event key Down # Scroll to 'Bookmarks'
+send_event key Right # Scroll to 'Former destinations'
+send_event key Right # Select 'Town'
+send_event key KP_Enter # Validate
+# Send 'oakl'
+send_event key o
+send_event key a
+send_event key k
+send_event key l
+send_event key Down # Highlight search area
+send_event key Down # Highlight first result
+send_event key KP_Enter # Validate
+
+# Switch to 3d view
+send_event key KP_Enter # Open main menu
+send_event key Down # Select 'Actions'
+send_event key Right # Select 'Settings'
+send_event key KP_Enter # Validate
+send_event key Down # Select 'Display'
+send_event key KP_Enter # Validate
+send_event key Down # Scroll to 'Layout'
+send_event key Right # Scroll to 'Fullscreen'
+send_event key Right # Select '3d'
+send_event key KP_Enter # Validate
+# Send 'Berk'
+
+# capture 5 seconds of usage
+for i in `seq 99994 99999`; do
+ import -window root $CIRCLE_ARTIFACTS/frames/${i}.png
+ sleep 1
+done
+
+# Quit
+send_event key KP_Enter # Open main menu
+send_event key Down # Select 'Actions'
+send_event key Down # Select 'Route'
+send_event key Right # Select 'About'
+send_event key Right # Select 'Quit'
+send_event key KP_Enter # Validate
+
+# Assemble the gif
+convert -delay 100 -loop 0 $CIRCLE_ARTIFACTS/frames/*.png $CIRCLE_ARTIFACTS/town_search.gif
diff --git a/navit/attr_def.h b/navit/attr_def.h
index b3f77163b..2b0bad448 100644
--- a/navit/attr_def.h
+++ b/navit/attr_def.h
@@ -281,7 +281,7 @@ ATTR_UNUSED
ATTR_UNUSED
ATTR_UNUSED
ATTR(window_title)
-ATTR_UNUSED
+ATTR(qt5_platform)
ATTR_UNUSED
/* poi */
ATTR_UNUSED
diff --git a/navit/graphics/egl/CMakeLists.txt b/navit/graphics/egl/CMakeLists.txt
new file mode 100644
index 000000000..1943f2bc0
--- /dev/null
+++ b/navit/graphics/egl/CMakeLists.txt
@@ -0,0 +1,2 @@
+module_add_library(graphics_egl graphics_egl.c)
+
diff --git a/navit/graphics/egl/graphics_egl.c b/navit/graphics/egl/graphics_egl.c
new file mode 100644
index 000000000..4d7780ff4
--- /dev/null
+++ b/navit/graphics/egl/graphics_egl.c
@@ -0,0 +1,1458 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2010 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program 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, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <unistd.h>
+#include <math.h>
+#include <stdio.h>
+
+#include <time.h>
+
+#include "item.h"
+#include "attr.h"
+#include "config.h"
+#include "point.h"
+#include "graphics.h"
+#include "color.h"
+#include "plugin.h"
+#include "event.h"
+#include "debug.h"
+#include "callback.h"
+#include "keys.h"
+#include "window.h"
+#include "navit/font/freetype/font_freetype.h"
+
+#include <SDL2/SDL_image.h>
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+
+/*
+ * This is work in progress *
+ * Remainng issues :
+ * - SDL mouse cursor sometimes raise an SDL assertion
+ * - Dashed lines to implement
+ * - Full Keyboard handling
+*/
+
+#define SCREEN_WIDTH 800
+#define SCREEN_HEIGHT 600
+
+#define glF(x) x
+#define glD(x) x
+#define GL_F GL_FLOAT
+typedef GLfloat GLf;
+
+struct graphics_gc_priv {
+ struct graphics_priv *gr;
+ float fr, fg, fb, fa;
+ float br, bg, bb, ba;
+ int linewidth;
+ unsigned char *dash_list;
+ int dash_count;
+ int dash_mask;
+} graphics_gc_priv;
+
+struct graphics_priv {
+ int fill_poly;
+ int show_overlays;
+ int button_timeout;
+ struct point p;
+ int width;
+ int height;
+ int library_init;
+ int visible;
+ int overlay_enabled;
+ int overlay_autodisabled;
+ int wraparound;
+ GLuint framebuffer_name;
+ GLuint overlay_texture;
+ struct graphics_priv *parent;
+ struct graphics_priv *overlays;
+ struct graphics_priv *next;
+ struct graphics_gc_priv *background_gc;
+ enum draw_mode_num mode;
+ GLuint program;
+ GLint mvp_location, position_location, color_location, texture_position_location, use_texture_location, texture_location;
+ struct callback_list *cbl;
+ struct font_freetype_methods freetype_methods;
+ struct navit *nav;
+ int timeout;
+ int delay;
+ struct window window;
+ int dirty; //display needs to be redrawn (draw on root graphics or overlay is done)
+ int force_redraw; //display needs to be redrawn (draw on root graphics or overlay is done)
+ time_t last_refresh_time; //last display refresh time
+ struct graphics_opengl_platform *platform;
+ struct graphics_opengl_platform_methods *platform_methods;
+};
+
+struct graphics_image_priv {
+ SDL_Surface *img;
+} graphics_image_priv;
+
+
+struct graphics_opengl_platform {
+ SDL_Window* eglwindow;
+ SDL_GLContext eglcontext;
+ EGLDisplay egldisplay;
+ EGLConfig config[1];
+};
+
+struct contour
+{
+ struct point *p;
+ unsigned int count;
+};
+
+static GHashTable *hImageData;
+static int USERWANTSTOQUIT = 0;
+static struct graphics_priv *graphics_priv_root;
+static struct graphics_priv *graphics_opengl_new_helper(struct
+ graphics_methods
+ *meth);
+
+/*
+ * GLES 2 Compatible vertex and fragment shaders
+ * Taken from opengl driver
+ */
+const char vertex_src [] =
+" \
+ attribute vec2 position; \
+ attribute vec2 texture_position; \
+ uniform mat4 mvp; \
+ varying vec2 v_texture_position; \
+ \
+ void main() \
+ { \
+ v_texture_position=texture_position; \
+ gl_Position = mvp*vec4(position, 0.0, 1.0); \
+ } \
+";
+
+const char fragment_src [] =
+" \
+ uniform lowp vec4 avcolor; \
+ uniform sampler2D texture; \
+ uniform bool use_texture; \
+ varying vec2 v_texture_position; \
+ void main() \
+ { \
+ if (use_texture) { \
+ gl_FragColor = texture2D(texture, v_texture_position); \
+ } else { \
+ gl_FragColor = avcolor; \
+ } \
+ } \
+";
+
+/*
+* C conversion of Efficient Polygon Triangulation
+* Found at http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
+* Adapted and debugged for this use
+*/
+float area(const struct contour* contour)
+{
+ int p, q;
+ int n = contour->count - 1;
+ float A = 0.f;
+
+ for (p=n-1, q=0; q < n; p=q++)
+ {
+ A += contour->p[p].x * contour->p[q].y - contour->p[q].x * contour->p[p].y;
+ }
+ return A * .5f;
+}
+
+int
+inside_triangle(float Ax, float Ay,
+ float Bx, float By,
+ float Cx, float Cy,
+ float Px, float Py)
+{
+ float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
+ float cCROSSap, bCROSScp, aCROSSbp;
+
+ ax = Cx - Bx; ay = Cy - By;
+ bx = Ax - Cx; by = Ay - Cy;
+ cx = Bx - Ax; cy = By - Ay;
+ apx= Px - Ax; apy= Py - Ay;
+ bpx= Px - Bx; bpy= Py - By;
+ cpx= Px - Cx; cpy= Py - Cy;
+
+ aCROSSbp = ax*bpy - ay*bpx;
+ cCROSSap = cx*apy - cy*apx;
+ bCROSScp = bx*cpy - by*cpx;
+
+ return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
+}
+
+int
+snip(const struct point* pnt,int u,int v,int w,int n,int *V)
+{
+ int p;
+ float Ax, Ay, Bx, By, Cx, Cy, Px, Py;
+
+ Ax = pnt[V[u]].x;
+ Ay = pnt[V[u]].y;
+
+ Bx = pnt[V[v]].x;
+ By = pnt[V[v]].y;
+
+ Cx = pnt[V[w]].x;
+ Cy = pnt[V[w]].y;
+
+ if ( (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) < 0.f )
+ return 0;
+
+ for (p=0;p<n;p++)
+ {
+ if( (p == u) || (p == v) || (p == w) )
+ continue;
+ Px = pnt[V[p]].x;
+ Py = pnt[V[p]].y;
+ if (inside_triangle(Ax,Ay,Bx,By,Cx,Cy,Px,Py))
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+process_triangles(const struct contour* contour, struct contour* result)
+{
+ int v;
+ int contour_size = contour->count - 1;
+ int polygon_temp_size = contour_size * 80;
+ int final_count = 0;
+ result->p = malloc(sizeof(struct point) * polygon_temp_size);
+
+ int n = contour_size;
+ if ( n < 3 ) return 0;
+
+ int *V = alloca(sizeof(int)*n);
+
+ if ( 0.0f < area(contour) )
+ for (v=0; v<n; v++) V[v] = v;
+ else
+ for(v=0; v<n; v++) V[v] = (n-1)-v;
+
+ int nv = n;
+
+ int count = 2*nv;
+
+ for(v=nv-1; nv>2; )
+ {
+ /* if we loop, it is probably a non-simple polygon */
+ if (0 >= (count--))
+ {
+ //** Triangulate: ERROR - probable bad polygon!
+ break;
+ }
+
+ /* three consecutive vertices in current polygon, <u,v,w> */
+ int u = v ; if (nv <= u) u = 0; /* previous */
+ v = u+1; if (nv <= v) v = 0; /* new v */
+ int w = v+1; if (nv <= w) w = 0; /* next */
+
+ if ( snip(contour->p,u,v,w,nv,V) )
+ {
+ int a,b,c,s,t;
+
+ /* true names of the vertices */
+ a = V[u]; b = V[v]; c = V[w];
+
+ /* output Triangle */
+ result->p[final_count++] = contour->p[a];
+ result->p[final_count++] = contour->p[b];
+ result->p[final_count++] = contour->p[c];
+
+ if (final_count >= polygon_temp_size){
+ free(result->p);
+ return 0;
+ }
+
+ /* remove v from remaining polygon */
+ for(s=v,t=v+1;t<nv;s++,t++)
+ V[s] = V[t];
+ nv--;
+
+ /* resest error detection counter */
+ count = 2*nv;
+ }
+ }
+
+ result->count = final_count;
+
+ return 1;
+}
+
+// ** Efficient Polygon Triangulation **
+
+/*
+ * Destroys SDL/EGL context
+ */
+static void
+sdl_egl_destroy(struct graphics_opengl_platform *egl)
+{
+ if (egl->eglwindow){
+ SDL_GL_DeleteContext(egl->eglcontext);
+ SDL_DestroyWindow(egl->eglwindow);
+ }
+ g_free(egl);
+ SDL_Quit();
+}
+
+/*
+ * Swap EGL buffer
+ */
+static void
+sdl_egl_swap_buffers(struct graphics_opengl_platform *egl)
+{
+ SDL_GL_SwapWindow(egl->eglwindow);
+}
+
+/*
+ * Main graphic destroy
+ */
+static void
+graphics_destroy(struct graphics_priv *gr)
+{
+ /*FIXME graphics_destroy is never called */
+ gr->freetype_methods.destroy();
+ g_free(gr);
+ gr = NULL;
+ sdl_egl_destroy(gr->platform);
+ SDL_Quit();
+}
+
+static void
+gc_destroy(struct graphics_gc_priv *gc)
+{
+ g_free(gc);
+ gc = NULL;
+}
+
+static void
+gc_set_linewidth(struct graphics_gc_priv *gc, int w)
+{
+ gc->linewidth = w;
+}
+
+static void
+gc_set_dashes(struct graphics_gc_priv *gc, int width, int offset,
+ unsigned char *dash_list, int n)
+{
+ int i;
+ const int cOpenglMaskBits = 16;
+ gc->dash_count = n;
+ if (1 == n) {
+ gc->dash_mask = 0;
+ for (i = 0; i < cOpenglMaskBits; ++i) {
+ gc->dash_mask <<= 1;
+ gc->dash_mask |= (i / n) % 2;
+ }
+ } else if (1 < n) {
+ unsigned char *curr = dash_list;
+ int cnt = 0; //dot counter
+ int dcnt = 0; //dash element counter
+ int sum_dash = 0;
+ gc->dash_mask = 0;
+
+ for (i = 0; i < n; ++i) {
+ sum_dash += dash_list[i];
+ }
+
+ //scale dashlist elements to max size
+ if (sum_dash > cOpenglMaskBits) {
+ int num_error[2] = { 0, 0 }; //count elements rounded to 0 for odd(drawn) and even(masked) for compensation
+ double factor = (1.0 * cOpenglMaskBits) / sum_dash;
+ for (i = 0; i < n; ++i) { //calculate dashlist max and largest common denomiator for scaling
+ dash_list[i] *= factor;
+ if (dash_list[i] == 0) {
+ ++dash_list[i];
+ ++num_error[i % 2];
+ } else if (0 < num_error[i % 2]
+ && 2 < dash_list[i]) {
+ ++dash_list[i];
+ --num_error[i % 2];
+ }
+ }
+ }
+ //calculate mask
+ for (i = 0; i < cOpenglMaskBits; ++i) {
+ gc->dash_mask <<= 1;
+ gc->dash_mask |= 1 - dcnt % 2;
+ ++cnt;
+ if (cnt == *curr) {
+ cnt = 0;
+ ++curr;
+ ++dcnt;
+ if (dcnt == n) {
+ curr = dash_list;
+ }
+ }
+ }
+ }
+}
+
+
+static void
+gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
+{
+ gc->fr = c->r / 65535.0;
+ gc->fg = c->g / 65535.0;
+ gc->fb = c->b / 65535.0;
+ gc->fa = c->a / 65535.0;
+}
+
+static void
+gc_set_background(struct graphics_gc_priv *gc, struct color *c)
+{
+ gc->br = c->r / 65535.0;
+ gc->bg = c->g / 65535.0;
+ gc->bb = c->b / 65535.0;
+ gc->ba = c->a / 65535.0;
+}
+
+static struct graphics_gc_methods gc_methods = {
+ gc_destroy,
+ gc_set_linewidth,
+ gc_set_dashes,
+ gc_set_foreground,
+ gc_set_background
+};
+
+static struct graphics_gc_priv *
+gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
+{
+ struct graphics_gc_priv *gc = g_new0(struct graphics_gc_priv, 1);
+
+ *meth = gc_methods;
+ gc->gr = gr;
+ gc->linewidth = 1;
+ return gc;
+}
+
+static struct graphics_image_priv image_error;
+
+static struct graphics_image_priv *
+image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h,
+ struct point *hot, int rotation)
+{
+ struct graphics_image_priv *gi;
+
+ /* FIXME: meth is not used yet.. so gi leaks. at least xpm is small */
+
+ struct graphics_image_priv *curr_elem =
+ g_hash_table_lookup(hImageData, name);
+
+ if (curr_elem == &image_error) {
+ //found but couldn't be loaded
+ return NULL;
+ } else if (curr_elem) {
+ //found and OK -> use hastable entry
+ *w = curr_elem->img->w;
+ *h = curr_elem->img->h;
+ hot->x = *w / 2;
+ hot->y = *h / 2;
+ return curr_elem;
+ }
+
+ if (strlen(name) < 4) {
+ g_hash_table_insert(hImageData, g_strdup(name),
+ &image_error);
+ return NULL;
+ }
+
+ gi = g_new0(struct graphics_image_priv, 1);
+ gi->img = IMG_Load(name);
+ if(gi->img)
+ {
+ *w=gi->img->w;
+ *h=gi->img->h;
+ hot->x=*w/2;
+ hot->y=*h/2;
+ }
+ else
+ {
+ /* TODO: debug "colour parse errors" on xpm */
+ dbg(lvl_error,"image_new on '%s' failed: %s\n", name, IMG_GetError());
+ g_free(gi);
+ gi = NULL;
+ g_hash_table_insert(hImageData,
+ g_strdup(name),
+ &image_error);
+ return gi;
+ }
+
+ g_hash_table_insert(hImageData, g_strdup(name), gi);
+ return gi;
+}
+
+static void
+image_free(struct graphics_priv *gr, struct graphics_image_priv * gi)
+{
+// SDL_FreeSurface(gi->img);
+// g_free(gi);
+}
+
+static void
+set_color(struct graphics_priv *gr, struct graphics_gc_priv *gc)
+{
+ GLfloat col[4];
+ col[0]=gc->fr;
+ col[1]=gc->fg;
+ col[2]=gc->fb;
+ col[3]=gc->fa;
+ glUniform4fv(gr->color_location, 1, col);
+}
+
+static void
+draw_array(struct graphics_priv *gr, struct point *p, int count, GLenum mode)
+{
+ int i;
+ GLf *x;//[count*2];
+ x = alloca(sizeof(GLf)*count*2);
+ for (i = 0 ; i < count ; i++) {
+ x[i*2]=glF(p[i].x);
+ x[i*2+1]=glF(p[i].y);
+ }
+
+ glVertexAttribPointer (gr->position_location, 2, GL_FLOAT, 0, 0, x );
+ glDrawArrays(mode, 0, count);
+}
+
+static void
+draw_rectangle_do(struct graphics_priv *gr, struct point *p, int w, int h)
+{
+ struct point pa[4];
+ pa[0]=pa[1]=pa[2]=pa[3]=*p;
+ pa[0].x+=w;
+ pa[1].x+=w;
+ pa[1].y+=h;
+ pa[3].y+=h;
+ draw_array(gr, pa, 4, GL_TRIANGLE_STRIP);
+}
+
+
+static void
+draw_image_es(struct graphics_priv *gr, struct point *p, int w, int h, unsigned char *data)
+{
+ GLf x[8];
+ GLuint texture;
+ memset(x, 0, sizeof(x));
+
+ glGenTextures(1, &texture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+
+ x[0]+=glF(1);
+ x[2]+=glF(1);
+ x[3]+=glF(1);
+ x[7]+=glF(1);
+ glUniform1i(gr->use_texture_location, 1);
+ glEnableVertexAttribArray(gr->texture_position_location);
+ glVertexAttribPointer (gr->texture_position_location, 2, GL_FLOAT, 0, 0, x );
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ draw_rectangle_do(gr, p, w, h);
+
+ glUniform1i(gr->use_texture_location, 0);
+ glDisableVertexAttribArray(gr->texture_position_location);
+
+ glDisable(GL_BLEND);
+ glDeleteTextures(1, &texture);
+}
+
+inline void
+get_overlay_pos(struct graphics_priv *gr, struct point *point_out)
+{
+ if (gr->parent == NULL) {
+ point_out->x = 0;
+ point_out->y = 0;
+ return;
+ }
+ point_out->x = gr->p.x;
+ if (point_out->x < 0) {
+ point_out->x += gr->parent->width;
+ }
+
+ point_out->y = gr->p.y;
+ if (point_out->y < 0) {
+ point_out->y += gr->parent->height;
+ }
+}
+
+inline void
+draw_overlay(struct graphics_priv *gr)
+{
+ struct point p_eff;
+ GLf x[8];
+
+ get_overlay_pos(gr, &p_eff);
+
+ memset(x, 0, 8*sizeof(GLf));
+ x[0]+=glF(1);
+ x[1]+=glF(1);
+ x[2]+=glF(1);
+ x[5]+=glF(1);
+
+ glUniform1i(gr->use_texture_location, 1);
+ glEnableVertexAttribArray(gr->texture_position_location);
+ glVertexAttribPointer (gr->texture_position_location, 2, GL_FLOAT, 0, 0, x);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, gr->overlay_texture);
+
+ draw_rectangle_do(graphics_priv_root, &p_eff, gr->width, gr->height);
+
+ glUniform1i(gr->use_texture_location, 0);
+ glDisableVertexAttribArray(gr->texture_position_location);
+
+ glDisable(GL_BLEND);
+}
+
+static void
+draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc,
+ struct point *p, int count)
+{
+ if ((gr->parent && !gr->parent->overlay_enabled)
+ || (gr->parent && gr->parent->overlay_enabled
+ && !gr->overlay_enabled)) {
+ return;
+ }
+
+ glLineWidth(gc->linewidth);
+
+ set_color(gr, gc);
+ graphics_priv_root->dirty = 1;
+
+ draw_array(gr, p, count, GL_LINE_STRIP);
+}
+
+
+static void
+draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc,
+ struct point *p, int count)
+{
+ int ok;
+ if ((gr->parent && !gr->parent->overlay_enabled)
+ || (gr->parent && gr->parent->overlay_enabled
+ && !gr->overlay_enabled)) {
+ return;
+ }
+ set_color(gr, gc);
+ graphics_priv_root->dirty = 1;
+ struct contour contour, result;
+ contour.count = count;
+ contour.p = p;
+ ok = process_triangles(&contour, &result);
+ if (ok && gr->fill_poly){
+ draw_array(gr, result.p, result.count, GL_TRIANGLES);
+ free(result.p);
+ } else {
+ draw_array(gr, p, count, GL_LINE_STRIP);
+ }
+}
+
+static void
+draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc,
+ struct point *p, int w, int h)
+{
+ if ((gr->parent && !gr->parent->overlay_enabled)
+ || (gr->parent && gr->parent->overlay_enabled
+ && !gr->overlay_enabled)) {
+ return;
+ }
+ set_color(gr, gc);
+ draw_rectangle_do(gr, p, w, h);
+ graphics_priv_root->dirty = 1;
+}
+
+static void
+display_text_draw(struct font_freetype_text *text,
+ struct graphics_priv *gr, struct graphics_gc_priv *fg,
+ struct graphics_gc_priv *bg, int color, struct point *p)
+{
+ int i, x, y, stride;
+ struct font_freetype_glyph *g, **gp;
+ unsigned char *shadow, *glyph;
+ struct color transparent = { 0x0000, 0x0000, 0x0000, 0x0000 };
+ struct color black =
+ { fg->fr * 65535, fg->fg * 65535, fg->fb * 65535,
+ fg->fa * 65535 };
+ struct color white = { 0xffff, 0xffff, 0xffff, 0xffff };
+
+ if (bg) {
+ if (COLOR_IS_WHITE(black) && COLOR_IS_BLACK(white)) {
+ black.r = 65535;
+ black.g = 65535;
+ black.b = 65535;
+ black.a = 65535;
+
+ white.r = 0;
+ white.g = 0;
+ white.b = 0;
+ white.a = 65535;
+ } else if (COLOR_IS_BLACK(black) && COLOR_IS_WHITE(white)) {
+ white.r = 65535;
+ white.g = 65535;
+ white.b = 65535;
+ white.a = 65535;
+
+ black.r = 0;
+ black.g = 0;
+ black.b = 0;
+ black.a = 65535;
+ } else {
+ white.r = bg->fr;
+ white.g = bg->fg;
+ white.b = bg->fb;
+ white.a = bg->fa;
+ }
+ } else {
+ white.r = 0;
+ white.g = 0;
+ white.b = 0;
+ white.a = 0;
+ }
+
+ gp = text->glyph;
+ i = text->glyph_count;
+ x = p->x << 6;
+ y = p->y << 6;
+ while (i-- > 0) {
+ g = *gp++;
+ if (g->w && g->h && bg) {
+ stride = (g->w + 2) * 4;
+ if (color) {
+ shadow = g_malloc(stride * (g->h + 2));
+ gr->freetype_methods.get_shadow(g, shadow,
+ stride,
+ &white,
+ &transparent);
+
+ struct point p;
+ p.x=((x + g->x) >> 6)-1;
+ p.y=((y + g->y) >> 6)-1;
+ draw_image_es(gr, &p, g->w+2, g->h+2, shadow);
+
+ g_free(shadow);
+ }
+ }
+ x += g->dx;
+ y += g->dy;
+ }
+
+ x = p->x << 6;
+ y = p->y << 6;
+ gp = text->glyph;
+ i = text->glyph_count;
+ while (i-- > 0) {
+ g = *gp++;
+ if (g->w && g->h) {
+ if (color) {
+ stride = g->w;
+ if (bg) {
+ glyph =
+ g_malloc(stride * g->h * 4);
+ gr->freetype_methods.get_glyph(g,
+ glyph,
+ stride
+ * 4,
+ &black,
+ &white,
+ &transparent);
+ struct point p;
+ p.x=(x + g->x) >> 6;
+ p.y=(y + g->y) >> 6;
+ draw_image_es(gr, &p, g->w, g->h, glyph);
+
+ g_free(glyph);
+ }
+ stride *= 4;
+ glyph = g_malloc(stride * g->h);
+ gr->freetype_methods.get_glyph(g, glyph,
+ stride,
+ &black,
+ &white,
+ &transparent);
+ struct point p;
+ p.x=(x + g->x) >> 6;
+ p.y=(y + g->y) >> 6;
+ draw_image_es(gr, &p, g->w, g->h, glyph);
+
+ g_free(glyph);
+ }
+ }
+ x += g->dx;
+ y += g->dy;
+ }
+}
+
+static void
+draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg,
+ struct graphics_gc_priv *bg, struct graphics_font_priv *font,
+ char *text, struct point *p, int dx, int dy)
+{
+ if ((gr->parent && !gr->parent->overlay_enabled)
+ || (gr->parent && gr->parent->overlay_enabled
+ && !gr->overlay_enabled)) {
+ return;
+ }
+
+ struct font_freetype_text *t;
+ int color = 1;
+
+ if (!font) {
+ dbg(lvl_error, "no font, returning\n");
+ return;
+ }
+ graphics_priv_root->dirty = 1;
+
+ t = gr->freetype_methods.text_new(text,
+ (struct font_freetype_font *)
+ font, dx, dy);
+
+ struct point p_eff;
+ p_eff.x = p->x;
+ p_eff.y = p->y;
+
+ display_text_draw(t, gr, fg, bg, color, &p_eff);
+ gr->freetype_methods.text_destroy(t);
+}
+
+
+static void
+draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg,
+ struct point *p, struct graphics_image_priv *img)
+{
+ draw_image_es(gr, p, img->img->w, img->img->h, img->img->pixels);
+}
+
+static void
+draw_drag(struct graphics_priv *gr, struct point *p)
+{
+ if (p) {
+ gr->p.x = p->x;
+ gr->p.y = p->y;
+ }
+}
+
+static void
+background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
+{
+ gr->background_gc = gc;
+}
+
+/*
+ * Draws map in background
+ */
+static void
+draw_background(struct graphics_priv *gr)
+{
+ struct point p_eff;
+ GLf x[8];
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glViewport(0, 0, gr->width, gr->height);
+ //get_overlay_pos(gr, &p_eff);
+ p_eff.x = gr->p.x;
+ p_eff.y = gr->p.y;
+
+ memset(x, 0, 8*sizeof(GLf));
+ x[0]+=glF(1);
+ x[1]+=glF(1);
+ x[2]+=glF(1);
+ x[5]+=glF(1);
+
+ glUniform1i(gr->use_texture_location, 1);
+ glEnableVertexAttribArray(gr->texture_position_location);
+ glVertexAttribPointer (gr->texture_position_location, 2, GL_FLOAT, 0, 0, x);
+
+ glDisable(GL_BLEND);
+ glBindTexture(GL_TEXTURE_2D, gr->overlay_texture);
+
+ draw_rectangle_do(gr, &p_eff, gr->width, gr->height);
+
+ glUniform1i(gr->use_texture_location, 0);
+ glDisableVertexAttribArray(gr->texture_position_location);
+}
+
+/*
+ Drawing method :
+ Map and overlays are rendered in an offscreen buffer (See render to texture)
+ and are recomposed altogether at draw_mode_end request for root
+*/
+static void
+draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
+{
+ GLfloat matrix[16];
+ struct graphics_priv *overlay = NULL;
+ int i;
+
+ if (mode == draw_mode_begin){
+ // Should not be necessary...
+ // SDL_GL_MakeCurrent(gr->platform->eglwindow, gr->platform->eglcontext);
+
+ if (gr->parent == NULL){
+ // Full redraw, reset drag position
+ gr->p.x = 0;
+ gr->p.y = 0;
+ }
+
+ // Need to setup appropriate projection matrix
+ for (i = 0; i < 16 ; i++){
+ matrix[i] = 0.0;
+ }
+
+ matrix[0]=2.0 / gr->width;
+ matrix[5]=-2.0 / gr->height;
+ matrix[10]=1;
+ matrix[12]=-1;
+ matrix[13]=1;
+ matrix[15]=1;
+ glUniformMatrix4fv(gr->mvp_location, 1, GL_FALSE, matrix);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, gr->framebuffer_name);
+ glViewport(0,0,gr->width,gr->height);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ if (mode == draw_mode_end && gr->parent == NULL) {
+ overlay = gr->overlays;
+ draw_background(gr);
+ while(overlay){
+ if (gr->overlay_enabled)
+ draw_overlay(overlay);
+ overlay = overlay->next;
+ }
+ sdl_egl_swap_buffers(gr->platform);
+ }
+
+ gr->mode = mode;
+}
+
+static int
+graphics_opengl_fullscreen(struct window *w, int on)
+{
+ return 1;
+}
+
+static void
+graphics_opengl_disable_suspend(struct window *w)
+{
+ // No op
+}
+
+
+static GLuint
+load_shader(const char *shader_source, GLenum type)
+{
+ GLuint shader = glCreateShader(type);
+
+ glShaderSource(shader, 1, &shader_source, NULL);
+ glCompileShader(shader);
+
+ return shader;
+}
+
+static void *
+get_data(struct graphics_priv *this, const char *type)
+{
+ GLuint vertexShader;
+ GLuint fragmentShader;
+ struct window* win;
+ int i;
+
+ if (!strcmp(type, "gtk_widget")) {
+ fprintf(stderr,
+ "Currently GTK gui is not yet supported with EGL graphics driver\n");
+ return NULL;
+ }
+
+ if(strcmp(type, "window") == 0) {
+ SDL_GL_MakeCurrent(this->platform->eglwindow, this->platform->eglcontext);
+
+ glClearColor ( 0 , 0 , 0 , 1);
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ callback_list_call_attr_2(graphics_priv_root->cbl, attr_resize,
+ GINT_TO_POINTER(this->width), GINT_TO_POINTER(this->height));
+
+ this->program = glCreateProgram();
+ vertexShader = load_shader(vertex_src, GL_VERTEX_SHADER);
+ fragmentShader = load_shader(fragment_src, GL_FRAGMENT_SHADER);
+
+ glAttachShader(this->program, vertexShader);
+ glAttachShader(this->program, fragmentShader);
+ glLinkProgram(this->program);
+ glUseProgram(this->program);
+
+ this->mvp_location = glGetUniformLocation(this->program, "mvp");
+ this->position_location = glGetAttribLocation(this->program, "position");
+ glEnableVertexAttribArray(this->position_location);
+ this->texture_position_location = glGetAttribLocation(this->program, "texture_position");
+ this->color_location = glGetUniformLocation(this->program, "avcolor");
+ this->texture_location = glGetUniformLocation(this->program, "texture");
+ this->use_texture_location = glGetUniformLocation(this->program, "use_texture");
+
+ glUniform1i(this->use_texture_location, 0);
+ glUniform1i(this->texture_location, 0);
+
+ win=g_new(struct window, 1);
+ win->priv=this;
+ win->disable_suspend=NULL;
+ win->fullscreen = graphics_opengl_fullscreen;
+ win->disable_suspend = graphics_opengl_disable_suspend;
+ return win;
+ }
+
+ return NULL;
+
+}
+
+static void
+overlay_disable(struct graphics_priv *gr, int disable)
+{
+ gr->overlay_enabled = !disable;
+ gr->force_redraw = 1;
+ draw_mode(gr, draw_mode_end);
+}
+
+// Need more testing
+static void
+overlay_resize(struct graphics_priv *gr, struct point *p, int w, int h,
+ int wraparound)
+{
+ int changed = 0;
+ int w2, h2;
+
+ if (w == 0) {
+ w2 = 1;
+ } else {
+ w2 = w;
+ }
+
+ if (h == 0) {
+ h2 = 1;
+ } else {
+ h2 = h;
+ }
+
+ gr->p = *p;
+ if (gr->width != w2) {
+ gr->width = w2;
+ changed = 1;
+ }
+
+ if (gr->height != h2) {
+ gr->height = h2;
+ changed = 1;
+ }
+
+ gr->wraparound = wraparound;
+
+ if (changed) {
+ if ((w == 0) || (h == 0)) {
+ gr->overlay_autodisabled = 1;
+ } else {
+ gr->overlay_autodisabled = 0;
+ // Reset overlay texture
+ glDeleteTextures(1, &gr->overlay_texture);
+ glGenTextures(1, &gr->overlay_texture);
+ glBindTexture(GL_TEXTURE_2D, gr->overlay_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, gr->width, gr->height, 0,GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gr->overlay_texture, 0);
+ }
+
+ callback_list_call_attr_2(gr->cbl, attr_resize,
+ GINT_TO_POINTER(gr->width),
+ GINT_TO_POINTER(gr->height));
+ }
+}
+
+
+static struct graphics_priv *overlay_new(struct graphics_priv *gr,
+ struct graphics_methods *meth,
+ struct point *p, int w, int h,
+ int wraparound);
+
+static struct graphics_methods graphics_methods = {
+ graphics_destroy,
+ draw_mode,
+ draw_lines,
+ draw_polygon,
+ draw_rectangle,
+ NULL,
+ draw_text,
+ draw_image,
+ NULL,
+ draw_drag,
+ NULL,
+ gc_new,
+ background_gc,
+ overlay_new,
+ image_new,
+ get_data,
+ image_free,
+ NULL,
+ overlay_disable,
+ overlay_resize,
+ NULL, /* set_attr, */
+ NULL, /* show_native_keyboard */
+ NULL, /* hide_native_keyboard */
+};
+
+static struct graphics_priv *
+graphics_opengl_new_helper(struct graphics_methods *meth)
+{
+ struct font_priv *(*font_freetype_new) (void *meth);
+ font_freetype_new = plugin_get_category_font("freetype");
+
+ if (!font_freetype_new) {
+ return NULL;
+ }
+
+ struct graphics_priv *this = g_new0(struct graphics_priv, 1);
+
+ font_freetype_new(&this->freetype_methods);
+ *meth = graphics_methods;
+
+ meth->font_new =
+ (struct graphics_font_priv *
+ (*)(struct graphics_priv *, struct graphics_font_methods *,
+ char *, int, int)) this->freetype_methods.font_new;
+ meth->get_text_bbox =
+ (void (*) (struct graphics_priv *, struct graphics_font_priv *,
+ char *, int, int, struct point*, int)) this->freetype_methods.get_text_bbox;
+ return this;
+}
+
+static void
+create_framebuffer_texture(struct graphics_priv *gr)
+{
+ GLenum status;
+ // Prepare a new framebuffer object
+ glGenFramebuffers(1, &gr->framebuffer_name);
+ glBindFramebuffer(GL_FRAMEBUFFER, gr->framebuffer_name);
+
+ glGenTextures(1, &gr->overlay_texture);
+ glBindTexture(GL_TEXTURE_2D, gr->overlay_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, gr->width, gr->height, 0,GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gr->overlay_texture, 0);
+
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ printf("Error creating texture framebuffer for overlay, exiting.\n");
+ SDL_Quit();
+ exit(1);
+ }
+}
+
+static struct graphics_priv *
+overlay_new(struct graphics_priv *gr, struct graphics_methods *meth,
+ struct point *p, int w, int h, int wraparound)
+{
+ struct graphics_priv *this = graphics_opengl_new_helper(meth);
+
+ this->p.x = p->x;
+ this->p.y = p->y;
+
+ this->width = w;
+ this->height = h;
+ this->parent = gr;
+ this->overlays = NULL;
+ this->fill_poly = 1;
+
+ // Copy shader locations parameters
+ this->mvp_location = graphics_priv_root->mvp_location;
+ this->position_location = graphics_priv_root->position_location;
+ this->texture_position_location = graphics_priv_root->texture_position_location;
+ this->color_location = graphics_priv_root->color_location;
+ this->texture_location = graphics_priv_root->texture_location;
+ this->use_texture_location = graphics_priv_root->use_texture_location;
+
+ if ((w == 0) || (h == 0)) {
+ this->overlay_autodisabled = 1;
+ } else {
+ this->overlay_autodisabled = 0;
+ }
+ this->overlay_enabled = 1;
+
+ this->next = gr->overlays;
+ gr->overlays = this;
+
+ create_framebuffer_texture(this);
+
+ return this;
+}
+
+
+static gboolean graphics_sdl_idle(void *data)
+{
+ struct graphics_priv *gr = (struct graphics_priv *)data;
+ struct point p;
+ SDL_Event ev;
+ int ret;
+ char key_mod = 0;
+ char keybuf[8];
+ char keycode;
+
+ // Process SDL events (KEYS + MOUSE)
+ while(1)
+ {
+ ret = SDL_PollEvent(&ev);
+
+ if(!ret)
+ break;
+
+ switch(ev.type)
+ {
+ case SDL_MOUSEMOTION:
+ {
+ p.x = ev.motion.x;
+ p.y = ev.motion.y;
+ //gr->force_redraw = 1;
+ callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p);
+ break;
+ }
+
+ case SDL_KEYDOWN:
+ {
+ memset(keybuf, 0, sizeof(keybuf));
+ switch(ev.key.keysym.sym)
+ {
+ case SDLK_F1:
+ graphics_priv_root->fill_poly = !graphics_priv_root->fill_poly;
+ break;
+ case SDLK_F2:
+ graphics_priv_root->show_overlays = !graphics_priv_root->show_overlays;
+ break;
+ case SDLK_LEFT:
+ {
+ keybuf[0] = NAVIT_KEY_LEFT;
+ break;
+ }
+ case SDLK_RIGHT:
+ {
+ keybuf[0] = NAVIT_KEY_RIGHT;
+ break;
+ }
+ case SDLK_BACKSPACE:
+ {
+ keybuf[0] = NAVIT_KEY_BACKSPACE;
+ break;
+ }
+ case SDLK_RETURN:
+ {
+ keybuf[0] = NAVIT_KEY_RETURN;
+ break;
+ }
+ case SDLK_DOWN:
+ {
+ keybuf[0] = NAVIT_KEY_DOWN;
+ break;
+ }
+ case SDLK_PAGEUP:
+ {
+ keybuf[0] = NAVIT_KEY_ZOOM_OUT;
+ break;
+ }
+ case SDLK_UP:
+ {
+ keybuf[0] = NAVIT_KEY_UP;
+ break;
+ }
+ case SDLK_PAGEDOWN:
+ {
+ keybuf[0] = NAVIT_KEY_ZOOM_IN;
+ break;
+ }
+ case SDLK_ESCAPE:
+ {
+ USERWANTSTOQUIT = 1;
+ break;
+ }
+ default:
+ {
+ /* return unicode chars when they can be converted to ascii */
+ // Need more work...
+ keycode = ev.key.keysym.sym;
+ keybuf[0] = keycode <= 127 ? keycode : 0;
+ break;
+ }
+ }
+ if (keybuf[0]) {
+ callback_list_call_attr_1(gr->cbl, attr_keypress, (void *)keybuf);
+ }
+ break;
+ }
+ case SDL_KEYUP:
+ {
+ break;
+ }
+ case SDL_MOUSEBUTTONDOWN:
+ {
+ p.x = ev.button.x;
+ p.y = ev.button.y;
+ graphics_priv_root->force_redraw = 1;
+ callback_list_call_attr_3(gr->cbl, attr_button, GINT_TO_POINTER(1), GINT_TO_POINTER((int)ev.button.button), (void *)&p);
+ break;
+ }
+
+ case SDL_MOUSEBUTTONUP:
+ {
+ p.x = ev.button.x;
+ p.y = ev.button.y;
+ callback_list_call_attr_3(gr->cbl, attr_button, GINT_TO_POINTER(0), GINT_TO_POINTER((int)ev.button.button), (void *)&p);
+ break;
+ }
+
+ case SDL_QUIT:
+ {
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ if (USERWANTSTOQUIT){
+ SDL_Quit();
+ exit(0);
+ }
+
+ return TRUE;
+}
+
+
+static struct graphics_priv *
+graphics_opengl_new(struct navit *nav, struct graphics_methods *meth,
+ struct attr **attrs, struct callback_list *cbl)
+{
+ struct attr *attr;
+ if (!event_request_system("glib", "graphics_opengl_new"))
+ return NULL;
+
+ hImageData = g_hash_table_new(g_str_hash, g_str_equal);
+ struct graphics_priv *this = graphics_opengl_new_helper(meth);
+ graphics_priv_root = this;
+
+ this->nav = nav;
+ this->parent = NULL;
+ this->overlay_enabled = 1;
+ this->framebuffer_name = 0;
+ this->overlays = NULL;
+ this->fill_poly = 1;
+ this->show_overlays = 1;
+
+ this->width = SCREEN_WIDTH;
+ if ((attr = attr_search(attrs, NULL, attr_w)))
+ this->width = attr->u.num;
+ this->height = SCREEN_HEIGHT;
+ if ((attr = attr_search(attrs, NULL, attr_h)))
+ this->height = attr->u.num;
+ this->timeout = 100;
+ if ((attr = attr_search(attrs, NULL, attr_timeout)))
+ this->timeout = attr->u.num;
+ this->delay = 0;
+ if ((attr = attr_search(attrs, NULL, attr_delay)))
+ this->delay = attr->u.num;
+ this->cbl = cbl;
+
+ this->framebuffer_name = 0;
+
+ graphics_priv_root->cbl = cbl;
+ graphics_priv_root->width = this->width;
+ graphics_priv_root->height = this->height;
+
+ struct graphics_opengl_platform *ret=g_new0(struct graphics_opengl_platform,1);
+
+ // SDL Init
+ int sdl_status = SDL_Init(SDL_INIT_VIDEO|SDL_INIT_EVENTS);
+
+ if (sdl_status != 0){
+ fprintf(stderr, "\nUnable to initialize SDL: %i %s\n", sdl_status, SDL_GetError() );
+ exit(1);
+ }
+
+ Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN;
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
+ // I think it's not necessary to sync vblank, update is quite slow
+ SDL_GL_SetSwapInterval(0);
+
+ ret->eglwindow = SDL_CreateWindow(
+ "Navit EGL", // window title
+ SDL_WINDOWPOS_UNDEFINED, // initial x position
+ SDL_WINDOWPOS_UNDEFINED, // initial y position
+ this->width, // width, in pixels
+ this->height, // height, in pixels
+ flags
+ );
+
+ if (ret->eglwindow == NULL) {
+ fprintf(stderr, "\nUnable to initialize SDL window: %s\n", SDL_GetError() );
+ goto error;
+ }
+
+ ret->eglcontext = SDL_GL_CreateContext(ret->eglwindow);
+ if (ret->eglcontext == NULL){
+ printf("EGL context creation failed\n");
+ goto error;
+ }
+
+ this->platform = ret;
+ create_framebuffer_texture(this);
+ g_timeout_add(G_PRIORITY_DEFAULT+10, graphics_sdl_idle, this);
+ glDisable(GL_DEPTH_TEST);
+ return this;
+error:
+ SDL_Quit();
+ return NULL;
+}
+
+void
+plugin_init(void)
+{
+ plugin_register_category_graphics("egl", graphics_opengl_new);
+}
+
diff --git a/navit/graphics/qt5/CMakeLists.txt b/navit/graphics/qt5/CMakeLists.txt
new file mode 100644
index 000000000..9c2574e8b
--- /dev/null
+++ b/navit/graphics/qt5/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Find includes in corresponding build directories
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+# Instruct CMake to run moc automatically when needed.
+set(CMAKE_AUTOMOC ON)
+
+# Find the QtWidgets library
+find_package(Qt5Widgets)
+
+module_add_library(graphics_qt5 graphics_qt5.cpp event_qt5.cpp QNavitWidget.cpp)
diff --git a/navit/graphics/qt5/QNavitWidget.cpp b/navit/graphics/qt5/QNavitWidget.cpp
new file mode 100644
index 000000000..fe3a618e2
--- /dev/null
+++ b/navit/graphics/qt5/QNavitWidget.cpp
@@ -0,0 +1,158 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program 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, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include "config.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "item.h"
+#include "point.h"
+#include "graphics.h"
+#include "color.h"
+#include "plugin.h"
+#include "event.h"
+#include "debug.h"
+#include "window.h"
+#include "callback.h"
+#if defined(WINDOWS) || defined(WIN32) || defined (HAVE_API_WIN32_CE)
+#include <windows.h>
+#endif
+#include "graphics_qt5.h"
+#include "QNavitWidget.h"
+#include "QNavitWidget.moc"
+
+QNavitWidget :: QNavitWidget(struct graphics_priv *my_graphics_priv,
+ QWidget * parent,
+ Qt::WindowFlags flags): QWidget(parent, flags)
+{
+ graphics_priv = my_graphics_priv;
+}
+
+bool QNavitWidget::event(QEvent *event)
+{
+ if (event->type() == QEvent::Gesture)
+ dbg(lvl_debug, "Gesture event caught");
+ //return gestureEvent(static_cast<QGestureEvent*>(event));
+ return QWidget::event(event);
+}
+
+void QNavitWidget :: paintEvent(QPaintEvent * event)
+{
+// dbg(lvl_debug,"enter\n");
+ QPainter painter(this);
+ /* color background if any */
+ if (graphics_priv->background_graphics_gc_priv != NULL)
+ {
+ painter.setPen(*graphics_priv->background_graphics_gc_priv->pen);
+ painter.fillRect(0, 0, graphics_priv->pixmap->width(),
+ graphics_priv->pixmap->height(),
+ *graphics_priv->background_graphics_gc_priv->brush);
+ }
+ painter.drawPixmap(0,0,*graphics_priv->pixmap);
+
+}
+
+void QNavitWidget::resizeEvent(QResizeEvent * event)
+{
+ QPainter * painter = NULL;
+ if(graphics_priv->pixmap != NULL)
+ {
+ delete graphics_priv->pixmap;
+ graphics_priv->pixmap = NULL;
+ }
+
+ graphics_priv->pixmap=new QPixmap(size());
+ graphics_priv->pixmap->fill();
+ painter = new QPainter(graphics_priv->pixmap);
+ QBrush brush;
+ painter->fillRect(0, 0, width(), height(), brush);
+ if(painter != NULL)
+ delete painter;
+ dbg(lvl_debug,"size %dx%d\n", width(), height());
+ dbg(lvl_debug,"pixmap %p %dx%d\n", graphics_priv->pixmap, graphics_priv->pixmap->width(), graphics_priv->pixmap->height());
+ /* if the root window got resized, tell navit about it */
+ if(graphics_priv->root)
+ resize_callback(width(),height());
+}
+
+void QNavitWidget::mouseEvent(int pressed, QMouseEvent *event)
+{
+ struct point p;
+// dbg(lvl_debug,"enter\n");
+ p.x=event->x();
+ p.y=event->y();
+ switch (event->button()) {
+ case Qt::LeftButton:
+ callback_list_call_attr_3(callbacks, attr_button, GINT_TO_POINTER(pressed), GINT_TO_POINTER(1), GINT_TO_POINTER(&p));
+ break;
+ case Qt::MidButton:
+ callback_list_call_attr_3(callbacks, attr_button, GINT_TO_POINTER(pressed), GINT_TO_POINTER(2), GINT_TO_POINTER(&p));
+ break;
+ case Qt::RightButton:
+ callback_list_call_attr_3(callbacks, attr_button, GINT_TO_POINTER(pressed), GINT_TO_POINTER(3), GINT_TO_POINTER(&p));
+ break;
+ default:
+ break;
+ }
+}
+
+void QNavitWidget::mousePressEvent(QMouseEvent *event)
+{
+// dbg(lvl_debug,"enter\n");
+ mouseEvent(1, event);
+}
+
+void QNavitWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+// dbg(lvl_debug,"enter\n");
+ mouseEvent(0, event);
+}
+
+void QNavitWidget::mouseMoveEvent(QMouseEvent *event)
+{
+ struct point p;
+// dbg(lvl_debug,"enter\n");
+ p.x=event->x();
+ p.y=event->y();
+ callback_list_call_attr_1(callbacks, attr_motion, (void *)&p);
+}
+
+void QNavitWidget::wheelEvent(QWheelEvent *event)
+{
+ struct point p;
+ int button;
+ dbg(lvl_debug,"enter");
+ p.x=event->x(); // xy-coordinates of the mouse pointer
+ p.y=event->y();
+
+ if (event->delta() > 0) // wheel movement away from the person
+ button=4;
+ else if (event->delta() < 0) // wheel movement towards the person
+ button=5;
+ else
+ button=-1;
+
+ if (button != -1) {
+ callback_list_call_attr_3(callbacks, attr_button, GINT_TO_POINTER(1), GINT_TO_POINTER(button), GINT_TO_POINTER(&p));
+ callback_list_call_attr_3(callbacks, attr_button, GINT_TO_POINTER(0), GINT_TO_POINTER(button), GINT_TO_POINTER(&p));
+ }
+
+ event->accept();
+}
diff --git a/navit/graphics/qt5/QNavitWidget.h b/navit/graphics/qt5/QNavitWidget.h
new file mode 100644
index 000000000..3b048ccf7
--- /dev/null
+++ b/navit/graphics/qt5/QNavitWidget.h
@@ -0,0 +1,33 @@
+#ifndef __QNavitWidget_h
+#define __QNavitWidget_h
+class QNavitWidget;
+#include "graphics_qt5.h"
+#include <QPixmap>
+#include <QWidget>
+#include <QMouseEvent>
+#include <QWheelEvent>
+#include <QEvent>
+
+class QNavitWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QNavitWidget(struct graphics_priv *my_graphics_priv,
+ QWidget * parent,
+ Qt::WindowFlags flags);
+protected:
+ virtual bool event(QEvent *event);
+ virtual void paintEvent(QPaintEvent * event);
+ virtual void resizeEvent(QResizeEvent * event);
+ virtual void mouseEvent(int pressed, QMouseEvent *event);
+ virtual void mousePressEvent(QMouseEvent *event);
+ virtual void mouseReleaseEvent(QMouseEvent *event);
+ virtual void mouseMoveEvent(QMouseEvent *event);
+ virtual void wheelEvent(QWheelEvent * event);
+
+
+private:
+ struct graphics_priv *graphics_priv;
+};
+#endif
+
diff --git a/navit/graphics/qt5/event_qt5.cpp b/navit/graphics/qt5/event_qt5.cpp
new file mode 100644
index 000000000..9cea3d921
--- /dev/null
+++ b/navit/graphics/qt5/event_qt5.cpp
@@ -0,0 +1,185 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program 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, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "config.h"
+#include "navit/point.h"
+#include "navit/item.h"
+#include "navit/graphics.h"
+#include "navit/color.h"
+#include "navit/debug.h"
+#include "navit/plugin.h"
+#include "navit/callback.h"
+#include "navit/event.h"
+#include "navit/window.h"
+#include "navit/keys.h"
+#include "navit/navit.h"
+#if defined(WINDOWS) || defined(WIN32) || defined (HAVE_API_WIN32_CE)
+#include <windows.h>
+#endif
+#include <QSocketNotifier>
+#include "graphics_qt5.h"
+#include "event_qt5.h"
+#include "event_qt5.moc"
+
+struct event_watch {
+ QSocketNotifier *sn;
+ struct callback *cb;
+ int fd;
+};
+
+static void event_qt5_remove_timeout(struct event_timeout *to);
+
+qt5_navit_timer :: qt5_navit_timer (QObject * parent) : QObject(parent)
+{
+ timer_type=g_hash_table_new(NULL, NULL);
+ timer_callback=g_hash_table_new(NULL, NULL);
+ watches=g_hash_table_new(NULL,NULL);
+ dbg(lvl_debug, "qt5_navit_timer object created\n");
+}
+
+void qt5_navit_timer :: timerEvent (QTimerEvent * event)
+{
+ int id=event->timerId();
+ void* multi = NULL;
+// dbg(lvl_debug, "TimerEvent (%d)\n", id);
+ struct callback *cb=(struct callback *)g_hash_table_lookup(timer_callback, (void *)(long)id);
+ if (cb)
+ callback_call_0(cb);
+ /* remove timer if it was oneshot timer */
+ if (g_hash_table_lookup_extended(timer_type, (void *)(long)id, NULL, &multi))
+ {
+ /* it's still in the list */
+ if(((int)(long)multi) == 0)
+ event_qt5_remove_timeout((struct event_timeout *)(long)id);
+ }
+// dbg(lvl_debug, "TimerEvent (%d) leave\n", id);
+}
+
+qt5_navit_timer * qt5_timer = NULL;
+
+static void
+event_qt5_main_loop_run(void)
+{
+
+ dbg(lvl_debug,"enter\n");
+ if(navit_app != NULL)
+ navit_app->exec();
+
+}
+
+static void event_qt5_main_loop_quit(void)
+{
+ dbg(lvl_debug,"enter\n");
+ exit(0);
+}
+
+static struct event_watch *
+event_qt5_add_watch(int fd, enum event_watch_cond cond, struct callback *cb)
+{
+ dbg(lvl_debug,"enter fd=%d\n",(int)(long)fd);
+ struct event_watch *ret=g_new0(struct event_watch, 1);
+ ret->fd=fd;
+ ret->cb=cb;
+ g_hash_table_insert(qt5_timer->watches, GINT_TO_POINTER(fd), ret);
+ ret->sn=new QSocketNotifier(fd, QSocketNotifier::Read, qt5_timer);
+ QObject::connect(ret->sn, SIGNAL(activated(int)), qt5_timer, SLOT(watchEvent(int)));
+ return ret;
+}
+
+static void
+event_qt5_remove_watch(struct event_watch *ev)
+{
+ dbg(lvl_debug,"enter\n");
+ g_hash_table_remove(qt5_timer->watches, GINT_TO_POINTER(ev->fd));
+ delete(ev->sn);
+ g_free(ev);
+}
+
+
+static struct event_timeout *
+event_qt5_add_timeout(int timeout, int multi, struct callback *cb)
+{
+ int id;
+ dbg(lvl_debug,"add timeout %d, mul %d, %p ==",timeout, multi, cb);
+ id=qt5_timer->startTimer(timeout);
+ dbg(lvl_debug,"%d\n", id);
+ g_hash_table_insert(qt5_timer->timer_callback, (void *)(long)id, cb);
+ g_hash_table_insert(qt5_timer->timer_type, (void *)(long)id, (void *)(long)!!multi);
+ return (struct event_timeout *)(long)id;
+}
+
+static void
+event_qt5_remove_timeout(struct event_timeout *to)
+{
+ dbg(lvl_debug,"remove timeout (%d)\n",(int)(long)to);
+ qt5_timer->killTimer((int)(long)to);
+ g_hash_table_remove(qt5_timer->timer_callback, to);
+ g_hash_table_remove(qt5_timer->timer_type, to);
+}
+
+
+static struct event_idle *
+event_qt5_add_idle(int priority, struct callback *cb)
+{
+ dbg(lvl_debug,"add idle event\n");
+ return (struct event_idle *)event_qt5_add_timeout(0, 1, cb);
+}
+
+static void
+event_qt5_remove_idle(struct event_idle *ev)
+{
+ dbg(lvl_debug,"Remove idle timeout\n");
+ event_qt5_remove_timeout((struct event_timeout *) ev);
+}
+
+static void
+event_qt5_call_callback(struct callback_list *cb)
+{
+ dbg(lvl_debug,"enter\n");
+}
+
+static struct event_methods event_qt5_methods = {
+ event_qt5_main_loop_run,
+ event_qt5_main_loop_quit,
+ event_qt5_add_watch,
+ event_qt5_remove_watch,
+ event_qt5_add_timeout,
+ event_qt5_remove_timeout,
+ event_qt5_add_idle,
+ event_qt5_remove_idle,
+ event_qt5_call_callback,
+};
+
+static struct event_priv *
+event_qt5_new(struct event_methods *meth)
+{
+ *meth=event_qt5_methods;
+ qt5_timer = new qt5_navit_timer(NULL);
+ return NULL;
+}
+
+
+void
+qt5_event_init(void)
+{
+ plugin_register_category_event("qt5", event_qt5_new);
+}
diff --git a/navit/graphics/qt5/event_qt5.h b/navit/graphics/qt5/event_qt5.h
new file mode 100644
index 000000000..f999d3a46
--- /dev/null
+++ b/navit/graphics/qt5/event_qt5.h
@@ -0,0 +1,18 @@
+#include <glib.h>
+#include <QObject>
+
+class qt5_navit_timer : public QObject
+{
+ Q_OBJECT
+public:
+ qt5_navit_timer(QObject * parent = 0);
+ GHashTable *timer_type;
+ GHashTable *timer_callback;
+ GHashTable *watches;
+protected:
+ void timerEvent(QTimerEvent * event);
+};
+
+
+void
+qt5_event_init(void);
diff --git a/navit/graphics/qt5/graphics_qt5.cpp b/navit/graphics/qt5/graphics_qt5.cpp
new file mode 100644
index 000000000..81fec32c2
--- /dev/null
+++ b/navit/graphics/qt5/graphics_qt5.cpp
@@ -0,0 +1,837 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program 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, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include "config.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "item.h"
+#include "point.h"
+#include "graphics.h"
+#include "color.h"
+#include "plugin.h"
+#include "event.h"
+#include "debug.h"
+#include "window.h"
+#include "callback.h"
+#if defined(WINDOWS) || defined(WIN32) || defined (HAVE_API_WIN32_CE)
+#include <windows.h>
+#endif
+#include "graphics_qt5.h"
+#include "event_qt5.h"
+#include "QNavitWidget.h"
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QPixmap>
+#include <QPainter>
+#include <QFont>
+#include <QSvgRenderer>
+#include <QPixmapCache>
+#include <QDBusConnection>
+#include <QDBusInterface>
+
+struct callback_list* callbacks;
+QApplication * navit_app = NULL;
+
+struct graphics_font_priv {
+ QFont * font;
+};
+
+struct graphics_image_priv {
+ QPixmap * pixmap;
+};
+
+static void
+graphics_destroy(struct graphics_priv *gr)
+{
+// dbg(lvl_debug,"enter\n");
+#ifdef QT_QPAINTER_USE_FREETYPE
+ gr->freetype_methods.destroy();
+#endif
+ /* destroy painter */
+ if(gr->painter != NULL)
+ delete(gr->painter);
+ /* destroy pixmap */
+ if(gr->pixmap != NULL)
+ delete(gr->pixmap);
+ /* destroy widget */
+ delete(gr->widget);
+ /* unregister from parent, if any */
+ if(gr->parent != NULL)
+ {
+ g_hash_table_remove(gr->parent->overlays, gr);
+ }
+#ifdef SAILFISH_OS
+ if(gr->display_on_ev != NULL)
+ {
+ event_remove_timeout(gr->display_on_ev);
+ }
+ if(gr->display_on_cb != NULL)
+ {
+ g_free(gr->display_on_cb);
+ }
+#endif
+ /* destroy overlays hash */
+ g_hash_table_destroy(gr->overlays);
+ /* destroy global application if destroying the last */
+ if(gr->root)
+ {
+ if(navit_app != NULL)
+ {
+ delete (navit_app);
+ }
+ navit_app = NULL;
+ /* destroy argv if any */
+ while(gr->argc > 0)
+ {
+ gr->argc --;
+ if(gr->argv[gr->argc] != NULL)
+ g_free(gr->argv[gr->argc]);
+ }
+ }
+ /* destroy self */
+ g_free(gr);
+}
+
+static void font_destroy(struct graphics_font_priv *font)
+{
+// dbg(lvl_debug,"enter\n");
+ if(font->font != NULL)
+ delete(font->font);
+ g_free(font);
+
+}
+
+static struct graphics_font_methods font_methods = {
+ font_destroy
+};
+
+static struct graphics_font_priv *font_new(struct graphics_priv *gr, struct graphics_font_methods *meth, char *font, int size, int flags)
+{
+ struct graphics_font_priv *font_priv;
+// dbg(lvl_debug,"enter (font %s, %d)\n", font, size);
+ font_priv = g_new0(struct graphics_font_priv, 1);
+ if(font != NULL)
+ font_priv->font=new QFont(font,size/16);
+ else
+ font_priv->font=new QFont("Arial",size/16);
+ font_priv->font->setStyleStrategy(QFont::NoAntialias);
+ *meth=font_methods;
+ return font_priv;
+}
+
+static void
+gc_destroy(struct graphics_gc_priv *gc)
+{
+// dbg(lvl_debug,"enter gc=%p\n", gc);
+ delete(gc->pen);
+ delete(gc->brush);
+ g_free(gc);
+}
+
+static void
+gc_set_linewidth(struct graphics_gc_priv *gc, int w)
+{
+// dbg(lvl_debug,"enter gc=%p, %d\n", gc, w);
+ gc->pen->setWidth(w);
+}
+
+static void
+gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
+{
+ if(n <= 0)
+ {
+ dbg(lvl_error, "Refuse to set dashes without dash pattern");
+ }
+ /* use Qt dash feature */
+ QVector<qreal> dashes;
+ gc->pen->setWidth(w);
+ gc->pen->setDashOffset(offset);
+ for(int a = 0; a < n; a ++)
+ {
+ dashes << dash_list[a];
+ }
+ /* Qt requires the pattern to have even element count. Add the last
+ * element twice if n doesn't divide by two
+ */
+ if((n % 2) != 0)
+ {
+ dashes << dash_list[n-1];
+ }
+ gc->pen->setDashPattern(dashes);
+}
+
+static void
+gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
+{
+ QColor col(c->r >> 8, c->g >> 8, c->b >> 8, c->a >> 8 );
+// dbg(lvl_debug,"context %p: color %02x%02x%02x\n",gc, c->r >> 8, c->g >> 8, c->b >> 8);
+ gc->pen->setColor(col);
+ gc->brush->setColor(col);
+ //gc->c=*c;
+}
+
+static void
+gc_set_background(struct graphics_gc_priv *gc, struct color *c)
+{
+ QColor col(c->r >> 8, c->g >> 8, c->b >> 8, c->a >> 8 );
+// dbg(lvl_debug,"context %p: color %02x%02x%02x\n",gc, c->r >> 8, c->g >> 8, c->b >> 8);
+ //gc->pen->setColor(col);
+ //gc->brush->setColor(col);
+}
+
+static struct graphics_gc_methods gc_methods = {
+ gc_destroy,
+ gc_set_linewidth,
+ gc_set_dashes,
+ gc_set_foreground,
+ gc_set_background
+};
+
+static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
+{
+ struct graphics_gc_priv * graphics_gc_priv = NULL;
+// dbg(lvl_debug,"enter gr==%p\n", gr);
+ graphics_gc_priv = g_new0(struct graphics_gc_priv, 1);
+ graphics_gc_priv->graphics_priv = gr;
+ graphics_gc_priv->pen=new QPen();
+ graphics_gc_priv->brush=new QBrush(Qt::SolidPattern);
+
+ *meth=gc_methods;
+ return graphics_gc_priv;
+}
+
+static void image_destroy(struct graphics_image_priv *img)
+{
+// dbg(lvl_debug, "enter\n");
+ if(img->pixmap != NULL)
+ delete(img->pixmap);
+ g_free(img);
+}
+
+struct graphics_image_methods image_methods ={
+ image_destroy
+};
+
+
+static struct graphics_image_priv *
+image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *path, int *w, int *h, struct point *hot, int rotation)
+{
+ struct graphics_image_priv * image_priv;
+// dbg(lvl_debug,"enter %s, %d %d\n", path, *w, *h);
+ if(path[0] == 0)
+ {
+ dbg(lvl_debug,"Refuse to load image without path\n");
+ return NULL;
+ }
+ QString key(path);
+ QString renderer_key(key);
+ QString extension = key.right(key.lastIndexOf("."));
+ QFile imagefile(key);
+ if(!imagefile.exists())
+ {
+ /* file doesn't exit. Either navit wants us to guess file name by
+ * ommitting exstension, or the file does really not exist.
+ */
+ if(extension != "")
+ {
+ /*file doesn't exist. give up */
+ dbg(lvl_debug,"File %s does not exist\n",path);
+ return NULL;
+ }
+ else
+ {
+ /* add ".svg" for renderer to try .svg file first in renderer */
+ dbg(lvl_debug, "Guess extension on %s\n", path);
+ renderer_key += ".svg";
+ }
+ }
+ image_priv = g_new0(struct graphics_image_priv, 1);
+ *meth = image_methods;
+
+ /* check if this can be rendered */
+ if(renderer_key.endsWith("svg"))
+ {
+ QSvgRenderer renderer(renderer_key);
+ if(renderer.isValid())
+ {
+ dbg(lvl_debug,"render %s\n", path);
+ /* try to render this */
+ /* assume "standard" size if size is not given */
+ if(*w <= 0) *w = renderer.defaultSize().width();
+ if(*h <= 0) *h = renderer.defaultSize().height();
+ image_priv->pixmap=new QPixmap(*w, *h);
+ image_priv->pixmap->fill(Qt::transparent);
+ QPainter painter(image_priv->pixmap);
+ renderer.render(&painter);
+ }
+ }
+
+ if (image_priv->pixmap == NULL) {
+ /*cannot be rendered. try to load it */
+ dbg(lvl_debug,"cannot render %s\n",path);
+ image_priv->pixmap=new QPixmap(key);
+ }
+
+ /* check if we got image */
+ if (image_priv->pixmap->isNull()) {
+ g_free(image_priv);
+ return NULL;
+ }
+ else
+ {
+ /* check if we need to scale this */
+ if((*w > 0) && (*h > 0))
+ {
+ if((image_priv->pixmap->width() != *w) ||
+ (image_priv->pixmap->height() != *h))
+ {
+ dbg(lvl_debug,"scale pixmap %s, %d->%d,%d->%d\n",path, image_priv->pixmap->width(), *w, image_priv->pixmap->height(), *h);
+ QPixmap * scaled = new QPixmap(image_priv->pixmap->scaled(*w, *h,Qt::IgnoreAspectRatio,Qt::FastTransformation));
+ delete (image_priv->pixmap);
+ image_priv->pixmap = scaled;
+ }
+ }
+ }
+
+ *w=image_priv->pixmap->width();
+ *h=image_priv->pixmap->height();
+// dbg(lvl_debug, "Got (%d,%d)\n", *w,*h);
+ if (hot) {
+ hot->x=*w/2;
+ hot->y=*h/2;
+ }
+
+ return image_priv;
+}
+
+static void
+draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+ int i;
+ QPolygon polygon;
+// dbg(lvl_debug,"enter gr=%p, gc=%p, (%d, %d)\n", gr, gc, p->x, p->y);
+ if(gr->painter == NULL)
+ return;
+
+ for (i = 0 ; i < count ; i++)
+ polygon.putPoints(i, 1, p[i].x, p[i].y);
+ gr->painter->setPen(*gc->pen);
+ gr->painter->drawPolyline(polygon);
+
+}
+
+static void
+draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+ int i;
+ QPolygon polygon;
+// dbg(lvl_debug,"enter gr=%p, gc=%p, (%d, %d)\n", gr, gc, p->x, p->y);
+ if(gr->painter == NULL)
+ return;
+
+ for (i = 0 ; i < count ; i++)
+ polygon.putPoints(i, 1, p[i].x, p[i].y);
+ gr->painter->setPen(*gc->pen);
+ gr->painter->setBrush(*gc->brush);
+ /* if the polygon is transparent, we need to clear it first */
+ if(!gc->brush->isOpaque())
+ {
+ QPainter::CompositionMode mode = gr->painter->compositionMode();
+ gr->painter->setCompositionMode(QPainter::CompositionMode_Clear);
+ gr->painter->drawPolygon(polygon);
+ gr->painter->setCompositionMode(mode);
+ }
+ gr->painter->drawPolygon(polygon);
+}
+
+static void
+draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
+{
+// dbg(lvl_debug,"gr=%p gc=%p %d,%d,%d,%d\n", gr, gc, p->x, p->y, w, h);
+ if(gr->painter == NULL)
+ return;
+ /* if the rectangle is transparent, we need to clear it first */
+ if(!gc->brush->isOpaque())
+ {
+ QPainter::CompositionMode mode = gr->painter->compositionMode();
+ gr->painter->setCompositionMode(QPainter::CompositionMode_Clear);
+ gr->painter->fillRect(p->x,p->y, w, h, *gc->brush);
+ gr->painter->setCompositionMode(mode);
+ }
+ gr->painter->fillRect(p->x,p->y, w, h, *gc->brush);
+}
+
+static void
+draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
+{
+// dbg(lvl_debug,"enter gr=%p, gc=%p, (%d,%d) r=%d\n", gr, gc, p->x, p->y, r);
+ if(gr->painter == NULL)
+ return;
+ gr->painter->setPen(*gc->pen);
+ gr->painter->drawArc(p->x-r/2, p->y-r/2, r, r, 0, 360*16);
+}
+
+
+static void
+draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg, struct graphics_font_priv *font, char *text, struct point *p, int dx, int dy)
+{
+// dbg(lvl_debug,"enter gc=%p, fg=%p, bg=%p pos(%d,%d) %s\n", gr, fg, bg, p->x, p->y, text);
+ QPainter *painter=gr->painter;
+ if(painter == NULL)
+ return;
+#ifdef QT_QPAINTER_USE_FREETYPE
+ struct font_freetype_text *t;
+ struct font_freetype_glyph *g, **gp;
+ struct color transparent = {0x0000, 0x0000, 0x0000, 0x0000};
+ struct color fgc;
+ struct color bgc;
+ QColor temp;
+
+ int i,x,y;
+
+ if (! font)
+ return;
+ /* extract colors */
+ fgc.r = fg->pen->color().red() << 8;
+ fgc.g = fg->pen->color().green() << 8;
+ fgc.b = fg->pen->color().blue() << 8;
+ fgc.a = fg->pen->color().alpha() << 8;
+ if(bg != NULL)
+ {
+ bgc.r = bg->pen->color().red() << 8;
+ bgc.g = bg->pen->color().green() << 8;
+ bgc.b = bg->pen->color().blue() << 8;
+ bgc.a = bg->pen->color().alpha() << 8;
+ }
+ else
+ {
+ bgc = transparent;
+ }
+
+ t=gr->freetype_methods.text_new(text, (struct font_freetype_font *)font, dx, dy);
+ x=p->x << 6;
+ y=p->y << 6;
+ gp=t->glyph;
+ i=t->glyph_count;
+ if (bg) {
+ while (i-- > 0) {
+ g=*gp++;
+ if (g->w && g->h) {
+ unsigned char *data;
+ QImage img(g->w+2, g->h+2, QImage::Format_ARGB32_Premultiplied);
+ data=img.bits();
+ gr->freetype_methods.get_shadow(g,(unsigned char *)data,img.bytesPerLine(),&bgc,&transparent);
+
+ painter->drawImage(((x+g->x)>>6)-1, ((y+g->y)>>6)-1, img);
+ }
+ x+=g->dx;
+ y+=g->dy;
+ }
+ }
+ x=p->x << 6;
+ y=p->y << 6;
+ gp=t->glyph;
+ i=t->glyph_count;
+ while (i-- > 0) {
+ g=*gp++;
+ if (g->w && g->h) {
+ unsigned char *data;
+ QImage img(g->w, g->h, QImage::Format_ARGB32_Premultiplied);
+ data=img.bits();
+ gr->freetype_methods.get_glyph(g,(unsigned char *)data,img.bytesPerLine(),&fgc,&bgc,&transparent);
+ painter->drawImage((x+g->x)>>6, (y+g->y)>>6, img);
+ }
+ x+=g->dx;
+ y+=g->dy;
+ }
+ gr->freetype_methods.text_destroy(t);
+#else
+ QString tmp=QString::fromUtf8(text);
+ QMatrix sav=gr->painter->worldMatrix();
+ QMatrix m(dx/65535.0,dy/65535.0,-dy/65535.0,dx/65535.0,p->x,p->y);
+ painter->setWorldMatrix(m,TRUE);
+ painter->setPen(*fg->pen);
+ painter->setFont(*font->font);
+ painter->drawText(0, 0, tmp);
+ painter->setWorldMatrix(sav);
+#endif
+}
+
+static void
+draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
+{
+// dbg(lvl_debug,"enter\n");
+ if(gr->painter != NULL)
+ gr->painter->drawPixmap(p->x, p->y, *img->pixmap);
+ else
+ dbg(lvl_debug, "Try to draw image, but no painter\n");
+}
+
+static void draw_drag(struct graphics_priv *gr, struct point *p)
+{
+ if(p != NULL)
+ {
+// dbg(lvl_debug,"enter %p (%d,%d)\n", gr, p->x, p->y);
+ gr->widget->move(p->x, p->y);
+ }
+ else
+ {
+// dbg(lvl_debug,"enter %p (NULL)\n", gr);
+ }
+}
+
+static void
+background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
+{
+// dbg(lvl_debug,"register context %p on %p\n", gc, gr);
+ gr->background_graphics_gc_priv = gc;
+}
+
+static void
+draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
+{
+ switch (mode)
+ {
+ case draw_mode_begin:
+ dbg(lvl_debug,"Begin drawing on context %p (use == %d)\n", gr, gr->use_count);
+ gr->use_count ++;
+ if(gr->painter == NULL)
+ gr->painter = new QPainter(gr->pixmap);
+ else
+ dbg(lvl_debug, "drawing on %p already active\n", gr);
+ break;
+ case draw_mode_end:
+ dbg(lvl_debug,"End drawing on context %p (use == %d)\n", gr, gr->use_count);
+ gr->use_count --;
+ if(gr->use_count > 0)
+ {
+ dbg(lvl_debug, "drawing on %p still in use\n", gr);
+ }
+ else if(gr->painter != NULL)
+ {
+ gr->painter->end();
+ delete(gr->painter);
+ gr->painter = NULL;
+ /* call repaint on widget */
+ gr->widget->repaint();
+ }
+ else
+ dbg(lvl_debug, "Context %p not active!\n", gr)
+
+ break;
+ default:
+ dbg(lvl_debug,"Unknown drawing %d on context %p\n", mode, gr);
+ break;
+ }
+}
+
+static struct graphics_priv * overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int wraparound);
+
+void
+resize_callback(int w, int h)
+{
+// dbg(lvl_debug,"enter (%d, %d)\n", w, h);
+ callback_list_call_attr_2(callbacks, attr_resize,
+ GINT_TO_POINTER(w), GINT_TO_POINTER(h));
+}
+
+static int
+graphics_qt5_fullscreen(struct window *w, int on)
+{
+ struct graphics_priv * gr;
+// dbg(lvl_debug,"enter\n");
+ gr = (struct graphics_priv *) w->priv;
+ if(on)
+ gr->widget->setWindowState(Qt::WindowFullScreen);
+ else
+ gr->widget->setWindowState(Qt::WindowMaximized);
+ return 1;
+}
+
+#ifdef SAILFISH_OS
+static void
+keep_display_on(struct graphics_priv * priv)
+{
+// dbg(lvl_debug,"enter\n");
+ QDBusConnection system = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "system");
+ QDBusInterface interface("com.nokia.mce", "/com/nokia/mce/request", "com.nokia.mce.request", system);
+
+ interface.call(QLatin1String("req_display_blanking_pause"));
+}
+#endif
+
+
+static void
+graphics_qt5_disable_suspend(struct window *w)
+{
+// dbg(lvl_debug,"enter\n");
+#ifdef SAILFISH_OS
+ struct graphics_priv * gr;
+ gr = (struct graphics_priv *) w->priv;
+ keep_display_on(gr);
+ /* to keep display on, d-bus trigger must be called at least once per second.
+ * to cope with fuzz, trigger it once per 30 seconds */
+ gr->display_on_cb = callback_new_1(callback_cast(keep_display_on), gr);
+ gr->display_on_ev = event_add_timeout(30000, 1, gr->display_on_cb);
+#endif
+}
+
+static void *
+get_data(struct graphics_priv *this_priv, char const *type)
+{
+// dbg(lvl_debug,"enter: %s\n", type);
+ if (strcmp(type, "window") == 0) {
+ struct window *win;
+// dbg(lvl_debug,"window detected\n");
+ win = g_new0(struct window, 1);
+ win->priv = this_priv;
+ win->fullscreen = graphics_qt5_fullscreen;
+ win->disable_suspend = graphics_qt5_disable_suspend;
+ resize_callback(this_priv->widget->width(),this_priv->widget->height());
+ return win;
+ }
+ return NULL;
+}
+
+static void image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
+{
+// dbg(lvl_debug,"enter\n");
+ delete(priv->pixmap);
+ g_free(priv);
+}
+
+static void get_text_bbox(struct graphics_priv *gr, struct graphics_font_priv *font, char *text, int dx, int dy, struct point *ret, int estimate)
+{
+// dbg(lvl_debug,"enter %s %d %d\n", text, dx, dy);
+ QPainter *painter=gr->painter;
+ QString tmp=QString::fromUtf8(text);
+ if(gr->painter != NULL)
+ {
+ gr->painter->setFont(*font->font);
+ QRect r=painter->boundingRect(0,0,gr->pixmap->width(),gr->pixmap->height(),0,tmp);
+// dbg (lvl_debug, "Text bbox: %d %d (%d,%d),(%d,%d)\n",dx, dy, r.left(), r.top(), r.right(), r.bottom());
+ /* low left */
+ ret[0].x = r.left();
+ ret[0].y = r.bottom();
+ /* top left */
+ ret[1].x = r.left();
+ ret[1].y = r.top();
+ /* top right */
+ ret[2].x = r.right();
+ ret[2].y = r.top();
+ /* low right */
+ ret[3].x = r.right();
+ ret[3].y = r.bottom();
+ }
+}
+
+static void overlay_disable(struct graphics_priv *gr, int disable)
+{
+ GHashTableIter iter;
+ struct graphics_priv * key, * value;
+// dbg(lvl_debug,"enter gr=%p, %d\n", gr, disable);
+
+ g_hash_table_iter_init (&iter, gr->overlays);
+ while (g_hash_table_iter_next (&iter, (void **)&key, (void **)&value))
+ {
+ /* disable or enable all overlays of this pane */
+ value->widget->setVisible(!disable);
+ }
+}
+
+static void overlay_resize(struct graphics_priv *gr, struct point *p, int w, int h, int wraparound)
+{
+// dbg(lvl_debug,"enter\n");
+ gr->widget->move(p->x, p->y);
+ gr->widget->resize(w, h);
+ if(gr->painter != NULL)
+ {
+ delete(gr->painter);
+ }
+ delete(gr->pixmap);
+ gr->pixmap = new QPixmap(gr->widget->size());
+ if(gr->painter != NULL)
+ gr->painter = new QPainter (gr->pixmap);
+}
+
+static struct graphics_methods graphics_methods = {
+ graphics_destroy,
+ draw_mode,
+ draw_lines,
+ draw_polygon,
+ draw_rectangle,
+ draw_circle,
+ draw_text,
+ draw_image,
+ NULL,
+ draw_drag,
+ font_new,
+ gc_new,
+ background_gc,
+ overlay_new,
+ image_new,
+ get_data,
+ image_free,
+ get_text_bbox,
+ overlay_disable,
+ overlay_resize,
+};
+
+/* create new graphics context on given context */
+static struct graphics_priv *
+overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int wraparound)
+{
+ struct graphics_priv * graphics_priv = NULL;
+ graphics_priv = g_new0(struct graphics_priv, 1);
+ *meth=graphics_methods;
+#ifdef QT_QPAINTER_USE_FREETYPE
+ if (gr->font_freetype_new) {
+ graphics_priv->font_freetype_new=gr->font_freetype_new;
+ gr->font_freetype_new(&graphics_priv->freetype_methods);
+ meth->font_new=(struct graphics_font_priv *(*)(struct graphics_priv *, struct graphics_font_methods *, char *, int, int))graphics_priv->freetype_methods.font_new;
+ meth->get_text_bbox=(void (*)(struct graphics_priv*, struct graphics_font_priv*, char*, int, int, struct point*, int))graphics_priv->freetype_methods.get_text_bbox;
+ }
+#endif
+ graphics_priv->widget = new QNavitWidget(graphics_priv, gr->widget, Qt::Widget);
+ graphics_priv->widget->move(p->x, p->y);
+ graphics_priv->widget->resize(w, h);
+ graphics_priv->widget->setVisible(true);
+ graphics_priv->pixmap = new QPixmap(graphics_priv->widget->size());
+ graphics_priv->painter = NULL;
+ graphics_priv->use_count = 0;
+ graphics_priv->parent = gr;
+ graphics_priv->overlays=g_hash_table_new(NULL, NULL);
+ graphics_priv->root = false;
+ graphics_priv->argc = 0;
+ graphics_priv->argv[0] = NULL;
+ /* register on parent */
+ g_hash_table_insert(gr->overlays, graphics_priv, graphics_priv);
+// dbg(lvl_debug,"New overlay: %p\n", graphics_priv);
+
+ return graphics_priv;
+}
+
+/* create application and initial graphics context */
+static struct graphics_priv *
+graphics_qt5_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
+{
+ struct graphics_priv * graphics_priv = NULL;
+ struct attr * event_loop_system = NULL;
+ struct attr * platform = NULL;
+ struct attr * fullscreen = NULL;
+ //dbg(lvl_debug,"enter\n");
+
+ /*register graphic methods by copying in our predefined ones */
+ *meth=graphics_methods;
+
+ /* get event loop from config and request event loop*/
+ event_loop_system = attr_search(attrs, NULL, attr_event_loop_system);
+ if (event_loop_system && event_loop_system->u.str) {
+ //dbg(lvl_debug, "event_system is %s\n", event_loop_system->u.str);
+ if (!event_request_system(event_loop_system->u.str, "graphics_qt5"))
+ return NULL;
+ } else {
+ /* no event system requested by config. Default to our own */
+ if (!event_request_system("qt5", "graphics_qt5"))
+ return NULL;
+ }
+
+#ifdef QT_QPAINTER_USE_FREETYPE
+ struct font_priv * (*font_freetype_new)(void *meth);
+ /* get font plugin if present */
+ font_freetype_new=(struct font_priv *(*)(void *))plugin_get_category_font("freetype");
+ if (!font_freetype_new) {
+ dbg(lvl_error,"no freetype\n");
+ return NULL;
+ }
+#endif
+
+ /* create root graphics layer */
+ graphics_priv = g_new0(struct graphics_priv, 1);
+ /* Prepare argc and argv to call Qt application*/
+ graphics_priv->root = true;
+ graphics_priv->argc = 0;
+ graphics_priv->argv[graphics_priv->argc] = g_strdup("navit");
+ graphics_priv->argc ++;
+ /* Get qt platform from config */
+ if ((platform=attr_search(attrs, NULL, attr_qt5_platform)))
+ {
+ graphics_priv->argv[graphics_priv->argc] = g_strdup("-platform");
+ graphics_priv->argc ++;
+ graphics_priv->argv[graphics_priv->argc] = g_strdup(platform->u.str);
+ graphics_priv->argc ++;
+ }
+ /* create surrounding application */
+ navit_app = new QApplication(graphics_priv->argc, graphics_priv->argv);
+
+#ifdef QT_QPAINTER_USE_FREETYPE
+ graphics_priv->font_freetype_new=font_freetype_new;
+ font_freetype_new(&graphics_priv->freetype_methods);
+ meth->font_new=(struct graphics_font_priv *(*)(struct graphics_priv *, struct graphics_font_methods *, char *, int, int))graphics_priv->freetype_methods.font_new;
+ meth->get_text_bbox=(void (*)(struct graphics_priv*, struct graphics_font_priv*, char*, int, int, struct point*, int))graphics_priv->freetype_methods.get_text_bbox;
+#endif
+ callbacks = cbl;
+ graphics_priv->pixmap = NULL;
+ graphics_priv->use_count = 0;
+ graphics_priv->painter = NULL;
+ graphics_priv->parent = NULL;
+ graphics_priv->overlays=g_hash_table_new(NULL, NULL);
+
+ graphics_priv->widget = new QNavitWidget(graphics_priv,NULL,Qt::Window);
+ if ((fullscreen=attr_search(attrs, NULL, attr_fullscreen)) && (fullscreen->u.num)) {
+ /* show this maximized */
+ graphics_priv->widget->setWindowState(Qt::WindowFullScreen);
+ }
+ else
+ {
+ /* not maximized. Check what size to use then */
+ struct attr * w = NULL;
+ struct attr * h = NULL;
+ /* default to desktop size if nothing else is given */
+ QRect geomet = navit_app->desktop()->screenGeometry(graphics_priv->widget);
+ /* check for height */
+ if ((h = attr_search(attrs, NULL, attr_h)) && (h->u.num > 100))
+ geomet.setHeight(h->u.num);
+ /* check for width */
+ if ((w = attr_search(attrs, NULL, attr_w)) && (w->u.num > 100))
+ geomet.setWidth(w->u.num);
+ graphics_priv->widget->resize(geomet.width(), geomet.height());
+ //graphics_priv->widget->setFixedSize(geomet.width(), geomet.height());
+ }
+ /* generate initial pixmap same size as window */
+ if(graphics_priv->pixmap == NULL)
+ graphics_priv->pixmap = new QPixmap(graphics_priv->widget->size());
+
+ /* tell Navit our geometry */
+ resize_callback(graphics_priv->widget->width(),graphics_priv->widget->height());
+
+ /* show our window */
+ graphics_priv->widget->show();
+ return graphics_priv;
+}
+
+void
+plugin_init(void)
+{
+// dbg(lvl_debug,"enter\n");
+ plugin_register_category_graphics("qt5", graphics_qt5_new);
+ qt5_event_init();
+}
diff --git a/navit/graphics/qt5/graphics_qt5.h b/navit/graphics/qt5/graphics_qt5.h
new file mode 100644
index 000000000..2f19390c4
--- /dev/null
+++ b/navit/graphics/qt5/graphics_qt5.h
@@ -0,0 +1,63 @@
+#ifndef __graphics_qt_h
+#define __graphics_qt_h
+#include <glib.h>
+#include <QApplication>
+#include <QPixmap>
+#include <QPainter>
+#include <QPen>
+#include <QBrush>
+#include "QNavitWidget.h"
+
+#ifndef QT_QPAINTER_USE_FREETYPE
+#define QT_QPAINTER_USE_FREETYPE 1
+#endif
+
+#ifndef SAILFISH_OS
+#define SAILFISH_OS 1
+#endif
+
+
+#ifdef QT_QPAINTER_USE_FREETYPE
+#include "navit/font/freetype/font_freetype.h"
+#endif
+
+struct graphics_gc_priv;
+struct graphics_priv;
+
+struct graphics_priv {
+ QNavitWidget * widget;
+ QPixmap * pixmap;
+ QPainter * painter;
+ int use_count;
+ struct graphics_gc_priv * background_graphics_gc_priv;
+#ifdef QT_QPAINTER_USE_FREETYPE
+ struct font_priv * (*font_freetype_new)(void *meth);
+ struct font_freetype_methods freetype_methods;
+#endif
+#ifdef SAILFISH_OS
+ struct callback *display_on_cb;
+ struct event_timeout *display_on_ev;
+#endif
+ GHashTable *overlays;
+ struct graphics_priv * parent;
+ bool root;
+ int argc;
+ char * argv[4];
+};
+
+struct graphics_gc_priv {
+ struct graphics_priv * graphics_priv;
+ QPen * pen;
+ QBrush * brush;
+};
+/* central exported application info */
+extern QApplication * navit_app;
+
+/* navit callback list */
+extern struct callback_list* callbacks;
+
+void
+resize_callback(int w, int h);
+
+#endif
+
diff --git a/navit/vehicle/qt5/CMakeLists.txt b/navit/vehicle/qt5/CMakeLists.txt
new file mode 100644
index 000000000..411d9d6ee
--- /dev/null
+++ b/navit/vehicle/qt5/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Find includes in corresponding build directories
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+# Instruct CMake to run moc automatically when needed.
+set(CMAKE_AUTOMOC ON)
+
+module_add_library(vehicle_qt5 vehicle_qt5.cpp)
diff --git a/navit/vehicle/qt5/vehicle_qt5.cpp b/navit/vehicle/qt5/vehicle_qt5.cpp
new file mode 100644
index 000000000..d6d33d7ab
--- /dev/null
+++ b/navit/vehicle/qt5/vehicle_qt5.cpp
@@ -0,0 +1,300 @@
+/** @file vehicle_null.c
+ * @brief null uses dbus signals
+ *
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program 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, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * @Author Tim Niemeyer <reddog@mastersword.de>
+ * @date 2008-2009
+ */
+
+#include "vehicle_qt5.h"
+#include "vehicle_qt5.moc"
+#include <QDateTime>
+QNavitGeoReceiver::QNavitGeoReceiver (QObject * parent, struct vehicle_priv * c):QObject(parent)
+{
+ priv = c;
+ if(priv->source != NULL)
+ {
+ connect(priv->source, SIGNAL(positionUpdated(QGeoPositionInfo)),this, SLOT(positionUpdated(QGeoPositionInfo)));
+ }
+ if(priv->satellites != NULL)
+ {
+ connect(priv->satellites, SIGNAL(satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &)), this, SLOT(satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &)));
+ connect(priv->satellites, SIGNAL(satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &)), this, SLOT(satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &)));
+ }
+}
+void QNavitGeoReceiver::satellitesInUseUpdated(const QList<QGeoSatelliteInfo> & sats)
+{
+ dbg(lvl_debug, "Sats in use: %d\n", sats.count());
+ priv->sats_used = sats.count();
+ callback_list_call_attr_0(priv->cbl, attr_position_sats_used);
+}
+
+void QNavitGeoReceiver::satellitesInViewUpdated(const QList<QGeoSatelliteInfo> & sats)
+{
+ dbg(lvl_debug, "Sats in view: %d\n", sats.count());
+ priv->sats = sats.count();
+ callback_list_call_attr_0(priv->cbl, attr_position_qual);
+}
+
+void QNavitGeoReceiver::positionUpdated(const QGeoPositionInfo &info)
+{
+
+ /* ignore stale view */
+ if(info.coordinate().isValid())
+ {
+ if(info.timestamp().toUTC().secsTo(QDateTime::currentDateTimeUtc()) > 20)
+ {
+ dbg(lvl_debug,"Ignoring old FIX\n");
+ return;
+ }
+ }
+
+ if(info.hasAttribute(QGeoPositionInfo::HorizontalAccuracy))
+ {
+ dbg(lvl_debug,"Horizontal acc (%f)\n",info.attribute(QGeoPositionInfo::HorizontalAccuracy));
+ priv->radius = info.attribute(QGeoPositionInfo::HorizontalAccuracy);
+ callback_list_call_attr_0(priv->cbl, attr_position_radius);
+ }
+ if(info.hasAttribute(QGeoPositionInfo::GroundSpeed))
+ {
+ dbg(lvl_debug,"Got ground speed (%f)\n",info.attribute(QGeoPositionInfo::GroundSpeed));
+ priv->speed = info.attribute(QGeoPositionInfo::GroundSpeed) * 3.6;
+ callback_list_call_attr_0(priv->cbl, attr_position_speed);
+ }
+ if(info.hasAttribute(QGeoPositionInfo::Direction))
+ {
+ dbg(lvl_debug,"Direction (%f)\n",info.attribute(QGeoPositionInfo::Direction));
+ priv->direction = info.attribute(QGeoPositionInfo::Direction);
+ callback_list_call_attr_0(priv->cbl, attr_position_direction);
+ }
+
+ switch(info.coordinate().type())
+ {
+ case QGeoCoordinate::Coordinate3D:
+ priv->fix_type = 2;
+ break;
+ case QGeoCoordinate::Coordinate2D:
+ priv->fix_type = 1;
+ break;
+ case QGeoCoordinate::InvalidCoordinate:
+ priv->fix_type = 0;
+ break;
+ }
+
+
+ if(info.coordinate().isValid())
+ {
+ dbg(lvl_debug, "Got valid coordinate (lat %f, lon %f)\n", info.coordinate().latitude(), info.coordinate().longitude());
+ priv->geo.lat = info.coordinate().latitude();
+ priv->geo.lng = info.coordinate().longitude();
+ priv->have_coords = 1;
+ if(info.coordinate().type() == QGeoCoordinate::Coordinate3D)
+ {
+ dbg(lvl_debug,"Got valid altitude (alt %f)\n", info.coordinate().altitude());
+ priv->height = info.coordinate().altitude();
+ }
+ //dbg(lvl_debug, "Time %s\n", info.timestamp().toUTC().toString().toLatin1().data());
+ priv->fix_time = info.timestamp().toUTC().toTime_t();
+ callback_list_call_attr_0(priv->cbl, attr_position_coord_geo);
+ }
+ else
+ {
+ dbg(lvl_debug, "Got invalid coordinate\n");
+ priv->have_coords = 0;
+ callback_list_call_attr_0(priv->cbl, attr_position_coord_geo);
+ }
+}
+
+
+/**
+ * @brief Free the null_vehicle
+ *
+ * @param priv
+ * @returns nothing
+ */
+static void
+vehicle_qt5_destroy(struct vehicle_priv *priv)
+{
+ dbg(lvl_debug,"enter\n");
+ if(priv->receiver != NULL)
+ delete priv->receiver;
+ if(priv->source != NULL)
+ delete priv->source;
+ g_free(priv);
+}
+
+/**
+ * @brief Provide the outside with information
+ *
+ * @param priv
+ * @param type TODO: What can this be?
+ * @param attr
+ * @returns true/false
+ */
+static int
+vehicle_qt5_position_attr_get(struct vehicle_priv *priv,
+ enum attr_type type, struct attr *attr)
+{
+ struct attr * active=NULL;
+ dbg(lvl_debug,"enter %s\n",attr_to_name(type));
+ switch (type) {
+ case attr_position_valid:
+ attr->u.num = priv->have_coords;
+ break;
+ case attr_position_fix_type:
+ attr->u.num = priv->fix_type;
+ break;
+ case attr_position_height:
+ attr->u.numd = &priv->height;
+ break;
+ case attr_position_speed:
+ attr->u.numd = &priv->speed;
+ break;
+ case attr_position_direction:
+ attr->u.numd = &priv->direction;
+ break;
+ case attr_position_radius:
+ attr->u.numd = &priv->radius;
+ break;
+ case attr_position_qual:
+ attr->u.num = priv->sats;
+ break;
+ case attr_position_sats_used:
+ attr->u.num = priv->sats_used;
+ break;
+ case attr_position_coord_geo:
+ attr->u.coord_geo = &priv->geo;
+ if (!priv->have_coords)
+ return 0;
+ break;
+ case attr_position_time_iso8601:
+ if (priv->fix_time) {
+ struct tm tm;
+ if (gmtime_r(&priv->fix_time, &tm)) {
+ strftime(priv->fixiso8601, sizeof(priv->fixiso8601),
+ "%Y-%m-%dT%TZ", &tm);
+ attr->u.str=priv->fixiso8601;
+ }
+ else {
+ priv->fix_time = 0;
+ return 0;
+ }
+ //dbg(lvl_debug,"Fix Time: %s\n", priv->fixiso8601);
+ }
+ else {
+ //dbg(lvl_debug,"Fix Time: 0\n");
+ return 0;
+ }
+ break;
+
+ case attr_active:
+ active = attr_search(priv->attrs,NULL,attr_active);
+ if(active != NULL) {
+ attr->u.num=active->u.num;
+ return 1;
+ } else
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+ dbg(lvl_debug,"ok\n");
+ attr->type = type;
+ return 1;
+}
+
+static int
+vehicle_qt5_set_attr(struct vehicle_priv *priv, struct attr *attr)
+{
+ switch (attr->type) {
+ case attr_position_speed:
+ priv->speed=*attr->u.numd;
+ break;
+ case attr_position_direction:
+ priv->direction=*attr->u.numd;
+ break;
+ case attr_position_coord_geo:
+ priv->geo=*attr->u.coord_geo;
+ priv->have_coords=1;
+ break;
+ default:
+ break;
+ }
+ callback_list_call_attr_0(priv->cbl, attr->type);
+ return 1;
+}
+
+
+struct vehicle_methods vehicle_null_methods = {
+ vehicle_qt5_destroy,
+ vehicle_qt5_position_attr_get,
+ vehicle_qt5_set_attr,
+};
+
+/**
+ * @brief Create null_vehicle
+ *
+ * @param meth
+ * @param cbl
+ * @param attrs
+ * @returns vehicle_priv
+ */
+static struct vehicle_priv *
+vehicle_qt5_new_qt5(struct vehicle_methods *meth,
+ struct callback_list *cbl,
+ struct attr **attrs)
+{
+ struct vehicle_priv *ret;
+
+ dbg(lvl_debug, "enter\n");
+ ret = g_new0(struct vehicle_priv, 1);
+ ret->cbl = cbl;
+ *meth = vehicle_null_methods;
+ ret->attrs = attrs;
+ ret->source = QGeoPositionInfoSource::createDefaultSource(NULL);
+ ret->satellites = QGeoSatelliteInfoSource::createDefaultSource(NULL);
+ if(ret->source == NULL)
+ {
+ dbg(lvl_error, "Got NO QGeoPositionInfoSource\n");
+ }
+ else
+ {
+ dbg(lvl_debug, "Using %s\n", ret->source->sourceName().toLatin1().data());
+ ret->receiver = new QNavitGeoReceiver(NULL,ret);
+ ret->satellites->setUpdateInterval(1000);
+ ret->satellites->startUpdates();
+ ret->source->setUpdateInterval(500);
+ ret->source->startUpdates();
+ }
+ dbg(lvl_debug, "return\n");
+ return ret;
+}
+
+/**
+ * @brief register vehicle_null
+ *
+ * @returns nothing
+ */
+void
+plugin_init(void)
+{
+ dbg(lvl_debug, "enter\n");
+ plugin_register_category_vehicle("qt5", vehicle_qt5_new_qt5);
+}
diff --git a/navit/vehicle/qt5/vehicle_qt5.h b/navit/vehicle/qt5/vehicle_qt5.h
new file mode 100644
index 000000000..c38c45284
--- /dev/null
+++ b/navit/vehicle/qt5/vehicle_qt5.h
@@ -0,0 +1,58 @@
+#ifndef __vehicle_qt5_h
+#define __vehicle_qt5_h
+
+#include <config.h>
+#include <string.h>
+#include <glib.h>
+#include <math.h>
+#include <time.h>
+#include "debug.h"
+#include "plugin.h"
+#include "coord.h"
+#include "item.h"
+#include "vehicle.h"
+
+#include <QObject>
+#include <QStringList>
+#include <QGeoPositionInfoSource>
+#include <QGeoSatelliteInfoSource>
+
+#include "callback.h"
+
+#include <QObject>
+
+class QNavitGeoReceiver;
+struct vehicle_priv {
+ struct callback_list *cbl;
+ struct coord_geo geo;
+ double speed;
+ double direction;
+ double height;
+ double radius;
+ int fix_type;
+ time_t fix_time;
+ char fixiso8601[128];
+ int sats;
+ int sats_used;
+ int have_coords;
+ struct attr ** attrs;
+
+ QGeoPositionInfoSource *source;
+ QGeoSatelliteInfoSource *satellites;
+ QNavitGeoReceiver * receiver;
+};
+
+class QNavitGeoReceiver : public QObject
+{
+ Q_OBJECT
+public:
+ QNavitGeoReceiver (QObject * parent, struct vehicle_priv * c);
+public slots:
+ void positionUpdated(const QGeoPositionInfo &info);
+ void satellitesInUseUpdated(const QList<QGeoSatelliteInfo> & satellites);
+ void satellitesInViewUpdated(const QList<QGeoSatelliteInfo> & satellites);
+
+private:
+ struct vehicle_priv * priv;
+};
+#endif \ No newline at end of file