summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2010-06-07 23:08:07 -0700
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-06-08 19:32:32 -0700
commit3a005cdf983881612a70836dcd3ab816b0ea7698 (patch)
tree615de8a3f796bde47174c6fcb9a2be6a825f3588
parentf68bab66aacded35be3d222e703e74e9db0bada3 (diff)
Add Wayland build & stub support
Add a new platform target, called wayland, to support building a Wayland-aware Qt library. Enabled by passing "-wayland" to configure. Defines a new window system type, Q_WS_WAYLAND, which can be used to pull in the right implementations or declare methods in various support classes.
-rw-r--r--.gitignore1
-rw-r--r--config.tests/wayland/client.cpp7
-rw-r--r--config.tests/wayland/client.pro5
-rwxr-xr-xconfigure25
-rw-r--r--mkspecs/common/linux.conf3
-rw-r--r--mkspecs/common/wayland.conf8
-rw-r--r--mkspecs/wayland/linux-generic-g++/qmake.conf9
-rw-r--r--mkspecs/wayland/linux-generic-g++/qplatformdefs.h1
-rw-r--r--src/corelib/global/qglobal.h2
-rw-r--r--src/corelib/global/qnamespace.h2
-rw-r--r--src/gui/egl/egl.pri4
-rw-r--r--src/gui/egl/qegl_wayland.cpp114
-rw-r--r--src/gui/gui.pro3
-rw-r--r--src/gui/image/image.pri4
-rw-r--r--src/gui/image/qpixmap.h2
-rw-r--r--src/gui/image/qpixmap_wayland.cpp64
-rw-r--r--src/gui/image/qpixmap_wayland_p.h140
-rw-r--r--src/gui/image/qpixmapdatafactory.cpp5
-rw-r--r--src/gui/inputmethod/inputmethod.pri5
-rw-r--r--src/gui/inputmethod/qwaylandinputcontext_p.h97
-rw-r--r--src/gui/inputmethod/qwaylandinputcontext_wayland.cpp246
-rw-r--r--src/gui/kernel/kernel.pri25
-rw-r--r--src/gui/kernel/qapplication.h5
-rw-r--r--src/gui/kernel/qapplication_p.h3
-rw-r--r--src/gui/kernel/qapplication_wayland.cpp614
-rw-r--r--src/gui/kernel/qclipboard_wayland.cpp257
-rw-r--r--src/gui/kernel/qcursor_wayland.cpp129
-rw-r--r--src/gui/kernel/qdesktopwidget_wayland.cpp98
-rw-r--r--src/gui/kernel/qdnd_wayland.cpp423
-rw-r--r--src/gui/kernel/qeventdispatcher_glib_wayland.cpp130
-rw-r--r--src/gui/kernel/qeventdispatcher_glib_wayland_p.h78
-rw-r--r--src/gui/kernel/qeventdispatcher_wayland.cpp107
-rw-r--r--src/gui/kernel/qeventdispatcher_wayland_p.h86
-rw-r--r--src/gui/kernel/qkeymapper_wayland.cpp77
-rw-r--r--src/gui/kernel/qsound_wayland.cpp63
-rw-r--r--src/gui/kernel/qwidget_wayland.cpp243
-rw-r--r--src/gui/kernel/qwindowdefs.h4
-rw-r--r--src/gui/kernel/wayland.pri3
-rw-r--r--src/gui/painting/painting.pri5
-rw-r--r--src/gui/painting/qgraphicssystem.cpp5
-rw-r--r--src/gui/painting/qgraphicssystem_wayland.cpp62
-rw-r--r--src/gui/painting/qgraphicssystem_wayland_p.h79
-rw-r--r--src/gui/painting/qprintengine_wayland.cpp886
-rw-r--r--src/gui/painting/qprintengine_wayland_p.h213
-rw-r--r--src/gui/painting/qregion.h4
-rw-r--r--src/gui/painting/qregion_wayland.cpp3183
-rw-r--r--src/gui/painting/qwindowsurface_wayland.cpp487
-rw-r--r--src/gui/painting/qwindowsurface_wayland_p.h288
-rw-r--r--src/gui/text/qabstractfontengine_wayland.cpp746
-rw-r--r--src/gui/text/qabstractfontengine_wayland.h221
-rw-r--r--src/gui/text/qfont.h4
-rw-r--r--src/gui/text/qfont_wayland.cpp192
-rw-r--r--src/gui/text/qfontdatabase.cpp10
-rw-r--r--src/gui/text/qfontdatabase.h2
-rw-r--r--src/gui/text/qfontdatabase_wayland.cpp662
-rw-r--r--src/gui/text/qfontengine_p.h2
-rw-r--r--src/gui/text/qfontengine_wayland.cpp83
-rw-r--r--src/gui/text/qfontsubset.cpp2
-rw-r--r--src/gui/text/text.pri14
-rw-r--r--src/gui/util/qdesktopservices.cpp2
-rw-r--r--src/gui/util/qdesktopservices_wayland.cpp75
-rw-r--r--src/gui/util/qsystemtrayicon_wayland.cpp91
-rw-r--r--src/gui/util/util.pri5
-rw-r--r--src/opengl/opengl.pro36
-rw-r--r--src/opengl/qgl_wayland.cpp1815
-rw-r--r--src/opengl/qgl_waylandegl.cpp540
-rw-r--r--src/opengl/qglpixelbuffer_wayland.cpp290
-rw-r--r--src/opengl/qpixmapdata_waylandgl_egl.cpp403
-rw-r--r--src/opengl/qpixmapdata_waylandgl_p.h98
-rw-r--r--src/opengl/qwindowsurface_waylandgl.cpp213
-rw-r--r--src/opengl/qwindowsurface_waylandgl_p.h83
71 files changed, 13873 insertions, 20 deletions
diff --git a/.gitignore b/.gitignore
index d88e69a766..8a36bd9279 100644
--- a/.gitignore
+++ b/.gitignore
@@ -230,3 +230,4 @@ qtc-debugging-helper
src/corelib/lib
src/network/lib
src/xml/lib/
+*cscope*
diff --git a/config.tests/wayland/client.cpp b/config.tests/wayland/client.cpp
new file mode 100644
index 0000000000..40ff2cbd75
--- /dev/null
+++ b/config.tests/wayland/client.cpp
@@ -0,0 +1,7 @@
+#include "wayland-client.h"
+#include "wayland-glib.h"
+
+int main(int, char **)
+{
+ return 0;
+}
diff --git a/config.tests/wayland/client.pro b/config.tests/wayland/client.pro
new file mode 100644
index 0000000000..56a6bf6d4c
--- /dev/null
+++ b/config.tests/wayland/client.pro
@@ -0,0 +1,5 @@
+SOURCES = client.cpp
+CONFIG -= qt
+
+QMAKE_CXXFLAGS += $$QT_CFLAGS_WAYLAND
+LIBS += $$QT_LIBS_WAYLAND
diff --git a/configure b/configure
index 991596f765..53a7be5804 100755
--- a/configure
+++ b/configure
@@ -187,6 +187,7 @@ fi
PLATFORM_X11=no
PLATFORM_MAC=no
PLATFORM_QWS=no
+PLATFORM_WAYLAND=maybe
if [ -f "$relpath"/src/gui/kernel/qapplication_mac.mm ] && [ -d /System/Library/Frameworks/Carbon.framework ]; then
# Qt/Mac
@@ -1311,6 +1312,9 @@ while [ "$#" -gt 0 ]; do
fi
PLATFORM_X11=yes
;;
+ wayland)
+ PLATFORM_WAYLAND=yes
+ ;;
sdk)
if [ "$PLATFORM_MAC" = "yes" ]; then
CFG_SDK="$VAL"
@@ -2710,7 +2714,7 @@ if [ '!' -f "${XQMAKESPEC}/qplatformdefs.h" ]; then
fi
# now look at the configs and figure out what platform we are config'd for
-[ "$CFG_EMBEDDED" = "no" ] \
+[ "$CFG_EMBEDDED" = "no" -a "$PLATFORM_WAYLAND" = "no" ] \
&& [ '!' -z "`getQMakeConf \"$XQMAKESPEC\" | grep QMAKE_LIBS_X11 | awk '{print $3;}'`" ] \
&& PLATFORM_X11=yes
### echo "$XQMAKESPEC" | grep mkspecs/qws >/dev/null 2>&1 && PLATFORM_QWS=yes
@@ -3411,6 +3415,7 @@ Usage: $relconf [-h] [-prefix <dir>] [-prefix-install] [-bindir <dir>] [-libdir
[-no-openssl] [-openssl] [-openssl-linked]
[-no-gtkstyle] [-gtkstyle] [-no-svg] [-svg] [-no-webkit] [-webkit] [-no-javascript-jit] [-javascript-jit]
[-no-script] [-script] [-no-scripttools] [-scripttools] [-no-declarative] [-declarative]
+ [-wayland]
[additional platform specific options (see below)]
@@ -3642,6 +3647,8 @@ Third Party Libraries:
-ptmalloc .......... Override the system memory allocator with ptmalloc.
(Experimental.)
+ -wayland ........... Use Wayland as the target platform
+
Additional options:
-make <part> ....... Add part to the list of parts to be built at make time.
@@ -4077,6 +4084,8 @@ elif [ "$PLATFORM_MAC" = "yes" ]; then
Platform="Qt for Mac OS X"
elif echo "$XPLATFORM" | grep "symbian" > /dev/null ; then
Platform="Qt for Symbian"
+elif [ "$PLATFORM_WAYLAND" = "yes" ]; then
+ Platform="Qt for Wayland"
elif [ '!' -z "`getQMakeConf \"$XQMAKESPEC\" | grep QMAKE_LIBS_X11 | awk '{print $3;}'`" ]; then
PLATFORM_X11=yes
Platform="Qt for Linux/X11"
@@ -5180,7 +5189,7 @@ if [ "$PLATFORM_MAC" = "yes" -a ! -z "$QT_NAMESPACE" ]; then
QT_NAMESPACE_MAC_CRC=`"$mactests/crc.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/mac/crc $QT_NAMESPACE $L_FLAGS $I_FLAGS $l_FLAGS`
fi
-if [ "$PLATFORM_X11" = "yes" -o "$PLATFORM_QWS" = "yes" ]; then
+if [ "$PLATFORM_X11" = "yes" -o "$PLATFORM_QWS" = "yes" -o "$PLATFORM_WAYLAND" = "yes" ]; then
# auto-detect Glib support
if [ "$CFG_GLIB" != "no" ]; then
@@ -5880,7 +5889,7 @@ if [ "$PLATFORM_QWS" = "yes" ]; then
fi # QWS
# EGL Support
-if [ "$PLATFORM_X11" = "yes" -o "$PLATFORM_QWS" = "yes" ]; then
+if [ "$PLATFORM_X11" = "yes" -o "$PLATFORM_QWS" = "yes" -o "$PLATFORM_WAYLAND" = "yes" ]; then
if [ "$CFG_EGL" != "no" ]; then
# detect EGL support
if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/egl" "EGL (EGL/egl.h)" $L_FLAGS $I_FLAGS $l_FLAGS; then
@@ -6482,6 +6491,12 @@ if [ "$PLATFORM_QWS" = "yes" ]; then
QT_CONFIG="$QT_CONFIG embedded"
rm -f "src/.moc/$QMAKE_OUTDIR/allmoc.cpp" # needs remaking if config changes
fi
+if [ "$PLATFORM_WAYLAND" = "yes" ]; then
+ QMAKE_OUTDIR="${QMAKE_OUTDIR}-wayland"
+ QMAKE_CONFIG="$QMAKE_CONFIG wayland"
+ QT_CONFIG="$QT_CONFIG wayland"
+fi
+
QMakeVar set PRECOMPILED_DIR ".pch/$QMAKE_OUTDIR"
QMakeVar set OBJECTS_DIR ".obj/$QMAKE_OUTDIR"
QMakeVar set MOC_DIR ".moc/$QMAKE_OUTDIR"
@@ -7418,6 +7433,10 @@ if [ "$PLATFORM_QWS" = "yes" ]; then
done
fi # QWS
+if [ "$PLATFORM_WAYLAND" = "yes" ]; then
+ QCONFIG_FLAGS="$QCONFIG_FLAGS Q_WS_WAYLAND"
+fi # WAYLAND
+
if [ "${CFG_USE_FLOATMATH}" = "yes" ]; then
QCONFIG_FLAGS="${QCONFIG_FLAGS} QT_USE_MATH_H_FLOATS"
fi
diff --git a/mkspecs/common/linux.conf b/mkspecs/common/linux.conf
index 4fbe2dcab5..e4f1067d1f 100644
--- a/mkspecs/common/linux.conf
+++ b/mkspecs/common/linux.conf
@@ -9,6 +9,8 @@ QMAKE_INCDIR =
QMAKE_LIBDIR =
QMAKE_INCDIR_X11 = /usr/X11R6/include
QMAKE_LIBDIR_X11 = /usr/X11R6/lib
+QMAKE_INCDIR_WAYLAND = /usr/include
+QMAKE_LIBDIR_WAYLAND = /usr/lib
QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS]
QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS]
QMAKE_INCDIR_OPENGL = /usr/X11R6/include
@@ -34,6 +36,7 @@ QMAKE_LIBS_OPENGL_ES1 = -lGLES_CM
QMAKE_LIBS_OPENGL_ES2 = -lGLESv2
QMAKE_LIBS_OPENVG = -lOpenVG
QMAKE_LIBS_THREAD = -lpthread
+QMAKE_LIBS_WAYLAND = -lwayland
QMAKE_MOC = $$[QT_INSTALL_BINS]/moc
QMAKE_UIC = $$[QT_INSTALL_BINS]/uic
diff --git a/mkspecs/common/wayland.conf b/mkspecs/common/wayland.conf
new file mode 100644
index 0000000000..691634d227
--- /dev/null
+++ b/mkspecs/common/wayland.conf
@@ -0,0 +1,8 @@
+MAKEFILE_GENERATOR = UNIX
+TARGET_PLATFORM = unix
+TEMPLATE = app
+CONFIG += qt warn_on release incremental link_prl
+QT += core gui network
+QMAKE_INCREMENTAL_STYLE = sublib
+
+c
diff --git a/mkspecs/wayland/linux-generic-g++/qmake.conf b/mkspecs/wayland/linux-generic-g++/qmake.conf
new file mode 100644
index 0000000000..0fe09a3a52
--- /dev/null
+++ b/mkspecs/wayland/linux-generic-g++/qmake.conf
@@ -0,0 +1,9 @@
+#
+# qmake configuration for building with g++
+#
+
+include(../../common/g++.conf)
+include(../../common/linux.conf)
+include(../../common/wayland.conf)
+
+load(qt_config)
diff --git a/mkspecs/wayland/linux-generic-g++/qplatformdefs.h b/mkspecs/wayland/linux-generic-g++/qplatformdefs.h
new file mode 100644
index 0000000000..99e9a27923
--- /dev/null
+++ b/mkspecs/wayland/linux-generic-g++/qplatformdefs.h
@@ -0,0 +1 @@
+#include "../../linux-g++/qplatformdefs.h"
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 1eab394296..69ea69b8eb 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -817,7 +817,7 @@ namespace QT_NAMESPACE {}
# if !defined(QT_NO_S60)
# define Q_WS_S60
# endif
-# elif !defined(Q_WS_QWS)
+# elif !defined(Q_WS_QWS) && !defined(Q_WS_WAYLAND)
# define Q_WS_X11
# endif
#endif
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 607ab52a60..6a33afd2d7 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -1651,6 +1651,8 @@ public:
typedef void * HANDLE;
#elif defined(Q_OS_SYMBIAN)
typedef unsigned long int HANDLE; // equivalent to TUint32
+#elif defined(Q_WS_WAYLAND)
+ typedef void *HANDLE;
#endif
typedef WindowFlags WFlags;
diff --git a/src/gui/egl/egl.pri b/src/gui/egl/egl.pri
index c6c020d307..c39c5ea9d9 100644
--- a/src/gui/egl/egl.pri
+++ b/src/gui/egl/egl.pri
@@ -23,6 +23,10 @@ contains(QT_CONFIG, egl): {
}
}
}
+
+ wayland {
+ SOURCES += egl/qegl_wayland.cpp
+ }
} else:symbian {
DEFINES += QT_NO_EGL
SOURCES += egl/qegl_stub.cpp
diff --git a/src/gui/egl/qegl_wayland.cpp b/src/gui/egl/qegl_wayland.cpp
new file mode 100644
index 0000000000..7510dabca8
--- /dev/null
+++ b/src/gui/egl/qegl_wayland.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qpaintdevice.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qwidget.h>
+
+#include "qegl_p.h"
+#include "qeglcontext_p.h"
+
+#if !defined(QT_NO_EGL)
+
+#include <qscreen_wayland.h>
+#include <qscreenproxy_wayland.h>
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+
+QT_BEGIN_NAMESPACE
+
+static QScreen *screenForDevice(QPaintDevice *device)
+{
+ QScreen *screen = qt_screen;
+ if (!screen)
+ return 0;
+ if (screen->classId() == QScreen::MultiClass) {
+ int screenNumber;
+ if (device && device->devType() == QInternal::Widget)
+ screenNumber = qApp->desktop()->screenNumber(static_cast<QWidget *>(device));
+ else
+ screenNumber = 0;
+ screen = screen->subScreens()[screenNumber];
+ }
+ while (screen->classId() == QScreen::ProxyClass ||
+ screen->classId() == QScreen::TransformedClass) {
+ screen = static_cast<QProxyScreen *>(screen)->screen();
+ }
+ return screen;
+}
+
+// Set pixel format and other properties based on a paint device.
+void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev)
+{
+ if (!dev)
+ return;
+
+ // Find the QGLScreen for this paint device.
+ QScreen *screen = screenForDevice(dev);
+ if (!screen)
+ return;
+ int devType = dev->devType();
+ if (devType == QInternal::Image)
+ setPixelFormat(static_cast<QImage *>(dev)->format());
+ else
+ setPixelFormat(screen->pixelFormat());
+}
+
+EGLNativeDisplayType QEgl::nativeDisplay()
+{
+ return EGLNativeDisplayType(EGL_DEFAULT_DISPLAY);
+}
+
+EGLNativeWindowType QEgl::nativeWindow(QWidget* widget)
+{
+ return (EGLNativeWindowType)(widget->winId()); // Might work
+}
+
+EGLNativePixmapType QEgl::nativePixmap(QPixmap*)
+{
+ qWarning("QEgl: EGL pixmap surfaces not supported on QWS");
+ return (EGLNativePixmapType)0;
+}
+
+
+QT_END_NAMESPACE
+
+#endif // !QT_NO_EGL
diff --git a/src/gui/gui.pro b/src/gui/gui.pro
index 7f1cb78280..cbc2ac6577 100644
--- a/src/gui/gui.pro
+++ b/src/gui/gui.pro
@@ -5,7 +5,7 @@ DEFINES += QT_BUILD_GUI_LIB QT_NO_USING_NAMESPACE
win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x65000000
irix-cc*:QMAKE_CXXFLAGS += -no_prelink -ptused
-!win32:!embedded:!mac:!symbian:CONFIG += x11
+!win32:!embedded:!mac:!symbian:!wayland:CONFIG += x11
unix:QMAKE_PKGCONFIG_REQUIRES = QtCore
@@ -22,6 +22,7 @@ symbian {
include(kernel/symbian.pri)
include(s60framework/s60framework.pri)
}
+wayland:include(kernel/wayland.pri)
#modules
include(animation/animation.pri)
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index 8d75fdd078..bc1fd19dbf 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -73,6 +73,10 @@ symbian {
HEADERS += image/qpixmap_s60_p.h
SOURCES += image/qpixmap_s60.cpp
}
+wayland {
+ HEADERS += image/qpixmap_wayland_p.h
+ SOURCES += image/qpixmap_wayland.cpp
+}
# Built-in image format support
HEADERS += \
diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h
index 82546da6a4..f727985a5e 100644
--- a/src/gui/image/qpixmap.h
+++ b/src/gui/image/qpixmap.h
@@ -195,7 +195,7 @@ public:
Qt::HANDLE macQDHandle() const;
Qt::HANDLE macQDAlphaHandle() const;
Qt::HANDLE macCGHandle() const;
-#elif defined(Q_WS_X11)
+#elif defined(Q_WS_X11) || defined(Q_WS_WAYLAND)
enum ShareMode { ImplicitlyShared, ExplicitlyShared };
static QPixmap fromX11Pixmap(Qt::HANDLE pixmap, ShareMode mode = ImplicitlyShared);
diff --git a/src/gui/image/qpixmap_wayland.cpp b/src/gui/image/qpixmap_wayland.cpp
new file mode 100644
index 0000000000..da31f160e8
--- /dev/null
+++ b/src/gui/image/qpixmap_wayland.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+
+#include "qdebug.h"
+#include "qiodevice.h"
+#include "qpixmap_wayland_p.h"
+#include "qbitmap.h"
+#include "qcolormap.h"
+#include "qimage.h"
+#include "qmatrix.h"
+#include "qapplication.h"
+#include <private/qdrawhelper_p.h>
+#include <private/qimage_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
+
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qpixmap_wayland_p.h b/src/gui/image/qpixmap_wayland_p.h
new file mode 100644
index 0000000000..f481cc62d2
--- /dev/null
+++ b/src/gui/image/qpixmap_wayland_p.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPIXMAPDATA_WAYLAND_P_H
+#define QPIXMAPDATA_WAYLAND_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qpixmapdata_p.h>
+#include <QtGui/private/qpixmapdatafactory_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandPaintEngine;
+
+class Q_GUI_EXPORT QWaylandPixmapData : public QPixmapData
+{
+public:
+ QWaylandPixmapData(PixelType type);
+// QWaylandPixmapData(PixelType type, int width, int height);
+// QWaylandPixmapData(PixelType type, const QImage &image,
+// Qt::ImageConversionFlags flags);
+ ~QWaylandPixmapData();
+
+ QPixmapData *createCompatiblePixmapData() const;
+
+ void resize(int width, int height);
+ void fromImage(const QImage &image, Qt::ImageConversionFlags flags);
+ void copy(const QPixmapData *data, const QRect &rect);
+ bool scroll(int dx, int dy, const QRect &rect);
+
+ void fill(const QColor &color);
+ QBitmap mask() const;
+ void setMask(const QBitmap &mask);
+ bool hasAlphaChannel() const;
+ void setAlphaChannel(const QPixmap &alphaChannel);
+ QPixmap alphaChannel() const;
+ QPixmap transformed(const QTransform &transform,
+ Qt::TransformationMode mode) const;
+ QImage toImage() const;
+ QPaintEngine* paintEngine() const;
+
+ Qt::HANDLE handle() const { return hd; }
+ Qt::HANDLE x11ConvertToDefaultDepth();
+
+ static Qt::HANDLE createBitmapFromImage(const QImage &image);
+
+ void* gl_surface;
+
+protected:
+ int metric(QPaintDevice::PaintDeviceMetric metric) const;
+
+private:
+ friend class QPixmap;
+ friend class QBitmap;
+ friend class QWaylandPaintEngine;
+ friend class QWaylandWindowSurface;
+ friend class QRasterWindowSurface;
+ friend class QGLContextPrivate; // Needs to access xinfo, gl_surface & flags
+ friend class QEglContext; // Needs gl_surface
+ friend class QGLContext; // Needs gl_surface
+ friend class QWaylandGLPixmapData; // Needs gl_surface
+ friend bool qt_createEGLSurfaceForPixmap(QPixmapData*, bool); // Needs gl_surface
+
+ void release();
+
+ QBitmap mask_to_bitmap(int screen) const;
+ static Qt::HANDLE bitmap_to_mask(const QBitmap &, int screen);
+ void bitmapFromImage(const QImage &image);
+
+ Qt::HANDLE hd;
+
+ enum Flag {
+ NoFlags = 0x0,
+ Uninitialized = 0x1,
+ Readonly = 0x2,
+ InvertedWhenBoundToTexture = 0x4,
+ GlSurfaceCreatedWithAlpha = 0x8
+ };
+ uint flags;
+
+ Qt::HANDLE picture;
+ Qt::HANDLE mask_picture;
+ Qt::HANDLE hd2; // sorted in the default display depth
+ QPixmap::ShareMode share_mode;
+
+ QWaylandPaintEngine *pengine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPIXMAPDATA_WAYLAND_P_H
+
diff --git a/src/gui/image/qpixmapdatafactory.cpp b/src/gui/image/qpixmapdatafactory.cpp
index 8014660c94..5aa874b920 100644
--- a/src/gui/image/qpixmapdatafactory.cpp
+++ b/src/gui/image/qpixmapdatafactory.cpp
@@ -56,6 +56,9 @@
#ifdef Q_WS_S60
# include <private/qpixmap_s60_p.h>
#endif
+#ifdef Q_WS_WAYLAND
+# include <private/qpixmap_wayland_p.h>
+#endif
#include "private/qapplication_p.h"
#include "private/qgraphicssystem_p.h"
@@ -84,6 +87,8 @@ QPixmapData* QSimplePixmapDataFactory::create(QPixmapData::PixelType type)
return new QMacPixmapData(type);
#elif defined(Q_WS_S60)
return new QS60PixmapData(type);
+#elif defined(Q_WS_WAYLAND)
+ return new QWaylandPixmapData(type);
#else
#error QSimplePixmapDataFactory::create() not implemented
#endif
diff --git a/src/gui/inputmethod/inputmethod.pri b/src/gui/inputmethod/inputmethod.pri
index 02e3e57024..86470aefbc 100644
--- a/src/gui/inputmethod/inputmethod.pri
+++ b/src/gui/inputmethod/inputmethod.pri
@@ -28,4 +28,7 @@ symbian:contains(QT_CONFIG, s60) {
SOURCES += inputmethod/qcoefepinputcontext_s60.cpp
LIBS += -lfepbase -lakninputlanguage
}
-
+embedded {
+ HEADERS += inputmethod/qwaylandinputcontext_p.h
+ SOURCES += inputmethod/qwaylandinputcontext_wayland.cpp
+}
diff --git a/src/gui/inputmethod/qwaylandinputcontext_p.h b/src/gui/inputmethod/qwaylandinputcontext_p.h
new file mode 100644
index 0000000000..55463855e9
--- /dev/null
+++ b/src/gui/inputmethod/qwaylandinputcontext_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWSINPUTCONTEXT_P_H
+#define QWSINPUTCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtGui/qinputcontext.h"
+
+#ifndef QT_NO_QWS_INPUTMETHODS
+
+QT_BEGIN_NAMESPACE
+
+class QWSIMEvent;
+class QWSIMQueryEvent;
+class QWSIMInitEvent;
+
+class QWSInputContext : public QInputContext
+{
+ Q_OBJECT
+public:
+ explicit QWSInputContext(QObject* parent = 0);
+ ~QWSInputContext() {}
+
+
+ QString identifierName() { return QString(); }
+ QString language() { return QString(); }
+
+ void reset();
+ void update();
+ void mouseHandler( int x, QMouseEvent *event);
+
+ void setFocusWidget( QWidget *w );
+ void widgetDestroyed(QWidget *w);
+
+ bool isComposing() const;
+
+ static QWidget *activeWidget();
+ static bool translateIMEvent(QWidget *w, const QWSIMEvent *e);
+ static bool translateIMQueryEvent(QWidget *w, const QWSIMQueryEvent *e);
+ static bool translateIMInitEvent(const QWSIMInitEvent *e);
+ static void updateImeStatus(QWidget *w, bool hasFocus);
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_INPUTMETHODS
+
+#endif // QWSINPUTCONTEXT_P_H
diff --git a/src/gui/inputmethod/qwaylandinputcontext_wayland.cpp b/src/gui/inputmethod/qwaylandinputcontext_wayland.cpp
new file mode 100644
index 0000000000..8a199249fe
--- /dev/null
+++ b/src/gui/inputmethod/qwaylandinputcontext_wayland.cpp
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwsinputcontext_p.h"
+#include "qinputcontext_p.h"
+#include "qwsdisplay_qws.h"
+#include "qwsevent_qws.h"
+#include "private/qwscommand_qws_p.h"
+#include "qwindowsystem_qws.h"
+#include "qevent.h"
+#include "qtextformat.h"
+
+#include <qbuffer.h>
+
+#include <qdebug.h>
+
+#ifndef QT_NO_QWS_INPUTMETHODS
+
+QT_BEGIN_NAMESPACE
+
+static QWidget* activeWidget = 0;
+
+//#define EXTRA_DEBUG
+
+QWSInputContext::QWSInputContext(QObject *parent)
+ :QInputContext(parent)
+{
+}
+
+void QWSInputContext::reset()
+{
+ QPaintDevice::qwsDisplay()->resetIM();
+}
+
+
+void QWSInputContext::setFocusWidget( QWidget *w )
+{
+ QWidget *oldFocus = focusWidget();
+ if (oldFocus == w)
+ return;
+
+ if (w) {
+ QWSInputContext::updateImeStatus(w, true);
+ } else {
+ if (oldFocus)
+ QWSInputContext::updateImeStatus(oldFocus, false);
+ }
+
+ if (oldFocus) {
+ QWidget *tlw = oldFocus->window();
+ int winid = tlw->internalWinId();
+
+ int widgetid = oldFocus->internalWinId();
+ QPaintDevice::qwsDisplay()->sendIMUpdate(QWSInputMethod::FocusOut, winid, widgetid);
+ }
+
+ QInputContext::setFocusWidget(w);
+
+ if (!w)
+ return;
+
+ QWidget *tlw = w->window();
+ int winid = tlw->winId();
+
+ int widgetid = w->winId();
+ QPaintDevice::qwsDisplay()->sendIMUpdate(QWSInputMethod::FocusIn, winid, widgetid);
+
+ //setfocus ???
+
+ update();
+}
+
+
+void QWSInputContext::widgetDestroyed(QWidget *w)
+{
+ if (w == QT_PREPEND_NAMESPACE(activeWidget))
+ QT_PREPEND_NAMESPACE(activeWidget) = 0;
+ QInputContext::widgetDestroyed(w);
+}
+
+void QWSInputContext::update()
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return;
+
+ QWidget *tlw = w->window();
+ int winid = tlw->winId();
+
+ int widgetid = w->winId();
+ QPaintDevice::qwsDisplay()->sendIMUpdate(QWSInputMethod::Update, winid, widgetid);
+
+}
+
+void QWSInputContext::mouseHandler( int x, QMouseEvent *event)
+{
+ if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease)
+ QPaintDevice::qwsDisplay()->sendIMMouseEvent( x, event->type() == QEvent::MouseButtonPress );
+}
+
+QWidget *QWSInputContext::activeWidget()
+{
+ return QT_PREPEND_NAMESPACE(activeWidget);
+}
+
+
+bool QWSInputContext::isComposing() const
+{
+ return QT_PREPEND_NAMESPACE(activeWidget) != 0;
+}
+
+bool QWSInputContext::translateIMQueryEvent(QWidget *w, const QWSIMQueryEvent *e)
+{
+ Qt::InputMethodQuery type = static_cast<Qt::InputMethodQuery>(e->simpleData.property);
+ QVariant result = w->inputMethodQuery(type);
+ QWidget *tlw = w->window();
+ int winId = tlw->winId();
+
+ if ( type == Qt::ImMicroFocus ) {
+ // translate to relative to tlw
+ QRect mf = result.toRect();
+ mf.moveTopLeft(w->mapTo(tlw,mf.topLeft()));
+ result = mf;
+ }
+
+ QPaintDevice::qwsDisplay()->sendIMResponse(winId, e->simpleData.property, result);
+
+ return false;
+}
+
+bool QWSInputContext::translateIMInitEvent(const QWSIMInitEvent *e)
+{
+ Q_UNUSED(e);
+ qDebug("### QWSInputContext::translateIMInitEvent not implemented ###");
+ return false;
+}
+
+bool QWSInputContext::translateIMEvent(QWidget *w, const QWSIMEvent *e)
+{
+ QDataStream stream(e->streamingData);
+ QString preedit;
+ QString commit;
+
+ stream >> preedit;
+ stream >> commit;
+
+ if (preedit.isEmpty() && QT_PREPEND_NAMESPACE(activeWidget))
+ w = QT_PREPEND_NAMESPACE(activeWidget);
+
+ QInputContext *qic = w->inputContext();
+ if (!qic)
+ return false;
+
+ QList<QInputMethodEvent::Attribute> attrs;
+
+
+ while (!stream.atEnd()) {
+ int type = -1;
+ int start = -1;
+ int length = -1;
+ QVariant data;
+ stream >> type >> start >> length >> data;
+ if (stream.status() != QDataStream::Ok) {
+ qWarning("corrupted QWSIMEvent");
+ //qic->reset(); //???
+ return false;
+ }
+ if (type == QInputMethodEvent::TextFormat)
+ data = qic->standardFormat(static_cast<QInputContext::StandardFormat>(data.toInt()));
+ attrs << QInputMethodEvent::Attribute(static_cast<QInputMethodEvent::AttributeType>(type), start, length, data);
+ }
+#ifdef EXTRA_DEBUG
+ qDebug() << "preedit" << preedit << "len" << preedit.length() <<"commit" << commit << "len" << commit.length()
+ << "n attr" << attrs.count();
+#endif
+
+ if (preedit.isEmpty())
+ QT_PREPEND_NAMESPACE(activeWidget) = 0;
+ else
+ QT_PREPEND_NAMESPACE(activeWidget) = w;
+
+
+ QInputMethodEvent ime(preedit, attrs);
+ if (!commit.isEmpty() || e->simpleData.replaceLength > 0)
+ ime.setCommitString(commit, e->simpleData.replaceFrom, e->simpleData.replaceLength);
+
+
+ extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); //qapplication_qws.cpp
+ qt_sendSpontaneousEvent(w, &ime);
+
+ return true;
+}
+
+Q_GUI_EXPORT void (*qt_qws_inputMethodStatusChanged)(QWidget*) = 0;
+
+void QWSInputContext::updateImeStatus(QWidget *w, bool hasFocus)
+{
+ Q_UNUSED(hasFocus);
+
+ if (!w || !qt_qws_inputMethodStatusChanged)
+ return;
+ qt_qws_inputMethodStatusChanged(w);
+}
+
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_INPUTMETHODS
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 6fd45adf44..ba7618c237 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -171,6 +171,31 @@ unix:x11 {
kernel/qeventdispatcher_x11_p.h
}
+wayland {
+ HEADERS += \
+ kernel/qeventdispatcher_wayland_p.h
+
+ SOURCES += \
+ kernel/qapplication_wayland.cpp \
+ kernel/qclipboard_wayland.cpp \
+ kernel/qcursor_wayland.cpp \
+ kernel/qdesktopwidget_wayland.cpp \
+ kernel/qdnd_wayland.cpp \
+ kernel/qeventdispatcher_wayland.cpp \
+ kernel/qsound_wayland.cpp \
+ kernel/qwidget_wayland.cpp \
+ kernel/qkeymapper_wayland.cpp \
+
+ contains(QT_CONFIG, glib) {
+ SOURCES += \
+ kernel/qeventdispatcher_glib_wayland.cpp
+ HEADERS += \
+ kernel/qeventdispatcher_glib_wayland_p.h
+ QMAKE_CXXFLAGS += $$QT_CFLAGS_GLIB
+ LIBS_PRIVATE +=$$QT_LIBS_GLIB
+ }
+}
+
embedded {
HEADERS += \
kernel/qeventdispatcher_qws_p.h
diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h
index cb1d063cb3..03cb32ffdd 100644
--- a/src/gui/kernel/qapplication.h
+++ b/src/gui/kernel/qapplication.h
@@ -235,10 +235,15 @@ public:
virtual bool macEventFilter(EventHandlerCallRef, EventRef);
#endif
#if defined(Q_WS_X11)
+#error foo
virtual bool x11EventFilter(XEvent *);
virtual int x11ClientMessage(QWidget*, XEvent*, bool passive_only);
int x11ProcessEvent(XEvent*);
#endif
+#if defined(Q_WS_WAYLAND)
+ virtual bool waylandEventFilter(struct wl_message *);
+ int waylandProcessEvent(const struct wl_message *);
+#endif
#if defined(Q_OS_SYMBIAN)
int symbianProcessEvent(const QSymbianEvent *event);
virtual bool symbianEventFilter(const QSymbianEvent *event);
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index 3a3f816097..570111a824 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -303,6 +303,9 @@ public:
static bool qws_apply_settings();
static QWidget *findWidget(const QObjectList&, const QPoint &, bool rec);
#endif
+#if defined(Q_WS_WAYLAND)
+ static QWidget *findWidget(const QObjectList&, const QPoint &, bool rec);
+#endif
static bool quitOnLastWindowClosed;
static void emitLastWindowClosed();
#ifdef Q_WS_WINCE
diff --git a/src/gui/kernel/qapplication_wayland.cpp b/src/gui/kernel/qapplication_wayland.cpp
new file mode 100644
index 0000000000..bffeb2e613
--- /dev/null
+++ b/src/gui/kernel/qapplication_wayland.cpp
@@ -0,0 +1,614 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+#include "qlibrary.h"
+#include "qcursor.h"
+#include "qapplication.h"
+#include "private/qapplication_p.h"
+#include "qwidget.h"
+#include "qbitarray.h"
+#include "qpainter.h"
+#include "qpixmapcache.h"
+#include "qdatetime.h"
+#include "qtextcodec.h"
+#include "qdatastream.h"
+#include "qbuffer.h"
+#include "qsocketnotifier.h"
+#include "qsessionmanager.h"
+#include "qclipboard.h"
+#include "qbitmap.h"
+
+#include "qfile.h"
+#include "qhash.h"
+#include "qdesktopwidget.h"
+#include "qcolormap.h"
+#include "private/qcursor_p.h"
+#include "qsettings.h"
+#include "qdebug.h"
+#include "qeventdispatcher_wayland_p.h"
+#if !defined(QT_NO_GLIB)
+# include "qeventdispatcher_glib_wayland_p.h"
+#endif
+
+
+#include "private/qwidget_p.h"
+#include "private/qbackingstore_p.h"
+#include "private/qwindowsurface_wayland_p.h"
+#include "private/qfont_p.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef Q_OS_VXWORKS
+# include <sys/times.h>
+#else
+# include <sys/time.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <qvfbhdr.h>
+
+#ifndef QT_NO_QWS_MULTIPROCESS
+#ifdef QT_NO_QSHM
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#ifndef Q_OS_DARWIN
+# include <sys/sem.h>
+#endif
+#include <sys/socket.h>
+#endif
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static QString appName;
+int *qt_last_x = 0;
+int *qt_last_y = 0;
+
+void QApplicationPrivate::createEventDispatcher()
+{
+}
+
+void QApplicationPrivate::initializeWidgetPaletteHash()
+{
+}
+
+static void init_display()
+{
+ // FIXME: Connect to Wayland server
+
+ // Get display parameters
+ // Set paintdevice parameters
+ // XXX initial info sent from server
+ // Misc. initialization
+
+ QColormap::initialize();
+ QFont::initialize();
+#ifndef QT_NO_CURSOR
+ QCursorData::initialize();
+#endif
+
+ qApp->setObjectName(appName);
+
+ if (!QApplicationPrivate::sys_font) {
+#ifdef QT_NO_FREETYPE
+ QFont f = QFont(QLatin1String("helvetica"), 10);
+#else
+ QFont f = QFont(QLatin1String("DejaVu Sans"), 12);
+#endif
+ QApplicationPrivate::setSystemFont(f);
+ }
+}
+
+void qt_init_display()
+{
+ qt_is_gui_used = true;
+ init_display();
+}
+
+static bool read_bool_env_var(const char *var, bool defaultvalue)
+{
+ // returns true if env variable is set to non-zero
+ // returns false if env var is set to zero
+ // returns defaultvalue if env var not set
+ char *x = ::getenv(var);
+ return (x && *x) ? (strcmp(x,"0") != 0) : defaultvalue;
+}
+
+static int read_int_env_var(const char *var, int defaultvalue)
+{
+ bool ok;
+ int r = qgetenv(var).toInt(&ok);
+ return ok ? r : defaultvalue;
+}
+
+void qt_init(QApplicationPrivate *priv, int type)
+{
+#ifdef QT_NO_QWS_MULTIPROCESS
+ if (type == QApplication::GuiClient)
+ type = QApplication::GuiServer;
+#endif
+ if (type == QApplication::GuiServer)
+ qt_is_gui_used = false; //we'll turn it on in a second
+
+ priv->inputContext = 0;
+
+ int flags = 0;
+ char *p;
+ int argc = priv->argc;
+ char **argv = priv->argv;
+ int j;
+
+ // Set application name
+
+ if (argv && *argv) { //apparently, we allow people to pass 0 on the other platforms
+ p = strrchr(argv[0], '/');
+ appName = QString::fromLocal8Bit(p ? p + 1 : argv[0]);
+ }
+
+ // Get command line params
+
+ j = argc ? 1 : 0;
+ QString decoration;
+ for (int i=1; i<argc; i++) {
+ if (argv[i] && *argv[i] != '-') {
+ argv[j++] = argv[i];
+ continue;
+ }
+ }
+ if(j < priv->argc) {
+ priv->argv[j] = 0;
+ priv->argc = j;
+ }
+}
+
+/*****************************************************************************
+ qt_cleanup() - cleans up when the application is finished
+ *****************************************************************************/
+
+void qt_cleanup()
+{
+ QPixmapCache::clear();
+#ifndef QT_NO_CURSOR
+ QCursorData::cleanup();
+#endif
+ QFont::cleanup();
+ QColormap::cleanup();
+}
+
+
+/*****************************************************************************
+ Platform specific global and internal functions
+ *****************************************************************************/
+
+QString QApplicationPrivate::appName() const // get application name
+{
+ return QT_PREPEND_NAMESPACE(appName);
+}
+
+/*****************************************************************************
+ Platform specific QApplication members
+ *****************************************************************************/
+
+#define NoValue 0x0000
+#define XValue 0x0001
+#define YValue 0x0002
+#define WidthValue 0x0004
+#define HeightValue 0x0008
+#define AllValues 0x000F
+#define XNegative 0x0010
+#define YNegative 0x0020
+
+/* Copyright notice for ReadInteger and parseGeometry
+
+Copyright (c) 1985, 1986, 1987 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the X Consortium.
+
+*/
+/*
+ * XParseGeometry parses strings of the form
+ * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
+ * width, height, xoffset, and yoffset are unsigned integers.
+ * Example: "=80x24+300-49"
+ * The equal sign is optional.
+ * It returns a bitmask that indicates which of the four values
+ * were actually found in the string. For each value found,
+ * the corresponding argument is updated; for each value
+ * not found, the corresponding argument is left unchanged.
+ */
+
+static int
+ReadInteger(char *string, char **NextString)
+{
+ register int Result = 0;
+ int Sign = 1;
+
+ if (*string == '+')
+ string++;
+ else if (*string == '-')
+ {
+ string++;
+ Sign = -1;
+ }
+ for (; (*string >= '0') && (*string <= '9'); string++)
+ {
+ Result = (Result * 10) + (*string - '0');
+ }
+ *NextString = string;
+ if (Sign >= 0)
+ return Result;
+ else
+ return -Result;
+}
+
+static int parseGeometry(const char* string,
+ int* x, int* y, int* width, int* height)
+{
+ int mask = NoValue;
+ register char *strind;
+ unsigned int tempWidth=0, tempHeight=0;
+ int tempX=0, tempY=0;
+ char *nextCharacter;
+
+ if (!string || (*string == '\0')) return mask;
+ if (*string == '=')
+ string++; /* ignore possible '=' at beg of geometry spec */
+
+ strind = const_cast<char *>(string);
+ if (*strind != '+' && *strind != '-' && *strind != 'x') {
+ tempWidth = ReadInteger(strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return 0;
+ strind = nextCharacter;
+ mask |= WidthValue;
+ }
+
+ if (*strind == 'x' || *strind == 'X') {
+ strind++;
+ tempHeight = ReadInteger(strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return 0;
+ strind = nextCharacter;
+ mask |= HeightValue;
+ }
+
+ if ((*strind == '+') || (*strind == '-')) {
+ if (*strind == '-') {
+ strind++;
+ tempX = -ReadInteger(strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return 0;
+ strind = nextCharacter;
+ mask |= XNegative;
+
+ }
+ else
+ { strind++;
+ tempX = ReadInteger(strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return 0;
+ strind = nextCharacter;
+ }
+ mask |= XValue;
+ if ((*strind == '+') || (*strind == '-')) {
+ if (*strind == '-') {
+ strind++;
+ tempY = -ReadInteger(strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return 0;
+ strind = nextCharacter;
+ mask |= YNegative;
+
+ }
+ else
+ {
+ strind++;
+ tempY = ReadInteger(strind, &nextCharacter);
+ if (strind == nextCharacter)
+ return 0;
+ strind = nextCharacter;
+ }
+ mask |= YValue;
+ }
+ }
+
+ /* If strind isn't at the end of the string then it's an invalid
+ geometry specification. */
+
+ if (*strind != '\0') return 0;
+
+ if (mask & XValue)
+ *x = tempX;
+ if (mask & YValue)
+ *y = tempY;
+ if (mask & WidthValue)
+ *width = tempWidth;
+ if (mask & HeightValue)
+ *height = tempHeight;
+ return mask;
+}
+
+#ifdef QT3_SUPPORT
+void QApplication::setMainWidget(QWidget *mainWidget)
+{
+ QApplicationPrivate::main_widget = mainWidget;
+}
+#endif
+
+/*****************************************************************************
+ QApplication cursor stack
+ *****************************************************************************/
+#ifndef QT_NO_CURSOR
+void QApplication::setOverrideCursor(const QCursor &cursor)
+{
+}
+
+void QApplication::restoreOverrideCursor()
+{
+}
+#endif// QT_NO_CURSOR
+
+
+
+/*****************************************************************************
+ Routines to find a Qt widget from a screen position
+ *****************************************************************************/
+
+/*!
+ \internal
+*/
+QWidget *QApplicationPrivate::findWidget(const QObjectList& list,
+ const QPoint &pos, bool rec)
+{
+ QWidget *w;
+
+ for (int i = list.size()-1; i >= 0; --i) {
+ if (list.at(i)->isWidgetType()) {
+ w = static_cast<QWidget*>(list.at(i));
+ if (w->isVisible() && !w->testAttribute(Qt::WA_TransparentForMouseEvents) && w->geometry().contains(pos)
+ && (!w->d_func()->extra || w->d_func()->extra->mask.isEmpty() || w->d_func()->extra->mask.contains(pos - w->geometry().topLeft()) )) {
+ if (!rec)
+ return w;
+ QWidget *c = w->childAt(w->mapFromParent(pos));
+ return c ? c : w;
+ }
+ }
+ }
+ return 0;
+}
+
+
+QWidget *QApplication::topLevelAt(const QPoint &pos)
+{
+ //### QWSDisplay::windowAt() is currently only implemented in the server process
+ //int winId = QPaintDevice::qwsDisplay()->windowAt(pos);
+ //if (winId !=0)
+ //return QWidget::find(winId);
+
+#if 1
+ // fallback implementation for client processes
+//### This is slightly wrong: we have no guarantee that the list is in
+//### stacking order, so if the topmost window is transparent, we may
+//### return the wrong widget
+
+ QWidgetList list = topLevelWidgets();
+ for (int i = list.size()-1; i >= 0; --i) {
+ QWidget *w = list[i];
+ if (w != QApplication::desktop() && w->isVisible())
+ return w;
+ }
+#endif
+ return 0;
+}
+
+void QApplication::beep()
+{
+}
+
+void QApplication::alert(QWidget *, int)
+{
+}
+
+int QApplication::waylandProcessEvent(const struct wl_message *msg)
+{
+}
+
+bool QApplication::waylandEventFilter(struct wl_message *msg)
+{
+ return false;
+}
+
+bool QApplicationPrivate::modalState()
+{
+ return false;
+}
+
+void QApplicationPrivate::enterModal_sys(QWidget *widget)
+{
+}
+
+void QApplicationPrivate::leaveModal_sys(QWidget *widget)
+{
+}
+
+void QApplicationPrivate::openPopup(QWidget *popup)
+{
+}
+
+void QApplicationPrivate::closePopup(QWidget *popup)
+{
+}
+
+void QApplication::setCursorFlashTime(int msecs)
+{
+ QApplicationPrivate::cursor_flash_time = msecs;
+}
+
+
+int QApplication::cursorFlashTime()
+{
+ return QApplicationPrivate::cursor_flash_time;
+}
+
+void QApplication::setDoubleClickInterval(int ms)
+{
+ QApplicationPrivate::mouse_double_click_time = ms;
+}
+
+int QApplication::doubleClickInterval()
+{
+ return QApplicationPrivate::mouse_double_click_time;
+}
+
+void QApplication::setKeyboardInputInterval(int ms)
+{
+ QApplicationPrivate::keyboard_input_time = ms;
+}
+
+int QApplication::keyboardInputInterval()
+{
+ return QApplicationPrivate::keyboard_input_time;
+}
+
+#ifndef QT_NO_WHEELEVENT
+void QApplication::setWheelScrollLines(int lines)
+{
+ QApplicationPrivate::wheel_scroll_lines = lines;
+}
+
+int QApplication::wheelScrollLines()
+{
+ return QApplicationPrivate::wheel_scroll_lines;
+}
+#endif
+
+void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
+{
+ switch (effect) {
+ case Qt::UI_AnimateMenu:
+ QApplicationPrivate::animate_menu = enable;
+ break;
+ case Qt::UI_FadeMenu:
+ if (enable)
+ QApplicationPrivate::animate_menu = true;
+ QApplicationPrivate::fade_menu = enable;
+ break;
+ case Qt::UI_AnimateCombo:
+ QApplicationPrivate::animate_combo = enable;
+ break;
+ case Qt::UI_AnimateTooltip:
+ QApplicationPrivate::animate_tooltip = enable;
+ break;
+ case Qt::UI_FadeTooltip:
+ if (enable)
+ QApplicationPrivate::animate_tooltip = true;
+ QApplicationPrivate::fade_tooltip = enable;
+ break;
+ case Qt::UI_AnimateToolBox:
+ QApplicationPrivate::animate_toolbox = enable;
+ break;
+ default:
+ QApplicationPrivate::animate_ui = enable;
+ break;
+ }
+}
+
+bool QApplication::isEffectEnabled(Qt::UIEffect effect)
+{
+ if (QColormap::instance().depth() < 16 || !QApplicationPrivate::animate_ui)
+ return false;
+
+ switch(effect) {
+ case Qt::UI_AnimateMenu:
+ return QApplicationPrivate::animate_menu;
+ case Qt::UI_FadeMenu:
+ return QApplicationPrivate::fade_menu;
+ case Qt::UI_AnimateCombo:
+ return QApplicationPrivate::animate_combo;
+ case Qt::UI_AnimateTooltip:
+ return QApplicationPrivate::animate_tooltip;
+ case Qt::UI_FadeTooltip:
+ return QApplicationPrivate::fade_tooltip;
+ case Qt::UI_AnimateToolBox:
+ return QApplicationPrivate::animate_toolbox;
+ default:
+ return QApplicationPrivate::animate_ui;
+ }
+}
+
+void QApplicationPrivate::initializeMultitouch_sys()
+{
+}
+
+void QApplicationPrivate::cleanupMultitouch_sys()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qclipboard_wayland.cpp b/src/gui/kernel/qclipboard_wayland.cpp
new file mode 100644
index 0000000000..f9b17d9690
--- /dev/null
+++ b/src/gui/kernel/qclipboard_wayland.cpp
@@ -0,0 +1,257 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qclipboard.h"
+
+#ifndef QT_NO_CLIPBOARD
+
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qdatetime.h"
+#include "qbuffer.h"
+#include "qwidget.h"
+#include "qevent.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_USE_NAMESPACE
+
+static const int TextClipboard=424242;
+static bool init = false;
+
+class QClipboardData
+{
+public:
+ QClipboardData();
+ ~QClipboardData();
+
+ void setSource(QMimeData* s)
+ {
+ if (s == src)
+ return;
+ delete src;
+ src = s;
+ }
+ QMimeData* source()
+ { return src; }
+#if 0
+ void addTransferredPixmap(QPixmap pm)
+ { /* TODO: queue them */
+ transferred[tindex] = pm;
+ tindex=(tindex+1)%2;
+ }
+ void clearTransfers()
+ {
+ transferred[0] = QPixmap();
+ transferred[1] = QPixmap();
+ }
+#endif
+
+ void clear();
+
+private:
+ QMimeData* src;
+
+#if 0
+ QPixmap transferred[2];
+ int tindex;
+#endif
+};
+
+QClipboardData::QClipboardData()
+{
+ src = 0;
+#if 0
+ tindex=0;
+#endif
+}
+
+QClipboardData::~QClipboardData()
+{
+ delete src;
+}
+
+void QClipboardData::clear()
+{
+ delete src;
+ src = 0;
+}
+
+
+static QClipboardData *internalCbData = 0;
+
+static void cleanupClipboardData()
+{
+ delete internalCbData;
+ internalCbData = 0;
+}
+
+static QClipboardData *clipboardData()
+{
+ if (internalCbData == 0) {
+ internalCbData = new QClipboardData;
+ qAddPostRoutine(cleanupClipboardData);
+ }
+ return internalCbData;
+}
+
+
+/*****************************************************************************
+ QClipboard member functions for FB.
+ *****************************************************************************/
+
+#if 0
+
+QString QClipboard::text() const
+{
+}
+
+void QClipboard::setText(const QString &text)
+{
+}
+
+QString QClipboard::text(QString& subtype) const
+{
+ QString r;
+ if (subtype == "plain")
+ r = text();
+ return r;
+}
+
+#endif
+
+void QClipboard::clear(Mode mode)
+{
+ setText(QString(), mode);
+}
+
+
+bool QClipboard::event(QEvent *e)
+{
+ static bool recursionWatch = false;
+ if (e->type() != QEvent::Clipboard || recursionWatch)
+ return QObject::event(e);
+
+ recursionWatch = true;
+#if 0
+ if (event) { //&& event->simpleData.state == QWSPropertyNotifyEvent::PropertyNewValue) {
+ QClipboardData *d = clipboardData();
+ QString t("foo");
+ if( (d->source() == 0 && !t.isEmpty()) || (d->source() != 0 && d->source()->text() != t) ) {
+ if( !d->source() )
+ d->setSource(new QMimeData);
+ d->source()->setText( t );
+ emitChanged(QClipboard::Clipboard);
+ }
+ }
+#endif
+ recursionWatch = false;
+ return true;
+}
+
+const QMimeData* QClipboard::mimeData(Mode mode) const
+{
+ if (mode != Clipboard) return 0;
+
+ QClipboardData *d = clipboardData();
+ // Try and get data from QWSProperty if no mime data has been set on us.
+ if( !d->source() ) {
+ QString t("foo");
+ if( !t.isEmpty() ) {
+ QMimeData* nd = new QMimeData;
+ nd->setText( t );
+ d->setSource( nd );
+ }
+ }
+ return d->source();
+}
+
+void QClipboard::setMimeData(QMimeData* src, Mode mode)
+{
+ if (mode != Clipboard) return;
+
+ QClipboardData *d = clipboardData();
+
+ /* Propagate text data to other QWSClients */
+
+ QString newText;
+ if( src != 0 )
+ newText = src->text();
+ QString oldText;
+ if( d->source() != 0 )
+ oldText = d->source()->text();
+
+ d->setSource(src);
+#if 0
+ if( oldText != newText ) {
+ if( d->source() == 0 ) {
+ qwsSetClipboardText( QString() );
+ } else {
+ qwsSetClipboardText( d->source()->text() );
+ }
+ }
+#endif
+ emitChanged(QClipboard::Clipboard);
+}
+
+bool QClipboard::supportsMode(Mode mode) const
+{
+ return (mode == Clipboard);
+}
+
+bool QClipboard::ownsMode(Mode mode) const
+{
+ if (mode == Clipboard)
+ qWarning("QClipboard::ownsClipboard: UNIMPLEMENTED!");
+ return false;
+}
+
+void QClipboard::connectNotify( const char * )
+{
+}
+
+void QClipboard::ownerDestroyed()
+{
+}
+
+#endif // QT_NO_CLIPBOARD
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qcursor_wayland.cpp b/src/gui/kernel/qcursor_wayland.cpp
new file mode 100644
index 0000000000..92589960af
--- /dev/null
+++ b/src/gui/kernel/qcursor_wayland.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qcursor.h>
+#include <private/qcursor_p.h>
+#include <qbitmap.h>
+
+QT_BEGIN_NAMESPACE
+
+QT_USE_NAMESPACE
+
+#ifndef QT_NO_CURSOR
+
+static int nextCursorId = Qt::BitmapCursor;
+
+/*****************************************************************************
+ Internal QCursorData class
+ *****************************************************************************/
+
+QCursorData::QCursorData(Qt::CursorShape s)
+ : cshape(s), bm(0), bmm(0), hx(0), hy(0)
+{
+ ref = 1;
+}
+
+QCursorData::~QCursorData()
+{
+ delete bm;
+ delete bmm;
+ QT_TRY {
+ /* FIXME: call wayland cursor destroy */
+ //QPaintDevice::qwsDisplay()->destroyCursor(id);
+ } QT_CATCH(const std::bad_alloc &) {
+ // do nothing.
+ }
+}
+
+
+/*****************************************************************************
+ Global cursors
+ *****************************************************************************/
+
+QCursorData *QCursorData::setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY)
+{
+ if (!QCursorData::initialized)
+ QCursorData::initialize();
+ if (bitmap.depth() != 1 || mask.depth() != 1 || bitmap.size() != mask.size()) {
+ qWarning("QCursor: Cannot create bitmap cursor; invalid bitmap(s)");
+ QCursorData *c = qt_cursorTable[0];
+ c->ref.ref();
+ return c;
+ }
+ QCursorData *d = new QCursorData;
+ d->bm = new QBitmap(bitmap);
+ d->bmm = new QBitmap(mask);
+ d->cshape = Qt::BitmapCursor;
+ d->hx = hotX >= 0 ? hotX : bitmap.width() / 2;
+ d->hy = hotY >= 0 ? hotY : bitmap.height() / 2;
+
+ return d;
+}
+
+void QCursorData::update()
+{
+}
+
+#endif //QT_NO_CURSOR
+
+extern int *qt_last_x,*qt_last_y;
+
+QPoint QCursor::pos()
+{
+ // This doesn't know about hotspots yet so we disable it
+ //qt_accel_update_cursor();
+ if (qt_last_x)
+ return QPoint(*qt_last_x, *qt_last_y);
+ else
+ return QPoint();
+}
+
+void QCursor::setPos(int x, int y)
+{
+ // Need to check, since some X servers generate null mouse move
+ // events, causing looping in applications which call setPos() on
+ // every mouse move event.
+ //
+ if (pos() == QPoint(x, y))
+ return;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qdesktopwidget_wayland.cpp b/src/gui/kernel/qdesktopwidget_wayland.cpp
new file mode 100644
index 0000000000..5d05d8df31
--- /dev/null
+++ b/src/gui/kernel/qdesktopwidget_wayland.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdesktopwidget.h"
+#include "private/qapplication_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_USE_NAMESPACE
+
+QDesktopWidget::QDesktopWidget()
+ : QWidget(0, Qt::Desktop)
+{
+ setObjectName(QLatin1String("desktop"));
+}
+
+QDesktopWidget::~QDesktopWidget()
+{
+}
+
+bool QDesktopWidget::isVirtualDesktop() const
+{
+ return true;
+}
+
+int QDesktopWidget::primaryScreen() const
+{
+ return 0;
+}
+
+int QDesktopWidget::numScreens() const
+{
+}
+
+QWidget *QDesktopWidget::screen(int)
+{
+ return this;
+}
+
+const QRect QDesktopWidget::availableGeometry(int screenNo) const
+{
+}
+
+const QRect QDesktopWidget::screenGeometry(int screenNo) const
+{
+}
+
+int QDesktopWidget::screenNumber(const QWidget *w) const
+{
+}
+
+int QDesktopWidget::screenNumber(const QPoint &p) const
+{
+}
+
+void QDesktopWidget::resizeEvent(QResizeEvent *)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qdnd_wayland.cpp b/src/gui/kernel/qdnd_wayland.cpp
new file mode 100644
index 0000000000..0dfc6dc968
--- /dev/null
+++ b/src/gui/kernel/qdnd_wayland.cpp
@@ -0,0 +1,423 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication.h"
+
+#ifndef QT_NO_DRAGANDDROP
+
+#include "qwidget.h"
+#include "qdatetime.h"
+#include "qbitmap.h"
+#include "qcursor.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qdnd_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_USE_NAMESPACE
+
+static QPixmap *defaultPm = 0;
+static const int default_pm_hotx = -2;
+static const int default_pm_hoty = -16;
+static const char *const default_pm[] = {
+"13 9 3 1",
+". c None",
+" c #000000",
+"X c #FFFFFF",
+"X X X X X X X",
+" X X X X X X ",
+"X ......... X",
+" X.........X ",
+"X ......... X",
+" X.........X ",
+"X ......... X",
+" X X X X X X ",
+"X X X X X X X",
+};
+
+// Shift/Ctrl handling, and final drop status
+static Qt::DropAction global_accepted_action = Qt::CopyAction;
+static Qt::DropActions possible_actions = Qt::IgnoreAction;
+
+
+// static variables in place of a proper cross-process solution
+static QDrag *drag_object;
+static bool qt_qws_dnd_dragging = false;
+
+
+static Qt::KeyboardModifiers oldstate;
+
+class QShapedPixmapWidget : public QWidget {
+ QPixmap pixmap;
+public:
+ QShapedPixmapWidget() :
+ QWidget(0, Qt::Tool | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint)
+ {
+ // ### Temporary workaround for 4.2-rc1!!! To prevent flickering when
+ // using drag'n drop in a client application. (task 126956)
+ // setAttribute() should be done unconditionally!
+ if (QApplication::type() == QApplication::GuiServer)
+ setAttribute(Qt::WA_TransparentForMouseEvents);
+ }
+
+ void setPixmap(QPixmap pm)
+ {
+ pixmap = pm;
+ if (!pixmap.mask().isNull()) {
+ setMask(pixmap.mask());
+ } else {
+ clearMask();
+ }
+ resize(pm.width(),pm.height());
+ }
+
+ void paintEvent(QPaintEvent*)
+ {
+ QPainter p(this);
+ p.drawPixmap(0,0,pixmap);
+ }
+};
+
+
+static QShapedPixmapWidget *qt_qws_dnd_deco = 0;
+
+
+void QDragManager::updatePixmap()
+{
+ if (qt_qws_dnd_deco) {
+ QPixmap pm;
+ QPoint pm_hot(default_pm_hotx,default_pm_hoty);
+ if (drag_object) {
+ pm = drag_object->pixmap();
+ if (!pm.isNull())
+ pm_hot = drag_object->hotSpot();
+ }
+ if (pm.isNull()) {
+ if (!defaultPm)
+ defaultPm = new QPixmap(default_pm);
+ pm = *defaultPm;
+ }
+ //qt_qws_dnd_deco->setPixmap(pm);
+ //qt_qws_dnd_deco->move(QCursor::pos()-pm_hot);
+ if (willDrop) {
+ //qt_qws_dnd_deco->show();
+ } else {
+ //qt_qws_dnd_deco->hide();
+ }
+ }
+}
+
+void QDragManager::timerEvent(QTimerEvent *) { }
+
+void QDragManager::move(const QPoint &) { }
+
+void QDragManager::updateCursor()
+{
+#ifndef QT_NO_CURSOR
+ if (willDrop) {
+ if (qt_qws_dnd_deco)
+ ;
+ //qt_qws_dnd_deco->show();
+ } else {
+ QCursor *overrideCursor = QApplication::overrideCursor();
+ if (!overrideCursor || overrideCursor->shape() != Qt::ForbiddenCursor) {
+ QApplication::changeOverrideCursor(QCursor(Qt::ForbiddenCursor));
+ }
+ if (qt_qws_dnd_deco)
+ ;
+ //qt_qws_dnd_deco->hide();
+ }
+#endif
+}
+
+
+bool QDragManager::eventFilter(QObject *o, QEvent *e)
+{
+ if (beingCancelled) {
+ if (e->type() == QEvent::KeyRelease && static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
+ qApp->removeEventFilter(this);
+ Q_ASSERT(object == 0);
+ beingCancelled = false;
+ eventLoop->exit();
+ return true; // block the key release
+ }
+ return false;
+ }
+
+
+
+ if (!o->isWidgetType())
+ return false;
+
+ switch(e->type()) {
+ case QEvent::ShortcutOverride:
+ // prevent accelerators from firing while dragging
+ e->accept();
+ return true;
+
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ {
+ QKeyEvent *ke = ((QKeyEvent*)e);
+ if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) {
+ cancel();
+ qApp->removeEventFilter(this);
+ beingCancelled = false;
+ eventLoop->exit();
+ } else {
+ updateCursor();
+ }
+ return true; // Eat all key events
+ }
+
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ {
+ if (!object) { //#### this should not happen
+ qWarning("QDragManager::eventFilter: No object");
+ return true;
+ }
+
+ QDragManager *manager = QDragManager::self();
+ QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData;
+ if (manager->object)
+ possible_actions = manager->dragPrivate()->possible_actions;
+ else
+ possible_actions = Qt::IgnoreAction;
+
+ QMouseEvent *me = (QMouseEvent *)e;
+ if (me->buttons()) {
+ Qt::DropAction prevAction = global_accepted_action;
+ QWidget *cw = QApplication::widgetAt(me->globalPos());
+
+ // Fix for when we move mouse on to the deco widget
+ if (qt_qws_dnd_deco && cw == qt_qws_dnd_deco)
+ cw = object->target();
+
+ while (cw && !cw->acceptDrops() && !cw->isWindow())
+ cw = cw->parentWidget();
+
+ if (object->target() != cw) {
+ if (object->target()) {
+ QDragLeaveEvent dle;
+ QApplication::sendEvent(object->target(), &dle);
+ willDrop = false;
+ global_accepted_action = Qt::IgnoreAction;
+ updateCursor();
+ restoreCursor = true;
+ object->d_func()->target = 0;
+ }
+ if (cw && cw->acceptDrops()) {
+ object->d_func()->target = cw;
+ QDragEnterEvent dee(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData,
+ me->buttons(), me->modifiers());
+ QApplication::sendEvent(object->target(), &dee);
+ willDrop = dee.isAccepted() && dee.dropAction() != Qt::IgnoreAction;
+ global_accepted_action = willDrop ? dee.dropAction() : Qt::IgnoreAction;
+ updateCursor();
+ restoreCursor = true;
+ }
+ } else if (cw) {
+ QDragMoveEvent dme(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData,
+ me->buttons(), me->modifiers());
+ if (global_accepted_action != Qt::IgnoreAction) {
+ dme.setDropAction(global_accepted_action);
+ dme.accept();
+ }
+ QApplication::sendEvent(cw, &dme);
+ willDrop = dme.isAccepted();
+ global_accepted_action = willDrop ? dme.dropAction() : Qt::IgnoreAction;
+ updatePixmap();
+ updateCursor();
+ }
+ if (global_accepted_action != prevAction)
+ emitActionChanged(global_accepted_action);
+ }
+ return true; // Eat all mouse events
+ }
+
+ case QEvent::MouseButtonRelease:
+ {
+ qApp->removeEventFilter(this);
+ if (restoreCursor) {
+ willDrop = false;
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+ restoreCursor = false;
+ }
+ if (object && object->target()) {
+ QMouseEvent *me = (QMouseEvent *)e;
+
+ QDragManager *manager = QDragManager::self();
+ QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData;
+
+ QDropEvent de(object->target()->mapFromGlobal(me->globalPos()), possible_actions, dropData,
+ me->buttons(), me->modifiers());
+ QApplication::sendEvent(object->target(), &de);
+ if (de.isAccepted())
+ global_accepted_action = de.dropAction();
+ else
+ global_accepted_action = Qt::IgnoreAction;
+
+ if (object)
+ object->deleteLater();
+ drag_object = object = 0;
+ }
+ eventLoop->exit();
+ return true; // Eat all mouse events
+ }
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+Qt::DropAction QDragManager::drag(QDrag *o)
+{
+ if (object == o || !o || !o->source())
+ return Qt::IgnoreAction;
+
+ if (object) {
+ cancel();
+ qApp->removeEventFilter(this);
+ beingCancelled = false;
+ }
+
+ object = drag_object = o;
+ qt_qws_dnd_deco = new QShapedPixmapWidget();
+ oldstate = Qt::NoModifier; // #### Should use state that caused the drag
+// drag_mode = mode;
+
+ willDrop = false;
+ updatePixmap();
+ updateCursor();
+ restoreCursor = true;
+ object->d_func()->target = 0;
+ qApp->installEventFilter(this);
+
+ global_accepted_action = Qt::CopyAction;
+#ifndef QT_NO_CURSOR
+ qApp->setOverrideCursor(Qt::ArrowCursor);
+ restoreCursor = true;
+ updateCursor();
+#endif
+
+ qt_qws_dnd_dragging = true;
+
+ eventLoop = new QEventLoop;
+ (void) eventLoop->exec();
+ delete eventLoop;
+ eventLoop = 0;
+
+ delete qt_qws_dnd_deco;
+ qt_qws_dnd_deco = 0;
+ qt_qws_dnd_dragging = false;
+
+
+ return global_accepted_action;
+}
+
+
+void QDragManager::cancel(bool deleteSource)
+{
+// qDebug("QDragManager::cancel");
+ beingCancelled = true;
+
+ if (object->target()) {
+ QDragLeaveEvent dle;
+ QApplication::sendEvent(object->target(), &dle);
+ }
+
+#ifndef QT_NO_CURSOR
+ if (restoreCursor) {
+ QApplication::restoreOverrideCursor();
+ restoreCursor = false;
+ }
+#endif
+
+ if (drag_object) {
+ if (deleteSource)
+ object->deleteLater();
+ drag_object = object = 0;
+ }
+
+ delete qt_qws_dnd_deco;
+ qt_qws_dnd_deco = 0;
+
+ global_accepted_action = Qt::IgnoreAction;
+}
+
+
+void QDragManager::drop()
+{
+}
+
+QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const
+{
+ if (!drag_object)
+ return QVariant();
+ QByteArray data = drag_object->mimeData()->data(mimetype);
+ if (type == QVariant::String)
+ return QString::fromUtf8(data);
+ return data;
+}
+
+bool QDropData::hasFormat_sys(const QString &format) const
+{
+ return formats().contains(format);
+}
+
+QStringList QDropData::formats_sys() const
+{
+ if (drag_object)
+ return drag_object->mimeData()->formats();
+ return QStringList();
+}
+
+
+#endif // QT_NO_DRAGANDDROP
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qeventdispatcher_glib_wayland.cpp b/src/gui/kernel/qeventdispatcher_glib_wayland.cpp
new file mode 100644
index 0000000000..9b4ce0eee6
--- /dev/null
+++ b/src/gui/kernel/qeventdispatcher_glib_wayland.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeventdispatcher_glib_wayland_p.h"
+
+#include "qapplication.h"
+
+#include "qplatformdefs.h"
+#include "qapplication.h"
+
+#include <glib.h>
+
+QT_BEGIN_NAMESPACE
+
+struct GWaylandEventSource
+{
+ GSource source;
+ QEventLoop::ProcessEventsFlags flags;
+ QWaylandEventDispatcherGlib *q;
+ QWaylandEventDispatcherGlibPrivate *d;
+};
+
+class QWaylandEventDispatcherGlibPrivate : public QEventDispatcherGlibPrivate
+{
+ Q_DECLARE_PUBLIC(QWaylandEventDispatcherGlib)
+
+public:
+ QWaylandEventDispatcherGlibPrivate();
+ GWaylandEventSource *waylandEventSource;
+ QList<struct wl_message*> queuedUserInputEvents;
+};
+
+static gboolean waylandEventSourcePrepare(GSource *s, gint *timeout)
+{
+ return false;
+}
+
+static gboolean waylandEventSourceCheck(GSource *s)
+{
+ return true;
+}
+
+static gboolean waylandEventSourceDispatch(GSource *s, GSourceFunc callback, gpointer user_data)
+{
+ return true;
+}
+
+static GSourceFuncs waylandEventSourceFuncs = {
+ waylandEventSourcePrepare,
+ waylandEventSourceCheck,
+ waylandEventSourceDispatch,
+ NULL,
+ NULL,
+ NULL
+};
+
+QWaylandEventDispatcherGlibPrivate::QWaylandEventDispatcherGlibPrivate()
+{
+ //g_source_attach(&waylandEventSource->source, mainContext);
+}
+
+QWaylandEventDispatcherGlib::QWaylandEventDispatcherGlib(QObject *parent)
+ : QEventDispatcherGlib(*new QWaylandEventDispatcherGlibPrivate, parent)
+{
+}
+
+QWaylandEventDispatcherGlib::~QWaylandEventDispatcherGlib()
+{
+ Q_D(QWaylandEventDispatcherGlib);
+
+ //g_source_destroy(&d->waylandEventSource->source);
+}
+
+bool
+QWaylandEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ Q_D(QWaylandEventDispatcherGlib);
+ QEventLoop::ProcessEventsFlags saved_flags = d->waylandEventSource->flags;
+ d->waylandEventSource->flags = flags;
+ bool returnValue = QEventDispatcherGlib::processEvents(flags);
+ d->waylandEventSource->flags = saved_flags;
+ return returnValue;
+}
+
+void QWaylandEventDispatcherGlib::startingUp()
+{
+ Q_D(QWaylandEventDispatcherGlib);
+ d->waylandEventSource->q = this;
+ d->waylandEventSource->d = d;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qeventdispatcher_glib_wayland_p.h b/src/gui/kernel/qeventdispatcher_glib_wayland_p.h
new file mode 100644
index 0000000000..b15fddb0eb
--- /dev/null
+++ b/src/gui/kernel/qeventdispatcher_glib_wayland_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WAYLANDEVENTDISPATCHER_GLIB_P_H
+#define WAYLANDEVENTDISPATCHER_GLIB_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qeventdispatcher_glib_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandEventDispatcherGlibPrivate;
+
+class QWaylandEventDispatcherGlib : public QEventDispatcherGlib
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandEventDispatcherGlib)
+
+public:
+ explicit QWaylandEventDispatcherGlib(QObject *parent = 0);
+ ~QWaylandEventDispatcherGlib();
+
+ bool processEvents(QEventLoop::ProcessEventsFlags flags);
+
+ void startingUp();
+};
+
+QT_END_NAMESPACE
+
+#endif // WAYLANDEVENTDISPATCHER_GLIB_P_H
diff --git a/src/gui/kernel/qeventdispatcher_wayland.cpp b/src/gui/kernel/qeventdispatcher_wayland.cpp
new file mode 100644
index 0000000000..b7c1764f3e
--- /dev/null
+++ b/src/gui/kernel/qeventdispatcher_wayland.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qapplication.h"
+#include "qeventdispatcher_wayland_p.h"
+#include "private/qeventdispatcher_unix_p.h"
+#ifndef QT_NO_THREAD
+# include "qmutex.h"
+#endif
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QT_USE_NAMESPACE
+
+class QEventDispatcherWaylandPrivate : public QEventDispatcherUNIXPrivate
+{
+ Q_DECLARE_PUBLIC(QEventDispatcherWayland)
+public:
+ inline QEventDispatcherWaylandPrivate()
+ { }
+ QList<struct wl_message*> queuedUserInputEvents;
+};
+
+
+QEventDispatcherWayland::QEventDispatcherWayland(QObject *parent)
+ : QEventDispatcherUNIX(*new QEventDispatcherWaylandPrivate, parent)
+{ }
+
+QEventDispatcherWayland::~QEventDispatcherWayland()
+{ }
+
+bool QEventDispatcherWayland::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ return true;
+}
+
+bool QEventDispatcherWayland::hasPendingEvents()
+{
+ extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
+ return qGlobalPostedEventsCount();
+}
+
+void QEventDispatcherWayland::startingUp()
+{
+
+}
+
+void QEventDispatcherWayland::closingDown()
+{
+
+}
+
+void QEventDispatcherWayland::flush()
+{
+ if(qApp)
+ qApp->sendPostedEvents();
+}
+
+
+int QEventDispatcherWayland::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ timeval *timeout)
+{
+ return QEventDispatcherUNIX::select(nfds, readfds, writefds, exceptfds, timeout);
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qeventdispatcher_wayland_p.h b/src/gui/kernel/qeventdispatcher_wayland_p.h
new file mode 100644
index 0000000000..342d2776dd
--- /dev/null
+++ b/src/gui/kernel/qeventdispatcher_wayland_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEVENTDISPATCHER_WAYLAND_P_H
+#define QEVENTDISPATCHER_WAYLAND_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qeventdispatcher_unix_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEventDispatcherWaylandPrivate;
+
+class QEventDispatcherWayland : public QEventDispatcherUNIX
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QEventDispatcherWayland)
+
+public:
+ explicit QEventDispatcherWayland(QObject *parent = 0);
+ ~QEventDispatcherWayland();
+
+ bool processEvents(QEventLoop::ProcessEventsFlags flags);
+ bool hasPendingEvents();
+
+ void flush();
+
+ void startingUp();
+ void closingDown();
+
+protected:
+ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ timeval *timeout);
+};
+
+QT_END_NAMESPACE
+
+#endif // QEVENTDISPATCHER_WAYLAND_P_H
diff --git a/src/gui/kernel/qkeymapper_wayland.cpp b/src/gui/kernel/qkeymapper_wayland.cpp
new file mode 100644
index 0000000000..5b6b1c45ee
--- /dev/null
+++ b/src/gui/kernel/qkeymapper_wayland.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qkeymapper_p.h"
+#include <qdebug.h>
+#include <private/qevent_p.h>
+#include <private/qlocale_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QT_USE_NAMESPACE
+
+
+QKeyMapperPrivate::QKeyMapperPrivate()
+{
+ keyboardInputLocale = QLocale::system();
+ keyboardInputDirection = Qt::RightToLeft;
+}
+
+QKeyMapperPrivate::~QKeyMapperPrivate()
+{
+ // clearMappings();
+}
+
+void QKeyMapperPrivate::clearMappings()
+{
+}
+
+QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *e)
+{
+ QList<int> result;
+ if (e->key() && (e->key() != Qt::Key_unknown))
+ result << int(e->key() + e->modifiers());
+ else if (!e->text().isEmpty())
+ result << int(e->text().at(0).unicode() + e->modifiers());
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qsound_wayland.cpp b/src/gui/kernel/qsound_wayland.cpp
new file mode 100644
index 0000000000..08daad0337
--- /dev/null
+++ b/src/gui/kernel/qsound_wayland.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication.h"
+
+#ifndef QT_NO_SOUND
+
+#include "qsound.h"
+#include "qpaintdevice.h"
+#include "qsound_p.h"
+
+#include "qhash.h"
+#include "qfileinfo.h"
+
+#include "qbytearray.h"
+#include "quuid.h"
+#include "qdatastream.h"
+#include "qbuffer.h"
+
+
+QT_BEGIN_NAMESPACE
+
+#endif // QT_NO_SOUND
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qwidget_wayland.cpp b/src/gui/kernel/qwidget_wayland.cpp
new file mode 100644
index 0000000000..fd538aca4a
--- /dev/null
+++ b/src/gui/kernel/qwidget_wayland.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcursor.h"
+#include "qapplication.h"
+#include "qapplication_p.h"
+#include "qpainter.h"
+#include "qbitmap.h"
+#include "qimage.h"
+#include "qhash.h"
+#include "qstack.h"
+#include "qlayout.h"
+#include "qtextcodec.h"
+#include "qinputcontext.h"
+#include "qdesktopwidget.h"
+
+#include "qpaintengine.h"
+
+#include "qdebug.h"
+
+#include "qwidget_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_USE_NAMESPACE
+
+
+/*****************************************************************************
+ QWidget member functions
+ *****************************************************************************/
+
+void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool /*destroyOldWindow*/)
+{
+}
+
+
+void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
+{
+}
+
+
+void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
+{
+}
+
+
+QPoint QWidget::mapToGlobal(const QPoint &pos) const
+{
+}
+
+QPoint QWidget::mapFromGlobal(const QPoint &pos) const
+{
+}
+
+void QWidgetPrivate::updateSystemBackground() {}
+
+#ifndef QT_NO_CURSOR
+void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
+{
+}
+
+void QWidgetPrivate::unsetCursor_sys()
+{
+}
+#endif //QT_NO_CURSOR
+
+void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
+{
+}
+
+void QWidgetPrivate::setWindowIcon_sys(bool /*forceReset*/)
+{
+}
+
+void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
+{
+ Q_UNUSED(iconText);
+}
+
+void QWidget::grabMouse()
+{
+}
+
+#ifndef QT_NO_CURSOR
+void QWidget::grabMouse(const QCursor &cursor)
+{
+}
+#endif
+
+void QWidget::releaseMouse()
+{
+}
+
+void QWidget::grabKeyboard()
+{
+}
+
+void QWidget::releaseKeyboard()
+{
+}
+
+
+QWidget *QWidget::mouseGrabber()
+{
+}
+
+
+QWidget *QWidget::keyboardGrabber()
+{
+}
+
+void QWidget::activateWindow()
+{
+}
+
+void QWidgetPrivate::show_sys()
+{
+}
+
+
+void QWidgetPrivate::hide_sys()
+{
+}
+
+void QWidget::setWindowState(Qt::WindowStates newstate)
+{
+}
+
+void QWidgetPrivate::setFocus_sys()
+{
+}
+
+void QWidgetPrivate::raise_sys()
+{
+}
+
+void QWidgetPrivate::lower_sys()
+{
+}
+
+void QWidgetPrivate::stackUnder_sys(QWidget*)
+{
+}
+
+void QWidgetPrivate::setConstraints_sys()
+{
+}
+
+void QWidgetPrivate::scroll_sys(int dx, int dy)
+{
+}
+
+int QWidget::metric(PaintDeviceMetric m) const
+{
+}
+
+void QWidgetPrivate::createSysExtra()
+{
+}
+
+void QWidgetPrivate::deleteSysExtra()
+{
+}
+
+void QWidgetPrivate::createTLSysExtra()
+{
+}
+
+void QWidgetPrivate::deleteTLSysExtra()
+{
+}
+
+void QWidgetPrivate::registerDropSite(bool on)
+{
+ Q_UNUSED(on);
+}
+
+inline bool QRect::intersects(const QRect &r) const
+{
+}
+
+void QWidgetPrivate::updateFrameStrut()
+{
+}
+
+void QWidgetPrivate::setWindowOpacity_sys(qreal level)
+{
+}
+
+QPaintEngine *QWidget::paintEngine() const
+{
+ qWarning("QWidget::paintEngine: Should no longer be called");
+ return 0;
+}
+
+QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
+{
+}
+
+void QWidgetPrivate::setModal_sys()
+{
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qwindowdefs.h b/src/gui/kernel/qwindowdefs.h
index a721c7da98..5b1b99e303 100644
--- a/src/gui/kernel/qwindowdefs.h
+++ b/src/gui/kernel/qwindowdefs.h
@@ -131,6 +131,10 @@ QT_END_HEADER
#endif // Q_WS_QWS
+#if defined(Q_WS_WAYLAND)
+typedef unsigned long WId;
+#endif // Q_WS_WAYLAND
+
#if defined(Q_OS_SYMBIAN)
class CCoeControl;
typedef CCoeControl * WId;
diff --git a/src/gui/kernel/wayland.pri b/src/gui/kernel/wayland.pri
new file mode 100644
index 0000000000..897cf53a6e
--- /dev/null
+++ b/src/gui/kernel/wayland.pri
@@ -0,0 +1,3 @@
+wayland {
+}
+
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index 123af1ce15..eff9944fb5 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -367,7 +367,10 @@ embedded {
SOURCES += painting/qwindowsurface_qws.cpp
}
-
+wayland {
+ HEADERS += painting/qwindowsurface_wayland_p.h
+ SOURCES += painting/qwindowsurface_wayland.cpp
+}
symbian {
HEADERS += painting/qwindowsurface_s60_p.h
diff --git a/src/gui/painting/qgraphicssystem.cpp b/src/gui/painting/qgraphicssystem.cpp
index 2ea3d3318b..a3ec8ab5c3 100644
--- a/src/gui/painting/qgraphicssystem.cpp
+++ b/src/gui/painting/qgraphicssystem.cpp
@@ -53,6 +53,9 @@
#ifdef Q_WS_S60
# include <private/qpixmap_s60_p.h>
#endif
+#ifdef Q_WS_WAYLAND
+# include <private/qpixmap_wayland_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -73,6 +76,8 @@ QPixmapData *QGraphicsSystem::createDefaultPixmapData(QPixmapData::PixelType typ
return new QMacPixmapData(type);
#elif defined(Q_WS_S60)
return new QS60PixmapData(type);
+#elif defined(Q_WS_WAYLAND)
+ return new QWaylandPixmapData(type);
#elif !defined(Q_WS_QWS)
#error QGraphicsSystem::createDefaultPixmapData() not implemented
#endif
diff --git a/src/gui/painting/qgraphicssystem_wayland.cpp b/src/gui/painting/qgraphicssystem_wayland.cpp
new file mode 100644
index 0000000000..db3d4b1a76
--- /dev/null
+++ b/src/gui/painting/qgraphicssystem_wayland.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qscreen_wayland.h>
+#include "qgraphicssystem_wayland_p.h"
+#include <private/qpixmap_raster_p.h>
+#include <private/qwindowsurface_wayland_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QPixmapData *QWSGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const
+{
+ if (screen->pixmapDataFactory())
+ return screen->pixmapDataFactory()->create(type); //### For 4.4 compatability
+ else
+ return new QRasterPixmapData(type);
+}
+
+QWindowSurface *QWSGraphicsSystem::createWindowSurface(QWidget *widget) const
+{
+ return screen->createSurface(widget);
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qgraphicssystem_wayland_p.h b/src/gui/painting/qgraphicssystem_wayland_p.h
new file mode 100644
index 0000000000..d078f54a5a
--- /dev/null
+++ b/src/gui/painting/qgraphicssystem_wayland_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSYSTEM_QWS_P_H
+#define QGRAPHICSSYSTEM_QWS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qgraphicssystem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QWSGraphicsSystem : public QGraphicsSystem
+{
+public:
+
+ QWSGraphicsSystem()
+ : screen(QScreen::instance()) {}
+
+ QWSGraphicsSystem(QScreen* s)
+ : screen(s) {}
+
+ virtual QPixmapData *createPixmapData(QPixmapData::PixelType type) const;
+ QWindowSurface *createWindowSurface(QWidget *widget) const;
+
+private:
+ QScreen* screen;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/painting/qprintengine_wayland.cpp b/src/gui/painting/qprintengine_wayland.cpp
new file mode 100644
index 0000000000..26847905f6
--- /dev/null
+++ b/src/gui/painting/qprintengine_wayland.cpp
@@ -0,0 +1,886 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qprintengine_wayland_p.h>
+
+#ifndef QT_NO_PRINTER
+
+#include <private/qpaintengine_raster_p.h>
+#include <qimage.h>
+#include <qfile.h>
+#include <qdebug.h>
+#include <QCopChannel>
+
+QT_BEGIN_NAMESPACE
+
+#define MM(n) int((n * 720 + 127) / 254)
+#define IN(n) int(n * 72)
+
+extern QSizeF qt_paperSizeToQSizeF(QPrinter::PaperSize size);
+
+QtopiaPrintEngine::QtopiaPrintEngine(QPrinter::PrinterMode mode)
+ : QPaintEngine(*(new QtopiaPrintEnginePrivate( mode )))
+{
+ d_func()->initialize();
+}
+
+bool QtopiaPrintEngine::begin(QPaintDevice *)
+{
+ Q_D(QtopiaPrintEngine);
+ Q_ASSERT_X(d->printerState == QPrinter::Idle, "QtopiaPrintEngine", "printer already active");
+
+ // Create a new off-screen monochrome image to handle the drawing process.
+ QSize size = paperRect().size();
+ if ( d->pageImage )
+ delete d->pageImage;
+ d->pageImage = new QImage( size, QImage::Format_RGB32 );
+ if ( !(d->pageImage) )
+ return false;
+
+ // Recreate the paint engine on the new image.
+ delete d->_paintEngine;
+ d->_paintEngine = 0;
+ d->paintEngine()->state = state;
+
+ // Begin the paint process on the image.
+ if (!d->paintEngine()->begin(d->pageImage))
+ return false;
+
+ // Clear the first page to all-white.
+ clearPage();
+
+ // Clear the print buffer and output the image header.
+ d->buffer.clear();
+ d->writeG3FaxHeader();
+
+ // The print engine is currently active.
+ d->printerState = QPrinter::Active;
+ return true;
+}
+
+bool QtopiaPrintEngine::end()
+{
+ Q_D(QtopiaPrintEngine);
+
+ d->paintEngine()->end();
+
+ // Flush the last page.
+ flushPage();
+
+ // Output the fax data to a file (TODO: send to the print queuing daemon).
+ QString filename;
+ if ( !d->outputFileName.isEmpty() )
+ filename = QString::fromLocal8Bit(qgetenv("HOME").constData()) + QLatin1String("/Documents/") + d->outputFileName;
+ else
+ filename = QString::fromLocal8Bit(qgetenv("HOME").constData()) + QLatin1String("/tmp/qwsfax.tiff");
+
+ setProperty(QPrintEngine::PPK_OutputFileName, filename);
+ QFile file( filename );
+ if ( !file.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) {
+ qDebug( "Failed to open %s for printer output",
+ filename.toLatin1().constData() );
+ } else {
+ file.write( d->buffer.data() );
+ file.close();
+ }
+
+ // Free up the memory for the image buffer.
+ d->buffer.clear();
+
+ // Finalize the print job.
+ d->printerState = QPrinter::Idle;
+
+ // call qcop service
+ QMap<QString, QVariant> map;
+ for ( int x = 0; x <= QPrintEngine::PPK_Duplex; x++ )
+ map.insert( QString::number(x), property((QPrintEngine::PrintEnginePropertyKey)(x)));
+ QVariant variant(map);
+
+ QByteArray data;
+ QDataStream out(&data, QIODevice::WriteOnly);
+ out << variant;
+ QCopChannel::send(QLatin1String("QPE/Service/Print"), QLatin1String("print(QVariant)"), data);
+
+ return true;
+}
+
+QPaintEngine *QtopiaPrintEngine::paintEngine() const
+{
+ return const_cast<QtopiaPrintEnginePrivate *>(d_func())->paintEngine();
+}
+
+void QtopiaPrintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
+{
+ Q_D(QtopiaPrintEngine);
+ Q_ASSERT(d->printerState == QPrinter::Active);
+ d->paintEngine()->drawPixmap(r, pm, sr);
+}
+
+void QtopiaPrintEngine::drawTextItem(const QPointF &p, const QTextItem &ti)
+{
+ Q_D(QtopiaPrintEngine);
+ Q_ASSERT(d->printerState == QPrinter::Active);
+ d->paintEngine()->drawTextItem(p, ti);
+}
+
+void QtopiaPrintEngine::updateState(const QPaintEngineState &state)
+{
+ Q_D(QtopiaPrintEngine);
+ d->paintEngine()->updateState(state);
+}
+
+QRect QtopiaPrintEngine::paperRect() const
+{
+ QSizeF s = qt_paperSizeToQSizeF(d_func()->paperSize);
+ s.rwidth() = MM(s.width());
+ s.rheight() = MM(s.height());
+ int w = qRound(s.width()*d_func()->resolution/72.);
+ int h = qRound(s.height()*d_func()->resolution/72.);
+ if (d_func()->orientation == QPrinter::Portrait)
+ return QRect(0, 0, w, h);
+ else
+ return QRect(0, 0, h, w);
+}
+
+QRect QtopiaPrintEngine::pageRect() const
+{
+ QRect r = paperRect();
+ if (d_func()->fullPage)
+ return r;
+ // would be nice to get better margins than this.
+ return QRect(d_func()->resolution/3, d_func()->resolution/3, r.width()-2*d_func()->resolution/3, r.height()-2*d_func()->resolution/3);
+}
+
+bool QtopiaPrintEngine::newPage()
+{
+ flushPage();
+ clearPage();
+ ++(d_func()->pageNumber);
+ return true;
+}
+
+bool QtopiaPrintEngine::abort()
+{
+ return false;
+}
+
+QPrinter::PrinterState QtopiaPrintEngine::printerState() const
+{
+ return d_func()->printerState;
+}
+
+int QtopiaPrintEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const
+{
+ int val;
+ QRect r = d_func()->fullPage ? paperRect() : pageRect();
+ switch (metricType) {
+ case QPaintDevice::PdmWidth:
+ val = r.width();
+ break;
+ case QPaintDevice::PdmHeight:
+ val = r.height();
+ break;
+ case QPaintDevice::PdmDpiX:
+ val = d_func()->resolution;
+ break;
+ case QPaintDevice::PdmDpiY:
+ val = d_func()->resolution;
+ break;
+ case QPaintDevice::PdmPhysicalDpiX:
+ case QPaintDevice::PdmPhysicalDpiY:
+ val = QT_QWS_PRINTER_DEFAULT_DPI;
+ break;
+ case QPaintDevice::PdmWidthMM:
+ val = qRound(r.width()*25.4/d_func()->resolution);
+ break;
+ case QPaintDevice::PdmHeightMM:
+ val = qRound(r.height()*25.4/d_func()->resolution);
+ break;
+ case QPaintDevice::PdmNumColors:
+ val = 2;
+ break;
+ case QPaintDevice::PdmDepth:
+ val = 1;
+ break;
+ default:
+ qWarning("QtopiaPrintEngine::metric: Invalid metric command");
+ return 0;
+ }
+ return val;
+}
+
+QVariant QtopiaPrintEngine::property(PrintEnginePropertyKey key) const
+{
+ Q_D(const QtopiaPrintEngine);
+ QVariant ret;
+
+ switch (key) {
+ case PPK_CollateCopies:
+ ret = d->collateCopies;
+ break;
+ case PPK_ColorMode:
+ ret = d->colorMode;
+ break;
+ case PPK_Creator:
+ ret = d->creator;
+ break;
+ case PPK_DocumentName:
+ ret = d->docName;
+ break;
+ case PPK_FullPage:
+ ret = d->fullPage;
+ break;
+ case PPK_CopyCount: // fallthrough
+ case PPK_NumberOfCopies:
+ ret = d->numCopies;
+ break;
+ case PPK_SupportsMultipleCopies:
+ ret = false;
+ break;
+ case PPK_Orientation:
+ ret = d->orientation;
+ break;
+ case PPK_OutputFileName:
+ ret = d->outputFileName;
+ break;
+ case PPK_PageOrder:
+ ret = d->pageOrder;
+ break;
+ case PPK_PageRect:
+ ret = pageRect();
+ break;
+ case PPK_PaperSize:
+ ret = d->paperSize;
+ break;
+ case PPK_PaperRect:
+ ret = paperRect();
+ break;
+ case PPK_PaperSource:
+ ret = d->paperSource;
+ break;
+ case PPK_PrinterName:
+ ret = d->printerName;
+ break;
+ case PPK_PrinterProgram:
+ ret = d->printProgram;
+ break;
+ case PPK_Resolution:
+ ret = d->resolution;
+ break;
+ case PPK_SupportedResolutions:
+ ret = QList<QVariant>() << QT_QWS_PRINTER_DEFAULT_DPI;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+void QtopiaPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
+{
+ Q_D(QtopiaPrintEngine);
+ switch (key) {
+ case PPK_CollateCopies:
+ d->collateCopies = value.toBool();
+ break;
+ case PPK_ColorMode:
+ d->colorMode = QPrinter::ColorMode(value.toInt());
+ break;
+ case PPK_Creator:
+ d->creator = value.toString();
+ break;
+ case PPK_DocumentName:
+ d->docName = value.toString();
+ break;
+ case PPK_FullPage:
+ d->fullPage = value.toBool();
+ break;
+ case PPK_CopyCount: // fallthrough
+ case PPK_NumberOfCopies:
+ d->numCopies = value.toInt();
+ break;
+ case PPK_Orientation:
+ d->orientation = QPrinter::Orientation(value.toInt());
+ break;
+ case PPK_OutputFileName:
+ d->outputFileName = value.toString();
+ break;
+ case PPK_PageOrder:
+ d->pageOrder = QPrinter::PageOrder(value.toInt());
+ break;
+ case PPK_PaperSize:
+ d->paperSize = QPrinter::PaperSize(value.toInt());
+ break;
+ case PPK_PaperSource:
+ d->paperSource = QPrinter::PaperSource(value.toInt());
+ case PPK_PrinterName:
+ d->printerName = value.toString();
+ break;
+ case PPK_PrinterProgram:
+ d->printProgram = value.toString();
+ break;
+ case PPK_Resolution:
+ d->resolution = value.toInt();
+ break;
+ default:
+ break;
+ }
+}
+
+void QtopiaPrintEngine::clearPage()
+{
+ d_func()->pageImage->fill(QColor(255, 255, 255).rgb());
+}
+
+void QtopiaPrintEngine::flushPage()
+{
+ d_func()->writeG3FaxPage();
+}
+
+QtopiaPrintEnginePrivate::~QtopiaPrintEnginePrivate()
+{
+ if ( pageImage )
+ delete pageImage;
+}
+
+void QtopiaPrintEnginePrivate::initialize()
+{
+ _paintEngine = 0;
+}
+
+QPaintEngine *QtopiaPrintEnginePrivate::paintEngine()
+{
+ if (!_paintEngine)
+ _paintEngine = new QRasterPaintEngine(pageImage);
+ return _paintEngine;
+}
+
+void QtopiaPrintEnginePrivate::writeG3FaxHeader()
+{
+ // Write the TIFF file magic number (little-endian TIFF).
+ buffer.append( (char)'I' );
+ buffer.append( (char)'I' );
+ buffer.append( (char)42 );
+ buffer.append( (char)0 );
+
+ // Leave a place-holder for the IFD offset of the first page.
+ ifdPatch = buffer.size();
+ buffer.append( (int)0 );
+}
+
+// Tag values, from RFC 2301.
+#define TIFF_IFD_NEW_SUB_FILE_TYPE 254
+#define TIFF_IFD_IMAGE_WIDTH 256
+#define TIFF_IFD_IMAGE_LENGTH 257
+#define TIFF_IFD_BITS_PER_SAMPLE 258
+#define TIFF_IFD_COMPRESSION 259
+#define TIFF_IFD_PHOTOMETRIC_INTERP 262
+#define TIFF_IFD_FILL_ORDER 266
+#define TIFF_IFD_STRIP_OFFSETS 273
+#define TIFF_IFD_ORIENTATION 274
+#define TIFF_IFD_SAMPLES_PER_PIXEL 277
+#define TIFF_IFD_ROWS_PER_STRIP 278
+#define TIFF_IFD_STRIP_BYTE_COUNTS 279
+#define TIFF_IFD_X_RESOLUTION 282
+#define TIFF_IFD_Y_RESOLUTION 283
+#define TIFF_IFD_PLANAR_CONFIG 284
+#define TIFF_IFD_T4_OPTIONS 292
+#define TIFF_IFD_RESOLUTION_UNIT 296
+#define TIFF_IFD_PAGE_NUMBER 297
+#define TIFF_IFD_CLEAN_FAX_DATA 327
+
+// IFD type values.
+#define TIFF_TYPE_SHORT 3
+#define TIFF_TYPE_LONG 4
+#define TIFF_TYPE_RATIONAL 5
+
+// Construct a SHORT pair from two values.
+#define TIFF_SHORT_PAIR(a,b) (((a) & 0xFFFF) | ((b) << 16))
+
+// Width of a FAX page in pixels, in the baseline specification from RFC 2301.
+// This must be hard-wired, as per the RFC. We truncate any pixels that
+// are beyond this limit, or pad lines to reach this limit.
+#define TIFF_FAX_WIDTH 1728
+
+void QtopiaPrintEnginePrivate::writeG3FaxPage()
+{
+ // Pad the image file to a word boundary, just in case.
+ buffer.pad();
+
+ // Back-patch the IFD link for the previous page.
+ buffer.patch( ifdPatch, buffer.size() );
+
+ // Output the contents of the IFD for this page (these must be
+ // in ascending order of tag value).
+ buffer.append( (short)19 ); // Number of IFD entries.
+ writeG3IFDEntry( TIFF_IFD_NEW_SUB_FILE_TYPE, TIFF_TYPE_LONG, 1, 2 );
+ writeG3IFDEntry( TIFF_IFD_IMAGE_WIDTH, TIFF_TYPE_LONG, 1, TIFF_FAX_WIDTH );
+ writeG3IFDEntry
+ ( TIFF_IFD_IMAGE_LENGTH, TIFF_TYPE_LONG, 1, pageImage->height() );
+ writeG3IFDEntry( TIFF_IFD_BITS_PER_SAMPLE, TIFF_TYPE_SHORT, 1, 1 );
+ writeG3IFDEntry( TIFF_IFD_COMPRESSION, TIFF_TYPE_SHORT, 1, 3 );
+ writeG3IFDEntry( TIFF_IFD_PHOTOMETRIC_INTERP, TIFF_TYPE_SHORT, 1, 0 );
+ writeG3IFDEntry( TIFF_IFD_FILL_ORDER, TIFF_TYPE_SHORT, 1, 1 );
+ int stripOffsets =
+ writeG3IFDEntry( TIFF_IFD_STRIP_OFFSETS, TIFF_TYPE_LONG, 1, 0 );
+ writeG3IFDEntry( TIFF_IFD_ORIENTATION, TIFF_TYPE_SHORT, 1, 1 );
+ writeG3IFDEntry( TIFF_IFD_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, 1 );
+ writeG3IFDEntry
+ ( TIFF_IFD_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, pageImage->height() );
+ int stripBytes = writeG3IFDEntry
+ ( TIFF_IFD_STRIP_BYTE_COUNTS, TIFF_TYPE_LONG, 1, 0 );
+ int xres =
+ writeG3IFDEntry( TIFF_IFD_X_RESOLUTION, TIFF_TYPE_RATIONAL, 1, 0 );
+ int yres =
+ writeG3IFDEntry( TIFF_IFD_Y_RESOLUTION, TIFF_TYPE_RATIONAL, 1, 0 );
+ writeG3IFDEntry( TIFF_IFD_PLANAR_CONFIG, TIFF_TYPE_SHORT, 1, 1 );
+ writeG3IFDEntry( TIFF_IFD_T4_OPTIONS, TIFF_TYPE_LONG, 1, 2 );
+ writeG3IFDEntry( TIFF_IFD_RESOLUTION_UNIT, TIFF_TYPE_SHORT, 1, 2 );
+ writeG3IFDEntry( TIFF_IFD_PAGE_NUMBER, TIFF_TYPE_SHORT, 2,
+ TIFF_SHORT_PAIR( pageNumber, 0 ) );
+ writeG3IFDEntry( TIFF_IFD_CLEAN_FAX_DATA, TIFF_TYPE_SHORT, 1, 0 );
+
+ // Leave a place-holder for the IFD offset of the next page.
+ ifdPatch = buffer.size();
+ buffer.append( (int)0 );
+
+ // Output the X and Y resolutions, as rational values (usually 200/1).
+ buffer.patch( xres, buffer.size() );
+ buffer.append( (int)resolution );
+ buffer.append( (int)1 );
+ buffer.patch( yres, buffer.size() );
+ buffer.append( (int)resolution );
+ buffer.append( (int)1 );
+
+ // We are now at the start of the image data - set the strip offset.
+ int start = buffer.size();
+ buffer.patch( stripOffsets, start );
+
+ // Output the image data.
+ int width = pageImage->width();
+ QImage::Format imageFormat = pageImage->format();
+ for ( int y = 0; y < pageImage->height(); ++y ) {
+ unsigned char *scan = pageImage->scanLine(y);
+ int prev, pixel, len;
+ writeG3EOL();
+ prev = 0;
+ len = 0;
+
+ uint currentColor = qRgb(255, 255, 255); // start with white
+
+ for ( int x = 0; x < width && x < TIFF_FAX_WIDTH; ++x ) {
+ if ( imageFormat == QImage::Format_RGB32 ) {
+ // read color of the current pixel
+ uint *p = (uint *)scan + x;
+
+ if ( *p == currentColor ) { // if it is the same color
+ len++; // imcrement length
+ } else { // otherwise write color into the buffer
+ if ( len > 0 ) {
+ if ( currentColor == qRgb(0, 0, 0) )
+ writeG3BlackRun( len );
+ else
+ writeG3WhiteRun( len );
+ }
+ // initialise length and color;
+ len = 1;
+ currentColor = *p;
+ }
+ } else if ( imageFormat == QImage::Format_Mono ) {
+ pixel = ((scan[x >> 3] & (1 << (x & 7))) != 0);
+ if ( pixel != prev ) {
+ if ( prev ) {
+ writeG3BlackRun( len );
+ } else {
+ writeG3WhiteRun( len );
+ }
+ prev = pixel;
+ len = 1;
+ } else {
+ ++len;
+ }
+ }
+ }
+
+ if ( imageFormat == QImage::Format_RGB32 ) {
+ // Output the last run on the line, and pad to TIFF_FAX_WIDTH.
+ if ( len != 0 ) {
+ if ( currentColor == qRgb(0, 0, 0) )
+ writeG3BlackRun( len );
+ else
+ writeG3WhiteRun( len );
+ }
+ if ( width < TIFF_FAX_WIDTH )
+ writeG3WhiteRun( TIFF_FAX_WIDTH - width );
+ } else if ( imageFormat == QImage::Format_Mono ) {
+ if ( len != 0 ) {
+ if ( prev ) {
+ writeG3BlackRun( len );
+ if ( width < TIFF_FAX_WIDTH ) {
+ writeG3WhiteRun( TIFF_FAX_WIDTH - width );
+ }
+ } else {
+ if ( width < TIFF_FAX_WIDTH ) {
+ writeG3WhiteRun( len + ( TIFF_FAX_WIDTH - width ) );
+ } else {
+ writeG3WhiteRun( len );
+ }
+ }
+ }
+ }
+ }
+
+ // Flush the last partial byte, which is padded with zero fill bits.
+ if ( partialBits > 0 ) {
+ buffer.append( (char)( partialByte << ( 8 - partialBits ) ) );
+ partialByte = 0;
+ partialBits = 0;
+ }
+
+ // end of page add six EOLs
+ for ( int i = 0; i < 6; i++ )
+ writeG3EOL();
+
+ // Update the byte count for the image data strip.
+ buffer.patch( stripBytes, buffer.size() - start );
+}
+
+int QtopiaPrintEnginePrivate::writeG3IFDEntry
+ ( int tag, int type, int count, int value )
+{
+ buffer.append( (short)tag );
+ buffer.append( (short)type );
+ buffer.append( count );
+ buffer.append( value );
+ return buffer.size() - 4; // Offset of the value for back-patching.
+}
+
+void QtopiaPrintEnginePrivate::writeG3Code( int code, int bits )
+{
+ partialByte = ( ( partialByte << bits ) | code );
+ partialBits += bits;
+ while ( partialBits >= 8 ) {
+ partialBits -= 8;
+ buffer.append( (char)( partialByte >> partialBits ) );
+ }
+}
+
+void QtopiaPrintEnginePrivate::writeG3WhiteRun( int len )
+{
+ static struct {
+ unsigned short code;
+ unsigned short bits;
+ } whiteCodes[64 + 27] = {
+ {0x0035, 8}, // 0
+ {0x0007, 6},
+ {0x0007, 4},
+ {0x0008, 4},
+ {0x000B, 4},
+ {0x000C, 4},
+ {0x000E, 4},
+ {0x000F, 4},
+ {0x0013, 5}, // 8
+ {0x0014, 5},
+ {0x0007, 5},
+ {0x0008, 5},
+ {0x0008, 6},
+ {0x0003, 6},
+ {0x0034, 6},
+ {0x0035, 6},
+ {0x002A, 6}, // 16
+ {0x002B, 6},
+ {0x0027, 7},
+ {0x000C, 7},
+ {0x0008, 7},
+ {0x0017, 7},
+ {0x0003, 7},
+ {0x0004, 7},
+ {0x0028, 7}, // 24
+ {0x002B, 7},
+ {0x0013, 7},
+ {0x0024, 7},
+ {0x0018, 7},
+ {0x0002, 8},
+ {0x0003, 8},
+ {0x001A, 8},
+ {0x001B, 8}, // 32
+ {0x0012, 8},
+ {0x0013, 8},
+ {0x0014, 8},
+ {0x0015, 8},
+ {0x0016, 8},
+ {0x0017, 8},
+ {0x0028, 8},
+ {0x0029, 8}, // 40
+ {0x002A, 8},
+ {0x002B, 8},
+ {0x002C, 8},
+ {0x002D, 8},
+ {0x0004, 8},
+ {0x0005, 8},
+ {0x000A, 8},
+ {0x000B, 8}, // 48
+ {0x0052, 8},
+ {0x0053, 8},
+ {0x0054, 8},
+ {0x0055, 8},
+ {0x0024, 8},
+ {0x0025, 8},
+ {0x0058, 8},
+ {0x0059, 8}, // 56
+ {0x005A, 8},
+ {0x005B, 8},
+ {0x004A, 8},
+ {0x004B, 8},
+ {0x0032, 8},
+ {0x0033, 8},
+ {0x0034, 8},
+ {0x001B, 5}, // Make up codes: 64
+ {0x0012, 5}, // 128
+ {0x0017, 6}, // 192
+ {0x0037, 7}, // 256
+ {0x0036, 8}, // 320
+ {0x0037, 8}, // 384
+ {0x0064, 8}, // 448
+ {0x0065, 8}, // 512
+ {0x0068, 8}, // 576
+ {0x0067, 8}, // 640
+ {0x00CC, 9}, // 704
+ {0x00CD, 9}, // 768
+ {0x00D2, 9}, // 832
+ {0x00D3, 9}, // 896
+ {0x00D4, 9}, // 960
+ {0x00D5, 9}, // 1024
+ {0x00D6, 9}, // 1088
+ {0x00D7, 9}, // 1152
+ {0x00D8, 9}, // 1216
+ {0x00D9, 9}, // 1280
+ {0x00DA, 9}, // 1344
+ {0x00DB, 9}, // 1408
+ {0x0098, 9}, // 1472
+ {0x0099, 9}, // 1536
+ {0x009A, 9}, // 1600
+ {0x0018, 6}, // 1664
+ {0x009B, 9}, // 1728
+ };
+ if ( len >= 64 ) {
+ int index = 63 + (len >> 6);
+ writeG3Code( whiteCodes[index].code, whiteCodes[index].bits );
+ len &= 63;
+ }
+ writeG3Code( whiteCodes[len].code, whiteCodes[len].bits );
+}
+
+void QtopiaPrintEnginePrivate::writeG3BlackRun( int len )
+{
+ static struct {
+ unsigned short code;
+ unsigned short bits;
+ } blackCodes[64 + 27] = {
+ {0x0037, 10}, // 0
+ {0x0002, 3},
+ {0x0003, 2},
+ {0x0002, 2},
+ {0x0003, 3},
+ {0x0003, 4},
+ {0x0002, 4},
+ {0x0003, 5},
+ {0x0005, 6}, // 8
+ {0x0004, 6},
+ {0x0004, 7},
+ {0x0005, 7},
+ {0x0007, 7},
+ {0x0004, 8},
+ {0x0007, 8},
+ {0x0018, 9},
+ {0x0017, 10}, // 16
+ {0x0018, 10},
+ {0x0008, 10},
+ {0x0067, 11},
+ {0x0068, 11},
+ {0x006C, 11},
+ {0x0037, 11},
+ {0x0028, 11},
+ {0x0017, 11}, // 24
+ {0x0018, 11},
+ {0x00CA, 12},
+ {0x00CB, 12},
+ {0x00CC, 12},
+ {0x00CD, 12},
+ {0x0068, 12},
+ {0x0069, 12},
+ {0x006A, 12}, // 32
+ {0x006B, 12},
+ {0x00D2, 12},
+ {0x00D3, 12},
+ {0x00D4, 12},
+ {0x00D5, 12},
+ {0x00D6, 12},
+ {0x00D7, 12},
+ {0x006C, 12}, // 40
+ {0x006D, 12},
+ {0x00DA, 12},
+ {0x00DB, 12},
+ {0x0054, 12},
+ {0x0055, 12},
+ {0x0056, 12},
+ {0x0057, 12},
+ {0x0064, 12}, // 48
+ {0x0065, 12},
+ {0x0052, 12},
+ {0x0053, 12},
+ {0x0024, 12},
+ {0x0037, 12},
+ {0x0038, 12},
+ {0x0027, 12},
+ {0x0028, 12}, // 56
+ {0x0058, 12},
+ {0x0059, 12},
+ {0x002B, 12},
+ {0x002C, 12},
+ {0x005A, 12},
+ {0x0066, 12},
+ {0x0067, 12},
+ {0x000F, 10}, // Make up codes: 64
+ {0x00C8, 12}, // 128
+ {0x00C9, 12}, // 192
+ {0x005B, 12}, // 256
+ {0x0033, 12}, // 320
+ {0x0034, 12}, // 384
+ {0x0035, 12}, // 448
+ {0x006C, 13}, // 512
+ {0x006D, 13}, // 576
+ {0x004A, 13}, // 640
+ {0x004B, 13}, // 704
+ {0x004C, 13}, // 768
+ {0x004D, 13}, // 832
+ {0x0072, 13}, // 896
+ {0x0073, 13}, // 960
+ {0x0074, 13}, // 1024
+ {0x0075, 13}, // 1088
+ {0x0076, 13}, // 1152
+ {0x0077, 13}, // 1216
+ {0x0052, 13}, // 1280
+ {0x0053, 13}, // 1344
+ {0x0054, 13}, // 1408
+ {0x0055, 13}, // 1472
+ {0x005A, 13}, // 1536
+ {0x005B, 13}, // 1600
+ {0x0064, 13}, // 1664
+ {0x0065, 13}, // 1728
+ };
+ if ( len >= 64 ) {
+ int index = 63 + (len >> 6);
+ writeG3Code( blackCodes[index].code, blackCodes[index].bits );
+ len &= 63;
+ }
+ writeG3Code( blackCodes[len].code, blackCodes[len].bits );
+}
+
+void QtopiaPrintEnginePrivate::writeG3EOL()
+{
+ int bitToPad;
+ if ( partialBits <= 4 ) {
+ bitToPad = 4 - partialBits;
+ } else {
+ bitToPad = 8 - partialBits + 4;
+ }
+
+ partialByte = ((partialByte << (bitToPad + 12)) | 0x0001);
+ partialBits += bitToPad + 12;
+
+ while ( partialBits >= 8 ) {
+ partialBits -= 8;
+ buffer.append( (char)(partialByte >> partialBits ) );
+ }
+// writeG3Code( 0x0001, 12 );
+}
+
+void QtopiaPrintBuffer::append( short value )
+{
+ if ( _bigEndian ) {
+ _data.append( (char)(value >> 8) );
+ _data.append( (char)value );
+ } else {
+ _data.append( (char)value );
+ _data.append( (char)(value >> 8) );
+ }
+}
+
+void QtopiaPrintBuffer::append( int value )
+{
+ if ( _bigEndian ) {
+ _data.append( (char)(value >> 24) );
+ _data.append( (char)(value >> 16) );
+ _data.append( (char)(value >> 8) );
+ _data.append( (char)value );
+ } else {
+ _data.append( (char)value );
+ _data.append( (char)(value >> 8) );
+ _data.append( (char)(value >> 16) );
+ _data.append( (char)(value >> 24) );
+ }
+}
+
+void QtopiaPrintBuffer::patch( int posn, int value )
+{
+ if ( _bigEndian ) {
+ _data[posn] = (char)(value >> 24);
+ _data[posn + 1] = (char)(value >> 16);
+ _data[posn + 2] = (char)(value >> 8);
+ _data[posn + 3] = (char)value;
+ } else {
+ _data[posn] = (char)value;
+ _data[posn + 1] = (char)(value >> 8);
+ _data[posn + 2] = (char)(value >> 16);
+ _data[posn + 3] = (char)(value >> 24);
+ }
+}
+
+void QtopiaPrintBuffer::pad()
+{
+ while ( ( _data.size() % 4 ) != 0 )
+ _data.append( (char)0 );
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PRINTER
diff --git a/src/gui/painting/qprintengine_wayland_p.h b/src/gui/painting/qprintengine_wayland_p.h
new file mode 100644
index 0000000000..e08fbcd9e1
--- /dev/null
+++ b/src/gui/painting/qprintengine_wayland_p.h
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPRINTENGINE_QWS_P_H
+#define QPRINTENGINE_QWS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtGui/qprinter.h"
+
+#ifndef QT_NO_PRINTER
+
+#include "QtGui/qprintengine.h"
+#include "QtCore/qbytearray.h"
+#include "private/qpaintengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QtopiaPrintEnginePrivate;
+class QRasterPaintEngine;
+class QPrinterPrivate;
+class QImage;
+
+class QtopiaPrintEngine : public QPaintEngine, public QPrintEngine
+{
+ Q_DECLARE_PRIVATE(QtopiaPrintEngine)
+public:
+ QtopiaPrintEngine(QPrinter::PrinterMode mode);
+
+ // override QWSPaintEngine
+ bool begin(QPaintDevice *dev);
+ bool end();
+ void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
+ void drawTextItem(const QPointF &p, const QTextItem &ti);
+ QPaintEngine::Type type() const { return QPaintEngine::X11; }
+
+ QPaintEngine *paintEngine() const;
+
+ void updateState(const QPaintEngineState &state);
+
+ QRect paperRect() const;
+ QRect pageRect() const;
+
+ bool newPage();
+ bool abort();
+
+ QPrinter::PrinterState printerState() const;
+
+ int metric(QPaintDevice::PaintDeviceMetric metricType) const;
+
+ QVariant property(PrintEnginePropertyKey key) const;
+ void setProperty(PrintEnginePropertyKey key, const QVariant &value);
+
+private:
+ friend class QPrintDialog;
+ friend class QPageSetupDialog;
+
+ void clearPage();
+ void flushPage();
+};
+
+class QtopiaPrintBuffer
+{
+public:
+ QtopiaPrintBuffer( bool bigEndian=FALSE ) { _bigEndian = bigEndian; }
+ ~QtopiaPrintBuffer() {}
+
+ const QByteArray& data() const { return _data; }
+
+ int size() const { return _data.size(); }
+
+ void clear() { _data.clear(); }
+
+ void append( char value ) { _data.append( value ); }
+ void append( short value );
+ void append( int value );
+ void append( const QByteArray& array ) { _data.append( array ); }
+
+ void patch( int posn, int value );
+
+ void pad();
+
+private:
+ QByteArray _data;
+ bool _bigEndian;
+};
+
+#define QT_QWS_PRINTER_DEFAULT_DPI 200
+
+class QtopiaPrintEnginePrivate : public QPaintEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QtopiaPrintEngine)
+public:
+ QtopiaPrintEnginePrivate(QPrinter::PrinterMode m) :
+ mode(m),
+ printerState(QPrinter::Idle),
+ orientation(QPrinter::Portrait),
+ paperSize(QPrinter::A4),
+ pageOrder(QPrinter::FirstPageFirst),
+ colorMode(QPrinter::GrayScale),
+ paperSource(QPrinter::OnlyOne),
+ resolution(QT_QWS_PRINTER_DEFAULT_DPI),
+ _paintEngine(0),
+ numCopies(1),
+ outputToFile(false),
+ fullPage(false),
+ collateCopies(false),
+ pageNumber(0),
+ pageImage(0),
+ partialByte(0),
+ partialBits(0)
+ {
+ }
+ ~QtopiaPrintEnginePrivate();
+
+ void initialize();
+ QPaintEngine *paintEngine();
+
+ QPrinter::PrinterMode mode;
+
+ QString printerName;
+ QString outputFileName;
+ QString printProgram;
+ QString docName;
+ QString creator;
+
+ QPrinter::PrinterState printerState;
+
+ QPrinter::Orientation orientation;
+ QPrinter::PaperSize paperSize;
+ QPrinter::PageOrder pageOrder;
+ QPrinter::ColorMode colorMode;
+ QPrinter::PaperSource paperSource;
+
+ int resolution;
+ QPaintEngine *_paintEngine;
+ int numCopies;
+
+ bool outputToFile;
+ bool fullPage;
+ bool collateCopies;
+
+ int pageNumber;
+
+ QImage *pageImage;
+
+ QtopiaPrintBuffer buffer;
+
+ // Definitions that are only relevant to G3FAX output.
+ int ifdPatch;
+ int partialByte;
+ int partialBits;
+ void writeG3FaxHeader();
+ void writeG3FaxPage();
+ int writeG3IFDEntry( int tag, int type, int count, int value );
+ void writeG3Code( int code, int bits );
+ void writeG3WhiteRun( int len );
+ void writeG3BlackRun( int len );
+ void writeG3EOL();
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PRINTER
+
+#endif // QPRINTENGINE_QWS_P_H
diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h
index bc4da285bb..8c74732788 100644
--- a/src/gui/painting/qregion.h
+++ b/src/gui/painting/qregion.h
@@ -59,7 +59,7 @@ QT_MODULE(Gui)
template <class T> class QVector;
class QVariant;
-#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN)
+#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || defined(Q_WS_WAYLAND)
struct QRegionPrivate;
#endif
@@ -203,7 +203,7 @@ private:
#elif defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
mutable RgnHandle unused; // Here for binary compatability reasons. ### Qt 5 remove.
#endif
-#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN)
+#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || defined(Q_WS_WAYLAND)
QRegionPrivate *qt_rgn;
#endif
};
diff --git a/src/gui/painting/qregion_wayland.cpp b/src/gui/painting/qregion_wayland.cpp
new file mode 100644
index 0000000000..4299c4689c
--- /dev/null
+++ b/src/gui/painting/qregion_wayland.cpp
@@ -0,0 +1,3183 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// XXX - add appropriate friendship relationships
+#define private public
+#include "qregion.h"
+#undef private
+#include "qpainterpath.h"
+#include "qpolygon.h"
+#include "qbuffer.h"
+#include "qimage.h"
+#include <qdebug.h>
+#include "qbitmap.h"
+#include <stdlib.h>
+#include <qatomic.h>
+#include <qsemaphore.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFastMutex
+{
+ QAtomicInt contenders;
+ QSemaphore semaphore;
+public:
+ inline QFastMutex()
+ : contenders(0), semaphore(0)
+ { }
+ inline void lock()
+ {
+ if (contenders.fetchAndAddAcquire(1) != 0) {
+ semaphore.acquire();
+ contenders.deref();
+ }
+ }
+ inline bool tryLock()
+ {
+ return contenders.testAndSetAcquire(0, 1);
+ }
+ inline void unlock()
+ {
+ if (!contenders.testAndSetRelease(1, 0))
+ semaphore.release();
+ }
+};
+
+
+/*
+ * 1 if r1 contains r2
+ * 0 if r1 does not completely contain r2
+ */
+#define CONTAINSCHECK(r1, r2) \
+ ((r2).left() >= (r1).left() && (r2).right() <= (r1).right() && \
+ (r2).top() >= (r1).top() && (r2).bottom() <= (r1).bottom())
+
+/*
+ * clip region
+ */
+struct QRegionPrivate : public QRegion::QRegionData {
+ enum { Single, Vector } mode;
+ int numRects;
+ QVector<QRect> rects;
+ QRect single;
+ QRect extents;
+ QRect innerRect;
+ union {
+ int innerArea;
+ QRegionPrivate *next;
+ };
+
+ inline void vector()
+ {
+ if(mode != Vector && numRects) {
+ if(rects.size() < 1) rects.resize(1);
+ rects[0] = single;
+ }
+ mode = Vector;
+ }
+
+ inline QRegionPrivate() : mode(Single), numRects(0), innerArea(-1) {}
+ inline QRegionPrivate(const QRect &r) : mode(Single) {
+ numRects = 1;
+// rects[0] = r;
+ single = r;
+ extents = r;
+ innerRect = r;
+ innerArea = r.width() * r.height();
+ }
+
+ inline QRegionPrivate(const QRegionPrivate &r) {
+ mode = r.mode;
+ rects = r.rects;
+ single = r.single;
+ numRects = r.numRects;
+ extents = r.extents;
+ innerRect = r.innerRect;
+ innerArea = r.innerArea;
+ }
+
+ inline QRegionPrivate &operator=(const QRegionPrivate &r) {
+ mode = r.mode;
+ rects = r.rects;
+ single = r.single;
+ numRects = r.numRects;
+ extents = r.extents;
+ innerRect = r.innerRect;
+ innerArea = r.innerArea;
+ return *this;
+ }
+
+ /*
+ * Returns true if r is guaranteed to be fully contained in this region.
+ * A false return value does not guarantee the opposite.
+ */
+ inline bool contains(const QRegionPrivate &r) const {
+ const QRect &r1 = innerRect;
+ const QRect &r2 = r.extents;
+ return CONTAINSCHECK(r1, r2);
+ }
+
+ inline void updateInnerRect(const QRect &rect) {
+ const int area = rect.width() * rect.height();
+ if (area > innerArea) {
+ innerArea = area;
+ innerRect = rect;
+ }
+ }
+
+ void append(const QRegionPrivate *r);
+ void prepend(const QRegionPrivate *r);
+ inline bool canAppend(const QRegionPrivate *r) const;
+ inline bool canPrepend(const QRegionPrivate *r) const;
+};
+
+static QRegionPrivate *qt_nextRegionPtr = 0;
+static QFastMutex qt_nextRegionLock;
+
+static QRegionPrivate *qt_allocRegionMemory()
+{
+ QRegionPrivate *rv = 0;
+ qt_nextRegionLock.lock();
+
+ if(qt_nextRegionPtr) {
+ rv = qt_nextRegionPtr;
+ qt_nextRegionPtr = rv->next;
+ } else {
+ qt_nextRegionPtr =
+ (QRegionPrivate *)malloc(256 * sizeof(QRegionPrivate));
+ for(int ii = 0; ii < 256; ++ii) {
+ if(ii == 255) {
+ qt_nextRegionPtr[ii].next = 0;
+ } else {
+ qt_nextRegionPtr[ii].next = &qt_nextRegionPtr[ii + 1];
+ }
+ }
+
+ rv = qt_nextRegionPtr;
+ qt_nextRegionPtr = rv->next;
+ }
+
+ qt_nextRegionLock.unlock();
+ return rv;
+}
+
+static void qt_freeRegionMemory(QRegionPrivate *rp)
+{
+ qt_nextRegionLock.lock();
+ rp->next = qt_nextRegionPtr;
+ qt_nextRegionPtr = rp;
+ qt_nextRegionLock.unlock();
+}
+
+static QRegionPrivate *qt_allocRegion()
+{
+ QRegionPrivate *mem = qt_allocRegionMemory();
+ return new (mem) QRegionPrivate;
+}
+
+static QRegionPrivate *qt_allocRegion(const QRect &r)
+{
+ QRegionPrivate *mem = qt_allocRegionMemory();
+ return new (mem) QRegionPrivate(r);
+}
+
+static QRegionPrivate *qt_allocRegion(const QRegionPrivate &r)
+{
+ QRegionPrivate *mem = qt_allocRegionMemory();
+ return new (mem) QRegionPrivate(r);
+}
+
+void qt_freeRegion(QRegionPrivate *rp)
+{
+ rp->~QRegionPrivate();
+ qt_freeRegionMemory(rp);
+// delete rp;
+}
+
+static inline bool isEmptyHelper(const QRegionPrivate *preg)
+{
+ return !preg || preg->numRects == 0;
+}
+
+void QRegionPrivate::append(const QRegionPrivate *r)
+{
+ Q_ASSERT(!isEmptyHelper(r));
+
+ vector();
+ QRect *destRect = rects.data() + numRects;
+ const QRect *srcRect = (r->mode==Vector)?r->rects.constData():&r->single;
+ int numAppend = r->numRects;
+
+ // test for merge in x direction
+ {
+ const QRect *rFirst = srcRect;
+ QRect *myLast = rects.data() + (numRects - 1);
+ if (rFirst->top() == myLast->top()
+ && rFirst->height() == myLast->height()
+ && rFirst->left() == (myLast->right() + 1))
+ {
+ myLast->setWidth(myLast->width() + rFirst->width());
+ updateInnerRect(*myLast);
+ ++srcRect;
+ --numAppend;
+ }
+ }
+
+ // append rectangles
+ const int newNumRects = numRects + numAppend;
+ if (newNumRects > rects.size()) {
+ rects.resize(newNumRects);
+ destRect = rects.data() + numRects;
+ }
+ memcpy(destRect, srcRect, numAppend * sizeof(QRect));
+
+ // update inner rectangle
+ if (innerArea < r->innerArea) {
+ innerArea = r->innerArea;
+ innerRect = r->innerRect;
+ }
+
+ // update extents
+ destRect = &extents;
+ srcRect = &r->extents;
+ extents.setCoords(qMin(destRect->left(), srcRect->left()),
+ qMin(destRect->top(), srcRect->top()),
+ qMax(destRect->right(), srcRect->right()),
+ qMax(destRect->bottom(), srcRect->bottom()));
+
+ numRects = newNumRects;
+}
+
+void QRegionPrivate::prepend(const QRegionPrivate *r)
+{
+#if 1
+ Q_UNUSED(r);
+#else
+ // XXX ak: does not respect vectorization of region
+
+ Q_ASSERT(!isEmpty(r));
+
+ // move existing rectangles
+ memmove(rects.data() + r->numRects, rects.constData(),
+ numRects * sizeof(QRect));
+
+ // prepend new rectangles
+ memcpy(rects.data(), r->rects.constData(), r->numRects * sizeof(QRect));
+
+ // update inner rectangle
+ if (innerArea < r->innerArea) {
+ innerArea = r->innerArea;
+ innerRect = r->innerRect;
+ }
+
+ // update extents
+ destRect = &extents;
+ srcRect = &r->extents;
+ extents.setCoords(qMin(destRect->left(), srcRect->left()),
+ qMin(destRect->top(), srcRect->top()),
+ qMax(destRect->right(), srcRect->right()),
+ qMax(destRect->bottom(), srcRect->bottom()));
+
+ numRects = newNumRects;
+#endif
+}
+
+bool QRegionPrivate::canAppend(const QRegionPrivate *r) const
+{
+ Q_ASSERT(!isEmptyHelper(r));
+
+ const QRect *rFirst = (r->mode==Vector)?r->rects.constData():&r->single;
+ const QRect *myLast = (mode==Vector)?(rects.constData() + (numRects - 1)):&single;
+ // XXX: possible improvements:
+ // - nFirst->top() == myLast->bottom() + 1, must possibly merge bands
+ if (rFirst->top() > (myLast->bottom() + 1)
+ || (rFirst->top() == myLast->top()
+ && rFirst->height() == myLast->height()
+ && rFirst->left() > myLast->right()))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool QRegionPrivate::canPrepend(const QRegionPrivate *r) const
+{
+#if 1
+ Q_UNUSED(r);
+ return false;
+#else
+ return r->canAppend(this);
+#endif
+}
+
+#if defined(Q_WS_X11)
+QT_BEGIN_INCLUDE_NAMESPACE
+# include "qregion_x11.cpp"
+QT_END_INCLUDE_NAMESPACE
+#elif defined(Q_WS_MAC)
+QT_BEGIN_INCLUDE_NAMESPACE
+# include "qregion_mac.cpp"
+QT_END_INCLUDE_NAMESPACE
+#elif defined(Q_WS_QWS)
+static QRegionPrivate qrp;
+QRegion::QRegionData QRegion::shared_empty = {Q_BASIC_ATOMIC_INITIALIZER(1), &qrp};
+#endif
+
+typedef void (*OverlapFunc)(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
+ register const QRect *r2, const QRect *r2End, register int y1, register int y2);
+typedef void (*NonOverlapFunc)(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd,
+ register int y1, register int y2);
+
+static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2);
+static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest);
+static void miRegionOp(register QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2,
+ OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
+ NonOverlapFunc nonOverlap2Func);
+
+#define RectangleOut 0
+#define RectangleIn 1
+#define RectanglePart 2
+#define EvenOddRule 0
+#define WindingRule 1
+
+// START OF region.h extract
+/* $XConsortium: region.h,v 11.14 94/04/17 20:22:20 rws Exp $ */
+/************************************************************************
+
+Copyright (c) 1987 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+************************************************************************/
+
+#ifndef _XREGION_H
+#define _XREGION_H
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <limits.h>
+QT_END_INCLUDE_NAMESPACE
+
+/* 1 if two BOXs overlap.
+ * 0 if two BOXs do not overlap.
+ * Remember, x2 and y2 are not in the region
+ */
+#define EXTENTCHECK(r1, r2) \
+ ((r1)->right() >= (r2)->left() && \
+ (r1)->left() <= (r2)->right() && \
+ (r1)->bottom() >= (r2)->top() && \
+ (r1)->top() <= (r2)->bottom())
+
+/*
+ * update region extents
+ */
+#define EXTENTS(r,idRect){\
+ if((r)->left() < (idRect)->extents.left())\
+ (idRect)->extents.setLeft((r)->left());\
+ if((r)->top() < (idRect)->extents.top())\
+ (idRect)->extents.setTop((r)->top());\
+ if((r)->right() > (idRect)->extents.right())\
+ (idRect)->extents.setRight((r)->right());\
+ if((r)->bottom() > (idRect)->extents.bottom())\
+ (idRect)->extents.setBottom((r)->bottom());\
+ }
+
+/*
+ * Check to see if there is enough memory in the present region.
+ */
+#define MEMCHECK(dest, rect, firstrect){\
+ if ((dest).numRects >= ((dest).rects.size()-1)){\
+ firstrect.resize(firstrect.size() * 2); \
+ (rect) = (firstrect).data() + (dest).numRects;\
+ }\
+ }
+
+
+/*
+ * number of points to buffer before sending them off
+ * to scanlines(): Must be an even number
+ */
+#define NUMPTSTOBUFFER 200
+
+/*
+ * used to allocate buffers for points and link
+ * the buffers together
+ */
+typedef struct _POINTBLOCK {
+ QPoint pts[NUMPTSTOBUFFER];
+ struct _POINTBLOCK *next;
+} POINTBLOCK;
+
+#endif
+// END OF region.h extract
+
+// START OF Region.c extract
+/* $XConsortium: Region.c /main/30 1996/10/22 14:21:24 kaleb $ */
+/************************************************************************
+
+Copyright (c) 1987, 1988 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+************************************************************************/
+/*
+ * The functions in this file implement the Region abstraction, similar to one
+ * used in the X11 sample server. A Region is simply an area, as the name
+ * implies, and is implemented as a "y-x-banded" array of rectangles. To
+ * explain: Each Region is made up of a certain number of rectangles sorted
+ * by y coordinate first, and then by x coordinate.
+ *
+ * Furthermore, the rectangles are banded such that every rectangle with a
+ * given upper-left y coordinate (y1) will have the same lower-right y
+ * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
+ * will span the entire vertical distance of the band. This means that some
+ * areas that could be merged into a taller rectangle will be represented as
+ * several shorter rectangles to account for shorter rectangles to its left
+ * or right but within its "vertical scope".
+ *
+ * An added constraint on the rectangles is that they must cover as much
+ * horizontal area as possible. E.g. no two rectangles in a band are allowed
+ * to touch.
+ *
+ * Whenever possible, bands will be merged together to cover a greater vertical
+ * distance (and thus reduce the number of rectangles). Two bands can be merged
+ * only if the bottom of one touches the top of the other and they have
+ * rectangles in the same places (of the same width, of course). This maintains
+ * the y-x-banding that's so nice to have...
+ */
+/* $XFree86: xc/lib/X11/Region.c,v 1.1.1.2.2.2 1998/10/04 15:22:50 hohndel Exp $ */
+
+static void UnionRectWithRegion(register const QRect *rect, const QRegionPrivate *source,
+ QRegionPrivate &dest)
+{
+ if (!rect->width() || !rect->height())
+ return;
+
+ QRegionPrivate region(*rect);
+
+ Q_ASSERT(EqualRegion(source, &dest));
+ Q_ASSERT(!isEmptyHelper(&region));
+
+ if (dest.numRects == 0)
+ dest = region;
+ else if (dest.canAppend(&region))
+ dest.append(&region);
+ else
+ UnionRegion(&region, source, dest);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * miSetExtents --
+ * Reset the extents and innerRect of a region to what they should be.
+ * Called by miSubtract and miIntersect b/c they can't figure it out
+ * along the way or do so easily, as miUnion can.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The region's 'extents' and 'innerRect' structure is overwritten.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void miSetExtents(QRegionPrivate &dest)
+{
+ register const QRect *pBox,
+ *pBoxEnd;
+ register QRect *pExtents;
+
+ dest.innerRect.setCoords(0, 0, -1, -1);
+ dest.innerArea = -1;
+ if (dest.numRects == 0) {
+ dest.extents.setCoords(0, 0, 0, 0);
+ return;
+ }
+
+ pExtents = &dest.extents;
+ pBox = (dest.mode==QRegionPrivate::Vector)?(dest.rects.constData()):(&dest.single);
+ pBoxEnd = (dest.mode==QRegionPrivate::Vector)?(&pBox[dest.numRects - 1]):(&dest.single);
+
+ /*
+ * Since pBox is the first rectangle in the region, it must have the
+ * smallest y1 and since pBoxEnd is the last rectangle in the region,
+ * it must have the largest y2, because of banding. Initialize x1 and
+ * x2 from pBox and pBoxEnd, resp., as good things to initialize them
+ * to...
+ */
+ pExtents->setLeft(pBox->left());
+ pExtents->setTop(pBox->top());
+ pExtents->setRight(pBoxEnd->right());
+ pExtents->setBottom(pBoxEnd->bottom());
+
+ Q_ASSERT(pExtents->top() <= pExtents->bottom());
+ while (pBox <= pBoxEnd) {
+ if (pBox->left() < pExtents->left())
+ pExtents->setLeft(pBox->left());
+ if (pBox->right() > pExtents->right())
+ pExtents->setRight(pBox->right());
+ dest.updateInnerRect(*pBox);
+ ++pBox;
+ }
+ Q_ASSERT(pExtents->left() <= pExtents->right());
+}
+
+/* TranslateRegion(pRegion, x, y)
+ translates in place
+ added by raymond
+*/
+
+static void OffsetRegion(register QRegionPrivate &region, register int x, register int y)
+{
+ register int nbox;
+ register QRect *pbox;
+
+ if(region.mode == QRegionPrivate::Single) {
+ region.single.translate(x, y);
+ } else {
+ pbox = region.rects.data();
+ nbox = region.numRects;
+
+ while (nbox--) {
+ pbox->translate(x, y);
+ ++pbox;
+ }
+ }
+ region.extents.translate(x, y);
+ region.innerRect.translate(x, y);
+}
+
+/*======================================================================
+ * Region Intersection
+ *====================================================================*/
+/*-
+ *-----------------------------------------------------------------------
+ * miIntersectO --
+ * Handle an overlapping band for miIntersect.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Rectangles may be added to the region.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void miIntersectO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
+ register const QRect *r2, const QRect *r2End, int y1, int y2)
+{
+ register int x1;
+ register int x2;
+ register QRect *pNextRect;
+
+ pNextRect = dest.rects.data() + dest.numRects;
+
+ while (r1 != r1End && r2 != r2End) {
+ x1 = qMax(r1->left(), r2->left());
+ x2 = qMin(r1->right(), r2->right());
+
+ /*
+ * If there's any overlap between the two rectangles, add that
+ * overlap to the new region.
+ * There's no need to check for subsumption because the only way
+ * such a need could arise is if some region has two rectangles
+ * right next to each other. Since that should never happen...
+ */
+ if (x1 <= x2) {
+ Q_ASSERT(y1 <= y2);
+ MEMCHECK(dest, pNextRect, dest.rects)
+ pNextRect->setCoords(x1, y1, x2, y2);
+ ++dest.numRects;
+ ++pNextRect;
+ }
+
+ /*
+ * Need to advance the pointers. Shift the one that extends
+ * to the right the least, since the other still has a chance to
+ * overlap with that region's next rectangle, if you see what I mean.
+ */
+ if (r1->right() < r2->right()) {
+ ++r1;
+ } else if (r2->right() < r1->right()) {
+ ++r2;
+ } else {
+ ++r1;
+ ++r2;
+ }
+ }
+}
+
+/*======================================================================
+ * Generic Region Operator
+ *====================================================================*/
+
+/*-
+ *-----------------------------------------------------------------------
+ * miCoalesce --
+ * Attempt to merge the boxes in the current band with those in the
+ * previous one. Used only by miRegionOp.
+ *
+ * Results:
+ * The new index for the previous band.
+ *
+ * Side Effects:
+ * If coalescing takes place:
+ * - rectangles in the previous band will have their y2 fields
+ * altered.
+ * - dest.numRects will be decreased.
+ *
+ *-----------------------------------------------------------------------
+ */
+static int miCoalesce(register QRegionPrivate &dest, int prevStart, int curStart)
+{
+ register QRect *pPrevBox; /* Current box in previous band */
+ register QRect *pCurBox; /* Current box in current band */
+ register QRect *pRegEnd; /* End of region */
+ int curNumRects; /* Number of rectangles in current band */
+ int prevNumRects; /* Number of rectangles in previous band */
+ int bandY1; /* Y1 coordinate for current band */
+ QRect *rData = dest.rects.data();
+
+ pRegEnd = rData + dest.numRects;
+
+ pPrevBox = rData + prevStart;
+ prevNumRects = curStart - prevStart;
+
+ /*
+ * Figure out how many rectangles are in the current band. Have to do
+ * this because multiple bands could have been added in miRegionOp
+ * at the end when one region has been exhausted.
+ */
+ pCurBox = rData + curStart;
+ bandY1 = pCurBox->top();
+ for (curNumRects = 0; pCurBox != pRegEnd && pCurBox->top() == bandY1; ++curNumRects) {
+ ++pCurBox;
+ }
+
+ if (pCurBox != pRegEnd) {
+ /*
+ * If more than one band was added, we have to find the start
+ * of the last band added so the next coalescing job can start
+ * at the right place... (given when multiple bands are added,
+ * this may be pointless -- see above).
+ */
+ --pRegEnd;
+ while ((pRegEnd - 1)->top() == pRegEnd->top())
+ --pRegEnd;
+ curStart = pRegEnd - rData;
+ pRegEnd = rData + dest.numRects;
+ }
+
+ if (curNumRects == prevNumRects && curNumRects != 0) {
+ pCurBox -= curNumRects;
+ /*
+ * The bands may only be coalesced if the bottom of the previous
+ * matches the top scanline of the current.
+ */
+ if (pPrevBox->bottom() == pCurBox->top() - 1) {
+ /*
+ * Make sure the bands have boxes in the same places. This
+ * assumes that boxes have been added in such a way that they
+ * cover the most area possible. I.e. two boxes in a band must
+ * have some horizontal space between them.
+ */
+ do {
+ if (pPrevBox->left() != pCurBox->left() || pPrevBox->right() != pCurBox->right()) {
+ // The bands don't line up so they can't be coalesced.
+ return curStart;
+ }
+ ++pPrevBox;
+ ++pCurBox;
+ --prevNumRects;
+ } while (prevNumRects != 0);
+
+ dest.numRects -= curNumRects;
+ pCurBox -= curNumRects;
+ pPrevBox -= curNumRects;
+
+ /*
+ * The bands may be merged, so set the bottom y of each box
+ * in the previous band to that of the corresponding box in
+ * the current band.
+ */
+ do {
+ pPrevBox->setBottom(pCurBox->bottom());
+ dest.updateInnerRect(*pPrevBox);
+ ++pPrevBox;
+ ++pCurBox;
+ curNumRects -= 1;
+ } while (curNumRects != 0);
+
+ /*
+ * If only one band was added to the region, we have to backup
+ * curStart to the start of the previous band.
+ *
+ * If more than one band was added to the region, copy the
+ * other bands down. The assumption here is that the other bands
+ * came from the same region as the current one and no further
+ * coalescing can be done on them since it's all been done
+ * already... curStart is already in the right place.
+ */
+ if (pCurBox == pRegEnd) {
+ curStart = prevStart;
+ } else {
+ do {
+ *pPrevBox++ = *pCurBox++;
+ dest.updateInnerRect(*pPrevBox);
+ } while (pCurBox != pRegEnd);
+ }
+ }
+ }
+ return curStart;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * miRegionOp --
+ * Apply an operation to two regions. Called by miUnion, miInverse,
+ * miSubtract, miIntersect...
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The new region is overwritten.
+ *
+ * Notes:
+ * The idea behind this function is to view the two regions as sets.
+ * Together they cover a rectangle of area that this function divides
+ * into horizontal bands where points are covered only by one region
+ * or by both. For the first case, the nonOverlapFunc is called with
+ * each the band and the band's upper and lower extents. For the
+ * second, the overlapFunc is called to process the entire band. It
+ * is responsible for clipping the rectangles in the band, though
+ * this function provides the boundaries.
+ * At the end of each band, the new region is coalesced, if possible,
+ * to reduce the number of rectangles in the region.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void miRegionOp(register QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2,
+ OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
+ NonOverlapFunc nonOverlap2Func)
+{
+ register const QRect *r1; // Pointer into first region
+ register const QRect *r2; // Pointer into 2d region
+ const QRect *r1End; // End of 1st region
+ const QRect *r2End; // End of 2d region
+ register int ybot; // Bottom of intersection
+ register int ytop; // Top of intersection
+ int prevBand; // Index of start of previous band in dest
+ int curBand; // Index of start of current band in dest
+ register const QRect *r1BandEnd; // End of current band in r1
+ register const QRect *r2BandEnd; // End of current band in r2
+ int top; // Top of non-overlapping band
+ int bot; // Bottom of non-overlapping band
+
+ /*
+ * Initialization:
+ * set r1, r2, r1End and r2End appropriately, preserve the important
+ * parts of the destination region until the end in case it's one of
+ * the two source regions, then mark the "new" region empty, allocating
+ * another array of rectangles for it to use.
+ */
+ r1 = (reg1->mode==QRegionPrivate::Vector)?reg1->rects.data():&reg1->single;
+ r2 = (reg2->mode==QRegionPrivate::Vector)?reg2->rects.data():&reg2->single;
+ r1End = r1 + reg1->numRects;
+ r2End = r2 + reg2->numRects;
+
+ dest.vector();
+ QVector<QRect> oldRects = dest.rects;
+
+ dest.numRects = 0;
+
+ /*
+ * Allocate a reasonable number of rectangles for the new region. The idea
+ * is to allocate enough so the individual functions don't need to
+ * reallocate and copy the array, which is time consuming, yet we don't
+ * have to worry about using too much memory. I hope to be able to
+ * nuke the realloc() at the end of this function eventually.
+ */
+ dest.rects.resize(qMax(reg1->numRects,reg2->numRects) * 2);
+
+ /*
+ * Initialize ybot and ytop.
+ * In the upcoming loop, ybot and ytop serve different functions depending
+ * on whether the band being handled is an overlapping or non-overlapping
+ * band.
+ * In the case of a non-overlapping band (only one of the regions
+ * has points in the band), ybot is the bottom of the most recent
+ * intersection and thus clips the top of the rectangles in that band.
+ * ytop is the top of the next intersection between the two regions and
+ * serves to clip the bottom of the rectangles in the current band.
+ * For an overlapping band (where the two regions intersect), ytop clips
+ * the top of the rectangles of both regions and ybot clips the bottoms.
+ */
+ if (reg1->extents.top() < reg2->extents.top())
+ ybot = reg1->extents.top() - 1;
+ else
+ ybot = reg2->extents.top() - 1;
+
+ /*
+ * prevBand serves to mark the start of the previous band so rectangles
+ * can be coalesced into larger rectangles. qv. miCoalesce, above.
+ * In the beginning, there is no previous band, so prevBand == curBand
+ * (curBand is set later on, of course, but the first band will always
+ * start at index 0). prevBand and curBand must be indices because of
+ * the possible expansion, and resultant moving, of the new region's
+ * array of rectangles.
+ */
+ prevBand = 0;
+
+ do {
+ curBand = dest.numRects;
+
+ /*
+ * This algorithm proceeds one source-band (as opposed to a
+ * destination band, which is determined by where the two regions
+ * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
+ * rectangle after the last one in the current band for their
+ * respective regions.
+ */
+ r1BandEnd = r1;
+ while (r1BandEnd != r1End && r1BandEnd->top() == r1->top())
+ ++r1BandEnd;
+
+ r2BandEnd = r2;
+ while (r2BandEnd != r2End && r2BandEnd->top() == r2->top())
+ ++r2BandEnd;
+
+ /*
+ * First handle the band that doesn't intersect, if any.
+ *
+ * Note that attention is restricted to one band in the
+ * non-intersecting region at once, so if a region has n
+ * bands between the current position and the next place it overlaps
+ * the other, this entire loop will be passed through n times.
+ */
+ if (r1->top() < r2->top()) {
+ top = qMax(r1->top(), ybot + 1);
+ bot = qMin(r1->bottom(), r2->top() - 1);
+
+ if (nonOverlap1Func != 0 && bot >= top)
+ (*nonOverlap1Func)(dest, r1, r1BandEnd, top, bot);
+ ytop = r2->top();
+ } else if (r2->top() < r1->top()) {
+ top = qMax(r2->top(), ybot + 1);
+ bot = qMin(r2->bottom(), r1->top() - 1);
+
+ if (nonOverlap2Func != 0 && bot >= top)
+ (*nonOverlap2Func)(dest, r2, r2BandEnd, top, bot);
+ ytop = r1->top();
+ } else {
+ ytop = r1->top();
+ }
+
+ /*
+ * If any rectangles got added to the region, try and coalesce them
+ * with rectangles from the previous band. Note we could just do
+ * this test in miCoalesce, but some machines incur a not
+ * inconsiderable cost for function calls, so...
+ */
+ if (dest.numRects != curBand)
+ prevBand = miCoalesce(dest, prevBand, curBand);
+
+ /*
+ * Now see if we've hit an intersecting band. The two bands only
+ * intersect if ybot >= ytop
+ */
+ ybot = qMin(r1->bottom(), r2->bottom());
+ curBand = dest.numRects;
+ if (ybot >= ytop)
+ (*overlapFunc)(dest, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
+
+ if (dest.numRects != curBand)
+ prevBand = miCoalesce(dest, prevBand, curBand);
+
+ /*
+ * If we've finished with a band (y2 == ybot) we skip forward
+ * in the region to the next band.
+ */
+ if (r1->bottom() == ybot)
+ r1 = r1BandEnd;
+ if (r2->bottom() == ybot)
+ r2 = r2BandEnd;
+ } while (r1 != r1End && r2 != r2End);
+
+ /*
+ * Deal with whichever region still has rectangles left.
+ */
+ curBand = dest.numRects;
+ if (r1 != r1End) {
+ if (nonOverlap1Func != 0) {
+ do {
+ r1BandEnd = r1;
+ while (r1BandEnd < r1End && r1BandEnd->top() == r1->top())
+ ++r1BandEnd;
+ (*nonOverlap1Func)(dest, r1, r1BandEnd, qMax(r1->top(), ybot + 1), r1->bottom());
+ r1 = r1BandEnd;
+ } while (r1 != r1End);
+ }
+ } else if ((r2 != r2End) && (nonOverlap2Func != 0)) {
+ do {
+ r2BandEnd = r2;
+ while (r2BandEnd < r2End && r2BandEnd->top() == r2->top())
+ ++r2BandEnd;
+ (*nonOverlap2Func)(dest, r2, r2BandEnd, qMax(r2->top(), ybot + 1), r2->bottom());
+ r2 = r2BandEnd;
+ } while (r2 != r2End);
+ }
+
+ if (dest.numRects != curBand)
+ (void)miCoalesce(dest, prevBand, curBand);
+
+ /*
+ * A bit of cleanup. To keep regions from growing without bound,
+ * we shrink the array of rectangles to match the new number of
+ * rectangles in the region.
+ *
+ * Only do this stuff if the number of rectangles allocated is more than
+ * twice the number of rectangles in the region (a simple optimization).
+ */
+ if (qMax(4, dest.numRects) < (dest.rects.size() >> 1))
+ dest.rects.resize(dest.numRects);
+}
+
+/*======================================================================
+ * Region Union
+ *====================================================================*/
+
+/*-
+ *-----------------------------------------------------------------------
+ * miUnionNonO --
+ * Handle a non-overlapping band for the union operation. Just
+ * Adds the rectangles into the region. Doesn't have to check for
+ * subsumption or anything.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * dest.numRects is incremented and the final rectangles overwritten
+ * with the rectangles we're passed.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+static void miUnionNonO(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd,
+ register int y1, register int y2)
+{
+ register QRect *pNextRect;
+
+ pNextRect = dest.rects.data() + dest.numRects;
+
+ Q_ASSERT(y1 <= y2);
+
+ while (r != rEnd) {
+ Q_ASSERT(r->left() <= r->right());
+ MEMCHECK(dest, pNextRect, dest.rects)
+ pNextRect->setCoords(r->left(), y1, r->right(), y2);
+ dest.numRects++;
+ ++pNextRect;
+ ++r;
+ }
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * miUnionO --
+ * Handle an overlapping band for the union operation. Picks the
+ * left-most rectangle each time and merges it into the region.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Rectangles are overwritten in dest.rects and dest.numRects will
+ * be changed.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+static void miUnionO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
+ register const QRect *r2, const QRect *r2End, register int y1, register int y2)
+{
+ register QRect *pNextRect;
+
+ pNextRect = dest.rects.data() + dest.numRects;
+
+#define MERGERECT(r) \
+ if ((dest.numRects != 0) && \
+ (pNextRect[-1].top() == y1) && \
+ (pNextRect[-1].bottom() == y2) && \
+ (pNextRect[-1].right() >= r->left()-1)) { \
+ if (pNextRect[-1].right() < r->right()) { \
+ pNextRect[-1].setRight(r->right()); \
+ dest.updateInnerRect(pNextRect[-1]); \
+ Q_ASSERT(pNextRect[-1].left() <= pNextRect[-1].right()); \
+ } \
+ } else { \
+ MEMCHECK(dest, pNextRect, dest.rects) \
+ pNextRect->setCoords(r->left(), y1, r->right(), y2); \
+ dest.updateInnerRect(*pNextRect); \
+ dest.numRects++; \
+ pNextRect++; \
+ } \
+ r++;
+
+ Q_ASSERT(y1 <= y2);
+ while (r1 != r1End && r2 != r2End) {
+ if (r1->left() < r2->left()) {
+ MERGERECT(r1)
+ } else {
+ MERGERECT(r2)
+ }
+ }
+
+ if (r1 != r1End) {
+ do {
+ MERGERECT(r1)
+ } while (r1 != r1End);
+ } else {
+ while (r2 != r2End) {
+ MERGERECT(r2)
+ }
+ }
+}
+
+static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest)
+{
+ Q_ASSERT(!isEmptyHelper(reg1) && !isEmptyHelper(reg2));
+ Q_ASSERT(!reg1->contains(*reg2));
+ Q_ASSERT(!reg2->contains(*reg1));
+ Q_ASSERT(!EqualRegion(reg1, reg2));
+ Q_ASSERT(!reg1->canAppend(reg2));
+ Q_ASSERT(!reg2->canAppend(reg1));
+
+ if (reg1->innerArea > reg2->innerArea) {
+ dest.innerArea = reg1->innerArea;
+ dest.innerRect = reg1->innerRect;
+ } else {
+ dest.innerArea = reg2->innerArea;
+ dest.innerRect = reg2->innerRect;
+ }
+ miRegionOp(dest, reg1, reg2, miUnionO, miUnionNonO, miUnionNonO);
+
+ dest.extents.setCoords(qMin(reg1->extents.left(), reg2->extents.left()),
+ qMin(reg1->extents.top(), reg2->extents.top()),
+ qMax(reg1->extents.right(), reg2->extents.right()),
+ qMax(reg1->extents.bottom(), reg2->extents.bottom()));
+}
+
+/*======================================================================
+ * Region Subtraction
+ *====================================================================*/
+
+/*-
+ *-----------------------------------------------------------------------
+ * miSubtractNonO --
+ * Deal with non-overlapping band for subtraction. Any parts from
+ * region 2 we discard. Anything from region 1 we add to the region.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * dest may be affected.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+static void miSubtractNonO1(register QRegionPrivate &dest, register const QRect *r,
+ const QRect *rEnd, register int y1, register int y2)
+{
+ register QRect *pNextRect;
+
+ pNextRect = dest.rects.data() + dest.numRects;
+
+ Q_ASSERT(y1<=y2);
+
+ while (r != rEnd) {
+ Q_ASSERT(r->left() <= r->right());
+ MEMCHECK(dest, pNextRect, dest.rects)
+ pNextRect->setCoords(r->left(), y1, r->right(), y2);
+ ++dest.numRects;
+ ++pNextRect;
+ ++r;
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * miSubtractO --
+ * Overlapping band subtraction. x1 is the left-most point not yet
+ * checked.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * dest may have rectangles added to it.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+static void miSubtractO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
+ register const QRect *r2, const QRect *r2End, register int y1, register int y2)
+{
+ register QRect *pNextRect;
+ register int x1;
+
+ x1 = r1->left();
+
+ Q_ASSERT(y1 <= y2);
+ pNextRect = dest.rects.data() + dest.numRects;
+
+ while (r1 != r1End && r2 != r2End) {
+ if (r2->right() < x1) {
+ /*
+ * Subtrahend missed the boat: go to next subtrahend.
+ */
+ ++r2;
+ } else if (r2->left() <= x1) {
+ /*
+ * Subtrahend precedes minuend: nuke left edge of minuend.
+ */
+ x1 = r2->right() + 1;
+ if (x1 > r1->right()) {
+ /*
+ * Minuend completely covered: advance to next minuend and
+ * reset left fence to edge of new minuend.
+ */
+ ++r1;
+ if (r1 != r1End)
+ x1 = r1->left();
+ } else {
+ // Subtrahend now used up since it doesn't extend beyond minuend
+ ++r2;
+ }
+ } else if (r2->left() <= r1->right()) {
+ /*
+ * Left part of subtrahend covers part of minuend: add uncovered
+ * part of minuend to region and skip to next subtrahend.
+ */
+ Q_ASSERT(x1 < r2->left());
+ MEMCHECK(dest, pNextRect, dest.rects)
+ pNextRect->setCoords(x1, y1, r2->left() - 1, y2);
+ ++dest.numRects;
+ ++pNextRect;
+
+ x1 = r2->right() + 1;
+ if (x1 > r1->right()) {
+ /*
+ * Minuend used up: advance to new...
+ */
+ ++r1;
+ if (r1 != r1End)
+ x1 = r1->left();
+ } else {
+ // Subtrahend used up
+ ++r2;
+ }
+ } else {
+ /*
+ * Minuend used up: add any remaining piece before advancing.
+ */
+ if (r1->right() >= x1) {
+ MEMCHECK(dest, pNextRect, dest.rects)
+ pNextRect->setCoords(x1, y1, r1->right(), y2);
+ ++dest.numRects;
+ ++pNextRect;
+ }
+ ++r1;
+ if (r1 != r1End)
+ x1 = r1->left();
+ }
+ }
+
+ /*
+ * Add remaining minuend rectangles to region.
+ */
+ while (r1 != r1End) {
+ Q_ASSERT(x1 <= r1->right());
+ MEMCHECK(dest, pNextRect, dest.rects)
+ pNextRect->setCoords(x1, y1, r1->right(), y2);
+ ++dest.numRects;
+ ++pNextRect;
+
+ ++r1;
+ if (r1 != r1End)
+ x1 = r1->left();
+ }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * miSubtract --
+ * Subtract regS from regM and leave the result in regD.
+ * S stands for subtrahend, M for minuend and D for difference.
+ *
+ * Side Effects:
+ * regD is overwritten.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+static void SubtractRegion(QRegionPrivate *regM, QRegionPrivate *regS,
+ register QRegionPrivate &dest)
+{
+ Q_ASSERT(!isEmptyHelper(regM));
+ Q_ASSERT(!isEmptyHelper(regS));
+ Q_ASSERT(EXTENTCHECK(&regM->extents, &regS->extents));
+ Q_ASSERT(!regS->contains(*regM));
+ Q_ASSERT(!EqualRegion(regM, regS));
+
+ miRegionOp(dest, regM, regS, miSubtractO, miSubtractNonO1, 0);
+
+ /*
+ * Can't alter dest's extents before we call miRegionOp because
+ * it might be one of the source regions and miRegionOp depends
+ * on the extents of those regions being the unaltered. Besides, this
+ * way there's no checking against rectangles that will be nuked
+ * due to coalescing, so we have to examine fewer rectangles.
+ */
+ miSetExtents(dest);
+}
+
+static void XorRegion(QRegionPrivate *sra, QRegionPrivate *srb, QRegionPrivate &dest)
+{
+ Q_ASSERT(!isEmptyHelper(sra) && !isEmptyHelper(srb));
+ Q_ASSERT(EXTENTCHECK(&sra->extents, &srb->extents));
+ Q_ASSERT(!EqualRegion(sra, srb));
+
+ QRegionPrivate tra, trb;
+
+ if (!srb->contains(*sra))
+ SubtractRegion(sra, srb, tra);
+ if (!sra->contains(*srb))
+ SubtractRegion(srb, sra, trb);
+
+ Q_ASSERT(isEmptyHelper(&trb) || !tra.contains(trb));
+ Q_ASSERT(isEmptyHelper(&tra) || !trb.contains(tra));
+
+ if (isEmptyHelper(&tra)) {
+ dest = trb;
+ } else if (isEmptyHelper(&trb)) {
+ dest = tra;
+ } else if (tra.canAppend(&trb)) {
+ dest = tra;
+ dest.append(&trb);
+ } else if (trb.canAppend(&tra)) {
+ dest = trb;
+ dest.append(&tra);
+ } else {
+ UnionRegion(&tra, &trb, dest);
+ }
+}
+
+/*
+ * Check to see if two regions are equal
+ */
+static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2)
+{
+ if (r1->numRects != r2->numRects) {
+ return false;
+ } else if (r1->numRects == 0) {
+ return true;
+ } else if (r1->extents != r2->extents) {
+ return false;
+ } else if (r1->mode == QRegionPrivate::Single && r2->mode == QRegionPrivate::Single) {
+ return r1->single == r2->single;
+ } else {
+ const QRect *rr1 = (r1->mode==QRegionPrivate::Vector)?r1->rects.constData():&r1->single;
+ const QRect *rr2 = (r2->mode==QRegionPrivate::Vector)?r2->rects.constData():&r2->single;
+ for (int i = 0; i < r1->numRects; ++i, ++rr1, ++rr2) {
+ if (*rr1 != *rr2)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool PointInRegion(QRegionPrivate *pRegion, int x, int y)
+{
+ int i;
+
+ if (pRegion->mode == QRegionPrivate::Single)
+ return pRegion->single.contains(x, y);
+ if (isEmptyHelper(pRegion))
+ return false;
+ if (!pRegion->extents.contains(x, y))
+ return false;
+ if (pRegion->innerRect.contains(x, y))
+ return true;
+ for (i = 0; i < pRegion->numRects; ++i) {
+ if (pRegion->rects[i].contains(x, y))
+ return true;
+ }
+ return false;
+}
+
+static bool RectInRegion(register QRegionPrivate *region, int rx, int ry, uint rwidth, uint rheight)
+{
+ register const QRect *pbox;
+ register const QRect *pboxEnd;
+ QRect rect(rx, ry, rwidth, rheight);
+ register QRect *prect = &rect;
+ int partIn, partOut;
+
+ if (!region || region->numRects == 0 || !EXTENTCHECK(&region->extents, prect))
+ return RectangleOut;
+
+ partOut = false;
+ partIn = false;
+
+ /* can stop when both partOut and partIn are true, or we reach prect->y2 */
+ for (pbox = (region->mode==QRegionPrivate::Vector)?region->rects.constData():&region->single, pboxEnd = pbox + region->numRects;
+ pbox < pboxEnd; ++pbox) {
+ if (pbox->bottom() < ry)
+ continue;
+
+ if (pbox->top() > ry) {
+ partOut = true;
+ if (partIn || pbox->top() > prect->bottom())
+ break;
+ ry = pbox->top();
+ }
+
+ if (pbox->right() < rx)
+ continue; /* not far enough over yet */
+
+ if (pbox->left() > rx) {
+ partOut = true; /* missed part of rectangle to left */
+ if (partIn)
+ break;
+ }
+
+ if (pbox->left() <= prect->right()) {
+ partIn = true; /* definitely overlap */
+ if (partOut)
+ break;
+ }
+
+ if (pbox->right() >= prect->right()) {
+ ry = pbox->bottom() + 1; /* finished with this band */
+ if (ry > prect->bottom())
+ break;
+ rx = prect->left(); /* reset x out to left again */
+ } else {
+ /*
+ * Because boxes in a band are maximal width, if the first box
+ * to overlap the rectangle doesn't completely cover it in that
+ * band, the rectangle must be partially out, since some of it
+ * will be uncovered in that band. partIn will have been set true
+ * by now...
+ */
+ break;
+ }
+ }
+ return partIn ? ((ry <= prect->bottom()) ? RectanglePart : RectangleIn) : RectangleOut;
+}
+// END OF Region.c extract
+// START OF poly.h extract
+/* $XConsortium: poly.h,v 1.4 94/04/17 20:22:19 rws Exp $ */
+/************************************************************************
+
+Copyright (c) 1987 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+************************************************************************/
+
+/*
+ * This file contains a few macros to help track
+ * the edge of a filled object. The object is assumed
+ * to be filled in scanline order, and thus the
+ * algorithm used is an extension of Bresenham's line
+ * drawing algorithm which assumes that y is always the
+ * major axis.
+ * Since these pieces of code are the same for any filled shape,
+ * it is more convenient to gather the library in one
+ * place, but since these pieces of code are also in
+ * the inner loops of output primitives, procedure call
+ * overhead is out of the question.
+ * See the author for a derivation if needed.
+ */
+
+
+/*
+ * In scan converting polygons, we want to choose those pixels
+ * which are inside the polygon. Thus, we add .5 to the starting
+ * x coordinate for both left and right edges. Now we choose the
+ * first pixel which is inside the pgon for the left edge and the
+ * first pixel which is outside the pgon for the right edge.
+ * Draw the left pixel, but not the right.
+ *
+ * How to add .5 to the starting x coordinate:
+ * If the edge is moving to the right, then subtract dy from the
+ * error term from the general form of the algorithm.
+ * If the edge is moving to the left, then add dy to the error term.
+ *
+ * The reason for the difference between edges moving to the left
+ * and edges moving to the right is simple: If an edge is moving
+ * to the right, then we want the algorithm to flip immediately.
+ * If it is moving to the left, then we don't want it to flip until
+ * we traverse an entire pixel.
+ */
+#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
+ int dx; /* local storage */ \
+\
+ /* \
+ * if the edge is horizontal, then it is ignored \
+ * and assumed not to be processed. Otherwise, do this stuff. \
+ */ \
+ if ((dy) != 0) { \
+ xStart = (x1); \
+ dx = (x2) - xStart; \
+ if (dx < 0) { \
+ m = dx / (dy); \
+ m1 = m - 1; \
+ incr1 = -2 * dx + 2 * (dy) * m1; \
+ incr2 = -2 * dx + 2 * (dy) * m; \
+ d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
+ } else { \
+ m = dx / (dy); \
+ m1 = m + 1; \
+ incr1 = 2 * dx - 2 * (dy) * m1; \
+ incr2 = 2 * dx - 2 * (dy) * m; \
+ d = -2 * m * (dy) + 2 * dx; \
+ } \
+ } \
+}
+
+#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
+ if (m1 > 0) { \
+ if (d > 0) { \
+ minval += m1; \
+ d += incr1; \
+ } \
+ else { \
+ minval += m; \
+ d += incr2; \
+ } \
+ } else {\
+ if (d >= 0) { \
+ minval += m1; \
+ d += incr1; \
+ } \
+ else { \
+ minval += m; \
+ d += incr2; \
+ } \
+ } \
+}
+
+
+/*
+ * This structure contains all of the information needed
+ * to run the bresenham algorithm.
+ * The variables may be hardcoded into the declarations
+ * instead of using this structure to make use of
+ * register declarations.
+ */
+typedef struct {
+ int minor_axis; /* minor axis */
+ int d; /* decision variable */
+ int m, m1; /* slope and slope+1 */
+ int incr1, incr2; /* error increments */
+} BRESINFO;
+
+
+#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
+ BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
+ bres.m, bres.m1, bres.incr1, bres.incr2)
+
+#define BRESINCRPGONSTRUCT(bres) \
+ BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
+
+
+
+/*
+ * These are the data structures needed to scan
+ * convert regions. Two different scan conversion
+ * methods are available -- the even-odd method, and
+ * the winding number method.
+ * The even-odd rule states that a point is inside
+ * the polygon if a ray drawn from that point in any
+ * direction will pass through an odd number of
+ * path segments.
+ * By the winding number rule, a point is decided
+ * to be inside the polygon if a ray drawn from that
+ * point in any direction passes through a different
+ * number of clockwise and counter-clockwise path
+ * segments.
+ *
+ * These data structures are adapted somewhat from
+ * the algorithm in (Foley/Van Dam) for scan converting
+ * polygons.
+ * The basic algorithm is to start at the top (smallest y)
+ * of the polygon, stepping down to the bottom of
+ * the polygon by incrementing the y coordinate. We
+ * keep a list of edges which the current scanline crosses,
+ * sorted by x. This list is called the Active Edge Table (AET)
+ * As we change the y-coordinate, we update each entry in
+ * in the active edge table to reflect the edges new xcoord.
+ * This list must be sorted at each scanline in case
+ * two edges intersect.
+ * We also keep a data structure known as the Edge Table (ET),
+ * which keeps track of all the edges which the current
+ * scanline has not yet reached. The ET is basically a
+ * list of ScanLineList structures containing a list of
+ * edges which are entered at a given scanline. There is one
+ * ScanLineList per scanline at which an edge is entered.
+ * When we enter a new edge, we move it from the ET to the AET.
+ *
+ * From the AET, we can implement the even-odd rule as in
+ * (Foley/Van Dam).
+ * The winding number rule is a little trickier. We also
+ * keep the EdgeTableEntries in the AET linked by the
+ * nextWETE (winding EdgeTableEntry) link. This allows
+ * the edges to be linked just as before for updating
+ * purposes, but only uses the edges linked by the nextWETE
+ * link as edges representing spans of the polygon to
+ * drawn (as with the even-odd rule).
+ */
+
+/*
+ * for the winding number rule
+ */
+#define CLOCKWISE 1
+#define COUNTERCLOCKWISE -1
+
+typedef struct _EdgeTableEntry {
+ int ymax; /* ycoord at which we exit this edge. */
+ BRESINFO bres; /* Bresenham info to run the edge */
+ struct _EdgeTableEntry *next; /* next in the list */
+ struct _EdgeTableEntry *back; /* for insertion sort */
+ struct _EdgeTableEntry *nextWETE; /* for winding num rule */
+ int ClockWise; /* flag for winding number rule */
+} EdgeTableEntry;
+
+
+typedef struct _ScanLineList{
+ int scanline; /* the scanline represented */
+ EdgeTableEntry *edgelist; /* header node */
+ struct _ScanLineList *next; /* next in the list */
+} ScanLineList;
+
+
+typedef struct {
+ int ymax; /* ymax for the polygon */
+ int ymin; /* ymin for the polygon */
+ ScanLineList scanlines; /* header node */
+} EdgeTable;
+
+
+/*
+ * Here is a struct to help with storage allocation
+ * so we can allocate a big chunk at a time, and then take
+ * pieces from this heap when we need to.
+ */
+#define SLLSPERBLOCK 25
+
+typedef struct _ScanLineListBlock {
+ ScanLineList SLLs[SLLSPERBLOCK];
+ struct _ScanLineListBlock *next;
+} ScanLineListBlock;
+
+
+
+/*
+ *
+ * a few macros for the inner loops of the fill code where
+ * performance considerations don't allow a procedure call.
+ *
+ * Evaluate the given edge at the given scanline.
+ * If the edge has expired, then we leave it and fix up
+ * the active edge table; otherwise, we increment the
+ * x value to be ready for the next scanline.
+ * The winding number rule is in effect, so we must notify
+ * the caller when the edge has been removed so he
+ * can reorder the Winding Active Edge Table.
+ */
+#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
+ if (pAET->ymax == y) { /* leaving this edge */ \
+ pPrevAET->next = pAET->next; \
+ pAET = pPrevAET->next; \
+ fixWAET = 1; \
+ if (pAET) \
+ pAET->back = pPrevAET; \
+ } \
+ else { \
+ BRESINCRPGONSTRUCT(pAET->bres) \
+ pPrevAET = pAET; \
+ pAET = pAET->next; \
+ } \
+}
+
+
+/*
+ * Evaluate the given edge at the given scanline.
+ * If the edge has expired, then we leave it and fix up
+ * the active edge table; otherwise, we increment the
+ * x value to be ready for the next scanline.
+ * The even-odd rule is in effect.
+ */
+#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
+ if (pAET->ymax == y) { /* leaving this edge */ \
+ pPrevAET->next = pAET->next; \
+ pAET = pPrevAET->next; \
+ if (pAET) \
+ pAET->back = pPrevAET; \
+ } \
+ else { \
+ BRESINCRPGONSTRUCT(pAET->bres) \
+ pPrevAET = pAET; \
+ pAET = pAET->next; \
+ } \
+}
+// END OF poly.h extract
+// START OF PolyReg.c extract
+/* $XConsortium: PolyReg.c,v 11.23 94/11/17 21:59:37 converse Exp $ */
+/************************************************************************
+
+Copyright (c) 1987 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+************************************************************************/
+/* $XFree86: xc/lib/X11/PolyReg.c,v 1.1.1.2.8.2 1998/10/04 15:22:49 hohndel Exp $ */
+
+#define LARGE_COORDINATE 1000000
+#define SMALL_COORDINATE -LARGE_COORDINATE
+
+/*
+ * InsertEdgeInET
+ *
+ * Insert the given edge into the edge table.
+ * First we must find the correct bucket in the
+ * Edge table, then find the right slot in the
+ * bucket. Finally, we can insert it.
+ *
+ */
+static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline,
+ ScanLineListBlock **SLLBlock, int *iSLLBlock)
+{
+ register EdgeTableEntry *start, *prev;
+ register ScanLineList *pSLL, *pPrevSLL;
+ ScanLineListBlock *tmpSLLBlock;
+
+ /*
+ * find the right bucket to put the edge into
+ */
+ pPrevSLL = &ET->scanlines;
+ pSLL = pPrevSLL->next;
+ while (pSLL && (pSLL->scanline < scanline)) {
+ pPrevSLL = pSLL;
+ pSLL = pSLL->next;
+ }
+
+ /*
+ * reassign pSLL (pointer to ScanLineList) if necessary
+ */
+ if ((!pSLL) || (pSLL->scanline > scanline)) {
+ if (*iSLLBlock > SLLSPERBLOCK-1)
+ {
+ tmpSLLBlock =
+ (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
+ (*SLLBlock)->next = tmpSLLBlock;
+ tmpSLLBlock->next = (ScanLineListBlock *)NULL;
+ *SLLBlock = tmpSLLBlock;
+ *iSLLBlock = 0;
+ }
+ pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
+
+ pSLL->next = pPrevSLL->next;
+ pSLL->edgelist = (EdgeTableEntry *)NULL;
+ pPrevSLL->next = pSLL;
+ }
+ pSLL->scanline = scanline;
+
+ /*
+ * now insert the edge in the right bucket
+ */
+ prev = 0;
+ start = pSLL->edgelist;
+ while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
+ prev = start;
+ start = start->next;
+ }
+ ETE->next = start;
+
+ if (prev)
+ prev->next = ETE;
+ else
+ pSLL->edgelist = ETE;
+}
+
+/*
+ * CreateEdgeTable
+ *
+ * This routine creates the edge table for
+ * scan converting polygons.
+ * The Edge Table (ET) looks like:
+ *
+ * EdgeTable
+ * --------
+ * | ymax | ScanLineLists
+ * |scanline|-->------------>-------------->...
+ * -------- |scanline| |scanline|
+ * |edgelist| |edgelist|
+ * --------- ---------
+ * | |
+ * | |
+ * V V
+ * list of ETEs list of ETEs
+ *
+ * where ETE is an EdgeTableEntry data structure,
+ * and there is one ScanLineList per scanline at
+ * which an edge is initially entered.
+ *
+ */
+
+static void CreateETandAET(register int count, register const QPoint *pts,
+ EdgeTable *ET, EdgeTableEntry *AET, register EdgeTableEntry *pETEs,
+ ScanLineListBlock *pSLLBlock)
+{
+ register const QPoint *top,
+ *bottom,
+ *PrevPt,
+ *CurrPt;
+ int iSLLBlock = 0;
+ int dy;
+
+ if (count < 2)
+ return;
+
+ /*
+ * initialize the Active Edge Table
+ */
+ AET->next = 0;
+ AET->back = 0;
+ AET->nextWETE = 0;
+ AET->bres.minor_axis = SMALL_COORDINATE;
+
+ /*
+ * initialize the Edge Table.
+ */
+ ET->scanlines.next = 0;
+ ET->ymax = SMALL_COORDINATE;
+ ET->ymin = LARGE_COORDINATE;
+ pSLLBlock->next = 0;
+
+ PrevPt = &pts[count - 1];
+
+ /*
+ * for each vertex in the array of points.
+ * In this loop we are dealing with two vertices at
+ * a time -- these make up one edge of the polygon.
+ */
+ while (count--) {
+ CurrPt = pts++;
+
+ /*
+ * find out which point is above and which is below.
+ */
+ if (PrevPt->y() > CurrPt->y()) {
+ bottom = PrevPt;
+ top = CurrPt;
+ pETEs->ClockWise = 0;
+ } else {
+ bottom = CurrPt;
+ top = PrevPt;
+ pETEs->ClockWise = 1;
+ }
+
+ /*
+ * don't add horizontal edges to the Edge table.
+ */
+ if (bottom->y() != top->y()) {
+ pETEs->ymax = bottom->y() - 1; /* -1 so we don't get last scanline */
+
+ /*
+ * initialize integer edge algorithm
+ */
+ dy = bottom->y() - top->y();
+ BRESINITPGONSTRUCT(dy, top->x(), bottom->x(), pETEs->bres)
+
+ InsertEdgeInET(ET, pETEs, top->y(), &pSLLBlock, &iSLLBlock);
+
+ if (PrevPt->y() > ET->ymax)
+ ET->ymax = PrevPt->y();
+ if (PrevPt->y() < ET->ymin)
+ ET->ymin = PrevPt->y();
+ ++pETEs;
+ }
+
+ PrevPt = CurrPt;
+ }
+}
+
+/*
+ * loadAET
+ *
+ * This routine moves EdgeTableEntries from the
+ * EdgeTable into the Active Edge Table,
+ * leaving them sorted by smaller x coordinate.
+ *
+ */
+
+static void loadAET(register EdgeTableEntry *AET, register EdgeTableEntry *ETEs)
+{
+ register EdgeTableEntry *pPrevAET;
+ register EdgeTableEntry *tmp;
+
+ pPrevAET = AET;
+ AET = AET->next;
+ while (ETEs) {
+ while (AET && AET->bres.minor_axis < ETEs->bres.minor_axis) {
+ pPrevAET = AET;
+ AET = AET->next;
+ }
+ tmp = ETEs->next;
+ ETEs->next = AET;
+ if (AET)
+ AET->back = ETEs;
+ ETEs->back = pPrevAET;
+ pPrevAET->next = ETEs;
+ pPrevAET = ETEs;
+
+ ETEs = tmp;
+ }
+}
+
+/*
+ * computeWAET
+ *
+ * This routine links the AET by the
+ * nextWETE (winding EdgeTableEntry) link for
+ * use by the winding number rule. The final
+ * Active Edge Table (AET) might look something
+ * like:
+ *
+ * AET
+ * ---------- --------- ---------
+ * |ymax | |ymax | |ymax |
+ * | ... | |... | |... |
+ * |next |->|next |->|next |->...
+ * |nextWETE| |nextWETE| |nextWETE|
+ * --------- --------- ^--------
+ * | | |
+ * V-------------------> V---> ...
+ *
+ */
+static void computeWAET(register EdgeTableEntry *AET)
+{
+ register EdgeTableEntry *pWETE;
+ register int inside = 1;
+ register int isInside = 0;
+
+ AET->nextWETE = 0;
+ pWETE = AET;
+ AET = AET->next;
+ while (AET) {
+ if (AET->ClockWise)
+ ++isInside;
+ else
+ --isInside;
+
+ if (!inside && !isInside || inside && isInside) {
+ pWETE->nextWETE = AET;
+ pWETE = AET;
+ inside = !inside;
+ }
+ AET = AET->next;
+ }
+ pWETE->nextWETE = 0;
+}
+
+/*
+ * InsertionSort
+ *
+ * Just a simple insertion sort using
+ * pointers and back pointers to sort the Active
+ * Edge Table.
+ *
+ */
+
+static int InsertionSort(register EdgeTableEntry *AET)
+{
+ register EdgeTableEntry *pETEchase;
+ register EdgeTableEntry *pETEinsert;
+ register EdgeTableEntry *pETEchaseBackTMP;
+ register int changed = 0;
+
+ AET = AET->next;
+ while (AET) {
+ pETEinsert = AET;
+ pETEchase = AET;
+ while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
+ pETEchase = pETEchase->back;
+
+ AET = AET->next;
+ if (pETEchase != pETEinsert) {
+ pETEchaseBackTMP = pETEchase->back;
+ pETEinsert->back->next = AET;
+ if (AET)
+ AET->back = pETEinsert->back;
+ pETEinsert->next = pETEchase;
+ pETEchase->back->next = pETEinsert;
+ pETEchase->back = pETEinsert;
+ pETEinsert->back = pETEchaseBackTMP;
+ changed = 1;
+ }
+ }
+ return changed;
+}
+
+/*
+ * Clean up our act.
+ */
+static void FreeStorage(register ScanLineListBlock *pSLLBlock)
+{
+ register ScanLineListBlock *tmpSLLBlock;
+
+ while (pSLLBlock) {
+ tmpSLLBlock = pSLLBlock->next;
+ free(pSLLBlock);
+ pSLLBlock = tmpSLLBlock;
+ }
+}
+
+/*
+ * Create an array of rectangles from a list of points.
+ * If indeed these things (POINTS, RECTS) are the same,
+ * then this proc is still needed, because it allocates
+ * storage for the array, which was allocated on the
+ * stack by the calling procedure.
+ *
+ */
+static void PtsToRegion(register int numFullPtBlocks, register int iCurPtBlock,
+ POINTBLOCK *FirstPtBlock, QRegionPrivate *reg)
+{
+ register QRect *rects;
+ register QPoint *pts;
+ register POINTBLOCK *CurPtBlock;
+ register int i;
+ register QRect *extents;
+ register int numRects;
+
+ extents = &reg->extents;
+ numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
+
+ reg->rects.resize(numRects);
+
+ CurPtBlock = FirstPtBlock;
+ rects = reg->rects.data() - 1;
+ numRects = 0;
+ extents->setLeft(INT_MAX);
+ extents->setRight(INT_MIN);
+ reg->innerArea = -1;
+
+ for (; numFullPtBlocks >= 0; --numFullPtBlocks) {
+ /* the loop uses 2 points per iteration */
+ i = NUMPTSTOBUFFER >> 1;
+ if (!numFullPtBlocks)
+ i = iCurPtBlock >> 1;
+ if(i) {
+ for (pts = CurPtBlock->pts; i--; pts += 2) {
+ if (pts->x() == pts[1].x())
+ continue;
+ if (numRects && pts->x() == rects->left() && pts->y() == rects->bottom() + 1
+ && pts[1].x() == rects->right()+1 && (numRects == 1 || rects[-1].top() != rects->top())
+ && (i && pts[2].y() > pts[1].y())) {
+ rects->setBottom(pts[1].y());
+ reg->updateInnerRect(*rects);
+ continue;
+ }
+ ++numRects;
+ ++rects;
+ rects->setCoords(pts->x(), pts->y(), pts[1].x() - 1, pts[1].y());
+ if (rects->left() < extents->left())
+ extents->setLeft(rects->left());
+ if (rects->right() > extents->right())
+ extents->setRight(rects->right());
+ reg->updateInnerRect(*rects);
+ }
+ }
+ CurPtBlock = CurPtBlock->next;
+ }
+
+ if (numRects) {
+ extents->setTop(reg->rects[0].top());
+ extents->setBottom(rects->bottom());
+ } else {
+ extents->setCoords(0, 0, 0, 0);
+ }
+ reg->numRects = numRects;
+}
+
+/*
+ * polytoregion
+ *
+ * Scan converts a polygon by returning a run-length
+ * encoding of the resultant bitmap -- the run-length
+ * encoding is in the form of an array of rectangles.
+ */
+static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule,
+ QRegionPrivate *region)
+ //Point *Pts; /* the pts */
+ //int Count; /* number of pts */
+ //int rule; /* winding rule */
+{
+ register EdgeTableEntry *pAET; /* Active Edge Table */
+ register int y; /* current scanline */
+ register int iPts = 0; /* number of pts in buffer */
+ register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
+ register ScanLineList *pSLL; /* current scanLineList */
+ register QPoint *pts; /* output buffer */
+ EdgeTableEntry *pPrevAET; /* ptr to previous AET */
+ EdgeTable ET; /* header node for ET */
+ EdgeTableEntry AET; /* header node for AET */
+ EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
+ ScanLineListBlock SLLBlock; /* header for scanlinelist */
+ int fixWAET = false;
+ POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
+ POINTBLOCK *tmpPtBlock;
+ int numFullPtBlocks = 0;
+
+ region->vector();
+
+ /* special case a rectangle */
+ if (((Count == 4) ||
+ ((Count == 5) && (Pts[4].x() == Pts[0].x()) && (Pts[4].y() == Pts[0].y())))
+ && (((Pts[0].y() == Pts[1].y()) && (Pts[1].x() == Pts[2].x()) && (Pts[2].y() == Pts[3].y())
+ && (Pts[3].x() == Pts[0].x())) || ((Pts[0].x() == Pts[1].x())
+ && (Pts[1].y() == Pts[2].y()) && (Pts[2].x() == Pts[3].x())
+ && (Pts[3].y() == Pts[0].y())))) {
+ int x = qMin(Pts[0].x(), Pts[2].x());
+ region->extents.setLeft(x);
+ int y = qMin(Pts[0].y(), Pts[2].y());
+ region->extents.setTop(y);
+ region->extents.setWidth(qMax(Pts[0].x(), Pts[2].x()) - x);
+ region->extents.setHeight(qMax(Pts[0].y(), Pts[2].y()) - y);
+ if ((region->extents.left() <= region->extents.right()) &&
+ (region->extents.top() <= region->extents.bottom())) {
+ region->numRects = 1;
+ region->rects.resize(1);
+ region->rects[0] = region->extents;
+ region->innerRect = region->extents;
+ region->innerArea = region->innerRect.width() * region->innerRect.height();
+ }
+ return region;
+ }
+
+ if (!(pETEs = static_cast<EdgeTableEntry *>(malloc(sizeof(EdgeTableEntry) * Count))))
+ return 0;
+
+ pts = FirstPtBlock.pts;
+ CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock);
+ pSLL = ET.scanlines.next;
+ curPtBlock = &FirstPtBlock;
+
+ if (rule == EvenOddRule) {
+ /*
+ * for each scanline
+ */
+ for (y = ET.ymin; y < ET.ymax; ++y) {
+ /*
+ * Add a new edge to the active edge table when we
+ * get to the next edge.
+ */
+ if (pSLL && y == pSLL->scanline) {
+ loadAET(&AET, pSLL->edgelist);
+ pSLL = pSLL->next;
+ }
+ pPrevAET = &AET;
+ pAET = AET.next;
+
+ /*
+ * for each active edge
+ */
+ while (pAET) {
+ pts->setX(pAET->bres.minor_axis);
+ pts->setY(y);
+ ++pts;
+ ++iPts;
+
+ /*
+ * send out the buffer
+ */
+ if (iPts == NUMPTSTOBUFFER) {
+ tmpPtBlock = (POINTBLOCK *)malloc(sizeof(POINTBLOCK));
+ curPtBlock->next = tmpPtBlock;
+ curPtBlock = tmpPtBlock;
+ pts = curPtBlock->pts;
+ ++numFullPtBlocks;
+ iPts = 0;
+ }
+ EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
+ }
+ InsertionSort(&AET);
+ }
+ } else {
+ /*
+ * for each scanline
+ */
+ for (y = ET.ymin; y < ET.ymax; ++y) {
+ /*
+ * Add a new edge to the active edge table when we
+ * get to the next edge.
+ */
+ if (pSLL && y == pSLL->scanline) {
+ loadAET(&AET, pSLL->edgelist);
+ computeWAET(&AET);
+ pSLL = pSLL->next;
+ }
+ pPrevAET = &AET;
+ pAET = AET.next;
+ pWETE = pAET;
+
+ /*
+ * for each active edge
+ */
+ while (pAET) {
+ /*
+ * add to the buffer only those edges that
+ * are in the Winding active edge table.
+ */
+ if (pWETE == pAET) {
+ pts->setX(pAET->bres.minor_axis);
+ pts->setY(y);
+ ++pts;
+ ++iPts;
+
+ /*
+ * send out the buffer
+ */
+ if (iPts == NUMPTSTOBUFFER) {
+ tmpPtBlock = static_cast<POINTBLOCK *>(malloc(sizeof(POINTBLOCK)));
+ curPtBlock->next = tmpPtBlock;
+ curPtBlock = tmpPtBlock;
+ pts = curPtBlock->pts;
+ ++numFullPtBlocks;
+ iPts = 0;
+ }
+ pWETE = pWETE->nextWETE;
+ }
+ EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
+ }
+
+ /*
+ * recompute the winding active edge table if
+ * we just resorted or have exited an edge.
+ */
+ if (InsertionSort(&AET) || fixWAET) {
+ computeWAET(&AET);
+ fixWAET = false;
+ }
+ }
+ }
+ FreeStorage(SLLBlock.next);
+ PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
+ for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
+ tmpPtBlock = curPtBlock->next;
+ free(curPtBlock);
+ curPtBlock = tmpPtBlock;
+ }
+ free(pETEs);
+ return region;
+}
+// END OF PolyReg.c extract
+
+QRegionPrivate *qt_bitmapToRegion(const QBitmap& bitmap, QRegionPrivate *region)
+{
+ region->vector();
+
+ QImage image = bitmap.toImage();
+
+ QRect xr;
+
+#define AddSpan \
+ { \
+ xr.setCoords(prev1, y, x-1, y); \
+ UnionRectWithRegion(&xr, region, *region); \
+ }
+
+ const uchar zero = 0;
+ bool little = image.format() == QImage::Format_MonoLSB;
+
+ int x,
+ y;
+ for (y = 0; y < image.height(); ++y) {
+ uchar *line = image.scanLine(y);
+ int w = image.width();
+ uchar all = zero;
+ int prev1 = -1;
+ for (x = 0; x < w;) {
+ uchar byte = line[x / 8];
+ if (x > w - 8 || byte!=all) {
+ if (little) {
+ for (int b = 8; b > 0 && x < w; --b) {
+ if (!(byte & 0x01) == !all) {
+ // More of the same
+ } else {
+ // A change.
+ if (all!=zero) {
+ AddSpan
+ all = zero;
+ } else {
+ prev1 = x;
+ all = ~zero;
+ }
+ }
+ byte >>= 1;
+ ++x;
+ }
+ } else {
+ for (int b = 8; b > 0 && x < w; --b) {
+ if (!(byte & 0x80) == !all) {
+ // More of the same
+ } else {
+ // A change.
+ if (all != zero) {
+ AddSpan
+ all = zero;
+ } else {
+ prev1 = x;
+ all = ~zero;
+ }
+ }
+ byte <<= 1;
+ ++x;
+ }
+ }
+ } else {
+ x += 8;
+ }
+ }
+ if (all != zero) {
+ AddSpan
+ }
+ }
+#undef AddSpan
+
+ return region;
+}
+
+/*
+ Constructs an empty region.
+
+ \sa isEmpty()
+*/
+
+QRegion::QRegion()
+ : d(&shared_empty)
+{
+ d->ref.ref();
+}
+
+/*
+ \overload
+
+ Create a region based on the rectange \a r with region type \a t.
+
+ If the rectangle is invalid a null region will be created.
+
+ \sa QRegion::RegionType
+*/
+
+QRegion::QRegion(const QRect &r, RegionType t)
+{
+ if (r.isEmpty()) {
+ d = &shared_empty;
+ d->ref.ref();
+ } else {
+// d = new QRegionData;
+ QRegionPrivate *rp = 0;
+ if (t == Rectangle) {
+// rp = new QRegionPrivate(r);
+ rp = qt_allocRegion(r);
+ } else if (t == Ellipse) {
+ QPainterPath path;
+ path.addEllipse(r.x(), r.y(), r.width(), r.height());
+ QPolygon a = path.toSubpathPolygons().at(0).toPolygon();
+ rp = qt_allocRegion();
+// rp = new QRegionPrivate;
+ PolygonRegion(a.constData(), a.size(), EvenOddRule, rp);
+ }
+ d = rp;
+ d->ref = 1;
+#if defined(Q_WS_X11)
+ d->rgn = 0;
+ d->xrectangles = 0;
+#elif defined(Q_WS_MAC)
+ d->rgn = 0;
+#endif
+ d->qt_rgn = rp;
+ }
+}
+
+/*
+ Constructs a polygon region from the point array \a a with the fill rule
+ specified by \a fillRule.
+
+ If \a fillRule is \l{Qt::WindingFill}, the polygon region is defined
+ using the winding algorithm; if it is \l{Qt::OddEvenFill}, the odd-even fill
+ algorithm is used.
+
+ \warning This constructor can be used to create complex regions that will
+ slow down painting when used.
+*/
+
+QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
+{
+ if (a.count() > 2) {
+ //d = new QRegionData;
+ // QRegionPrivate *rp = new QRegionPrivate;
+ QRegionPrivate *rp = qt_allocRegion();
+ PolygonRegion(a.constData(), a.size(),
+ fillRule == Qt::WindingFill ? WindingRule : EvenOddRule, rp);
+ d = rp;
+ d->ref = 1;
+#if defined(Q_WS_X11)
+ d->rgn = 0;
+ d->xrectangles = 0;
+#elif defined(Q_WS_MAC)
+ d->rgn = 0;
+#endif
+ d->qt_rgn = rp;
+ } else {
+ d = &shared_empty;
+ d->ref.ref();
+ }
+}
+
+
+/*
+ Constructs a new region which is equal to region \a r.
+*/
+
+QRegion::QRegion(const QRegion &r)
+{
+ d = r.d;
+ d->ref.ref();
+}
+
+
+/*
+ Constructs a region from the bitmap \a bm.
+
+ The resulting region consists of the pixels in bitmap \a bm that
+ are Qt::color1, as if each pixel was a 1 by 1 rectangle.
+
+ This constructor may create complex regions that will slow down
+ painting when used. Note that drawing masked pixmaps can be done
+ much faster using QPixmap::setMask().
+*/
+QRegion::QRegion(const QBitmap &bm)
+{
+ if (bm.isNull()) {
+ d = &shared_empty;
+ d->ref.ref();
+ } else {
+ // d = new QRegionData;
+// QRegionPrivate *rp = new QRegionPrivate;
+ QRegionPrivate *rp = qt_allocRegion();
+
+ qt_bitmapToRegion(bm, rp);
+ d = rp;
+ d->ref = 1;
+#if defined(Q_WS_X11)
+ d->rgn = 0;
+ d->xrectangles = 0;
+#elif defined(Q_WS_MAC)
+ d->rgn = 0;
+#endif
+ d->qt_rgn = rp;
+ }
+}
+
+void QRegion::cleanUp(QRegion::QRegionData *x)
+{
+ // delete x->qt_rgn;
+#if defined(Q_WS_X11)
+ if (x->rgn)
+ XDestroyRegion(x->rgn);
+ if (x->xrectangles)
+ free(x->xrectangles);
+#elif defined(Q_WS_MAC)
+ if (x->rgn)
+ qt_mac_dispose_rgn(x->rgn);
+#endif
+ if(x->qt_rgn) {
+// delete x->qt_rgn;
+ qt_freeRegion(x->qt_rgn);
+ } else {
+ delete x;
+ }
+}
+
+/*
+ Destroys the region.
+*/
+
+QRegion::~QRegion()
+{
+ if (!d->ref.deref())
+ cleanUp(d);
+}
+
+
+/*
+ Assigns \a r to this region and returns a reference to the region.
+*/
+
+QRegion &QRegion::operator=(const QRegion &r)
+{
+ r.d->ref.ref();
+ if (!d->ref.deref())
+ cleanUp(d);
+ d = r.d;
+ return *this;
+}
+
+
+/*
+ \internal
+*/
+
+QRegion QRegion::copy() const
+{
+ QRegion r;
+ QRegionData *x = 0; // new QRegionData;
+ QRegionPrivate *rp = 0;
+ if (d->qt_rgn)
+// rp = new QRegionPrivate(*d->qt_rgn);
+ rp = qt_allocRegion(*d->qt_rgn);
+ else
+ rp = qt_allocRegion();
+ x = rp;
+ x->qt_rgn = rp;
+ x->ref = 1;
+#if defined(Q_WS_X11)
+ x->rgn = 0;
+ x->xrectangles = 0;
+#elif defined(Q_WS_MAC)
+ x->rgn = 0;
+#endif
+
+ if (!r.d->ref.deref())
+ cleanUp(r.d);
+ r.d = x;
+ return r;
+}
+
+/*
+ Returns true if the region is empty; otherwise returns false. An
+ empty region is a region that contains no points.
+
+ Example:
+ \snippet doc/src/snippets/code/src.gui.painting.qregion_qws.cpp 0
+*/
+
+bool QRegion::isEmpty() const
+{
+ return d == &shared_empty || d->qt_rgn->numRects == 0;
+}
+
+
+/*
+ Returns true if the region contains the point \a p; otherwise
+ returns false.
+*/
+
+bool QRegion::contains(const QPoint &p) const
+{
+ return PointInRegion(d->qt_rgn, p.x(), p.y());
+}
+
+/*
+ \overload
+
+ Returns true if the region overlaps the rectangle \a r; otherwise
+ returns false.
+*/
+
+bool QRegion::contains(const QRect &r) const
+{
+ if(!d->qt_rgn)
+ return false;
+ if(d->qt_rgn->mode == QRegionPrivate::Single)
+ return d->qt_rgn->single.contains(r);
+
+ return RectInRegion(d->qt_rgn, r.left(), r.top(), r.width(), r.height()) != RectangleOut;
+}
+
+
+
+/*
+ Translates (moves) the region \a dx along the X axis and \a dy
+ along the Y axis.
+*/
+
+void QRegion::translate(int dx, int dy)
+{
+ if ((dx == 0 && dy == 0) || isEmptyHelper(d->qt_rgn))
+ return;
+
+ detach();
+ OffsetRegion(*d->qt_rgn, dx, dy);
+#if defined(Q_WS_X11)
+ if (d->xrectangles) {
+ free(d->xrectangles);
+ d->xrectangles = 0;
+ }
+#elif defined(Q_WS_MAC)
+ if(d->rgn) {
+ qt_mac_dispose_rgn(d->rgn);
+ d->rgn = 0;
+ }
+#endif
+}
+
+/*
+ \fn QRegion QRegion::unite(const QRegion &r) const
+ \obsolete
+
+ Use united(\a r) instead.
+*/
+
+/*
+ \fn QRegion QRegion::united(const QRegion &r) const
+ \since 4.2
+
+ Returns a region which is the union of this region and \a r.
+
+ \img runion.png Region Union
+
+ The figure shows the union of two elliptical regions.
+
+ \sa intersected(), subtracted(), xored()
+*/
+
+QRegion QRegion::unite(const QRegion &r) const
+{
+ if (isEmptyHelper(d->qt_rgn))
+ return r;
+ if (isEmptyHelper(r.d->qt_rgn))
+ return *this;
+
+ if (d->qt_rgn->contains(*r.d->qt_rgn)) {
+ return *this;
+ } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
+ return r;
+ } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
+ QRegion result(*this);
+ result.detach();
+ result.d->qt_rgn->append(r.d->qt_rgn);
+ return result;
+ } else if (r.d->qt_rgn->canAppend(d->qt_rgn)) {
+ QRegion result(r);
+ result.detach();
+ result.d->qt_rgn->append(d->qt_rgn);
+ return result;
+ } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
+ return *this;
+ } else {
+ QRegion result;
+ result.detach();
+ UnionRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
+ return result;
+ }
+}
+
+QRegion& QRegion::operator+=(const QRegion &r)
+{
+ if (isEmptyHelper(d->qt_rgn))
+ return *this = r;
+ if (isEmptyHelper(r.d->qt_rgn))
+ return *this;
+
+ if (d->qt_rgn->contains(*r.d->qt_rgn)) {
+ return *this;
+ } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
+ return *this = r;
+ } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
+ detach();
+ d->qt_rgn->append(r.d->qt_rgn);
+ return *this;
+ } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
+ detach();
+ d->qt_rgn->prepend(r.d->qt_rgn);
+ return *this;
+ } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
+ return *this;
+ }
+
+ return *this = unite(r);
+}
+
+/*
+ \fn QRegion QRegion::intersect(const QRegion &r) const
+ \obsolete
+
+ Use intersected(\a r) instead.
+*/
+
+/*
+ \fn QRegion QRegion::intersected(const QRegion &r) const
+ \since 4.2
+
+ Returns a region which is the intersection of this region and \a r.
+
+ \img rintersect.png Region Intersection
+
+ The figure shows the intersection of two elliptical regions.
+*/
+
+QRegion QRegion::intersect(const QRegion &r) const
+{
+ if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn)
+ || !EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
+ return QRegion();
+
+ /* this is fully contained in r */
+ if (r.d->qt_rgn->contains(*d->qt_rgn))
+ return *this;
+
+ /* r is fully contained in this */
+ if (d->qt_rgn->contains(*r.d->qt_rgn))
+ return r;
+
+ if(r.d->qt_rgn->mode == QRegionPrivate::Single &&
+ d->qt_rgn->mode == QRegionPrivate::Single)
+ return QRegion(r.d->qt_rgn->single.intersected(d->qt_rgn->single));
+#ifdef QT_GREENPHONE_OPT
+ else if(r.d->qt_rgn->mode == QRegionPrivate::Single)
+ return intersect(r.d->qt_rgn->single);
+ else if(d->qt_rgn->mode == QRegionPrivate::Single)
+ return r.intersect(d->qt_rgn->single);
+#endif
+
+ QRegion result;
+ result.detach();
+ miRegionOp(*result.d->qt_rgn, d->qt_rgn, r.d->qt_rgn, miIntersectO, 0, 0);
+
+ /*
+ * Can't alter dest's extents before we call miRegionOp because
+ * it might be one of the source regions and miRegionOp depends
+ * on the extents of those regions being the same. Besides, this
+ * way there's no checking against rectangles that will be nuked
+ * due to coalescing, so we have to examine fewer rectangles.
+ */
+ miSetExtents(*result.d->qt_rgn);
+ return result;
+}
+
+#ifdef QT_GREENPHONE_OPT
+/*
+ \overload
+ */
+QRegion QRegion::intersect(const QRect &r) const
+{
+ // No intersection
+ if(r.isEmpty() || isEmpty() || !EXTENTCHECK(&r, &d->qt_rgn->extents))
+ return QRegion();
+
+ // This is fully contained in r
+ if(CONTAINSCHECK(r, d->qt_rgn->extents))
+ return *this;
+
+ // r is fully contained in this
+ if(CONTAINSCHECK(d->qt_rgn->innerRect, r))
+ return QRegion(r);
+
+ if(d->qt_rgn->mode == QRegionPrivate::Single) {
+ return QRegion(d->qt_rgn->single & r);
+ } else {
+ QRegion rv(*this);
+ rv.detach();
+
+ rv.d->qt_rgn->extents &= r;
+ rv.d->qt_rgn->innerRect &= r;
+ rv.d->qt_rgn->innerArea = rv.d->qt_rgn->innerRect.height() *
+ rv.d->qt_rgn->innerRect.width();
+
+ int numRects = 0;
+ for(int ii = 0; ii < rv.d->qt_rgn->numRects; ++ii) {
+ QRect result = rv.d->qt_rgn->rects[ii] & r;
+ if(!result.isEmpty())
+ rv.d->qt_rgn->rects[numRects++] = result;
+ }
+ rv.d->qt_rgn->numRects = numRects;
+ return rv;
+ }
+}
+
+/*
+ \overload
+ */
+const QRegion QRegion::operator&(const QRect &r) const
+{
+ return intersect(r);
+}
+
+/*
+ \overload
+ */
+QRegion& QRegion::operator&=(const QRect &r)
+{
+ if(isEmpty() || CONTAINSCHECK(r, d->qt_rgn->extents)) {
+ // Do nothing
+ } else if(r.isEmpty() || !EXTENTCHECK(&r, &d->qt_rgn->extents)) {
+ *this = QRegion();
+ } else if(CONTAINSCHECK(d->qt_rgn->innerRect, r)) {
+ *this = QRegion(r);
+ } else {
+ detach();
+ if(d->qt_rgn->mode == QRegionPrivate::Single) {
+ QRect result = d->qt_rgn->single & r;
+ d->qt_rgn->single = result;
+ d->qt_rgn->extents = result;
+ d->qt_rgn->innerRect = result;
+ d->qt_rgn->innerArea = result.height() * result.width();
+ } else {
+ d->qt_rgn->extents &= r;
+ d->qt_rgn->innerRect &= r;
+ d->qt_rgn->innerArea = d->qt_rgn->innerRect.height() *
+ d->qt_rgn->innerRect.width();
+
+ int numRects = 0;
+ for(int ii = 0; ii < d->qt_rgn->numRects; ++ii) {
+ QRect result = d->qt_rgn->rects[ii] & r;
+ if(!result.isEmpty())
+ d->qt_rgn->rects[numRects++] = result;
+ }
+ d->qt_rgn->numRects = numRects;
+ }
+ }
+ return *this;
+}
+#endif
+
+/*
+ \fn QRegion QRegion::subtract(const QRegion &r) const
+ \obsolete
+
+ Use subtracted(\a r) instead.
+*/
+
+/*
+ \fn QRegion QRegion::subtracted(const QRegion &r) const
+ \since 4.2
+
+ Returns a region which is \a r subtracted from this region.
+
+ \img rsubtract.png Region Subtraction
+
+ The figure shows the result when the ellipse on the right is
+ subtracted from the ellipse on the left (\c {left - right}).
+
+ \sa intersected(), united(), xored()
+*/
+
+QRegion QRegion::subtract(const QRegion &r) const
+{
+ if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn))
+ return *this;
+ if (r.d->qt_rgn->contains(*d->qt_rgn))
+ return QRegion();
+ if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
+ return *this;
+ if (EqualRegion(d->qt_rgn, r.d->qt_rgn))
+ return QRegion();
+
+ QRegion result;
+ result.detach();
+ SubtractRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
+ return result;
+}
+
+/*
+ \fn QRegion QRegion::eor(const QRegion &r) const
+ \obsolete
+
+ Use xored(\a r) instead.
+*/
+
+/*
+ \fn QRegion QRegion::xored(const QRegion &r) const
+ \since 4.2
+
+ Returns a region which is the exclusive or (XOR) of this region
+ and \a r.
+
+ \img rxor.png Region XORed
+
+ The figure shows the exclusive or of two elliptical regions.
+
+ \sa intersected(), united(), subtracted()
+*/
+
+QRegion QRegion::eor(const QRegion &r) const
+{
+ if (isEmptyHelper(d->qt_rgn)) {
+ return r;
+ } else if (isEmptyHelper(r.d->qt_rgn)) {
+ return *this;
+ } else if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) {
+ return (*this + r);
+ } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
+ return QRegion();
+ } else {
+ QRegion result;
+ result.detach();
+ XorRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
+ return result;
+ }
+}
+
+/*
+ Returns the bounding rectangle of this region. An empty region
+ gives a rectangle that is QRect::isNull().
+*/
+
+QRect QRegion::boundingRect() const
+{
+ if (isEmpty())
+ return QRect();
+ return d->qt_rgn->extents;
+}
+
+/* \internal
+ Returns true if \a rect is guaranteed to be fully contained in \a region.
+ A false return value does not guarantee the opposite.
+*/
+bool qt_region_strictContains(const QRegion &region, const QRect &rect)
+{
+ if (isEmptyHelper(region.d->qt_rgn) || !rect.isValid())
+ return false;
+
+#if 0 // TEST_INNERRECT
+ static bool guard = false;
+ if (guard)
+ return QRect();
+ guard = true;
+ QRegion inner = region.d->qt_rgn->innerRect;
+ Q_ASSERT((inner - region).isEmpty());
+ guard = false;
+
+ int maxArea = 0;
+ for (int i = 0; i < region.d->qt_rgn->numRects; ++i) {
+ const QRect r = region.d->qt_rgn->rects.at(i);
+ if (r.width() * r.height() > maxArea)
+ maxArea = r.width() * r.height();
+ }
+
+ if (maxArea > region.d->qt_rgn->innerArea) {
+ qDebug() << "not largest rectangle" << region << region.d->qt_rgn->innerRect;
+ }
+ Q_ASSERT(maxArea <= region.d->qt_rgn->innerArea);
+#endif
+
+ const QRect r1 = region.d->qt_rgn->innerRect;
+ return (rect.left() >= r1.left() && rect.right() <= r1.right()
+ && rect.top() >= r1.top() && rect.bottom() <= r1.bottom());
+}
+
+/*
+ Returns an array of non-overlapping rectangles that make up the
+ region.
+
+ The union of all the rectangles is equal to the original region.
+*/
+QVector<QRect> QRegion::rects() const
+{
+ if (d->qt_rgn) {
+ d->qt_rgn->vector();
+ d->qt_rgn->rects.resize(d->qt_rgn->numRects);
+ return d->qt_rgn->rects;
+ } else {
+ return QVector<QRect>();
+ }
+}
+
+/*
+ \fn void QRegion::setRects(const QRect *rects, int number)
+
+ Sets the region using the array of rectangles specified by \a rects and
+ \a number.
+ The rectangles \e must be optimally Y-X sorted and follow these restrictions:
+
+ \list
+ \o The rectangles must not intersect.
+ \o All rectangles with a given top coordinate must have the same height.
+ \o No two rectangles may abut horizontally (they should be combined
+ into a single wider rectangle in that case).
+ \o The rectangles must be sorted in ascending order, with Y as the major
+ sort key and X as the minor sort key.
+ \endlist
+ \omit
+ Only some platforms have these restrictions (Qt for Embedded Linux, X11 and Mac OS X).
+ \endomit
+*/
+void QRegion::setRects(const QRect *rects, int num)
+{
+ *this = QRegion();
+ if (!rects || num == 0 || (num == 1 && rects->isEmpty()))
+ return;
+
+ detach();
+
+ if(num == 1) {
+ d->qt_rgn->single = *rects;
+ d->qt_rgn->mode = QRegionPrivate::Single;
+ d->qt_rgn->numRects = num;
+ d->qt_rgn->extents = *rects;
+ d->qt_rgn->innerRect = *rects;
+ } else {
+ d->qt_rgn->mode = QRegionPrivate::Vector;
+ d->qt_rgn->rects.resize(num);
+ d->qt_rgn->numRects = num;
+ int left = INT_MAX,
+ right = INT_MIN,
+ top = INT_MAX,
+ bottom = INT_MIN;
+ for (int i = 0; i < num; ++i) {
+ const QRect &rect = rects[i];
+ d->qt_rgn->rects[i] = rect;
+ left = qMin(rect.left(), left);
+ right = qMax(rect.right(), right);
+ top = qMin(rect.top(), top);
+ bottom = qMax(rect.bottom(), bottom);
+ d->qt_rgn->updateInnerRect(rect);
+ }
+ d->qt_rgn->extents = QRect(QPoint(left, top), QPoint(right, bottom));
+ }
+}
+
+/*
+ Returns true if the region is equal to \a r; otherwise returns
+ false.
+*/
+
+bool QRegion::operator==(const QRegion &r) const
+{
+ if (!d->qt_rgn || !r.d->qt_rgn)
+ return r.d->qt_rgn == d->qt_rgn;
+
+ if (d == r.d)
+ return true;
+ else
+ return EqualRegion(d->qt_rgn, r.d->qt_rgn);
+}
+
+#ifdef QT_GREENPHONE_OPT
+bool QRegion::isRect() const
+{
+ return d->qt_rgn && d->qt_rgn->mode == QRegionPrivate::Single;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qwindowsurface_wayland.cpp b/src/gui/painting/qwindowsurface_wayland.cpp
new file mode 100644
index 0000000000..bf2a7e2429
--- /dev/null
+++ b/src/gui/painting/qwindowsurface_wayland.cpp
@@ -0,0 +1,487 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwindowsurface_wayland_p.h"
+#include <qwidget.h>
+#include <qapplication.h>
+#include <qrgb.h>
+#include <qpaintengine.h>
+#include <qdesktopwidget.h>
+#include <private/qapplication_p.h>
+#include <private/qwidget_p.h>
+#include <private/qbackingstore_p.h>
+#include <stdio.h>
+
+QT_BEGIN_NAMESPACE
+
+QWaylandWindowSurface* qt_findWindowSurface(int winId)
+{
+ return NULL;
+}
+
+void QWaylandWindowSurface::invalidateBuffer()
+{
+}
+
+QWaylandWindowSurfacePrivate::QWaylandWindowSurfacePrivate()
+ : flags(0),
+#ifdef QT_QWS_CLIENTBLIT
+ directId(-1),
+#endif
+ winId(0)
+{
+}
+
+void QWaylandWindowSurfacePrivate::setWinId(int id)
+{
+ winId = id;
+}
+
+int QWaylandWindowSurface::winId() const
+{
+ return d_ptr->winId;
+}
+
+void QWaylandWindowSurface::setWinId(int id)
+{
+ d_ptr->winId = id;
+}
+
+/*!
+ \class QWaylandWindowSurface
+ \since 4.2
+ \ingroup qws
+ \preliminary
+ \internal
+
+ \brief The QWaylandWindowSurface class provides the drawing area for top-level
+ windows in Qt for Embedded Linux.
+
+ Note that this class is only available in Qt for Embedded Linux.
+
+ In \l{Qt for Embedded Linux}, the default behavior is for each client to
+ render its widgets into memory while the server is responsible for
+ putting the contents of the memory onto the
+ screen. QWaylandWindowSurface is used by the window system to implement
+ the associated memory allocation.
+
+ When a screen update is required, the server runs through all the
+ top-level windows that intersect with the region that is about to
+ be updated, and ensures that the associated clients have updated
+ their memory buffer. Then the server uses the screen driver to
+ copy the content of the memory to the screen. To locate the
+ relevant parts of memory, the driver is provided with the list of
+ top-level windows that intersect with the given region. Associated
+ with each of the top-level windows there is a window surface
+ representing the drawing area of the window.
+
+ When deriving from the QWaylandWindowSurface class, e.g., when adding
+ an \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
+ {accelerated graphics driver}, there are several pure virtual
+ functions that must be implemented. In addition, QWaylandWindowSurface
+ provides several virtual functions that can be reimplemented to
+ customize the drawing process.
+
+ \tableofcontents
+
+ \section1 Pure Virtual Functions
+
+ There are in fact two window surface instances for each top-level
+ window; one used by the application when drawing a window, and
+ another used by the server application to perform window
+ compositioning. Implement the attach() to create the server-side
+ representation of the surface. The data() function must be
+ implemented to provide the required data.
+
+ Implement the key() function to uniquely identify the surface
+ class, and the isValid() function to determine is a surface
+ corresponds to a given widget.
+
+ The geometry() function must be implemented to let the window
+ system determine the area required by the window surface
+ (QWaylandWindowSurface also provides a corresponding virtual
+ setGeometry() function that is called whenever the area necessary
+ for the top-level window to be drawn, changes). The image()
+ function is called by the window system during window
+ compositioning, and must be implemented to return an image of the
+ top-level window.
+
+ Finally, the paintDevice() function must be implemented to return
+ the appropriate paint device, and the scroll() function must be
+ implemented to scroll the given region of the surface the given
+ number of pixels.
+
+ \section1 Virtual Functions
+
+ When painting onto the surface, the window system will always call
+ the beginPaint() function before any painting operations are
+ performed. Likewise the endPaint() function is automatically
+ called when the painting is done. Reimplement the painterOffset()
+ function to alter the offset that is applied when drawing.
+
+ The window system uses the flush() function to put a given region
+ of the widget onto the screen, and the release() function to
+ deallocate the screen region corresponding to this window surface.
+
+ \section1 Other Members
+
+ QWaylandWindowSurface provides the window() function returning a
+ pointer to the top-level window the surface is representing. The
+ currently visible region of the associated widget can be retrieved
+ and set using the clipRegion() and setClipRegion() functions,
+ respectively.
+
+ When the window system performs the window compositioning, it uses
+ the SurfaceFlag enum describing the surface content. The currently
+ set surface flags can be retrieved and altered using the
+ surfaceFlags() and setSurfaceFlags() functions. In addition,
+ QWaylandWindowSurface provides the isBuffered(), isOpaque() and
+ isRegionReserved() convenience functions.
+
+ \sa {Qt for Embedded Linux Architecture#Drawing on Screen}{Qt for
+ Embedded Linux Architecture}
+*/
+
+/*!
+ \enum QWaylandWindowSurface::SurfaceFlag
+
+ This enum is used to describe the window surface's contents. It
+ is used by the screen driver to handle region allocation and
+ composition.
+
+ \value RegionReserved The surface contains a reserved area. Once
+ allocated, a reserved area can not not be changed by the window
+ system, i.e., no other widgets can be drawn on top of this.
+
+ \value Buffered
+ The surface is in a memory area which is not part of a framebuffer.
+ (A top-level window with QWidget::windowOpacity() other than 1.0 must use
+ a buffered surface in order to making blending with the background work.)
+
+ \value Opaque
+ The surface contains only opaque pixels.
+
+ \sa surfaceFlags(), setSurfaceFlags()
+*/
+
+/*!
+ \fn bool QWaylandWindowSurface::isValid() const
+ \since 4.3
+
+ Implement this function to return true if the surface is a valid
+ surface for the given top-level \a window; otherwise return
+ false.
+
+ \sa window(), key()
+*/
+
+/*!
+ \fn QString QWaylandWindowSurface::key() const
+
+ Implement this function to return a string that uniquely
+ identifies the class of this surface.
+
+ \sa window(), isValid()
+*/
+
+/*!
+ \fn QByteArray QWaylandWindowSurface::permanentState() const
+ \since 4.3
+
+ Implement this function to return the data required for creating a
+ server-side representation of the surface.
+
+ \sa attach()
+*/
+
+/*!
+ \fn void QWaylandWindowSurface::setPermanentState(const QByteArray &data)
+ \since 4.3
+
+ Implement this function to attach a server-side surface instance
+ to the corresponding client side instance using the given \a
+ data. Return true if successful; otherwise return false.
+
+ \sa data()
+*/
+
+/*!
+ \fn const QImage QWaylandWindowSurface::image() const
+
+ Implement this function to return an image of the top-level window.
+
+ \sa geometry()
+*/
+
+/*!
+ \fn bool QWaylandWindowSurface::isRegionReserved() const
+
+ Returns true if the QWaylandWindowSurface::RegionReserved is set; otherwise
+ returns false.
+
+ \sa surfaceFlags()
+*/
+
+/*!
+ \fn bool QWaylandWindowSurface::isBuffered() const
+
+ Returns true if the QWaylandWindowSurface::Buffered is set; otherwise returns false.
+
+ \sa surfaceFlags()
+*/
+
+/*!
+ \fn bool QWaylandWindowSurface::isOpaque() const
+
+ Returns true if the QWaylandWindowSurface::Opaque is set; otherwise
+ returns false.
+
+ \sa surfaceFlags()
+*/
+
+
+/*!
+ Constructs an empty surface.
+*/
+QWaylandWindowSurface::QWaylandWindowSurface()
+ : QWindowSurface(0), d_ptr(new QWaylandWindowSurfacePrivate)
+{
+}
+
+/*!
+ Constructs an empty surface for the given top-level \a widget.
+*/
+QWaylandWindowSurface::QWaylandWindowSurface(QWidget *widget)
+ : QWindowSurface(widget), d_ptr(new QWaylandWindowSurfacePrivate)
+{
+}
+
+QWaylandWindowSurface::~QWaylandWindowSurface()
+{
+#ifdef Q_BACKINGSTORE_SUBSURFACES
+ if (d_ptr->winId)
+ winIdToSurfaceMap()->remove(d_ptr->winId);
+#endif
+
+ delete d_ptr;
+}
+
+/*!
+ Returns the offset to be used when painting.
+
+ \sa paintDevice()
+*/
+QPoint QWaylandWindowSurface::painterOffset() const
+{
+ const QWidget *w = window();
+ if (!w)
+ return QPoint();
+ return w->geometry().topLeft() - w->frameGeometry().topLeft();
+}
+
+void QWaylandWindowSurface::beginPaint(const QRegion &)
+{
+ lock();
+}
+
+void QWaylandWindowSurface::endPaint(const QRegion &)
+{
+ unlock();
+}
+
+// XXX: documentation!!!
+QByteArray QWaylandWindowSurface::transientState() const
+{
+ return QByteArray();
+}
+
+QByteArray QWaylandWindowSurface::permanentState() const
+{
+ return QByteArray();
+}
+
+void QWaylandWindowSurface::setTransientState(const QByteArray &state)
+{
+ Q_UNUSED(state);
+}
+
+void QWaylandWindowSurface::setPermanentState(const QByteArray &state)
+{
+ Q_UNUSED(state);
+}
+
+bool QWaylandWindowSurface::lock(int timeout)
+{
+ Q_UNUSED(timeout);
+ return true;
+}
+
+void QWaylandWindowSurface::unlock()
+{
+}
+
+#ifdef QT_QWS_CLIENTBLIT
+/*! \internal */
+const QRegion QWaylandWindowSurface::directRegion() const
+{
+ return d_ptr->direct;
+}
+
+/*! \internal */
+int QWaylandWindowSurface::directRegionId() const
+{
+ return d_ptr->directId;
+}
+
+/*! \internal */
+void QWaylandWindowSurface::setDirectRegion(const QRegion &r, int id)
+{
+ d_ptr->direct = r;
+ d_ptr->directId = id;
+}
+#endif
+
+/*!
+ Returns the region currently visible on the screen.
+
+ \sa setClipRegion()
+*/
+const QRegion QWaylandWindowSurface::clipRegion() const
+{
+ return d_ptr->clip;
+}
+
+/*!
+ Sets the region currently visible on the screen to be the given \a
+ clip region.
+
+ \sa clipRegion()
+*/
+void QWaylandWindowSurface::setClipRegion(const QRegion &clip)
+{
+}
+
+/*!
+ Returns the surface flags describing the contents of this surface.
+
+ \sa isBuffered(), isOpaque(), isRegionReserved()
+*/
+QWaylandWindowSurface::SurfaceFlags QWaylandWindowSurface::surfaceFlags() const
+{
+ return d_ptr->flags;
+}
+
+/*!
+ Sets the surface flags describing the contents of this surface, to
+ be the given \a flags.
+
+ \sa surfaceFlags()
+*/
+void QWaylandWindowSurface::setSurfaceFlags(SurfaceFlags flags)
+{
+ d_ptr->flags = flags;
+}
+
+void QWaylandWindowSurface::setGeometry(const QRect &rect)
+{
+}
+
+void QWaylandWindowSurface::setGeometry(const QRect &rect, const QRegion &mask)
+{
+}
+
+static inline void flushUpdate(QWidget *widget, const QRegion &region,
+ const QPoint &offset)
+{
+}
+
+void QWaylandWindowSurface::flush(QWidget *widget, const QRegion &region,
+ const QPoint &offset)
+{
+}
+
+/*!
+ Move the surface with the given \a offset.
+
+ A subclass may reimplement this function to enable accelerated window move.
+ It must return true if the move was successful and no repaint is necessary,
+ false otherwise.
+
+ The default implementation updates the QWindowSurface geometry and
+ returns true if the surface is buffered; false otherwise.
+
+ This function is called by the window system on the client instance.
+
+ \sa isBuffered()
+*/
+bool QWaylandWindowSurface::move(const QPoint &offset)
+{
+ QWindowSurface::setGeometry(geometry().translated(offset));
+ return isBuffered();
+}
+
+/*!
+ Move the surface with the given \a offset.
+
+ The new visible region after the window move is given by \a newClip
+ in screen coordinates.
+
+ A subclass may reimplement this function to enable accelerated window move.
+ The returned region indicates the area that still needs to be composed
+ on the screen.
+
+ The default implementation updates the QWindowSurface geometry and
+ returns the union of the old and new geometry.
+
+ This function is called by the window system on the server instance.
+*/
+QRegion QWaylandWindowSurface::move(const QPoint &offset, const QRegion &newClip)
+{
+ const QRegion oldGeometry = geometry();
+ QWindowSurface::setGeometry(geometry().translated(offset));
+ return oldGeometry + newClip;
+}
+
+void QWaylandWindowSurface::releaseSurface()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qwindowsurface_wayland_p.h b/src/gui/painting/qwindowsurface_wayland_p.h
new file mode 100644
index 0000000000..668796a601
--- /dev/null
+++ b/src/gui/painting/qwindowsurface_wayland_p.h
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSURFACE_QWAYLAND_P_H
+#define QWINDOWSURFACE_QWAYLAND_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qwindowsurface_p.h"
+#include <qregion.h>
+#include <qimage.h>
+#include <qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QScreen;
+class QWaylandWindowSurfacePrivate;
+
+class Q_GUI_EXPORT QWaylandWindowSurface : public QWindowSurface
+{
+public:
+ QWaylandWindowSurface();
+ QWaylandWindowSurface(QWidget *widget);
+ ~QWaylandWindowSurface();
+
+ virtual bool isValid() const = 0;
+
+ virtual void setGeometry(const QRect &rect);
+ virtual void setGeometry(const QRect &rect, const QRegion &mask);
+ virtual void flush(QWidget *widget, const QRegion &region,
+ const QPoint &offset);
+
+ virtual bool move(const QPoint &offset);
+ virtual QRegion move(const QPoint &offset, const QRegion &newClip);
+
+ virtual QPoint painterOffset() const; // remove!!!
+
+ virtual void beginPaint(const QRegion &);
+ virtual void endPaint(const QRegion &);
+
+ virtual bool lock(int timeout = -1);
+ virtual void unlock();
+
+ virtual QString key() const = 0;
+
+ // XXX: not good enough
+ virtual QByteArray transientState() const;
+ virtual QByteArray permanentState() const;
+ virtual void setTransientState(const QByteArray &state);
+ virtual void setPermanentState(const QByteArray &state);
+
+ virtual QImage image() const = 0;
+ virtual QPaintDevice *paintDevice() = 0;
+
+ const QRegion clipRegion() const;
+ void setClipRegion(const QRegion &);
+
+ enum SurfaceFlag {
+ RegionReserved = 0x1,
+ Buffered = 0x2,
+ Opaque = 0x4
+ };
+ Q_DECLARE_FLAGS(SurfaceFlags, SurfaceFlag)
+
+ SurfaceFlags surfaceFlags() const;
+
+ inline bool isRegionReserved() const {
+ return surfaceFlags() & RegionReserved;
+ }
+ inline bool isBuffered() const { return surfaceFlags() & Buffered; }
+ inline bool isOpaque() const { return surfaceFlags() & Opaque; }
+
+ int winId() const;
+ virtual void releaseSurface();
+
+protected:
+ void setSurfaceFlags(SurfaceFlags type);
+ void setWinId(int id);
+
+private:
+ friend class QWidgetPrivate;
+
+ void invalidateBuffer();
+
+ QWaylandWindowSurfacePrivate *d_ptr;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QWaylandWindowSurface::SurfaceFlags)
+
+class QWaylandWindowSurfacePrivate
+{
+public:
+ QWaylandWindowSurfacePrivate();
+
+ void setWinId(int id);
+
+ QWaylandWindowSurface::SurfaceFlags flags;
+ QRegion clip;
+#ifdef QT_QWayland_CLIENTBLIT
+ QRegion direct;
+ int directId;
+#endif
+
+ int winId;
+};
+
+class QWaylandLock;
+
+class Q_GUI_EXPORT QWaylandMemorySurface : public QWaylandWindowSurface
+{
+public:
+ QWaylandMemorySurface();
+ QWaylandMemorySurface(QWidget *widget);
+ ~QWaylandMemorySurface();
+
+ bool isValid() const;
+
+ QPaintDevice *paintDevice() { return &img; }
+ bool scroll(const QRegion &area, int dx, int dy);
+
+ QImage image() const { return img; }
+ QPoint painterOffset() const;
+
+ void beginPaint(const QRegion &rgn);
+
+ bool lock(int timeout = -1);
+ void unlock();
+
+protected:
+ QImage::Format preferredImageFormat(const QWidget *widget) const;
+
+#ifndef QT_NO_QWayland_MULTIPROCESS
+ void setLock(int lockId);
+ QWaylandLock *memlock;
+#endif
+#ifndef QT_NO_THREAD
+ QMutex threadLock;
+#endif
+
+ QImage img;
+};
+
+class Q_GUI_EXPORT QWaylandLocalMemSurface : public QWaylandMemorySurface
+{
+public:
+ QWaylandLocalMemSurface();
+ QWaylandLocalMemSurface(QWidget *widget);
+ ~QWaylandLocalMemSurface();
+
+ void setGeometry(const QRect &rect);
+
+ QString key() const { return QLatin1String("mem"); }
+ QByteArray permanentState() const;
+
+ void setPermanentState(const QByteArray &data);
+ virtual void releaseSurface();
+protected:
+ uchar *mem;
+ int memsize;
+};
+
+#ifndef QT_NO_QWayland_MULTIPROCESS
+class Q_GUI_EXPORT QWaylandSharedMemSurface : public QWaylandMemorySurface
+{
+public:
+ QWaylandSharedMemSurface();
+ QWaylandSharedMemSurface(QWidget *widget);
+ ~QWaylandSharedMemSurface();
+
+ void setGeometry(const QRect &rect);
+
+ QString key() const { return QLatin1String("shm"); }
+ QByteArray permanentState() const;
+
+ void setPermanentState(const QByteArray &data);
+
+#ifdef QT_QWayland_CLIENTBLIT
+ virtual void setDirectRegion(const QRegion &, int);
+ virtual const QRegion directRegion() const;
+#endif
+ virtual void releaseSurface();
+
+private:
+ bool setMemory(int memId);
+};
+#endif // QT_NO_QWayland_MULTIPROCESS
+
+#ifndef QT_NO_PAINTONSCREEN
+class Q_GUI_EXPORT QWaylandOnScreenSurface : public QWaylandMemorySurface
+{
+public:
+ QWaylandOnScreenSurface();
+ QWaylandOnScreenSurface(QWidget *widget);
+ ~QWaylandOnScreenSurface();
+
+ bool isValid() const;
+ QPoint painterOffset() const;
+
+ QString key() const { return QLatin1String("OnScreen"); }
+ QByteArray permanentState() const;
+
+ void setPermanentState(const QByteArray &data);
+
+private:
+ void attachToScreen(const QScreen *screen);
+
+ const QScreen *screen;
+};
+#endif // QT_NO_PAINTONSCREEN
+
+#ifndef QT_NO_PAINT_DEBUG
+class Q_GUI_EXPORT QWaylandYellowSurface : public QWaylandWindowSurface
+{
+public:
+ QWaylandYellowSurface(bool isClient = false);
+ ~QWaylandYellowSurface();
+
+ void setDelay(int msec) { delay = msec; }
+
+ bool isValid() const { return true; }
+
+ void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
+
+ QString key() const { return QLatin1String("Yellow"); }
+ QByteArray permanentState() const;
+
+ void setPermanentState(const QByteArray &data);
+
+ QPaintDevice *paintDevice() { return &img; }
+ QImage image() const { return img; }
+
+private:
+ int delay;
+ QSize surfaceSize; // client side
+ QImage img; // server side
+};
+#endif // QT_NO_PAINT_DEBUG
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSURFACE_QWAYLAND_P_H
diff --git a/src/gui/text/qabstractfontengine_wayland.cpp b/src/gui/text/qabstractfontengine_wayland.cpp
new file mode 100644
index 0000000000..6b632b4150
--- /dev/null
+++ b/src/gui/text/qabstractfontengine_wayland.cpp
@@ -0,0 +1,746 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractfontengine_qws.h"
+#include "qabstractfontengine_p.h"
+
+#include <private/qtextengine_p.h>
+#include <private/qpaintengine_raster_p.h>
+
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFontEngineInfoPrivate
+{
+public:
+ inline QFontEngineInfoPrivate()
+ : pixelSize(0), weight(QFont::Normal), style(QFont::StyleNormal)
+ {}
+
+ QString family;
+ qreal pixelSize;
+ int weight;
+ QFont::Style style;
+ QList<QFontDatabase::WritingSystem> writingSystems;
+};
+
+/*!
+ \class QFontEngineInfo
+ \preliminary
+ \brief The QFontEngineInfo class describes a specific font provided by a font engine plugin.
+ \since 4.3
+ \ingroup qws
+
+ \tableofcontents
+
+ QFontEngineInfo is used to describe a request of a font to a font engine plugin as well as to
+ describe the actual fonts a plugin provides.
+
+ \sa QAbstractFontEngine, QFontEnginePlugin
+*/
+
+/*!
+ Constructs a new empty QFontEngineInfo.
+*/
+QFontEngineInfo::QFontEngineInfo()
+{
+ d = new QFontEngineInfoPrivate;
+}
+
+/*!
+ Constructs a new QFontEngineInfo with the specified \a family.
+ The resulting object represents a freely scalable font with normal
+ weight and style.
+*/
+QFontEngineInfo::QFontEngineInfo(const QString &family)
+{
+ d = new QFontEngineInfoPrivate;
+ d->family = family;
+}
+
+/*!
+ Creates a new font engine info object with the same attributes as \a other.
+*/
+QFontEngineInfo::QFontEngineInfo(const QFontEngineInfo &other)
+ : d(new QFontEngineInfoPrivate(*other.d))
+{
+}
+
+/*!
+ Assigns \a other to this font engine info object, and returns a reference
+ to this.
+*/
+QFontEngineInfo &QFontEngineInfo::operator=(const QFontEngineInfo &other)
+{
+ *d = *other.d;
+ return *this;
+}
+
+/*!
+ Destroys this QFontEngineInfo object.
+*/
+QFontEngineInfo::~QFontEngineInfo()
+{
+ delete d;
+}
+
+/*!
+ \property QFontEngineInfo::family
+ the family name of the font
+*/
+
+void QFontEngineInfo::setFamily(const QString &family)
+{
+ d->family = family;
+}
+
+QString QFontEngineInfo::family() const
+{
+ return d->family;
+}
+
+/*!
+ \property QFontEngineInfo::pixelSize
+ the pixel size of the font
+
+ A pixel size of 0 represents a freely scalable font.
+*/
+
+void QFontEngineInfo::setPixelSize(qreal size)
+{
+ d->pixelSize = size;
+}
+
+qreal QFontEngineInfo::pixelSize() const
+{
+ return d->pixelSize;
+}
+
+/*!
+ \property QFontEngineInfo::weight
+ the weight of the font
+
+ The value should be from the \l{QFont::Weight} enumeration.
+*/
+
+void QFontEngineInfo::setWeight(int weight)
+{
+ d->weight = weight;
+}
+
+int QFontEngineInfo::weight() const
+{
+ return d->weight;
+}
+
+/*!
+ \property QFontEngineInfo::style
+ the style of the font
+*/
+
+void QFontEngineInfo::setStyle(QFont::Style style)
+{
+ d->style = style;
+}
+
+QFont::Style QFontEngineInfo::style() const
+{
+ return d->style;
+}
+
+/*!
+ \property QFontEngineInfo::writingSystems
+ the writing systems supported by the font
+
+ An empty list means that any writing system is supported.
+*/
+
+QList<QFontDatabase::WritingSystem> QFontEngineInfo::writingSystems() const
+{
+ return d->writingSystems;
+}
+
+void QFontEngineInfo::setWritingSystems(const QList<QFontDatabase::WritingSystem> &writingSystems)
+{
+ d->writingSystems = writingSystems;
+}
+
+class QFontEnginePluginPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QFontEnginePlugin)
+
+ QString foundry;
+};
+
+/*!
+ \class QFontEnginePlugin
+ \preliminary
+ \brief The QFontEnginePlugin class is the base class for font engine factory plugins in Qt for Embedded Linux.
+ \since 4.3
+ \ingroup qws
+ \ingroup plugins
+
+ \tableofcontents
+
+ QFontEnginePlugin is provided by font engine plugins to create
+ instances of subclasses of QAbstractFontEngine.
+
+ The member functions create() and availableFontEngines() must be
+ implemented.
+
+ \sa QAbstractFontEngine, QFontEngineInfo
+*/
+
+/*!
+ Creates a font engine plugin that creates font engines with the
+ specified \a foundry and \a parent.
+*/
+QFontEnginePlugin::QFontEnginePlugin(const QString &foundry, QObject *parent)
+ : QObject(*new QFontEnginePluginPrivate, parent)
+{
+ Q_D(QFontEnginePlugin);
+ d->foundry = foundry;
+}
+
+/*!
+ Destroys this font engine plugin.
+*/
+QFontEnginePlugin::~QFontEnginePlugin()
+{
+}
+
+/*!
+ Returns a list of foundries the font engine plugin provides.
+ The default implementation returns the foundry specified with the constructor.
+*/
+QStringList QFontEnginePlugin::keys() const
+{
+ Q_D(const QFontEnginePlugin);
+ return QStringList(d->foundry);
+}
+
+/*!
+ \fn QAbstractFontEngine *QFontEnginePlugin::create(const QFontEngineInfo &info)
+
+ Implemented in subclasses to create a new font engine that provides a font that
+ matches \a info.
+*/
+
+/*!
+ \fn QList<QFontEngineInfo> QFontEnginePlugin::availableFontEngines() const
+
+ Implemented in subclasses to return a list of QFontEngineInfo objects that represents all font
+ engines the plugin can create.
+*/
+
+class QAbstractFontEnginePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractFontEngine)
+public:
+};
+
+//The <classname> class is|provides|contains|specifies...
+/*!
+ \class QAbstractFontEngine
+ \preliminary
+ \brief The QAbstractFontEngine class is the base class for font engine plugins in Qt for Embedded Linux.
+ \since 4.3
+ \ingroup qws
+
+ \tableofcontents
+
+ QAbstractFontEngine is implemented by font engine plugins through QFontEnginePlugin.
+
+ \sa QFontEnginePlugin, QFontEngineInfo
+*/
+
+/*!
+ \enum QAbstractFontEngine::Capability
+
+ This enum describes the capabilities of a font engine.
+
+ \value CanRenderGlyphs_Gray The font engine can render individual glyphs into 8 bpp images.
+ \value CanRenderGlyphs_Mono The font engine can render individual glyphs into 1 bpp images.
+ \value CanRenderGlyphs The font engine can render individual glyphs into images.
+ \value CanOutlineGlyphs The font engine can convert glyphs to painter paths.
+*/
+
+/*!
+ \enum QAbstractFontEngine::FontProperty
+
+ This enum describes the properties of a font provided by a font engine.
+
+ \value Ascent The ascent of the font, specified as a 26.6 fixed point value.
+ \value Descent The descent of the font, specified as a 26.6 fixed point value.
+ \value Leading The leading of the font, specified as a 26.6 fixed point value.
+ \value XHeight The 'x' height of the font, specified as a 26.6 fixed point value.
+ \value AverageCharWidth The average character width of the font, specified as a 26.6 fixed point value.
+ \value LineThickness The thickness of the underline and strikeout lines for the font, specified as a 26.6 fixed point value.
+ \value UnderlinePosition The distance from the base line to the underline position for the font, specified as a 26.6 fixed point value.
+ \value MaxCharWidth The width of the widest character in the font, specified as a 26.6 fixed point value.
+ \value MinLeftBearing The minimum left bearing of the font, specified as a 26.6 fixed point value.
+ \value MinRightBearing The maximum right bearing of the font, specified as a 26.6 fixed point value.
+ \value GlyphCount The number of glyphs in the font, specified as an integer value.
+ \value CacheGlyphsHint A boolean value specifying whether rendered glyphs should be cached by Qt.
+ \value OutlineGlyphsHint A boolean value specifying whether the font engine prefers outline drawing over image rendering for uncached glyphs.
+*/
+
+/*!
+ \enum QAbstractFontEngine::TextShapingFlag
+
+ This enum describes flags controlling conversion of characters to glyphs and their metrics.
+
+ \value RightToLeft The text is used in a right-to-left context.
+ \value ReturnDesignMetrics Return font design metrics instead of pixel metrics.
+*/
+
+/*!
+ \typedef QAbstractFontEngine::Fixed
+
+ This type is \c int, interpreted as a 26.6 fixed point value.
+*/
+
+/*!
+ \class QAbstractFontEngine::GlyphMetrics
+ \brief QAbstractFontEngine::GlyphMetrics defines the metrics of a single glyph.
+ \preliminary
+ \since 4.3
+*/
+
+/*!
+ \variable QAbstractFontEngine::GlyphMetrics::x
+
+ The horizontal offset from the origin.
+*/
+
+/*!
+ \fn QAbstractFontEngine::GlyphMetrics::GlyphMetrics()
+
+ Constructs an empty glyph metrics object with all values
+ set to zero.
+*/
+
+/*!
+ \variable QAbstractFontEngine::GlyphMetrics::y
+
+ The vertical offset from the origin (baseline).
+*/
+
+/*!
+ \variable QAbstractFontEngine::GlyphMetrics::width
+
+ The width of the glyph.
+*/
+
+/*!
+ \variable QAbstractFontEngine::GlyphMetrics::height
+
+ The height of the glyph.
+*/
+
+/*!
+ \variable QAbstractFontEngine::GlyphMetrics::advance
+
+ The advance of the glyph.
+*/
+
+/*!
+ \class QAbstractFontEngine::FixedPoint
+ \brief QAbstractFontEngine::FixedPoint defines a point in the place using 26.6 fixed point precision.
+ \preliminary
+ \since 4.3
+*/
+
+/*!
+ \variable QAbstractFontEngine::FixedPoint::x
+
+ The x coordinate of this point.
+*/
+
+/*!
+ \variable QAbstractFontEngine::FixedPoint::y
+
+ The y coordinate of this point.
+*/
+
+/*!
+ Constructs a new QAbstractFontEngine with the given \a parent.
+*/
+QAbstractFontEngine::QAbstractFontEngine(QObject *parent)
+ : QObject(*new QAbstractFontEnginePrivate, parent)
+{
+}
+
+/*!
+ Destroys this QAbstractFontEngine object.
+*/
+QAbstractFontEngine::~QAbstractFontEngine()
+{
+}
+
+/*!
+ \fn QAbstractFontEngine::Capabilities QAbstractFontEngine::capabilities() const
+
+ Implemented in subclasses to specify the font engine's capabilities. The return value
+ may be cached by the caller and is expected not to change during the lifetime of the
+ font engine.
+*/
+
+/*!
+ \fn QVariant QAbstractFontEngine::fontProperty(FontProperty property) const
+
+ Implemented in subclasses to return the value of the font attribute \a property. The return
+ value may be cached by the caller and is expected not to change during the lifetime of the font
+ engine.
+*/
+
+/*!
+ \fn bool QAbstractFontEngine::convertStringToGlyphIndices(const QChar *string, int length, uint *glyphs, int *numGlyphs, TextShapingFlags flags) const
+
+ Implemented in subclasses to convert the characters specified by \a string and \a length to
+ glyph indicies, using \a flags. The glyph indicies should be returned in the \a glyphs array
+ provided by the caller. The maximum size of \a glyphs is specified by the value pointed to by \a
+ numGlyphs. If successful, the subclass implementation sets the value pointed to by \a numGlyphs
+ to the actual number of glyph indices generated, and returns true. Otherwise, e.g. if there is
+ not enough space in the provided \a glyphs array, it should set \a numGlyphs to the number of
+ glyphs needed for the conversion and return false.
+*/
+
+/*!
+ \fn void QAbstractFontEngine::getGlyphAdvances(const uint *glyphs, int numGlyphs, Fixed *advances, TextShapingFlags flags) const
+
+ Implemented in subclasses to retrieve the advances of the array specified by \a glyphs and \a
+ numGlyphs, using \a flags. The result is returned in \a advances, which is allocated by the
+ caller and contains \a numGlyphs elements.
+*/
+
+/*!
+ \fn QAbstractFontEngine::GlyphMetrics QAbstractFontEngine::glyphMetrics(uint glyph) const
+
+ Implemented in subclass to return the metrics for \a glyph.
+*/
+
+/*!
+ Implemented in subclasses to render the specified \a glyph into a \a buffer with the given \a depth ,
+ \a bytesPerLine and \a height.
+
+ Returns true if rendering succeeded, false otherwise.
+*/
+bool QAbstractFontEngine::renderGlyph(uint glyph, int depth, int bytesPerLine, int height, uchar *buffer)
+{
+ Q_UNUSED(glyph)
+ Q_UNUSED(depth)
+ Q_UNUSED(bytesPerLine)
+ Q_UNUSED(height)
+ Q_UNUSED(buffer)
+ qWarning("QAbstractFontEngine: renderGlyph is not implemented in font plugin!");
+ return false;
+}
+
+/*!
+ Implemented in subclasses to add the outline of the glyphs specified by \a glyphs and \a
+ numGlyphs at the specified \a positions to the painter path \a path.
+*/
+void QAbstractFontEngine::addGlyphOutlinesToPath(uint *glyphs, int numGlyphs, FixedPoint *positions, QPainterPath *path)
+{
+ Q_UNUSED(glyphs)
+ Q_UNUSED(numGlyphs)
+ Q_UNUSED(positions)
+ Q_UNUSED(path)
+ qWarning("QAbstractFontEngine: addGlyphOutlinesToPath is not implemented in font plugin!");
+}
+
+/*
+bool QAbstractFontEngine::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension)
+ return false;
+}
+
+QVariant QAbstractFontEngine::extension(Extension extension, const QVariant &argument)
+{
+ Q_UNUSED(argument)
+ Q_UNUSED(extension)
+ return QVariant();
+}
+*/
+
+QProxyFontEngine::QProxyFontEngine(QAbstractFontEngine *customEngine, const QFontDef &def)
+ : engine(customEngine)
+{
+ fontDef = def;
+ engineCapabilities = engine->capabilities();
+}
+
+QProxyFontEngine::~QProxyFontEngine()
+{
+ delete engine;
+}
+
+bool QProxyFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
+{
+ if (*nglyphs < len) {
+ *nglyphs = len;
+ return false;
+ }
+
+ QVarLengthArray<uint> glyphIndicies(*nglyphs);
+ if (!engine->convertStringToGlyphIndices(str, len, glyphIndicies.data(), nglyphs, QAbstractFontEngine::TextShapingFlags(int(flags))))
+ return false;
+
+ // ### use memcopy instead
+ for (int i = 0; i < *nglyphs; ++i) {
+ glyphs->glyphs[i] = glyphIndicies[i];
+ }
+ glyphs->numGlyphs = *nglyphs;
+
+ recalcAdvances(glyphs, flags);
+ return true;
+}
+
+void QProxyFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
+{
+ const int nglyphs = glyphs->numGlyphs;
+
+ QVarLengthArray<QAbstractFontEngine::Fixed> advances(nglyphs);
+ engine->getGlyphAdvances(glyphs->glyphs, nglyphs, advances.data(), QAbstractFontEngine::TextShapingFlags(int(flags)));
+
+
+ // ### use memcopy instead
+ for (int i = 0; i < nglyphs; ++i) {
+ glyphs->advances_x[i] = QFixed::fromFixed(advances[i]);
+ glyphs->advances_y[i] = 0;
+ }
+}
+
+
+static QImage alphaMapFromPath(QFontEngine *fe, glyph_t glyph)
+{
+ glyph_metrics_t gm = fe->boundingBox(glyph);
+ int glyph_x = qFloor(gm.x.toReal());
+ int glyph_y = qFloor(gm.y.toReal());
+ int glyph_width = qCeil((gm.x + gm.width).toReal()) - glyph_x;
+ int glyph_height = qCeil((gm.y + gm.height).toReal()) - glyph_y;
+
+ if (glyph_width <= 0 || glyph_height <= 0)
+ return QImage();
+ QFixedPoint pt;
+ pt.x = 0;
+ pt.y = -glyph_y; // the baseline
+ QPainterPath path;
+ QImage im(glyph_width + qAbs(glyph_x) + 4, glyph_height, QImage::Format_ARGB32_Premultiplied);
+ im.fill(Qt::transparent);
+ QPainter p(&im);
+ p.setRenderHint(QPainter::Antialiasing);
+ fe->addGlyphsToPath(&glyph, &pt, 1, &path, 0);
+ p.setPen(Qt::NoPen);
+ p.setBrush(Qt::black);
+ p.drawPath(path);
+ p.end();
+
+ QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
+ QVector<QRgb> colors(256);
+ for (int i=0; i<256; ++i)
+ colors[i] = qRgba(0, 0, 0, i);
+ indexed.setColorTable(colors);
+
+ for (int y=0; y<im.height(); ++y) {
+ uchar *dst = (uchar *) indexed.scanLine(y);
+ uint *src = (uint *) im.scanLine(y);
+ for (int x=0; x<im.width(); ++x)
+ dst[x] = qAlpha(src[x]);
+ }
+
+ return indexed;
+}
+
+
+QImage QProxyFontEngine::alphaMapForGlyph(glyph_t glyph)
+{
+ if (!(engineCapabilities & QAbstractFontEngine::CanRenderGlyphs_Gray))
+ return alphaMapFromPath(this, glyph);
+
+ QAbstractFontEngine::GlyphMetrics metrics = engine->glyphMetrics(glyph);
+ if (metrics.width <= 0 || metrics.height <= 0)
+ return QImage();
+
+ QImage img(metrics.width >> 6, metrics.height >> 6, QImage::Format_Indexed8);
+
+ // ### we should have QImage::Format_GrayScale8
+ static QVector<QRgb> colorMap;
+ if (colorMap.isEmpty()) {
+ colorMap.resize(256);
+ for (int i=0; i<256; ++i)
+ colorMap[i] = qRgba(0, 0, 0, i);
+ }
+
+ img.setColorTable(colorMap);
+
+ engine->renderGlyph(glyph, /*depth*/8, img.bytesPerLine(), img.height(), img.bits());
+
+ return img;
+}
+
+void QProxyFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags)
+{
+ if (engineCapabilities & QAbstractFontEngine::CanOutlineGlyphs)
+ engine->addGlyphOutlinesToPath(glyphs, nglyphs, reinterpret_cast<QAbstractFontEngine::FixedPoint *>(positions), path);
+ else
+ QFontEngine::addGlyphsToPath(glyphs, positions, nglyphs, path, flags);
+}
+
+glyph_metrics_t QProxyFontEngine::boundingBox(const QGlyphLayout &glyphs)
+{
+ if (glyphs.numGlyphs == 0)
+ return glyph_metrics_t();
+
+ QFixed w = 0;
+ for (int i = 0; i < glyphs.numGlyphs; ++i)
+ w += glyphs.effectiveAdvance(i);
+
+ return glyph_metrics_t(0, -ascent(), w, ascent() + descent(), w, 0);
+}
+
+glyph_metrics_t QProxyFontEngine::boundingBox(glyph_t glyph)
+{
+ glyph_metrics_t m;
+
+ QAbstractFontEngine::GlyphMetrics metrics = engine->glyphMetrics(glyph);
+ m.x = QFixed::fromFixed(metrics.x);
+ m.y = QFixed::fromFixed(metrics.y);
+ m.width = QFixed::fromFixed(metrics.width);
+ m.height = QFixed::fromFixed(metrics.height);
+ m.xoff = QFixed::fromFixed(metrics.advance);
+
+ return m;
+}
+
+QFixed QProxyFontEngine::ascent() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::Ascent).toInt());
+}
+
+QFixed QProxyFontEngine::descent() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::Descent).toInt());
+}
+
+QFixed QProxyFontEngine::leading() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::Leading).toInt());
+}
+
+QFixed QProxyFontEngine::xHeight() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::XHeight).toInt());
+}
+
+QFixed QProxyFontEngine::averageCharWidth() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::AverageCharWidth).toInt());
+}
+
+QFixed QProxyFontEngine::lineThickness() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::LineThickness).toInt());
+}
+
+QFixed QProxyFontEngine::underlinePosition() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::UnderlinePosition).toInt());
+}
+
+qreal QProxyFontEngine::maxCharWidth() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::MaxCharWidth).toInt()).toReal();
+}
+
+qreal QProxyFontEngine::minLeftBearing() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::MinLeftBearing).toInt()).toReal();
+}
+
+qreal QProxyFontEngine::minRightBearing() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::MinRightBearing).toInt()).toReal();
+}
+
+int QProxyFontEngine::glyphCount() const
+{
+ return engine->fontProperty(QAbstractFontEngine::GlyphCount).toInt();
+}
+
+bool QProxyFontEngine::canRender(const QChar *string, int len)
+{
+ QVarLengthArray<uint> glyphs(len);
+ int numGlyphs = len;
+
+ if (!engine->convertStringToGlyphIndices(string, len, glyphs.data(), &numGlyphs, /*flags*/0))
+ return false;
+
+ for (int i = 0; i < numGlyphs; ++i)
+ if (!glyphs[i])
+ return false;
+
+ return true;
+}
+
+void QProxyFontEngine::draw(QPaintEngine *p, qreal _x, qreal _y, const QTextItemInt &si)
+{
+
+}
+
+/*
+ * This is only called when we use the proxy fontengine directly (without sharing the rendered
+ * glyphs). So we prefer outline rendering over rendering of unshared glyphs. That decision is
+ * done in qfontdatabase_qws.cpp by looking at the ShareGlyphsHint and the pixel size of the font.
+ */
+bool QProxyFontEngine::drawAsOutline() const
+{
+ if (!(engineCapabilities & QAbstractFontEngine::CanOutlineGlyphs))
+ return false;
+
+ QVariant outlineHint = engine->fontProperty(QAbstractFontEngine::OutlineGlyphsHint);
+ return !outlineHint.isValid() || outlineHint.toBool();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qabstractfontengine_wayland.h b/src/gui/text/qabstractfontengine_wayland.h
new file mode 100644
index 0000000000..b2eadd94a1
--- /dev/null
+++ b/src/gui/text/qabstractfontengine_wayland.h
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTFONTENGINE_QWS_H
+#define QABSTRACTFONTENGINE_QWS_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qfactoryinterface.h>
+#include <QtGui/qpaintengine.h>
+#include <QtGui/qfontdatabase.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QFontEngineInfoPrivate;
+
+class Q_GUI_EXPORT QFontEngineInfo
+{
+public:
+ QDOC_PROPERTY(QString family READ family WRITE setFamily)
+ QDOC_PROPERTY(qreal pixelSize READ pixelSize WRITE setPixelSize)
+ QDOC_PROPERTY(int weight READ weight WRITE setWeight)
+ QDOC_PROPERTY(QFont::Style style READ style WRITE setStyle)
+ QDOC_PROPERTY(QList<QFontDatabase::WritingSystem> writingSystems READ writingSystems WRITE setWritingSystems)
+
+ QFontEngineInfo();
+ explicit QFontEngineInfo(const QString &family);
+ QFontEngineInfo(const QFontEngineInfo &other);
+ QFontEngineInfo &operator=(const QFontEngineInfo &other);
+ ~QFontEngineInfo();
+
+ void setFamily(const QString &name);
+ QString family() const;
+
+ void setPixelSize(qreal size);
+ qreal pixelSize() const;
+
+ void setWeight(int weight);
+ int weight() const;
+
+ void setStyle(QFont::Style style);
+ QFont::Style style() const;
+
+ QList<QFontDatabase::WritingSystem> writingSystems() const;
+ void setWritingSystems(const QList<QFontDatabase::WritingSystem> &writingSystems);
+
+private:
+ QFontEngineInfoPrivate *d;
+};
+
+class QAbstractFontEngine;
+
+struct Q_GUI_EXPORT QFontEngineFactoryInterface : public QFactoryInterface
+{
+ virtual QAbstractFontEngine *create(const QFontEngineInfo &info) = 0;
+ virtual QList<QFontEngineInfo> availableFontEngines() const = 0;
+};
+
+#define QFontEngineFactoryInterface_iid "com.trolltech.Qt.QFontEngineFactoryInterface"
+Q_DECLARE_INTERFACE(QFontEngineFactoryInterface, QFontEngineFactoryInterface_iid)
+
+class QFontEnginePluginPrivate;
+
+class Q_GUI_EXPORT QFontEnginePlugin : public QObject, public QFontEngineFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QFontEngineFactoryInterface:QFactoryInterface)
+public:
+ QFontEnginePlugin(const QString &foundry, QObject *parent = 0);
+ ~QFontEnginePlugin();
+
+ virtual QStringList keys() const;
+
+ virtual QAbstractFontEngine *create(const QFontEngineInfo &info) = 0;
+ virtual QList<QFontEngineInfo> availableFontEngines() const = 0;
+
+private:
+ Q_DECLARE_PRIVATE(QFontEnginePlugin)
+ Q_DISABLE_COPY(QFontEnginePlugin)
+};
+
+class QAbstractFontEnginePrivate;
+
+class Q_GUI_EXPORT QAbstractFontEngine : public QObject
+{
+ Q_OBJECT
+public:
+ enum Capability {
+ CanOutlineGlyphs = 1,
+ CanRenderGlyphs_Mono = 2,
+ CanRenderGlyphs_Gray = 4,
+ CanRenderGlyphs = CanRenderGlyphs_Mono | CanRenderGlyphs_Gray
+ };
+ Q_DECLARE_FLAGS(Capabilities, Capability)
+
+ explicit QAbstractFontEngine(QObject *parent = 0);
+ ~QAbstractFontEngine();
+
+ typedef int Fixed; // 26.6
+
+ struct FixedPoint
+ {
+ Fixed x;
+ Fixed y;
+ };
+
+ struct GlyphMetrics
+ {
+ inline GlyphMetrics()
+ : x(0), y(0), width(0), height(0),
+ advance(0) {}
+ Fixed x;
+ Fixed y;
+ Fixed width;
+ Fixed height;
+ Fixed advance;
+ };
+
+ enum FontProperty {
+ Ascent,
+ Descent,
+ Leading,
+ XHeight,
+ AverageCharWidth,
+ LineThickness,
+ UnderlinePosition,
+ MaxCharWidth,
+ MinLeftBearing,
+ MinRightBearing,
+ GlyphCount,
+
+ // hints
+ CacheGlyphsHint,
+ OutlineGlyphsHint
+ };
+
+ // keep in sync with QTextEngine::ShaperFlag!!
+ enum TextShapingFlag {
+ RightToLeft = 0x0001,
+ ReturnDesignMetrics = 0x0002
+ };
+ Q_DECLARE_FLAGS(TextShapingFlags, TextShapingFlag)
+
+ virtual Capabilities capabilities() const = 0;
+ virtual QVariant fontProperty(FontProperty property) const = 0;
+
+ virtual bool convertStringToGlyphIndices(const QChar *string, int length, uint *glyphs, int *numGlyphs, TextShapingFlags flags) const = 0;
+
+ virtual void getGlyphAdvances(const uint *glyphs, int numGlyphs, Fixed *advances, TextShapingFlags flags) const = 0;
+
+ virtual GlyphMetrics glyphMetrics(uint glyph) const = 0;
+
+ virtual bool renderGlyph(uint glyph, int depth, int bytesPerLine, int height, uchar *buffer);
+
+ virtual void addGlyphOutlinesToPath(uint *glyphs, int numGlyphs, FixedPoint *positions, QPainterPath *path);
+
+ /*
+ enum Extension {
+ GetTrueTypeTable
+ };
+
+ virtual bool supportsExtension(Extension extension) const;
+ virtual QVariant extension(Extension extension, const QVariant &argument = QVariant());
+ */
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractFontEngine)
+ Q_DISABLE_COPY(QAbstractFontEngine)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractFontEngine::Capabilities)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractFontEngine::TextShapingFlags)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h
index 6f624246b9..a952cf4c55 100644
--- a/src/gui/text/qfont.h
+++ b/src/gui/text/qfont.h
@@ -46,7 +46,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qsharedpointer.h>
-#if defined(Q_WS_X11) || defined(Q_WS_QWS)
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_WAYLAND)
typedef struct FT_FaceRec_* FT_Face;
#endif
@@ -233,7 +233,7 @@ public:
#ifdef Q_WS_MAC
quint32 macFontID() const;
#endif
-#if defined(Q_WS_X11) || defined(Q_WS_QWS)
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_WAYLAND)
FT_Face freetypeFace() const;
#endif
diff --git a/src/gui/text/qfont_wayland.cpp b/src/gui/text/qfont_wayland.cpp
new file mode 100644
index 0000000000..256de8447c
--- /dev/null
+++ b/src/gui/text/qfont_wayland.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define QT_FATAL_ASSERT
+
+#include "qplatformdefs.h"
+
+#include "qfont.h"
+#include "qapplication.h"
+#include "qfontinfo.h"
+#include "qfontdatabase.h"
+#include "qfontmetrics.h"
+#include "qpaintdevice.h"
+#include "qtextcodec.h"
+#include "qiodevice.h"
+#include "qhash.h"
+
+#include <private/qunicodetables_p.h>
+#include "qfont_p.h"
+#include "qfontengine_p.h"
+#include "qtextengine_p.h"
+
+#include <time.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define QFONTLOADER_DEBUG
+#define QFONTLOADER_DEBUG_VERBOSE
+
+QT_BEGIN_NAMESPACE
+
+void QFont::initialize()
+{
+}
+
+void QFont::cleanup()
+{
+ QFontCache::cleanup();
+}
+
+Qt::HANDLE QFont::handle() const
+{
+ return 0;
+}
+
+
+FT_Face QFont::freetypeFace() const
+{
+ return 0;
+}
+
+QString QFont::rawName() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ if (engine->type() == QFontEngine::Multi)
+ engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
+ if (engine->type() == QFontEngine::XLFD)
+ return QString::fromLatin1(engine->name());
+ return QString();
+}
+struct QtFontDesc;
+
+void QFont::setRawName(const QString &name)
+{
+ detach();
+}
+
+QString QFont::lastResortFamily() const
+{
+ return QString::fromLatin1("Helvetica");
+}
+
+QString QFont::defaultFamily() const
+{
+ switch (d->request.styleHint) {
+ case QFont::Times:
+ return QString::fromLatin1("Times");
+
+ case QFont::Courier:
+ return QString::fromLatin1("Courier");
+
+ case QFont::Decorative:
+ return QString::fromLatin1("Old English");
+
+ case QFont::Helvetica:
+ case QFont::System:
+ default:
+ return QString::fromLatin1("Helvetica");
+ }
+}
+
+/*
+ Returns a last resort raw font name for the font matching algorithm.
+ This is used if even the last resort family is not available. It
+ returns \e something, almost no matter what. The current
+ implementation tries a wide variety of common fonts, returning the
+ first one it finds. The implementation may change at any time.
+*/
+static const char * const tryFonts[] = {
+ "-*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*",
+ "-*-courier-medium-r-*-*-*-120-*-*-*-*-*-*",
+ "-*-times-medium-r-*-*-*-120-*-*-*-*-*-*",
+ "-*-lucida-medium-r-*-*-*-120-*-*-*-*-*-*",
+ "-*-helvetica-*-*-*-*-*-120-*-*-*-*-*-*",
+ "-*-courier-*-*-*-*-*-120-*-*-*-*-*-*",
+ "-*-times-*-*-*-*-*-120-*-*-*-*-*-*",
+ "-*-lucida-*-*-*-*-*-120-*-*-*-*-*-*",
+ "-*-helvetica-*-*-*-*-*-*-*-*-*-*-*-*",
+ "-*-courier-*-*-*-*-*-*-*-*-*-*-*-*",
+ "-*-times-*-*-*-*-*-*-*-*-*-*-*-*",
+ "-*-lucida-*-*-*-*-*-*-*-*-*-*-*-*",
+ "-*-fixed-*-*-*-*-*-*-*-*-*-*-*-*",
+ "6x13",
+ "7x13",
+ "8x13",
+ "9x15",
+ "fixed",
+ 0
+};
+
+// Returns true if the font exists, false otherwise
+static bool fontExists(const QString &fontName)
+{
+ return false;
+}
+
+QString QFont::lastResortFont() const
+{
+ static QString last;
+
+ // already found
+ if (! last.isNull())
+ return last;
+
+ int i = 0;
+ const char* f;
+
+ while ((f = tryFonts[i])) {
+ last = QString::fromLatin1(f);
+
+ if (fontExists(last))
+ return last;
+
+ i++;
+ }
+
+#if defined(CHECK_NULL)
+ qFatal("QFontPrivate::lastResortFont: Cannot find any reasonable font");
+#endif
+ return last;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index ff29462d3f..4cc90dcc9d 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -153,7 +153,7 @@ struct QtFontSize
QtFontEncoding *encodingID(int id, uint xpoint = 0, uint xres = 0,
uint yres = 0, uint avgwidth = 0, bool add = false);
#endif // Q_WS_X11
-#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) || defined(Q_WS_WAYLAND)
QByteArray fileName;
int fileIndex;
#endif // defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
@@ -255,7 +255,7 @@ struct QtFontStyle
const char *weightName;
const char *setwidthName;
#endif // Q_WS_X11
-#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) || defined(Q_WS_WAYLAND)
bool antialiased;
#endif
@@ -662,7 +662,7 @@ public:
bool loadFromCache(const QString &fontPath);
void addQPF2File(const QByteArray &file);
#endif // Q_WS_QWS
-#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)
+#if defined(Q_WS_QWS) || (defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WAYLAND)
void addFont(const QString &familyname, const char *foundryname, int weight,
bool italic, int pixelSize, const QByteArray &file, int fileIndex,
bool antialiased,
@@ -884,7 +884,7 @@ static const int scriptForWritingSystem[] = {
};
-#if defined Q_WS_QWS || (defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)) || defined(Q_WS_WIN)
+#if defined Q_WS_QWS || (defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)) || defined(Q_WS_WIN) || defined(Q_WS_WAYLAND)
static inline bool requiresOpenType(int writingSystem)
{
return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala)
@@ -1050,6 +1050,8 @@ QT_BEGIN_INCLUDE_NAMESPACE
# include "qfontdatabase_qws.cpp"
#elif defined(Q_OS_SYMBIAN)
# include "qfontdatabase_s60.cpp"
+#elif defined(Q_WS_WAYLAND)
+# include "qfontdatabase_wayland.cpp"
#endif
QT_END_INCLUDE_NAMESPACE
diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h
index 719242cb60..e00658fcc1 100644
--- a/src/gui/text/qfontdatabase.h
+++ b/src/gui/text/qfontdatabase.h
@@ -152,7 +152,7 @@ public:
private:
static void createDatabase();
static void parseFontName(const QString &name, QString &foundry, QString &family);
-#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) || defined(Q_WS_WAYLAND)
static QFontEngine *findFont(int script, const QFontPrivate *fp, const QFontDef &request);
#endif
static void load(const QFontPrivate *d, int script);
diff --git a/src/gui/text/qfontdatabase_wayland.cpp b/src/gui/text/qfontdatabase_wayland.cpp
new file mode 100644
index 0000000000..f2e396f3ea
--- /dev/null
+++ b/src/gui/text/qfontdatabase_wayland.cpp
@@ -0,0 +1,662 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdir.h"
+#include "qlibraryinfo.h"
+#include "qabstractfileengine.h"
+#include <QtCore/qsettings.h>
+#include "qfontengine_ft_p.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include "private/qfactoryloader_p.h"
+#include "private/qcore_unix_p.h" // overrides QT_OPEN
+#include "qabstractfontengine_wayland.h"
+#include "qabstractfontengine_p.h"
+#include <qdatetime.h>
+#include "qplatformdefs.h"
+
+// for mmap
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+
+class QFontEngineFT;
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QFontEngineFactoryInterface_iid, QLatin1String("/fontengines"), Qt::CaseInsensitive))
+#endif
+
+const quint8 DatabaseVersion = 4;
+
+// QFontDatabasePrivate::addFont() went into qfontdatabase.cpp
+
+// QFontDatabasePrivate::addTTFile() went into qfontdatabase.cpp
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
+
+extern QString qws_fontCacheDir();
+
+/*!
+ \internal
+*/
+
+static QString qwsFontPath()
+{
+ QString fontpath = QString::fromLocal8Bit(qgetenv("QT_QWS_FONTDIR"));
+ if (fontpath.isEmpty()) {
+#ifdef QT_FONTS_ARE_RESOURCES
+ fontpath = QLatin1String(":/qt/fonts");
+#else
+#ifndef QT_NO_SETTINGS
+ fontpath = QLibraryInfo::location(QLibraryInfo::LibrariesPath);
+ fontpath += QLatin1String("/fonts");
+#else
+ fontpath = QLatin1String("/lib/fonts");
+#endif
+#endif //QT_FONTS_ARE_RESOURCES
+ }
+
+ return fontpath;
+}
+
+#if defined(QFONTDATABASE_DEBUG) && defined(QT_FONTS_ARE_RESOURCES)
+class FriendlyResource : public QResource
+{
+public:
+ bool isDir () const { return QResource::isDir(); }
+ bool isFile () const { return QResource::isFile(); }
+ QStringList children () const { return QResource::children(); }
+};
+#endif
+/*!
+ \internal
+*/
+static void initializeDb()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if (!db || db->count)
+ return;
+
+ QString fontpath = qwsFontPath();
+#ifndef QT_FONTS_ARE_RESOURCES
+ QString fontDirFile = fontpath + QLatin1String("/fontdir");
+
+ if(!QFile::exists(fontpath)) {
+ qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
+ fontpath.toLocal8Bit().constData());
+ }
+
+ if (db->reregisterAppFonts) {
+ db->reregisterAppFonts = false;
+ for (int i = 0; i < db->applicationFonts.count(); ++i)
+ if (!db->applicationFonts.at(i).families.isEmpty()) {
+ registerFont(&db->applicationFonts[i]);
+ }
+ }
+
+ QString dbFileName = qws_fontCacheDir() + QLatin1String("/fontdb");
+
+ QFile binaryDb(dbFileName + QLatin1String(".tmp"));
+ binaryDb.open(QIODevice::WriteOnly | QIODevice::Truncate);
+
+ // Load in font definition file
+ FILE* fontdef=fopen(fontDirFile.toLocal8Bit().constData(),"r");
+ if (fontdef) {
+ char buf[200]="";
+ char name[200]="";
+ char render[200]="";
+ char file[200]="";
+ char isitalic[10]="";
+ char flags[10]="";
+ do {
+ fgets(buf,200,fontdef);
+ if (buf[0] != '#') {
+ int weight=50;
+ int size=0;
+ sscanf(buf,"%s %s %s %s %d %d %s",name,file,render,isitalic,&weight,&size,flags);
+ QString filename;
+ if (file[0] != '/')
+ filename.append(fontpath).append(QLatin1Char('/'));
+ filename += QLatin1String(file);
+ bool italic = isitalic[0] == 'y';
+ bool smooth = QByteArray(flags).contains('s');
+ }
+ } while (!feof(fontdef));
+ fclose(fontdef);
+ }
+
+
+ QDir dir(fontpath, QLatin1String("*.qpf"));
+ for (int i=0; i<int(dir.count()); i++) {
+ int u0 = dir[i].indexOf(QLatin1Char('_'));
+ int u1 = dir[i].indexOf(QLatin1Char('_'), u0+1);
+ int u2 = dir[i].indexOf(QLatin1Char('_'), u1+1);
+ int u3 = dir[i].indexOf(QLatin1Char('.'), u1+1);
+ if (u2 < 0) u2 = u3;
+
+ QString familyname = dir[i].left(u0);
+ int pixelSize = dir[i].mid(u0+1,u1-u0-1).toInt()/10;
+ bool italic = dir[i].mid(u2-1,1) == QLatin1String("i");
+ int weight = dir[i].mid(u1+1,u2-u1-1-(italic?1:0)).toInt();
+ }
+
+#ifndef QT_NO_FREETYPE
+ dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
+ << QLatin1String("*.ttc") << QLatin1String("*.pfa")
+ << QLatin1String("*.pfb"));
+ dir.refresh();
+ for (int i = 0; i < int(dir.count()); ++i) {
+ const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
+// qDebug() << "looking at" << file;
+ db->addTTFile(file);
+ }
+#endif
+
+#else //QT_FONTS_ARE_RESOURCES
+#ifdef QFONTDATABASE_DEBUG
+ {
+ QResource fontdir(fontpath);
+ FriendlyResource *fr = static_cast<FriendlyResource*>(&fontdir);
+ qDebug() << "fontdir" << fr->isValid() << fr->isDir() << fr->children();
+
+ }
+#endif
+ QDir dir(fontpath, QLatin1String("*.qpf2"));
+ for (int i = 0; i < int(dir.count()); ++i) {
+ const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
+ //qDebug() << "looking at" << file;
+ db->addQPF2File(file);
+ }
+#endif //QT_FONTS_ARE_RESOURCES
+
+
+#ifdef QFONTDATABASE_DEBUG
+ // print the database
+ for (int f = 0; f < db->count; f++) {
+ QtFontFamily *family = db->families[f];
+ FD_DEBUG("'%s' %s", qPrintable(family->name), (family->fixedPitch ? "fixed" : ""));
+#if 0
+ for (int i = 0; i < QFont::LastPrivateScript; ++i) {
+ FD_DEBUG("\t%s: %s", qPrintable(QFontDatabase::scriptName((QFont::Script) i)),
+ ((family->scripts[i] & QtFontFamily::Supported) ? "Supported" :
+ (family->scripts[i] & QtFontFamily::UnSupported) == QtFontFamily::UnSupported ?
+ "UnSupported" : "Unknown"));
+ }
+#endif
+
+ for (int fd = 0; fd < family->count; fd++) {
+ QtFontFoundry *foundry = family->foundries[fd];
+ FD_DEBUG("\t\t'%s'", qPrintable(foundry->name));
+ for (int s = 0; s < foundry->count; s++) {
+ QtFontStyle *style = foundry->styles[s];
+ FD_DEBUG("\t\t\tstyle: style=%d weight=%d\n"
+ "\t\t\tstretch=%d",
+ style->key.style, style->key.weight,
+ style->key.stretch);
+ if (style->smoothScalable)
+ FD_DEBUG("\t\t\t\tsmooth scalable");
+ else if (style->bitmapScalable)
+ FD_DEBUG("\t\t\t\tbitmap scalable");
+ if (style->pixelSizes) {
+ FD_DEBUG("\t\t\t\t%d pixel sizes", style->count);
+ for (int z = 0; z < style->count; ++z) {
+ QtFontSize *size = style->pixelSizes + z;
+ FD_DEBUG("\t\t\t\t size %5d",
+ size->pixelSize);
+ }
+ }
+ }
+ }
+ }
+#endif // QFONTDATABASE_DEBUG
+
+#ifndef QT_NO_LIBRARY
+ QStringList pluginFoundries = loader()->keys();
+// qDebug() << "plugin foundries:" << pluginFoundries;
+ for (int i = 0; i < pluginFoundries.count(); ++i) {
+ const QString foundry(pluginFoundries.at(i));
+
+ QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry));
+ if (!factory) {
+ qDebug() << "Could not load plugin for foundry" << foundry;
+ continue;
+ }
+
+ QList<QFontEngineInfo> fonts = factory->availableFontEngines();
+ for (int i = 0; i < fonts.count(); ++i) {
+ QFontEngineInfo info = fonts.at(i);
+
+ int weight = info.weight();
+ if (weight <= 0)
+ weight = QFont::Normal;
+
+ db->addFont(info.family(), foundry.toLatin1().constData(),
+ weight, info.style() != QFont::StyleNormal,
+ qRound(info.pixelSize()), /*file*/QByteArray(),
+ /*fileIndex*/0, /*antiAliased*/true,
+ info.writingSystems());
+ }
+ }
+#endif
+
+ {
+ bool coveredWritingSystems[QFontDatabase::WritingSystemsCount] = { 0 };
+
+ for (int i = 0; i < db->count; ++i) {
+ QtFontFamily *family = db->families[i];
+ bool add = false;
+ if (family->count == 0)
+ continue;
+ for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
+ if (coveredWritingSystems[ws])
+ continue;
+ if (family->writingSystems[ws] & QtFontFamily::Supported) {
+ coveredWritingSystems[ws] = true;
+ add = true;
+ }
+ }
+ }
+ }
+}
+
+// called from qwindowsystem_qws.cpp
+void qt_qws_init_fontdb()
+{
+ initializeDb();
+}
+
+#ifndef QT_NO_SETTINGS
+// called from qapplication_qws.cpp
+void qt_applyFontDatabaseSettings(const QSettings &settings)
+{
+ initializeDb();
+ QFontDatabasePrivate *db = privateDb();
+}
+#endif // QT_NO_SETTINGS
+
+static inline void load(const QString & = QString(), int = -1)
+{
+ initializeDb();
+}
+
+#ifndef QT_NO_FREETYPE
+
+#if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
+#define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
+#define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
+#else
+#define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
+#define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
+#endif
+
+#endif // QT_NO_FREETYPE
+
+static
+QFontEngine *loadSingleEngine(int script, const QFontPrivate *fp,
+ const QFontDef &request,
+ QtFontFamily *family, QtFontFoundry *foundry,
+ QtFontStyle *style, QtFontSize *size)
+{
+ Q_UNUSED(script);
+ Q_UNUSED(fp);
+ Q_UNUSED(family);
+ Q_ASSERT(size);
+
+ int pixelSize = size->pixelSize;
+ if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE))
+ pixelSize = request.pixelSize;
+
+ int f = ::open(size->fileName, O_RDONLY, 0);
+ if (f >= 0) {
+ qDebug() << "fontengine is not valid!";
+ }
+ if ( foundry->name != QLatin1String("qt") ) { ///#### is this the best way????
+ QFontDef def = request;
+ def.pixelSize = pixelSize;
+
+ QScopedPointer<QFontEngine> engine;
+
+#ifndef QT_NO_LIBRARY
+ QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry->name));
+ if (factory) {
+ QFontEngineInfo info;
+ info.setFamily(request.family);
+ info.setPixelSize(request.pixelSize);
+ info.setStyle(QFont::Style(request.style));
+ info.setWeight(request.weight);
+ // #### antialiased
+
+ QAbstractFontEngine *customEngine = factory->create(info);
+ if (customEngine) {
+ engine.reset(new QProxyFontEngine(customEngine, def));
+ }
+ }
+#endif // QT_NO_LIBRARY
+ if ((engine.isNull())) {
+ QFontEngine::FaceId faceId;
+ faceId.index = size->fileIndex;
+ }
+ if (!engine.isNull()) {
+ return engine.take();
+ }
+ } else
+ {
+ }
+ return new QFontEngineBox(pixelSize);
+}
+
+static
+QFontEngine *loadEngine(int script, const QFontPrivate *fp,
+ const QFontDef &request,
+ QtFontFamily *family, QtFontFoundry *foundry,
+ QtFontStyle *style, QtFontSize *size)
+{
+ QScopedPointer<QFontEngine> engine(loadSingleEngine(script, fp, request, family, foundry,
+ style, size));
+ if (!engine.isNull()
+ && script == QUnicodeTables::Common
+ && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
+
+ engine.take();
+ }
+ return engine.take();
+}
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
+{
+ QFontDatabasePrivate *db = privateDb();
+ db->reregisterAppFonts = true;
+}
+
+bool QFontDatabase::removeApplicationFont(int handle)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ if (handle < 0 || handle >= db->applicationFonts.count())
+ return false;
+
+ db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
+
+ db->reregisterAppFonts = true;
+ db->invalidate();
+ return true;
+}
+
+bool QFontDatabase::removeAllApplicationFonts()
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ if (db->applicationFonts.isEmpty())
+ return false;
+
+ db->applicationFonts.clear();
+ db->invalidate();
+ return true;
+}
+
+bool QFontDatabase::supportsThreadedFontRendering()
+{
+ return true;
+}
+
+/*!
+ \internal
+*/
+QFontEngine *
+QFontDatabase::findFont(int script, const QFontPrivate *fp,
+ const QFontDef &request)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ const int force_encoding_id = -1;
+
+ if (!privateDb()->count)
+ initializeDb();
+
+ QScopedPointer<QFontEngine> fe;
+ if (fp) {
+ if (fp->rawMode) {
+ fe.reset(loadEngine(script, fp, request, 0, 0, 0, 0));
+
+ // if we fail to load the rawmode font, use a 12pixel box engine instead
+ if (fe.isNull())
+ fe.reset(new QFontEngineBox(12));
+ return fe.take();
+ }
+
+ QFontCache::Key key(request, script);
+ fe.reset(QFontCache::instance()->findEngine(key));
+ if (! fe.isNull())
+ return fe.take();
+ }
+
+ QString family_name, foundry_name;
+ QtFontStyle::Key styleKey;
+ styleKey.style = request.style;
+ styleKey.weight = request.weight;
+ styleKey.stretch = request.stretch;
+ char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
+
+ parseFontName(request.family, foundry_name, family_name);
+
+ FM_DEBUG("QFontDatabase::findFont\n"
+ " request:\n"
+ " family: %s [%s], script: %d\n"
+ " weight: %d, style: %d\n"
+ " stretch: %d\n"
+ " pixelSize: %g\n"
+ " pitch: %c",
+ family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
+ foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
+ script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
+
+ if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
+ fe.reset(new QTestFontEngine(request.pixelSize));
+ fe->fontDef = request;
+ }
+
+ if (fe.isNull())
+ {
+ QtFontDesc desc;
+ match(script, request, family_name, foundry_name, force_encoding_id, &desc);
+
+ if (desc.family != 0 && desc.foundry != 0 && desc.style != 0
+ ) {
+ FM_DEBUG(" BEST:\n"
+ " family: %s [%s]\n"
+ " weight: %d, style: %d\n"
+ " stretch: %d\n"
+ " pixelSize: %d\n"
+ " pitch: %c\n"
+ " encoding: %d\n",
+ desc.family->name.toLatin1().constData(),
+ desc.foundry->name.isEmpty() ? "-- none --" : desc.foundry->name.toLatin1().constData(),
+ desc.style->key.weight, desc.style->key.style,
+ desc.style->key.stretch, desc.size ? desc.size->pixelSize : 0xffff,
+ 'p', 0
+ );
+
+ fe.reset(loadEngine(script, fp, request, desc.family, desc.foundry, desc.style, desc.size
+ ));
+ } else {
+ FM_DEBUG(" NO MATCH FOUND\n");
+ }
+ }
+
+#ifndef QT_NO_FREETYPE
+ if (! fe.isNull()) {
+ if (scriptRequiresOpenType(script) && fe->type() == QFontEngine::Freetype) {
+ HB_Face hbFace = static_cast<QFontEngineFT *>(fe.data())->harfbuzzFace();
+ if (!hbFace || !hbFace->supported_scripts[script]) {
+ FM_DEBUG(" OpenType support missing for script\n");
+ fe.reset(0);
+ }
+ }
+ }
+#endif
+
+ if (! fe.isNull()) {
+ if (fp) {
+ QFontDef def = request;
+ if (def.family.isEmpty()) {
+ def.family = fp->request.family;
+ def.family = def.family.left(def.family.indexOf(QLatin1Char(',')));
+ }
+ QFontCache::Key key(def, script);
+ QFontCache::instance()->insertEngine(key, fe.data());
+ }
+ }
+
+ if (fe.isNull()) {
+ if (!request.family.isEmpty())
+ return 0;
+
+ FM_DEBUG("returning box engine");
+
+ fe.reset(new QFontEngineBox(request.pixelSize));
+
+ if (fp) {
+ QFontCache::Key key(request, script);
+ QFontCache::instance()->insertEngine(key, fe.data());
+ }
+ }
+
+ if (fp && fp->dpi > 0) {
+ fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / fp->dpi));
+ } else {
+ fe->fontDef.pointSize = request.pointSize;
+ }
+
+ return fe.take();
+}
+
+void QFontDatabase::load(const QFontPrivate *d, int script)
+{
+ QFontDef req = d->request;
+
+ if (req.pixelSize == -1)
+ req.pixelSize = qRound(req.pointSize*d->dpi/72);
+ if (req.pointSize < 0)
+ req.pointSize = req.pixelSize*72.0/d->dpi;
+
+ if (!d->engineData) {
+ QFontCache::Key key(req, script);
+
+ // look for the requested font in the engine data cache
+ d->engineData = QFontCache::instance()->findEngineData(key);
+
+ if (!d->engineData) {
+ // create a new one
+ d->engineData = new QFontEngineData;
+ QT_TRY {
+ QFontCache::instance()->insertEngineData(key, d->engineData);
+ } QT_CATCH(...) {
+ delete d->engineData;
+ d->engineData = 0;
+ QT_RETHROW;
+ }
+ } else {
+ d->engineData->ref.ref();
+ }
+ }
+
+ // the cached engineData could have already loaded the engine we want
+ if (d->engineData->engines[script]) return;
+
+ // double scale = 1.0; // ### TODO: fix the scale calculations
+
+ // list of families to try
+ QStringList family_list;
+
+ if (!req.family.isEmpty()) {
+ family_list = req.family.split(QLatin1Char(','));
+
+ // append the substitute list for each family in family_list
+ QStringList subs_list;
+ QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
+ for (; it != end; ++it)
+ subs_list += QFont::substitutes(*it);
+ family_list += subs_list;
+
+ // append the default fallback font for the specified script
+ // family_list << ... ; ###########
+
+ // add the default family
+ QString defaultFamily = QApplication::font().family();
+ if (! family_list.contains(defaultFamily))
+ family_list << defaultFamily;
+
+ // add QFont::defaultFamily() to the list, for compatibility with
+ // previous versions
+ family_list << QApplication::font().defaultFamily();
+ }
+
+ // null family means find the first font matching the specified script
+ family_list << QString();
+
+ // load the font
+ QFontEngine *engine = 0;
+ QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
+ for (; !engine && it != end; ++it) {
+ req.family = *it;
+
+ engine = QFontDatabase::findFont(script, d, req);
+ if (engine && (engine->type()==QFontEngine::Box) && !req.family.isEmpty())
+ engine = 0;
+ }
+
+ engine->ref.ref();
+ d->engineData->engines[script] = engine;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 922acfb34c..9818189823 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -235,7 +235,7 @@ public:
bool symbol;
mutable HB_FontRec hbFont;
mutable HB_Face hbFace;
-#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) || defined(Q_WS_WAYLAND)
struct KernPair {
uint left_right;
QFixed adjust;
diff --git a/src/gui/text/qfontengine_wayland.cpp b/src/gui/text/qfontengine_wayland.cpp
new file mode 100644
index 0000000000..414ef8ebf0
--- /dev/null
+++ b/src/gui/text/qfontengine_wayland.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfontengine_p.h"
+#include <private/qunicodetables_p.h>
+#include <qwsdisplay_qws.h>
+#include <qvarlengtharray.h>
+#include <private/qpainter_p.h>
+#include <private/qpaintengine_raster_p.h>
+#include <private/qpdf_p.h>
+#include "qtextengine_p.h"
+#include "private/qcore_unix_p.h" // overrides QT_OPEN
+
+#include <qdebug.h>
+
+
+#ifndef QT_NO_QWS_QPF
+
+#include "qfile.h"
+#include "qdir.h"
+
+#define QT_USE_MMAP
+#include <stdlib.h>
+
+#ifdef QT_USE_MMAP
+// for mmap
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+
+# if defined(QT_LINUXBASE) && !defined(MAP_FILE)
+ // LSB 3.2 does not define MAP_FILE
+# define MAP_FILE 0
+# endif
+
+#endif
+
+#endif // QT_NO_QWS_QPF
+
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp
index e49f5b4554..22e2d7ec8c 100644
--- a/src/gui/text/qfontsubset.cpp
+++ b/src/gui/text/qfontsubset.cpp
@@ -50,7 +50,7 @@
#endif
#ifndef QT_NO_FREETYPE
-#if defined(Q_WS_X11) || defined(Q_WS_QWS)
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_WAYLAND)
# include "private/qfontengine_ft_p.h"
#endif
#include <ft2build.h>
diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri
index 9ec314299c..068a437319 100644
--- a/src/gui/text/text.pri
+++ b/src/gui/text/text.pri
@@ -129,6 +129,20 @@ symbian {
}
}
+wayland {
+ SOURCES += \
+ text/qfont_wayland.cpp \
+ text/qfontengine_wayland.cpp \
+ text/qfontengine_ft.cpp \
+ text/qabstractfontengine_wayland.cpp
+ HEADERS += \
+ text/qfontengine_ft_p.h \
+ text/qabstractfontengine_wayland.h \
+ text/qabstractfontengine_p.h
+ DEFINES += QT_NO_FONTCONFIG
+}
+
+
contains(QT_CONFIG, freetype) {
SOURCES += \
../3rdparty/freetype/src/base/ftbase.c \
diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp
index 8b36b32476..52bac8c8bf 100644
--- a/src/gui/util/qdesktopservices.cpp
+++ b/src/gui/util/qdesktopservices.cpp
@@ -55,6 +55,8 @@
#include "qdesktopservices_mac.cpp"
#elif defined(Q_OS_SYMBIAN)
#include "qdesktopservices_s60.cpp"
+#elif defined(Q_WS_WAYLAND)
+#include "qdesktopservices_wayland.cpp"
#endif
#include <qhash.h>
diff --git a/src/gui/util/qdesktopservices_wayland.cpp b/src/gui/util/qdesktopservices_wayland.cpp
new file mode 100644
index 0000000000..777dc05862
--- /dev/null
+++ b/src/gui/util/qdesktopservices_wayland.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qcoreapplication.h>
+#include <qdir.h>
+
+QT_BEGIN_NAMESPACE
+
+static bool launchWebBrowser(const QUrl &url)
+{
+ Q_UNUSED(url);
+ qWarning("QDesktopServices::launchWebBrowser not implemented");
+ return false;
+}
+
+static bool openDocument(const QUrl &file)
+{
+ Q_UNUSED(file);
+ qWarning("QDesktopServices::openDocument not implemented");
+ return false;
+}
+
+
+QString QDesktopServices::storageLocation(StandardLocation type)
+{
+ qWarning("QDesktopServices::storageLocation %d not implemented", type);
+ return QString();
+}
+
+QString QDesktopServices::displayName(StandardLocation type)
+{
+ Q_UNUSED(type);
+ qWarning("QDesktopServices::displayName not implemented");
+ return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qsystemtrayicon_wayland.cpp b/src/gui/util/qsystemtrayicon_wayland.cpp
new file mode 100644
index 0000000000..b1b895ba8c
--- /dev/null
+++ b/src/gui/util/qsystemtrayicon_wayland.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsystemtrayicon_p.h"
+
+#ifndef QT_NO_SYSTEMTRAYICON
+
+QT_BEGIN_NAMESPACE
+
+void QSystemTrayIconPrivate::install_sys()
+{
+}
+
+void QSystemTrayIconPrivate::remove_sys()
+{
+}
+
+QRect QSystemTrayIconPrivate::geometry_sys() const
+{
+ return QRect();
+}
+
+void QSystemTrayIconPrivate::updateIcon_sys()
+{
+}
+
+void QSystemTrayIconPrivate::updateMenu_sys()
+{
+}
+
+void QSystemTrayIconPrivate::updateToolTip_sys()
+{
+}
+
+bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys()
+{
+ return false;
+}
+
+void QSystemTrayIconPrivate::showMessage_sys(const QString &message,
+ const QString &title,
+ QSystemTrayIcon::MessageIcon icon,
+ int msecs)
+{
+ Q_UNUSED(message);
+ Q_UNUSED(title);
+ Q_UNUSED(icon);
+ Q_UNUSED(msecs);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SYSTEMTRAYICON
diff --git a/src/gui/util/util.pri b/src/gui/util/util.pri
index be8db93d39..f3ce448ee5 100644
--- a/src/gui/util/util.pri
+++ b/src/gui/util/util.pri
@@ -33,6 +33,11 @@ unix:x11 {
util/qsystemtrayicon_x11.cpp
}
+wayland {
+ SOURCHES += \
+ util/qsystemtrayicon_wayland.cpp
+}
+
embedded {
SOURCES += \
util/qsystemtrayicon_qws.cpp
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index d6011cf2f9..2d2ed15899 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -11,7 +11,7 @@ unix:QMAKE_PKGCONFIG_REQUIRES = QtCore QtGui
include(../qbase.pri)
-!win32:!embedded:!mac:CONFIG += x11
+!wayland:!win32:!embedded:!mac:CONFIG += x11
contains(QT_CONFIG, opengl):CONFIG += opengl
contains(QT_CONFIG, opengles1):CONFIG += opengles1
contains(QT_CONFIG, opengles2):CONFIG += opengles2
@@ -111,6 +111,40 @@ x11 {
LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
}
+wayland {
+ contains(QT_CONFIG, egl) {
+ SOURCES += qgl_waylandegl.cpp \
+ qglpixelbuffer_egl.cpp \
+ qgl_egl.cpp \
+ qpixmapdata_waylandgl_egl.cpp \
+ qwindowsurface_waylandgl.cpp
+
+ HEADERS += qgl_egl_p.h \
+ qpixmapdata_waylandgl_p.h \
+ qwindowsurface_waylandgl_p.h
+
+ } else {
+ SOURCES += qgl_wayland.cpp \
+ qglpixelbuffer_wayland.cpp
+ }
+
+ contains(QT_CONFIG, fontconfig) {
+ contains(QT_CONFIG, system-freetype) {
+ embedded:CONFIG += opentype
+ # pull in the proper freetype2 include directory
+ include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri)
+ LIBS_PRIVATE += -lfreetype
+ } else {
+ ### Note: how does this compile with a non-system freetype?
+ # This probably does not compile
+ }
+ } else {
+ DEFINES *= QT_NO_FREETYPE
+ }
+
+ LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
+}
+
mac {
OBJECTIVE_SOURCES += qgl_mac.mm \
qglpixelbuffer_mac.mm
diff --git a/src/opengl/qgl_wayland.cpp b/src/opengl/qgl_wayland.cpp
new file mode 100644
index 0000000000..d203646803
--- /dev/null
+++ b/src/opengl/qgl_wayland.cpp
@@ -0,0 +1,1815 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgl.h"
+#include "qgl_p.h"
+
+#include "qmap.h"
+#include "qapplication.h"
+#include "qcolormap.h"
+#include "qdesktopwidget.h"
+#include "qpixmap.h"
+#include "qhash.h"
+#include "qlibrary.h"
+#include "qdebug.h"
+#include <private/qfontengine_ft_p.h>
+#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
+#ifdef Q_OS_HPUX
+// for GLXPBuffer
+#include <private/qglpixelbuffer_p.h>
+#endif
+
+// We always define GLX_EXT_texture_from_pixmap ourselves because
+// we can't trust system headers to do it properly
+#define GLX_EXT_texture_from_pixmap 1
+
+#define INT8 dummy_INT8
+#define INT32 dummy_INT32
+#include <GL/glx.h>
+#undef INT8
+#undef INT32
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#ifdef Q_OS_VXWORS
+# ifdef open
+# undef open
+# endif
+# ifdef getpid
+# undef getpid
+# endif
+#endif // Q_OS_VXWORKS
+#include <X11/Xatom.h>
+
+#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
+#include <dlfcn.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern Drawable qt_x11Handle(const QPaintDevice *pd);
+extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
+
+#ifndef GLX_ARB_multisample
+#define GLX_SAMPLE_BUFFERS_ARB 100000
+#define GLX_SAMPLES_ARB 100001
+#endif
+
+#ifndef GLX_TEXTURE_2D_BIT_EXT
+#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
+#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
+#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
+#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1
+#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2
+#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3
+#define GLX_Y_INVERTED_EXT 0x20D4
+#define GLX_TEXTURE_FORMAT_EXT 0x20D5
+#define GLX_TEXTURE_TARGET_EXT 0x20D6
+#define GLX_MIPMAP_TEXTURE_EXT 0x20D7
+#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8
+#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9
+#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA
+#define GLX_TEXTURE_2D_EXT 0x20DC
+#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD
+#define GLX_FRONT_LEFT_EXT 0x20DE
+#endif
+
+/*
+ The qt_gl_choose_cmap function is internal and used by QGLWidget::setContext()
+ and GLX (not Windows). If the application can't find any sharable
+ colormaps, it must at least create as few colormaps as possible. The
+ dictionary solution below ensures only one colormap is created per visual.
+ Colormaps are also deleted when the application terminates.
+*/
+
+struct QCMapEntry {
+ QCMapEntry();
+ ~QCMapEntry();
+
+ Colormap cmap;
+ bool alloc;
+ XStandardColormap scmap;
+};
+
+QCMapEntry::QCMapEntry()
+{
+ cmap = 0;
+ alloc = false;
+ scmap.colormap = 0;
+}
+
+QCMapEntry::~QCMapEntry()
+{
+ if (alloc)
+ XFreeColormap(X11->display, cmap);
+}
+typedef QHash<int, QCMapEntry *> CMapEntryHash;
+typedef QHash<int, QMap<int, QRgb> > GLCMapHash;
+static bool mesa_gl = false;
+static bool first_time = true;
+
+static void cleanup_cmaps();
+
+struct QGLCMapCleanupHandler {
+ QGLCMapCleanupHandler() {
+ cmap_hash = new CMapEntryHash;
+ qglcmap_hash = new GLCMapHash;
+ }
+ ~QGLCMapCleanupHandler() {
+ delete cmap_hash;
+ delete qglcmap_hash;
+ }
+ CMapEntryHash *cmap_hash;
+ GLCMapHash *qglcmap_hash;
+};
+Q_GLOBAL_STATIC(QGLCMapCleanupHandler, cmap_handler)
+
+static void cleanup_cmaps()
+{
+ CMapEntryHash *hash = cmap_handler()->cmap_hash;
+ QHash<int, QCMapEntry *>::ConstIterator it = hash->constBegin();
+ while (it != hash->constEnd()) {
+ delete it.value();
+ ++it;
+ }
+
+ hash->clear();
+ cmap_handler()->qglcmap_hash->clear();
+}
+
+Colormap qt_gl_choose_cmap(Display *dpy, XVisualInfo *vi)
+{
+ if (first_time) {
+ const char *v = glXQueryServerString(dpy, vi->screen, GLX_VERSION);
+ if (v)
+ mesa_gl = (strstr(v, "Mesa") != 0);
+ first_time = false;
+ }
+
+ CMapEntryHash *hash = cmap_handler()->cmap_hash;
+ CMapEntryHash::ConstIterator it = hash->constFind((long) vi->visualid + (vi->screen * 256));
+ if (it != hash->constEnd())
+ return it.value()->cmap; // found colormap for visual
+
+ if (vi->visualid ==
+ XVisualIDFromVisual((Visual *) QX11Info::appVisual(vi->screen))) {
+ // qDebug("Using x11AppColormap");
+ return QX11Info::appColormap(vi->screen);
+ }
+
+ QCMapEntry *x = new QCMapEntry();
+
+ XStandardColormap *c;
+ int n, i;
+
+ // qDebug("Choosing cmap for vID %0x", vi->visualid);
+
+ if (mesa_gl) { // we're using MesaGL
+ Atom hp_cmaps = XInternAtom(dpy, "_HP_RGB_SMOOTH_MAP_LIST", true);
+ if (hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8) {
+ if (XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
+ hp_cmaps)) {
+ i = 0;
+ while (i < n && x->cmap == 0) {
+ if (c[i].visualid == vi->visual->visualid) {
+ x->cmap = c[i].colormap;
+ x->scmap = c[i];
+ //qDebug("Using HP_RGB scmap");
+
+ }
+ i++;
+ }
+ XFree((char *)c);
+ }
+ }
+ }
+ if (!x->cmap) {
+ if (XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
+ XA_RGB_DEFAULT_MAP)) {
+ for (int i = 0; i < n && x->cmap == 0; ++i) {
+ if (!c[i].red_max ||
+ !c[i].green_max ||
+ !c[i].blue_max ||
+ !c[i].red_mult ||
+ !c[i].green_mult ||
+ !c[i].blue_mult)
+ continue; // invalid stdcmap
+ if (c[i].visualid == vi->visualid) {
+ x->cmap = c[i].colormap;
+ x->scmap = c[i];
+ //qDebug("Using RGB_DEFAULT scmap");
+ }
+ }
+ XFree((char *)c);
+ }
+ }
+ if (!x->cmap) { // no shared cmap found
+ x->cmap = XCreateColormap(dpy, RootWindow(dpy,vi->screen), vi->visual,
+ AllocNone);
+ x->alloc = true;
+ // qDebug("Allocating cmap");
+ }
+
+ // colormap hash should be cleanup only when the QApplication dtor is called
+ if (hash->isEmpty())
+ qAddPostRoutine(cleanup_cmaps);
+
+ // associate cmap with visualid
+ hash->insert((long) vi->visualid + (vi->screen * 256), x);
+ return x->cmap;
+}
+
+struct QTransColor
+{
+ VisualID vis;
+ int screen;
+ long color;
+};
+
+static QVector<QTransColor> trans_colors;
+static int trans_colors_init = false;
+
+static void find_trans_colors()
+{
+ struct OverlayProp {
+ long visual;
+ long type;
+ long value;
+ long layer;
+ };
+
+ trans_colors_init = true;
+
+ Display* appDisplay = X11->display;
+
+ int scr;
+ int lastsize = 0;
+ for (scr = 0; scr < ScreenCount(appDisplay); scr++) {
+ QWidget* rootWin = QApplication::desktop()->screen(scr);
+ if (!rootWin)
+ return; // Should not happen
+ Atom overlayVisualsAtom = XInternAtom(appDisplay,
+ "SERVER_OVERLAY_VISUALS", True);
+ if (overlayVisualsAtom == XNone)
+ return; // Server has no overlays
+
+ Atom actualType;
+ int actualFormat;
+ ulong nItems;
+ ulong bytesAfter;
+ unsigned char *retval = 0;
+ int res = XGetWindowProperty(appDisplay, rootWin->winId(),
+ overlayVisualsAtom, 0, 10000, False,
+ overlayVisualsAtom, &actualType,
+ &actualFormat, &nItems, &bytesAfter,
+ &retval);
+
+ if (res != Success || actualType != overlayVisualsAtom
+ || actualFormat != 32 || nItems < 4 || !retval)
+ return; // Error reading property
+
+ OverlayProp *overlayProps = (OverlayProp *)retval;
+
+ int numProps = nItems / 4;
+ trans_colors.resize(lastsize + numProps);
+ int j = lastsize;
+ for (int i = 0; i < numProps; i++) {
+ if (overlayProps[i].type == 1) {
+ trans_colors[j].vis = (VisualID)overlayProps[i].visual;
+ trans_colors[j].screen = scr;
+ trans_colors[j].color = (int)overlayProps[i].value;
+ j++;
+ }
+ }
+ XFree(overlayProps);
+ lastsize = j;
+ trans_colors.resize(lastsize);
+ }
+}
+
+/*****************************************************************************
+ QGLFormat UNIX/GLX-specific code
+ *****************************************************************************/
+
+void* qglx_getProcAddress(const char* procName)
+{
+ // On systems where the GL driver is pluggable (like Mesa), we have to use
+ // the glXGetProcAddressARB extension to resolve other function pointers as
+ // the symbols wont be in the GL library, but rather in a plugin loaded by
+ // the GL library.
+ typedef void* (*qt_glXGetProcAddressARB)(const char *);
+ static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
+ static bool triedResolvingGlxGetProcAddress = false;
+ if (!triedResolvingGlxGetProcAddress) {
+ triedResolvingGlxGetProcAddress = true;
+ QGLExtensionMatcher extensions(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
+ if (extensions.match("GLX_ARB_get_proc_address")) {
+#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
+ void *handle = dlopen(NULL, RTLD_LAZY);
+ if (handle) {
+ glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB");
+ dlclose(handle);
+ }
+ if (!glXGetProcAddressARB)
+#endif
+ {
+#if !defined(QT_NO_LIBRARY)
+ extern const QString qt_gl_library_name();
+ QLibrary lib(qt_gl_library_name());
+ glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
+#endif
+ }
+ }
+ }
+
+ void *procAddress = 0;
+ if (glXGetProcAddressARB)
+ procAddress = glXGetProcAddressARB(procName);
+
+ // If glXGetProcAddress didn't work, try looking the symbol up in the GL library
+#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
+ if (!procAddress) {
+ void *handle = dlopen(NULL, RTLD_LAZY);
+ if (handle) {
+ procAddress = dlsym(handle, procName);
+ dlclose(handle);
+ }
+ }
+#endif
+#if !defined(QT_NO_LIBRARY)
+ if (!procAddress) {
+ extern const QString qt_gl_library_name();
+ QLibrary lib(qt_gl_library_name());
+ procAddress = lib.resolve(procName);
+ }
+#endif
+
+ return procAddress;
+}
+
+bool QGLFormat::hasOpenGL()
+{
+ return glXQueryExtension(X11->display, 0, 0) != 0;
+}
+
+
+bool QGLFormat::hasOpenGLOverlays()
+{
+ if (!trans_colors_init)
+ find_trans_colors();
+ return trans_colors.size() > 0;
+}
+
+/*****************************************************************************
+ QGLContext UNIX/GLX-specific code
+ *****************************************************************************/
+
+bool QGLContext::chooseContext(const QGLContext* shareContext)
+{
+ Q_D(QGLContext);
+ const QX11Info *xinfo = qt_x11Info(d->paintDevice);
+
+ Display* disp = xinfo->display();
+ d->vi = chooseVisual();
+ if (!d->vi)
+ return false;
+
+ if (deviceIsPixmap() &&
+ (((XVisualInfo*)d->vi)->depth != xinfo->depth() ||
+ ((XVisualInfo*)d->vi)->screen != xinfo->screen()))
+ {
+ XFree(d->vi);
+ XVisualInfo appVisInfo;
+ memset(&appVisInfo, 0, sizeof(XVisualInfo));
+ appVisInfo.visualid = XVisualIDFromVisual((Visual *) xinfo->visual());
+ appVisInfo.screen = xinfo->screen();
+ int nvis;
+ d->vi = XGetVisualInfo(disp, VisualIDMask | VisualScreenMask, &appVisInfo, &nvis);
+ if (!d->vi)
+ return false;
+
+ int useGL;
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_USE_GL, &useGL);
+ if (!useGL)
+ return false; //# Chickening out already...
+ }
+ int res;
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_LEVEL, &res);
+ d->glFormat.setPlane(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DOUBLEBUFFER, &res);
+ d->glFormat.setDoubleBuffer(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DEPTH_SIZE, &res);
+ d->glFormat.setDepth(res);
+ if (d->glFormat.depth())
+ d->glFormat.setDepthBufferSize(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RGBA, &res);
+ d->glFormat.setRgba(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RED_SIZE, &res);
+ d->glFormat.setRedBufferSize(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_GREEN_SIZE, &res);
+ d->glFormat.setGreenBufferSize(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_BLUE_SIZE, &res);
+ d->glFormat.setBlueBufferSize(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ALPHA_SIZE, &res);
+ d->glFormat.setAlpha(res);
+ if (d->glFormat.alpha())
+ d->glFormat.setAlphaBufferSize(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ACCUM_RED_SIZE, &res);
+ d->glFormat.setAccum(res);
+ if (d->glFormat.accum())
+ d->glFormat.setAccumBufferSize(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STENCIL_SIZE, &res);
+ d->glFormat.setStencil(res);
+ if (d->glFormat.stencil())
+ d->glFormat.setStencilBufferSize(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STEREO, &res);
+ d->glFormat.setStereo(res);
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLE_BUFFERS_ARB, &res);
+ d->glFormat.setSampleBuffers(res);
+ if (d->glFormat.sampleBuffers()) {
+ glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLES_ARB, &res);
+ d->glFormat.setSamples(res);
+ }
+
+ Bool direct = format().directRendering() ? True : False;
+
+ if (shareContext &&
+ (!shareContext->isValid() || !shareContext->d_func()->cx)) {
+ qWarning("QGLContext::chooseContext(): Cannot share with invalid context");
+ shareContext = 0;
+ }
+
+ // 1. Sharing between rgba and color-index will give wrong colors.
+ // 2. Contexts cannot be shared btw. direct/non-direct renderers.
+ // 3. Pixmaps cannot share contexts that are set up for direct rendering.
+ // 4. If the contexts are not created on the same screen, they can't be shared
+
+ if (shareContext
+ && (format().rgba() != shareContext->format().rgba()
+ || (deviceIsPixmap() && glXIsDirect(disp, (GLXContext)shareContext->d_func()->cx))
+ || (shareContext->d_func()->screen != xinfo->screen())))
+ {
+ shareContext = 0;
+ }
+
+ d->cx = 0;
+ if (shareContext) {
+ d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi,
+ (GLXContext)shareContext->d_func()->cx, direct);
+ d->screen = ((XVisualInfo*)d->vi)->screen;
+ if (d->cx) {
+ QGLContext *share = const_cast<QGLContext *>(shareContext);
+ d->sharing = true;
+ share->d_func()->sharing = true;
+ }
+ }
+ if (!d->cx) {
+ d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, NULL, direct);
+ d->screen = ((XVisualInfo*)d->vi)->screen;
+ }
+ if (!d->cx)
+ return false;
+ d->glFormat.setDirectRendering(glXIsDirect(disp, (GLXContext)d->cx));
+ if (deviceIsPixmap()) {
+#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT)
+ d->gpm = glXCreateGLXPixmapMESA(disp, (XVisualInfo *)d->vi,
+ qt_x11Handle(d->paintDevice),
+ qt_gl_choose_cmap(disp, (XVisualInfo *)d->vi));
+#else
+ d->gpm = (quint32)glXCreateGLXPixmap(disp, (XVisualInfo *)d->vi,
+ qt_x11Handle(d->paintDevice));
+#endif
+ if (!d->gpm)
+ return false;
+ }
+ QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
+ if (extensions.match("GLX_SGI_video_sync")) {
+ if (d->glFormat.swapInterval() == -1)
+ d->glFormat.setSwapInterval(0);
+ } else {
+ d->glFormat.setSwapInterval(-1);
+ }
+ return true;
+}
+
+/*
+ See qgl.cpp for qdoc comment.
+ */
+void *QGLContext::chooseVisual()
+{
+ Q_D(QGLContext);
+ static const int bufDepths[] = { 8, 4, 2, 1 }; // Try 16, 12 also?
+ //todo: if pixmap, also make sure that vi->depth == pixmap->depth
+ void* vis = 0;
+ int i = 0;
+ bool fail = false;
+ QGLFormat fmt = format();
+ bool tryDouble = !fmt.doubleBuffer(); // Some GL impl's only have double
+ bool triedDouble = false;
+ bool triedSample = false;
+ if (fmt.sampleBuffers())
+ fmt.setSampleBuffers(QGLExtensions::glExtensions() & QGLExtensions::SampleBuffers);
+ while(!fail && !(vis = tryVisual(fmt, bufDepths[i]))) {
+ if (!fmt.rgba() && bufDepths[i] > 1) {
+ i++;
+ continue;
+ }
+ if (tryDouble) {
+ fmt.setDoubleBuffer(true);
+ tryDouble = false;
+ triedDouble = true;
+ continue;
+ } else if (triedDouble) {
+ fmt.setDoubleBuffer(false);
+ triedDouble = false;
+ }
+ if (!triedSample && fmt.sampleBuffers()) {
+ fmt.setSampleBuffers(false);
+ triedSample = true;
+ continue;
+ }
+ if (fmt.stereo()) {
+ fmt.setStereo(false);
+ continue;
+ }
+ if (fmt.accum()) {
+ fmt.setAccum(false);
+ continue;
+ }
+ if (fmt.stencil()) {
+ fmt.setStencil(false);
+ continue;
+ }
+ if (fmt.alpha()) {
+ fmt.setAlpha(false);
+ continue;
+ }
+ if (fmt.depth()) {
+ fmt.setDepth(false);
+ continue;
+ }
+ if (fmt.doubleBuffer()) {
+ fmt.setDoubleBuffer(false);
+ continue;
+ }
+ fail = true;
+ }
+ d->glFormat = fmt;
+ return vis;
+}
+
+/*
+ See qgl.cpp for qdoc comment.
+ */
+void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth)
+{
+ Q_D(QGLContext);
+ int spec[45];
+ int i = 0;
+ spec[i++] = GLX_LEVEL;
+ spec[i++] = f.plane();
+ const QX11Info *xinfo = qt_x11Info(d->paintDevice);
+ bool useFBConfig = false;
+
+#if defined(GLX_VERSION_1_3) && !defined(QT_NO_XRENDER) && !defined(Q_OS_HPUX)
+ /*
+ HPUX defines GLX_VERSION_1_3 but does not implement the corresponding functions.
+ Specifically glXChooseFBConfig and glXGetVisualFromFBConfig are not implemented.
+ */
+ QWidget* widget = 0;
+ if (d->paintDevice->devType() == QInternal::Widget)
+ widget = static_cast<QWidget*>(d->paintDevice);
+
+ // Only use glXChooseFBConfig for widgets if we're trying to get an ARGB visual
+ if (widget && widget->testAttribute(Qt::WA_TranslucentBackground) && X11->use_xrender)
+ useFBConfig = true;
+#endif
+
+#if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
+ static bool useTranspExt = false;
+ static bool useTranspExtChecked = false;
+ if (f.plane() && !useTranspExtChecked && d->paintDevice) {
+ QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
+ useTranspExt = extensions.match("GLX_EXT_visual_info");
+ //# (A bit simplistic; that could theoretically be a substring)
+ if (useTranspExt) {
+ QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR));
+ useTranspExt = !cstr.contains("Xi Graphics"); // bug workaround
+ if (useTranspExt) {
+ // bug workaround - some systems (eg. FireGL) refuses to return an overlay
+ // visual if the GLX_TRANSPARENT_TYPE_EXT attribute is specified, even if
+ // the implementation supports transparent overlays
+ int tmpSpec[] = { GLX_LEVEL, f.plane(), GLX_TRANSPARENT_TYPE_EXT,
+ f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT,
+ XNone };
+ XVisualInfo * vinf = glXChooseVisual(xinfo->display(), xinfo->screen(), tmpSpec);
+ if (!vinf) {
+ useTranspExt = false;
+ }
+ }
+ }
+
+ useTranspExtChecked = true;
+ }
+ if (f.plane() && useTranspExt && !useFBConfig) {
+ // Required to avoid non-transparent overlay visual(!) on some systems
+ spec[i++] = GLX_TRANSPARENT_TYPE_EXT;
+ spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT;
+ }
+#endif
+
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ // GLX_RENDER_TYPE is only in glx >=1.3
+ if (useFBConfig) {
+ spec[i++] = GLX_RENDER_TYPE;
+ spec[i++] = f.rgba() ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
+ }
+#endif
+
+ if (f.doubleBuffer())
+ spec[i++] = GLX_DOUBLEBUFFER;
+ if (useFBConfig)
+ spec[i++] = True;
+ if (f.depth()) {
+ spec[i++] = GLX_DEPTH_SIZE;
+ spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
+ }
+ if (f.stereo()) {
+ spec[i++] = GLX_STEREO;
+ if (useFBConfig)
+ spec[i++] = True;
+ }
+ if (f.stencil()) {
+ spec[i++] = GLX_STENCIL_SIZE;
+ spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
+ }
+ if (f.rgba()) {
+ if (!useFBConfig)
+ spec[i++] = GLX_RGBA;
+ spec[i++] = GLX_RED_SIZE;
+ spec[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize();
+ spec[i++] = GLX_GREEN_SIZE;
+ spec[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize();
+ spec[i++] = GLX_BLUE_SIZE;
+ spec[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize();
+ if (f.alpha()) {
+ spec[i++] = GLX_ALPHA_SIZE;
+ spec[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize();
+ }
+ if (f.accum()) {
+ spec[i++] = GLX_ACCUM_RED_SIZE;
+ spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+ spec[i++] = GLX_ACCUM_GREEN_SIZE;
+ spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+ spec[i++] = GLX_ACCUM_BLUE_SIZE;
+ spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+ if (f.alpha()) {
+ spec[i++] = GLX_ACCUM_ALPHA_SIZE;
+ spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+ }
+ }
+ } else {
+ spec[i++] = GLX_BUFFER_SIZE;
+ spec[i++] = bufDepth;
+ }
+
+ if (f.sampleBuffers()) {
+ spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
+ spec[i++] = 1;
+ spec[i++] = GLX_SAMPLES_ARB;
+ spec[i++] = f.samples() == -1 ? 4 : f.samples();
+ }
+
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ if (useFBConfig) {
+ spec[i++] = GLX_DRAWABLE_TYPE;
+ switch(d->paintDevice->devType()) {
+ case QInternal::Pixmap:
+ spec[i++] = GLX_PIXMAP_BIT;
+ break;
+ case QInternal::Pbuffer:
+ spec[i++] = GLX_PBUFFER_BIT;
+ break;
+ default:
+ qWarning("QGLContext: Unknown paint device type %d", d->paintDevice->devType());
+ // Fall-through & assume it's a window
+ case QInternal::Widget:
+ spec[i++] = GLX_WINDOW_BIT;
+ break;
+ };
+ }
+#endif
+
+ spec[i] = XNone;
+
+
+ XVisualInfo* chosenVisualInfo = 0;
+
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ while (useFBConfig) {
+ GLXFBConfig *configs;
+ int configCount = 0;
+ configs = glXChooseFBConfig(xinfo->display(), xinfo->screen(), spec, &configCount);
+
+ if (!configs)
+ break; // fallback to trying glXChooseVisual
+
+ for (i = 0; i < configCount; ++i) {
+ XVisualInfo* vi;
+ vi = glXGetVisualFromFBConfig(xinfo->display(), configs[i]);
+ if (!vi)
+ continue;
+
+#if !defined(QT_NO_XRENDER)
+ QWidget* w = 0;
+ if (d->paintDevice->devType() == QInternal::Widget)
+ w = static_cast<QWidget*>(d->paintDevice);
+
+ if (w && w->testAttribute(Qt::WA_TranslucentBackground) && f.alpha()) {
+ // Attempt to find a config who's visual has a proper alpha channel
+ XRenderPictFormat *pictFormat;
+ pictFormat = XRenderFindVisualFormat(xinfo->display(), vi->visual);
+
+ if (pictFormat && (pictFormat->type == PictTypeDirect) && pictFormat->direct.alphaMask) {
+ // The pict format for the visual matching the FBConfig indicates ARGB
+ if (chosenVisualInfo)
+ XFree(chosenVisualInfo);
+ chosenVisualInfo = vi;
+ break;
+ }
+ } else
+#endif //QT_NO_XRENDER
+ if (chosenVisualInfo) {
+ // If we've got a visual we can use and we're not trying to find one with a
+ // real alpha channel, we might as well just use the one we've got
+ break;
+ }
+
+ if (!chosenVisualInfo)
+ chosenVisualInfo = vi; // Have something to fall back to
+ else
+ XFree(vi);
+ }
+
+ XFree(configs);
+ break;
+ }
+#endif // defined(GLX_VERSION_1_3)
+
+ if (!chosenVisualInfo)
+ chosenVisualInfo = glXChooseVisual(xinfo->display(), xinfo->screen(), spec);
+
+ return chosenVisualInfo;
+}
+
+
+void QGLContext::reset()
+{
+ Q_D(QGLContext);
+ if (!d->valid)
+ return;
+ d->cleanup();
+ const QX11Info *xinfo = qt_x11Info(d->paintDevice);
+ doneCurrent();
+ if (d->gpm)
+ glXDestroyGLXPixmap(xinfo->display(), (GLXPixmap)d->gpm);
+ d->gpm = 0;
+ glXDestroyContext(xinfo->display(), (GLXContext)d->cx);
+ if (d->vi)
+ XFree(d->vi);
+ d->vi = 0;
+ d->cx = 0;
+ d->crWin = false;
+ d->sharing = false;
+ d->valid = false;
+ d->transpColor = QColor();
+ d->initDone = false;
+ QGLContextGroup::removeShare(this);
+}
+
+
+void QGLContext::makeCurrent()
+{
+ Q_D(QGLContext);
+ if (!d->valid) {
+ qWarning("QGLContext::makeCurrent(): Cannot make invalid context current.");
+ return;
+ }
+ const QX11Info *xinfo = qt_x11Info(d->paintDevice);
+ bool ok = true;
+ if (d->paintDevice->devType() == QInternal::Pixmap) {
+ ok = glXMakeCurrent(xinfo->display(), (GLXPixmap)d->gpm, (GLXContext)d->cx);
+ } else if (d->paintDevice->devType() == QInternal::Pbuffer) {
+ ok = glXMakeCurrent(xinfo->display(), (GLXPbuffer)d->pbuf, (GLXContext)d->cx);
+ } else if (d->paintDevice->devType() == QInternal::Widget) {
+ ok = glXMakeCurrent(xinfo->display(), ((QWidget *)d->paintDevice)->winId(), (GLXContext)d->cx);
+ }
+ if (!ok)
+ qWarning("QGLContext::makeCurrent(): Failed.");
+
+ if (ok)
+ QGLContextPrivate::setCurrentContext(this);
+}
+
+void QGLContext::doneCurrent()
+{
+ Q_D(QGLContext);
+ glXMakeCurrent(qt_x11Info(d->paintDevice)->display(), 0, 0);
+ QGLContextPrivate::setCurrentContext(0);
+}
+
+
+void QGLContext::swapBuffers() const
+{
+ Q_D(const QGLContext);
+ if (!d->valid)
+ return;
+ if (!deviceIsPixmap()) {
+ int interval = d->glFormat.swapInterval();
+ if (interval > 0) {
+ typedef int (*qt_glXGetVideoSyncSGI)(uint *);
+ typedef int (*qt_glXWaitVideoSyncSGI)(int, int, uint *);
+ static qt_glXGetVideoSyncSGI glXGetVideoSyncSGI = 0;
+ static qt_glXWaitVideoSyncSGI glXWaitVideoSyncSGI = 0;
+ static bool resolved = false;
+ if (!resolved) {
+ const QX11Info *xinfo = qt_x11Info(d->paintDevice);
+ QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
+ if (extensions.match("GLX_SGI_video_sync")) {
+ glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI)qglx_getProcAddress("glXGetVideoSyncSGI");
+ glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI)qglx_getProcAddress("glXWaitVideoSyncSGI");
+ }
+ resolved = true;
+ }
+ if (glXGetVideoSyncSGI && glXWaitVideoSyncSGI) {
+ uint counter;
+ if (!glXGetVideoSyncSGI(&counter))
+ glXWaitVideoSyncSGI(interval + 1, (counter + interval) % (interval + 1), &counter);
+ }
+ }
+ glXSwapBuffers(qt_x11Info(d->paintDevice)->display(),
+ static_cast<QWidget *>(d->paintDevice)->winId());
+ }
+}
+
+QColor QGLContext::overlayTransparentColor() const
+{
+ if (isValid())
+ return Qt::transparent;
+ return QColor(); // Invalid color
+}
+
+static uint qt_transparent_pixel(VisualID id, int screen)
+{
+ for (int i = 0; i < trans_colors.size(); i++) {
+ if (trans_colors[i].vis == id && trans_colors[i].screen == screen)
+ return trans_colors[i].color;
+ }
+ return 0;
+}
+
+uint QGLContext::colorIndex(const QColor& c) const
+{
+ Q_D(const QGLContext);
+ int screen = ((XVisualInfo *)d->vi)->screen;
+ QColormap colmap = QColormap::instance(screen);
+ if (isValid()) {
+ if (format().plane() && c == Qt::transparent) {
+ return qt_transparent_pixel(((XVisualInfo *)d->vi)->visualid,
+ ((XVisualInfo *)d->vi)->screen);
+ }
+ if (((XVisualInfo*)d->vi)->visualid ==
+ XVisualIDFromVisual((Visual *) QX11Info::appVisual(screen)))
+ return colmap.pixel(c); // We're using QColor's cmap
+
+ XVisualInfo *info = (XVisualInfo *) d->vi;
+ CMapEntryHash *hash = cmap_handler()->cmap_hash;
+ CMapEntryHash::ConstIterator it = hash->constFind(long(info->visualid)
+ + (info->screen * 256));
+ QCMapEntry *x = 0;
+ if (it != hash->constEnd())
+ x = it.value();
+ if (x && !x->alloc) { // It's a standard colormap
+ int rf = (int)(((float)c.red() * (x->scmap.red_max+1))/256.0);
+ int gf = (int)(((float)c.green() * (x->scmap.green_max+1))/256.0);
+ int bf = (int)(((float)c.blue() * (x->scmap.blue_max+1))/256.0);
+ uint p = x->scmap.base_pixel
+ + (rf * x->scmap.red_mult)
+ + (gf * x->scmap.green_mult)
+ + (bf * x->scmap.blue_mult);
+ return p;
+ } else {
+ QMap<int, QRgb> &cmap = (*cmap_handler()->qglcmap_hash)[(long)info->visualid];
+
+ // already in the map?
+ QRgb target = c.rgb();
+ QMap<int, QRgb>::Iterator it = cmap.begin();
+ for (; it != cmap.end(); ++it) {
+ if ((*it) == target)
+ return it.key();
+ }
+
+ // need to alloc color
+ unsigned long plane_mask[2];
+ unsigned long color_map_entry;
+ if (!XAllocColorCells (QX11Info::display(), x->cmap, true, plane_mask, 0,
+ &color_map_entry, 1))
+ return colmap.pixel(c);
+
+ XColor col;
+ col.flags = DoRed | DoGreen | DoBlue;
+ col.pixel = color_map_entry;
+ col.red = (ushort)((qRed(c.rgb()) / 255.0) * 65535.0 + 0.5);
+ col.green = (ushort)((qGreen(c.rgb()) / 255.0) * 65535.0 + 0.5);
+ col.blue = (ushort)((qBlue(c.rgb()) / 255.0) * 65535.0 + 0.5);
+ XStoreColor(QX11Info::display(), x->cmap, &col);
+
+ cmap.insert(color_map_entry, target);
+ return color_map_entry;
+ }
+ }
+ return 0;
+}
+
+#ifndef QT_NO_FONTCONFIG
+/*! \internal
+ This is basically a substitute for glxUseXFont() which can only
+ handle XLFD fonts. This version relies on freetype to render the
+ glyphs, but it works with all fonts that fontconfig provides - both
+ antialiased and aliased bitmap and outline fonts.
+*/
+static void qgl_use_font(QFontEngineFT *engine, int first, int count, int listBase)
+{
+ GLfloat color[4];
+ glGetFloatv(GL_CURRENT_COLOR, color);
+
+ // save the pixel unpack state
+ GLint gl_swapbytes, gl_lsbfirst, gl_rowlength, gl_skiprows, gl_skippixels, gl_alignment;
+ glGetIntegerv (GL_UNPACK_SWAP_BYTES, &gl_swapbytes);
+ glGetIntegerv (GL_UNPACK_LSB_FIRST, &gl_lsbfirst);
+ glGetIntegerv (GL_UNPACK_ROW_LENGTH, &gl_rowlength);
+ glGetIntegerv (GL_UNPACK_SKIP_ROWS, &gl_skiprows);
+ glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &gl_skippixels);
+ glGetIntegerv (GL_UNPACK_ALIGNMENT, &gl_alignment);
+
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ const bool antialiased = engine->drawAntialiased();
+ FT_Face face = engine->lockFace();
+
+ // start generating font glyphs
+ for (int i = first; i < count; ++i) {
+ int list = listBase + i;
+ GLfloat x0, y0, dx, dy;
+
+ FT_Error err;
+
+ err = FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT);
+ if (err) {
+ qDebug("failed loading glyph %d from font", i);
+ Q_ASSERT(!err);
+ }
+ err = FT_Render_Glyph(face->glyph, (antialiased ? FT_RENDER_MODE_NORMAL
+ : FT_RENDER_MODE_MONO));
+ if (err) {
+ qDebug("failed rendering glyph %d from font", i);
+ Q_ASSERT(!err);
+ }
+
+ FT_Bitmap bm = face->glyph->bitmap;
+ x0 = face->glyph->metrics.horiBearingX >> 6;
+ y0 = (face->glyph->metrics.height - face->glyph->metrics.horiBearingY) >> 6;
+ dx = face->glyph->metrics.horiAdvance >> 6;
+ dy = 0;
+ int sz = bm.pitch * bm.rows;
+ uint *aa_glyph = 0;
+ uchar *ua_glyph = 0;
+
+ if (antialiased)
+ aa_glyph = new uint[sz];
+ else
+ ua_glyph = new uchar[sz];
+
+ // convert to GL format
+ for (int y = 0; y < bm.rows; ++y) {
+ for (int x = 0; x < bm.pitch; ++x) {
+ int c1 = y*bm.pitch + x;
+ int c2 = (bm.rows - y - 1) > 0 ? (bm.rows-y-1)*bm.pitch + x : x;
+ if (antialiased) {
+ aa_glyph[c1] = (int(color[0]*255) << 24)
+ | (int(color[1]*255) << 16)
+ | (int(color[2]*255) << 8) | bm.buffer[c2];
+ } else {
+ ua_glyph[c1] = bm.buffer[c2];
+ }
+ }
+ }
+
+ glNewList(list, GL_COMPILE);
+ if (antialiased) {
+ // calling glBitmap() is just a trick to move the current
+ // raster pos, since glGet*() won't work in display lists
+ glBitmap(0, 0, 0, 0, x0, -y0, 0);
+ glDrawPixels(bm.pitch, bm.rows, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, aa_glyph);
+ glBitmap(0, 0, 0, 0, dx-x0, y0, 0);
+ } else {
+ glBitmap(bm.pitch*8, bm.rows, -x0, y0, dx, dy, ua_glyph);
+ }
+ glEndList();
+ antialiased ? delete[] aa_glyph : delete[] ua_glyph;
+ }
+
+ engine->unlockFace();
+
+ // restore pixel unpack settings
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, gl_swapbytes);
+ glPixelStorei(GL_UNPACK_LSB_FIRST, gl_lsbfirst);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, gl_rowlength);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, gl_skiprows);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, gl_skippixels);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, gl_alignment);
+}
+#endif
+
+#undef d
+void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
+{
+ QFont f(fnt);
+ QFontEngine *engine = f.d->engineForScript(QUnicodeTables::Common);
+
+ if (engine->type() == QFontEngine::Multi)
+ engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
+#ifndef QT_NO_FONTCONFIG
+ if(engine->type() == QFontEngine::Freetype) {
+ qgl_use_font(static_cast<QFontEngineFT *>(engine), 0, 256, listBase);
+ return;
+ }
+#endif
+ // glXUseXFont() only works with XLFD font structures and a few GL
+ // drivers crash if 0 is passed as the font handle
+ f.setStyleStrategy(QFont::OpenGLCompatible);
+ if (f.handle() && engine->type() == QFontEngine::XLFD)
+ glXUseXFont(static_cast<Font>(f.handle()), 0, 256, listBase);
+}
+
+void *QGLContext::getProcAddress(const QString &proc) const
+{
+ typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *);
+ static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
+ static bool resolved = false;
+
+ if (resolved && !glXGetProcAddressARB)
+ return 0;
+ if (!glXGetProcAddressARB) {
+ QGLExtensionMatcher extensions(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
+ if (extensions.match("GLX_ARB_get_proc_address")) {
+#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
+ void *handle = dlopen(NULL, RTLD_LAZY);
+ if (handle) {
+ glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB");
+ dlclose(handle);
+ }
+ if (!glXGetProcAddressARB)
+#endif
+ {
+#if !defined(QT_NO_LIBRARY)
+ extern const QString qt_gl_library_name();
+ QLibrary lib(qt_gl_library_name());
+ glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
+#endif
+ }
+ }
+ resolved = true;
+ }
+ if (!glXGetProcAddressARB)
+ return 0;
+ return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(proc.toLatin1().data()));
+}
+
+/*
+ QGLTemporaryContext implementation
+*/
+
+class QGLTemporaryContextPrivate {
+public:
+ bool initialized;
+ Window drawable;
+ GLXContext context;
+ GLXDrawable oldDrawable;
+ GLXContext oldContext;
+};
+
+QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
+ : d(new QGLTemporaryContextPrivate)
+{
+ d->initialized = false;
+ d->oldDrawable = 0;
+ d->oldContext = 0;
+ int screen = 0;
+
+ int attribs[] = {GLX_RGBA, XNone};
+ XVisualInfo *vi = glXChooseVisual(X11->display, screen, attribs);
+ if (!vi) {
+ qWarning("QGLTempContext: No GL capable X visuals available.");
+ return;
+ }
+
+ int useGL;
+ glXGetConfig(X11->display, vi, GLX_USE_GL, &useGL);
+ if (!useGL) {
+ XFree(vi);
+ return;
+ }
+
+ d->oldDrawable = glXGetCurrentDrawable();
+ d->oldContext = glXGetCurrentContext();
+
+ XSetWindowAttributes a;
+ a.colormap = qt_gl_choose_cmap(X11->display, vi);
+ d->drawable = XCreateWindow(X11->display, RootWindow(X11->display, screen),
+ 0, 0, 1, 1, 0,
+ vi->depth, InputOutput, vi->visual,
+ CWColormap, &a);
+ d->context = glXCreateContext(X11->display, vi, 0, True);
+ if (d->context && glXMakeCurrent(X11->display, d->drawable, d->context)) {
+ d->initialized = true;
+ } else {
+ qWarning("QGLTempContext: Unable to create GL context.");
+ XDestroyWindow(X11->display, d->drawable);
+ }
+ XFree(vi);
+}
+
+QGLTemporaryContext::~QGLTemporaryContext()
+{
+ if (d->initialized) {
+ glXMakeCurrent(X11->display, 0, 0);
+ glXDestroyContext(X11->display, d->context);
+ XDestroyWindow(X11->display, d->drawable);
+ }
+ if (d->oldDrawable && d->oldContext)
+ glXMakeCurrent(X11->display, d->oldDrawable, d->oldContext);
+}
+
+/*****************************************************************************
+ QGLOverlayWidget (Internal overlay class for X11)
+ *****************************************************************************/
+
+class QGLOverlayWidget : public QGLWidget
+{
+ Q_OBJECT
+public:
+ QGLOverlayWidget(const QGLFormat& format, QGLWidget* parent, const QGLWidget* shareWidget=0);
+
+protected:
+ void initializeGL();
+ void paintGL();
+ void resizeGL(int w, int h);
+ bool x11Event(XEvent *e) { return realWidget->x11Event(e); }
+
+private:
+ QGLWidget* realWidget;
+
+private:
+ Q_DISABLE_COPY(QGLOverlayWidget)
+};
+
+
+QGLOverlayWidget::QGLOverlayWidget(const QGLFormat& format, QGLWidget* parent,
+ const QGLWidget* shareWidget)
+ : QGLWidget(format, parent, shareWidget ? shareWidget->d_func()->olw : 0)
+{
+ setAttribute(Qt::WA_X11OpenGLOverlay);
+ realWidget = parent;
+}
+
+
+
+void QGLOverlayWidget::initializeGL()
+{
+ QColor transparentColor = context()->overlayTransparentColor();
+ if (transparentColor.isValid())
+ qglClearColor(transparentColor);
+ else
+ qWarning("QGLOverlayWidget::initializeGL(): Could not get transparent color");
+ realWidget->initializeOverlayGL();
+}
+
+
+void QGLOverlayWidget::resizeGL(int w, int h)
+{
+ glViewport(0, 0, w, h);
+ realWidget->resizeOverlayGL(w, h);
+}
+
+
+void QGLOverlayWidget::paintGL()
+{
+ realWidget->paintOverlayGL();
+}
+
+#undef Bool
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "qgl_x11.moc"
+QT_END_INCLUDE_NAMESPACE
+
+/*****************************************************************************
+ QGLWidget UNIX/GLX-specific code
+ *****************************************************************************/
+void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
+{
+ Q_Q(QGLWidget);
+ initContext(context, shareWidget);
+ olw = 0;
+
+ if (q->isValid() && context->format().hasOverlay()) {
+ QString olwName = q->objectName();
+ olwName += QLatin1String("-QGL_internal_overlay_widget");
+ olw = new QGLOverlayWidget(QGLFormat::defaultOverlayFormat(), q, shareWidget);
+ olw->setObjectName(olwName);
+ if (olw->isValid()) {
+ olw->setAutoBufferSwap(false);
+ olw->setFocusProxy(q);
+ }
+ else {
+ delete olw;
+ olw = 0;
+ glcx->d_func()->glFormat.setOverlay(false);
+ }
+ }
+}
+
+bool QGLWidgetPrivate::renderCxPm(QPixmap* pm)
+{
+ Q_Q(QGLWidget);
+ if (((XVisualInfo*)glcx->d_func()->vi)->depth != pm->depth())
+ return false;
+
+ GLXPixmap glPm;
+#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT)
+ glPm = glXCreateGLXPixmapMESA(X11->display,
+ (XVisualInfo*)glcx->vi,
+ (Pixmap)pm->handle(),
+ qt_gl_choose_cmap(pm->X11->display,
+ (XVisualInfo*)glcx->vi));
+#else
+ glPm = (quint32)glXCreateGLXPixmap(X11->display,
+ (XVisualInfo*)glcx->d_func()->vi,
+ (Pixmap)pm->handle());
+#endif
+
+ if (!glXMakeCurrent(X11->display, glPm, (GLXContext)glcx->d_func()->cx)) {
+ glXDestroyGLXPixmap(X11->display, glPm);
+ return false;
+ }
+
+ glDrawBuffer(GL_FRONT);
+ if (!glcx->initialized())
+ q->glInit();
+ q->resizeGL(pm->width(), pm->height());
+ q->paintGL();
+ glFlush();
+ q->makeCurrent();
+ glXDestroyGLXPixmap(X11->display, glPm);
+ q->resizeGL(q->width(), q->height());
+ return true;
+}
+
+/*! \internal
+ Free up any allocated colormaps. This fn is only called for
+ top-level widgets.
+*/
+void QGLWidgetPrivate::cleanupColormaps()
+{
+ if (!cmap.handle()) {
+ return;
+ } else {
+ XFreeColormap(X11->display, (Colormap) cmap.handle());
+ cmap.setHandle(0);
+ }
+}
+
+void QGLWidget::setMouseTracking(bool enable)
+{
+ Q_D(QGLWidget);
+ if (d->olw)
+ d->olw->setMouseTracking(enable);
+ QWidget::setMouseTracking(enable);
+}
+
+
+void QGLWidget::resizeEvent(QResizeEvent *)
+{
+ Q_D(QGLWidget);
+ if (!isValid())
+ return;
+ makeCurrent();
+ if (!d->glcx->initialized())
+ glInit();
+ glXWaitX();
+ resizeGL(width(), height());
+ if (d->olw)
+ d->olw->setGeometry(rect());
+}
+
+const QGLContext* QGLWidget::overlayContext() const
+{
+ Q_D(const QGLWidget);
+ if (d->olw)
+ return d->olw->context();
+ else
+ return 0;
+}
+
+
+void QGLWidget::makeOverlayCurrent()
+{
+ Q_D(QGLWidget);
+ if (d->olw)
+ d->olw->makeCurrent();
+}
+
+
+void QGLWidget::updateOverlayGL()
+{
+ Q_D(QGLWidget);
+ if (d->olw)
+ d->olw->updateGL();
+}
+
+/*!
+ \internal
+
+ Sets a new QGLContext, \a context, for this QGLWidget, using the
+ shared context, \a shareContext. If \a deleteOldContext is true,
+ the original context is deleted; otherwise it is overridden.
+*/
+void QGLWidget::setContext(QGLContext *context,
+ const QGLContext* shareContext,
+ bool deleteOldContext)
+{
+ Q_D(QGLWidget);
+ if (context == 0) {
+ qWarning("QGLWidget::setContext: Cannot set null context");
+ return;
+ }
+ if (!context->deviceIsPixmap() && context->device() != this) {
+ qWarning("QGLWidget::setContext: Context must refer to this widget");
+ return;
+ }
+
+ if (d->glcx)
+ d->glcx->doneCurrent();
+ QGLContext* oldcx = d->glcx;
+ d->glcx = context;
+
+ if (parentWidget()) {
+ // force creation of delay-created widgets
+ parentWidget()->winId();
+ if (parentWidget()->x11Info().screen() != x11Info().screen())
+ d_func()->xinfo = parentWidget()->d_func()->xinfo;
+ }
+
+ // If the application has set WA_TranslucentBackground and not explicitly set
+ // the alpha buffer size to zero, modify the format so it have an alpha channel
+ QGLFormat& fmt = d->glcx->d_func()->glFormat;
+ if (testAttribute(Qt::WA_TranslucentBackground) && fmt.alphaBufferSize() == -1)
+ fmt.setAlphaBufferSize(1);
+
+ bool createFailed = false;
+ if (!d->glcx->isValid()) {
+ if (!d->glcx->create(shareContext ? shareContext : oldcx))
+ createFailed = true;
+ }
+ if (createFailed) {
+ if (deleteOldContext)
+ delete oldcx;
+ return;
+ }
+
+ if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
+ if (deleteOldContext)
+ delete oldcx;
+ return;
+ }
+
+ bool visible = isVisible();
+ if (visible)
+ hide();
+
+ XVisualInfo *vi = (XVisualInfo*)d->glcx->d_func()->vi;
+ XSetWindowAttributes a;
+
+ QColormap colmap = QColormap::instance(vi->screen);
+ a.colormap = qt_gl_choose_cmap(QX11Info::display(), vi); // find best colormap
+ a.background_pixel = colmap.pixel(palette().color(backgroundRole()));
+ a.border_pixel = colmap.pixel(Qt::black);
+ Window p = RootWindow(X11->display, vi->screen);
+ if (parentWidget())
+ p = parentWidget()->winId();
+
+ Window w = XCreateWindow(X11->display, p, x(), y(), width(), height(),
+ 0, vi->depth, InputOutput, vi->visual,
+ CWBackPixel|CWBorderPixel|CWColormap, &a);
+ Window *cmw;
+ Window *cmwret;
+ int count;
+ if (XGetWMColormapWindows(X11->display, window()->winId(),
+ &cmwret, &count)) {
+ cmw = new Window[count+1];
+ memcpy((char *)cmw, (char *)cmwret, sizeof(Window)*count);
+ XFree((char *)cmwret);
+ int i;
+ for (i=0; i<count; i++) {
+ if (cmw[i] == winId()) { // replace old window
+ cmw[i] = w;
+ break;
+ }
+ }
+ if (i >= count) // append new window
+ cmw[count++] = w;
+ } else {
+ count = 1;
+ cmw = new Window[count];
+ cmw[0] = w;
+ }
+
+#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT)
+ if (oldcx && oldcx->windowCreated())
+ glXReleaseBuffersMESA(X11->display, winId());
+#endif
+ if (deleteOldContext)
+ delete oldcx;
+ oldcx = 0;
+
+ if (testAttribute(Qt::WA_WState_Created))
+ create(w);
+ else
+ d->createWinId(w);
+ XSetWMColormapWindows(X11->display, window()->winId(), cmw, count);
+ delete [] cmw;
+
+ // calling QWidget::create() will always result in a new paint
+ // engine being created - get rid of it and replace it with our
+ // own
+
+ if (visible)
+ show();
+ XFlush(X11->display);
+ d->glcx->setWindowCreated(true);
+}
+
+const QGLColormap & QGLWidget::colormap() const
+{
+ Q_D(const QGLWidget);
+ return d->cmap;
+}
+
+/*\internal
+ Store color values in the given colormap.
+*/
+static void qStoreColors(QWidget * tlw, Colormap cmap,
+ const QGLColormap & cols)
+{
+ Q_UNUSED(tlw);
+ XColor c;
+ QRgb color;
+
+ for (int i = 0; i < cols.size(); i++) {
+ color = cols.entryRgb(i);
+ c.pixel = i;
+ c.red = (ushort)((qRed(color) / 255.0) * 65535.0 + 0.5);
+ c.green = (ushort)((qGreen(color) / 255.0) * 65535.0 + 0.5);
+ c.blue = (ushort)((qBlue(color) / 255.0) * 65535.0 + 0.5);
+ c.flags = DoRed | DoGreen | DoBlue;
+ XStoreColor(X11->display, cmap, &c);
+ }
+}
+
+/*\internal
+ Check whether the given visual supports dynamic colormaps or not.
+*/
+static bool qCanAllocColors(QWidget * w)
+{
+ bool validVisual = false;
+ int numVisuals;
+ long mask;
+ XVisualInfo templ;
+ XVisualInfo * visuals;
+ VisualID id = XVisualIDFromVisual((Visual *) w->window()->x11Info().visual());
+
+ mask = VisualScreenMask;
+ templ.screen = w->x11Info().screen();
+ visuals = XGetVisualInfo(X11->display, mask, &templ, &numVisuals);
+
+ for (int i = 0; i < numVisuals; i++) {
+ if (visuals[i].visualid == id) {
+ switch (visuals[i].c_class) {
+ case TrueColor:
+ case StaticColor:
+ case StaticGray:
+ case XGrayScale:
+ validVisual = false;
+ break;
+ case DirectColor:
+ case PseudoColor:
+ validVisual = true;
+ break;
+ }
+ break;
+ }
+ }
+ XFree(visuals);
+
+ if (!validVisual)
+ return false;
+ return true;
+}
+
+
+void QGLWidget::setColormap(const QGLColormap & c)
+{
+ Q_D(QGLWidget);
+ QWidget * tlw = window(); // must return a valid widget
+
+ d->cmap = c;
+ if (!d->cmap.handle())
+ return;
+
+ if (!qCanAllocColors(this)) {
+ qWarning("QGLWidget::setColormap: Cannot create a read/write "
+ "colormap for this visual");
+ return;
+ }
+
+ // If the child GL widget is not of the same visual class as the
+ // toplevel widget we will get in trouble..
+ Window wid = tlw->winId();
+ Visual * vis = (Visual *) tlw->x11Info().visual();;
+ VisualID cvId = XVisualIDFromVisual((Visual *) x11Info().visual());
+ VisualID tvId = XVisualIDFromVisual((Visual *) tlw->x11Info().visual());
+ if (cvId != tvId) {
+ wid = winId();
+ vis = (Visual *) x11Info().visual();
+ }
+
+ if (!d->cmap.handle()) // allocate a cmap if necessary
+ d->cmap.setHandle(XCreateColormap(X11->display, wid, vis, AllocAll));
+
+ qStoreColors(this, (Colormap) d->cmap.handle(), c);
+ XSetWindowColormap(X11->display, wid, (Colormap) d->cmap.handle());
+
+ // tell the wm that this window has a special colormap
+ Window * cmw;
+ Window * cmwret;
+ int count;
+ if (XGetWMColormapWindows(X11->display, tlw->winId(), &cmwret, &count))
+ {
+ cmw = new Window[count+1];
+ memcpy((char *) cmw, (char *) cmwret, sizeof(Window) * count);
+ XFree((char *) cmwret);
+ int i;
+ for (i = 0; i < count; i++) {
+ if (cmw[i] == winId()) {
+ break;
+ }
+ }
+ if (i >= count) // append new window only if not in the list
+ cmw[count++] = winId();
+ } else {
+ count = 1;
+ cmw = new Window[count];
+ cmw[0] = winId();
+ }
+ XSetWMColormapWindows(X11->display, tlw->winId(), cmw, count);
+ delete [] cmw;
+}
+
+// Solaris defines glXBindTexImageEXT as part of the GL library
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+typedef void (*qt_glXBindTexImageEXT)(Display*, GLXDrawable, int, const int*);
+typedef void (*qt_glXReleaseTexImageEXT)(Display*, GLXDrawable, int);
+static qt_glXBindTexImageEXT glXBindTexImageEXT = 0;
+static qt_glXReleaseTexImageEXT glXReleaseTexImageEXT = 0;
+
+static bool qt_resolveTextureFromPixmap(QPaintDevice *paintDevice)
+{
+ static bool resolvedTextureFromPixmap = false;
+
+ if (!resolvedTextureFromPixmap) {
+ resolvedTextureFromPixmap = true;
+
+ // Check to see if we have NPOT texture support
+ if ( !(QGLExtensions::glExtensions() & QGLExtensions::NPOTTextures) &&
+ !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0))
+ {
+ return false; // Can't use TFP without NPOT
+ }
+
+ const QX11Info *xinfo = qt_x11Info(paintDevice);
+ Display *display = xinfo ? xinfo->display() : X11->display;
+ int screen = xinfo ? xinfo->screen() : X11->defaultScreen;
+
+ QGLExtensionMatcher serverExtensions(glXQueryExtensionsString(display, screen));
+ QGLExtensionMatcher clientExtensions(glXGetClientString(display, GLX_EXTENSIONS));
+ if (serverExtensions.match("GLX_EXT_texture_from_pixmap")
+ && clientExtensions.match("GLX_EXT_texture_from_pixmap"))
+ {
+ glXBindTexImageEXT = (qt_glXBindTexImageEXT) qglx_getProcAddress("glXBindTexImageEXT");
+ glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) qglx_getProcAddress("glXReleaseTexImageEXT");
+ }
+ }
+
+ return glXBindTexImageEXT && glXReleaseTexImageEXT;
+}
+#endif //defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+
+
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key,
+ QGLContext::BindOptions options)
+{
+#if !defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
+ return 0;
+#else
+
+ // Check we have GLX 1.3, as it is needed for glXCreatePixmap & glXDestroyPixmap
+ int majorVersion = 0;
+ int minorVersion = 0;
+ glXQueryVersion(X11->display, &majorVersion, &minorVersion);
+ if (majorVersion < 1 || (majorVersion == 1 && minorVersion < 3))
+ return 0;
+
+ Q_Q(QGLContext);
+
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data());
+ Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class);
+
+ if (!qt_resolveTextureFromPixmap(paintDevice))
+ return 0;
+
+ const QX11Info &x11Info = pixmapData->xinfo;
+
+ // Store the configs (Can be static because configs aren't dependent on current context)
+ static GLXFBConfig glxRGBPixmapConfig = 0;
+ static bool RGBConfigInverted = false;
+ static GLXFBConfig glxRGBAPixmapConfig = 0;
+ static bool RGBAConfigInverted = false;
+
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+
+ // Check to see if we need a config
+ if ( (hasAlpha && !glxRGBAPixmapConfig) || (!hasAlpha && !glxRGBPixmapConfig) ) {
+ GLXFBConfig *configList = 0;
+ int configCount = 0;
+
+ int configAttribs[] = {
+ hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True,
+ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
+ // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can:
+ GLX_Y_INVERTED_EXT, options & QGLContext::CanFlipNativePixmapBindOption ? GLX_DONT_CARE : False,
+ XNone
+ };
+ configList = glXChooseFBConfig(x11Info.display(), x11Info.screen(), configAttribs, &configCount);
+ if (!configList)
+ return 0;
+
+ int yInv;
+ glXGetFBConfigAttrib(x11Info.display(), configList[0], GLX_Y_INVERTED_EXT, &yInv);
+
+ if (hasAlpha) {
+ glxRGBAPixmapConfig = configList[0];
+ RGBAConfigInverted = yInv;
+ }
+ else {
+ glxRGBPixmapConfig = configList[0];
+ RGBConfigInverted = yInv;
+ }
+
+ XFree(configList);
+ }
+
+ // Check to see if the surface is still valid
+ if (pixmapData->gl_surface &&
+ hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
+ {
+ // Surface is invalid!
+ destroyGlSurfaceForPixmap(pixmapData);
+ }
+
+ // Check to see if we need a surface
+ if (!pixmapData->gl_surface) {
+ GLXPixmap glxPixmap;
+ int pixmapAttribs[] = {
+ GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
+ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+ GLX_MIPMAP_TEXTURE_EXT, False, // Maybe needs to be don't care
+ XNone
+ };
+
+ // Wrap the X Pixmap into a GLXPixmap:
+ glxPixmap = glXCreatePixmap(x11Info.display(),
+ hasAlpha ? glxRGBAPixmapConfig : glxRGBPixmapConfig,
+ pixmapData->handle(), pixmapAttribs);
+
+ if (!glxPixmap)
+ return 0;
+
+ pixmapData->gl_surface = (void*)glxPixmap;
+
+ // Make sure the cleanup hook gets called so we can delete the glx pixmap
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData);
+ }
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ glXBindTexImageEXT(x11Info.display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT, 0);
+
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ if (!((hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted)))
+ options &= ~QGLContext::InvertedYBindOption;
+
+ QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
+ if (texture->options & QGLContext::InvertedYBindOption)
+ pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
+
+ // We assume the cost of bound pixmaps is zero
+ QGLTextureCache::instance()->insert(q, key, texture, 0);
+
+ return texture;
+#endif //!defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
+}
+
+
+void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
+{
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ glXDestroyPixmap(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface);
+ pixmapData->gl_surface = 0;
+ }
+#endif
+}
+
+void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
+{
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ Q_ASSERT(QGLContext::currentContext());
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface)
+ glXReleaseTexImageEXT(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT);
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qgl_waylandegl.cpp b/src/opengl/qgl_waylandegl.cpp
new file mode 100644
index 0000000000..9d28de0b02
--- /dev/null
+++ b/src/opengl/qgl_waylandegl.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgl.h"
+#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
+#include <private/qgl_p.h>
+#include <private/qpaintengine_opengl_p.h>
+#include "qgl_egl_p.h"
+#include "qcolormap.h"
+#include <QDebug>
+#include <QPixmap>
+
+
+QT_BEGIN_NAMESPACE
+
+
+/*
+ QGLTemporaryContext implementation
+*/
+
+class QGLTemporaryContextPrivate
+{
+public:
+ bool initialized;
+ Window window;
+ EGLContext context;
+ EGLSurface surface;
+ EGLDisplay display;
+};
+
+QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
+ : d(new QGLTemporaryContextPrivate)
+{
+ d->initialized = false;
+ d->window = 0;
+ d->context = 0;
+ d->surface = 0;
+ int screen = 0;
+
+ d->display = QEgl::display();
+
+ EGLConfig config;
+ int numConfigs = 0;
+ EGLint attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+#ifdef QT_OPENGL_ES_2
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+#endif
+ EGL_NONE
+ };
+
+ eglChooseConfig(d->display, attribs, &config, 1, &numConfigs);
+ if (!numConfigs) {
+ qWarning("QGLTemporaryContext: No EGL configurations available.");
+ return;
+ }
+
+ XVisualInfo visualInfo;
+ XVisualInfo *vi;
+ int numVisuals;
+ EGLint id = 0;
+
+ visualInfo.visualid = QEgl::getCompatibleVisualId(config);
+ vi = XGetVisualInfo(X11->display, VisualIDMask, &visualInfo, &numVisuals);
+ if (!vi || numVisuals < 1) {
+ qWarning("QGLTemporaryContext: Unable to get X11 visual info id.");
+ return;
+ }
+
+ d->window = XCreateWindow(X11->display, RootWindow(X11->display, screen),
+ 0, 0, 1, 1, 0,
+ vi->depth, InputOutput, vi->visual,
+ 0, 0);
+
+ d->surface = eglCreateWindowSurface(d->display, config, (EGLNativeWindowType) d->window, NULL);
+
+ if (d->surface == EGL_NO_SURFACE) {
+ qWarning("QGLTemporaryContext: Error creating EGL surface.");
+ XFree(vi);
+ XDestroyWindow(X11->display, d->window);
+ return;
+ }
+
+ EGLint contextAttribs[] = {
+#ifdef QT_OPENGL_ES_2
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+#endif
+ EGL_NONE
+ };
+ d->context = eglCreateContext(d->display, config, 0, contextAttribs);
+ if (d->context != EGL_NO_CONTEXT
+ && eglMakeCurrent(d->display, d->surface, d->surface, d->context))
+ {
+ d->initialized = true;
+ } else {
+ qWarning("QGLTemporaryContext: Error creating EGL context.");
+ eglDestroySurface(d->display, d->surface);
+ XDestroyWindow(X11->display, d->window);
+ }
+ XFree(vi);
+}
+
+QGLTemporaryContext::~QGLTemporaryContext()
+{
+ if (d->initialized) {
+ eglMakeCurrent(d->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroyContext(d->display, d->context);
+ eglDestroySurface(d->display, d->surface);
+ XDestroyWindow(X11->display, d->window);
+ }
+}
+
+bool QGLFormat::hasOpenGLOverlays()
+{
+ return false;
+}
+
+// Chooses the EGL config and creates the EGL context
+bool QGLContext::chooseContext(const QGLContext* shareContext)
+{
+ Q_D(QGLContext);
+
+ if (!device())
+ return false;
+
+ int devType = device()->devType();
+
+ QX11PixmapData *x11PixmapData = 0;
+ if (devType == QInternal::Pixmap) {
+ QPixmapData *pmd = static_cast<QPixmap*>(device())->data_ptr().data();
+ if (pmd->classId() == QPixmapData::X11Class)
+ x11PixmapData = static_cast<QX11PixmapData*>(pmd);
+ else {
+ // TODO: Replace the pixmap's data with a new QX11PixmapData
+ qWarning("WARNING: Creating a QGLContext on a QPixmap is only supported for X11 pixmap backend");
+ return false;
+ }
+ } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) {
+ qWarning("WARNING: Creating a QGLContext not supported on device type %d", devType);
+ return false;
+ }
+
+ // Only create the eglContext if we don't already have one:
+ if (d->eglContext == 0) {
+ d->eglContext = new QEglContext();
+ d->ownsEglContext = true;
+ d->eglContext->setApi(QEgl::OpenGL);
+
+ // If the device is a widget with WA_TranslucentBackground set, make sure the glFormat
+ // has the alpha channel option set:
+ if (devType == QInternal::Widget) {
+ QWidget* widget = static_cast<QWidget*>(device());
+ if (widget->testAttribute(Qt::WA_TranslucentBackground))
+ d->glFormat.setAlpha(true);
+ }
+
+ // Construct the configuration we need for this surface.
+ QEglProperties configProps;
+ configProps.setDeviceType(devType);
+ configProps.setRenderableType(QEgl::OpenGL);
+ qt_eglproperties_set_glformat(configProps, d->glFormat);
+
+ // Set buffer preserved for regular QWidgets, QGLWidgets are ok with either preserved or destroyed:
+ if ((devType == QInternal::Widget) && qobject_cast<QGLWidget*>(static_cast<QWidget*>(device())) == 0)
+ configProps.setValue(EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
+
+ if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) {
+ delete d->eglContext;
+ d->eglContext = 0;
+ return false;
+ }
+
+ // Create a new context for the configuration.
+ QEglContext* eglSharedContext = shareContext ? shareContext->d_func()->eglContext : 0;
+ if (!d->eglContext->createContext(eglSharedContext)) {
+ delete d->eglContext;
+ d->eglContext = 0;
+ return false;
+ }
+ d->sharing = d->eglContext->isSharing();
+ if (d->sharing && shareContext)
+ const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
+ }
+
+ // Inform the higher layers about the actual format properties
+ qt_glformat_from_eglconfig(d->glFormat, d->eglContext->config());
+
+ // Do don't create the EGLSurface for everything.
+ // QWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface
+ // QGLWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface
+ // QPixmap - yes, create the EGLSurface but store it in QX11PixmapData::gl_surface
+ // QGLPixelBuffer - no, it creates the surface itself and stores it in QGLPixelBufferPrivate::pbuf
+
+ if (devType == QInternal::Widget) {
+ if (d->eglSurface != EGL_NO_SURFACE)
+ eglDestroySurface(d->eglContext->display(), d->eglSurface);
+ d->eglSurface = QEgl::createSurface(device(), d->eglContext->config());
+ XFlush(X11->display);
+ setWindowCreated(true);
+ }
+
+ if (x11PixmapData) {
+ // TODO: Actually check to see if the existing surface can be re-used
+ if (x11PixmapData->gl_surface)
+ eglDestroySurface(d->eglContext->display(), (EGLSurface)x11PixmapData->gl_surface);
+
+ x11PixmapData->gl_surface = (void*)QEgl::createSurface(device(), d->eglContext->config());
+ }
+
+ return true;
+}
+
+void QGLWidget::resizeEvent(QResizeEvent *)
+{
+ Q_D(QGLWidget);
+ if (!isValid())
+ return;
+ makeCurrent();
+ if (!d->glcx->initialized())
+ glInit();
+ resizeGL(width(), height());
+ //handle overlay
+}
+
+const QGLContext* QGLWidget::overlayContext() const
+{
+ return 0;
+}
+
+void QGLWidget::makeOverlayCurrent()
+{
+ //handle overlay
+}
+
+void QGLWidget::updateOverlayGL()
+{
+ //handle overlay
+}
+
+void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
+{
+ Q_D(QGLWidget);
+ if (context == 0) {
+ qWarning("QGLWidget::setContext: Cannot set null context");
+ return;
+ }
+ if (!context->deviceIsPixmap() && context->device() != this) {
+ qWarning("QGLWidget::setContext: Context must refer to this widget");
+ return;
+ }
+
+ if (d->glcx)
+ d->glcx->doneCurrent();
+ QGLContext* oldcx = d->glcx;
+ d->glcx = context;
+
+ bool createFailed = false;
+ if (!d->glcx->isValid()) {
+ // Create the QGLContext here, which in turn chooses the EGL config
+ // and creates the EGL context:
+ if (!d->glcx->create(shareContext ? shareContext : oldcx))
+ createFailed = true;
+ }
+ if (createFailed) {
+ if (deleteOldContext)
+ delete oldcx;
+ return;
+ }
+
+
+ d->eglSurfaceWindowId = winId(); // Remember the window id we created the surface for
+}
+
+void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
+{
+ Q_Q(QGLWidget);
+
+ initContext(context, shareWidget);
+
+ if (q->isValid() && glcx->format().hasOverlay()) {
+ //no overlay
+ qWarning("QtOpenGL ES doesn't currently support overlays");
+ }
+}
+
+void QGLWidgetPrivate::cleanupColormaps()
+{
+}
+
+const QGLColormap & QGLWidget::colormap() const
+{
+ return d_func()->cmap;
+}
+
+void QGLWidget::setColormap(const QGLColormap &)
+{
+}
+
+// Re-creates the EGL surface if the window ID has changed or if there isn't a surface
+void QGLWidgetPrivate::recreateEglSurface()
+{
+ Q_Q(QGLWidget);
+
+ Window currentId = q->winId();
+
+ // If the window ID has changed since the surface was created, we need to delete the
+ // old surface before re-creating a new one. Note: This should not be the case as the
+ // surface should be deleted before the old window id.
+ if (glcx->d_func()->eglSurface != EGL_NO_SURFACE && (currentId != eglSurfaceWindowId)) {
+ qWarning("EGL surface for deleted window %x was not destroyed", eglSurfaceWindowId);
+ glcx->d_func()->destroyEglSurfaceForDevice();
+ }
+
+ if (glcx->d_func()->eglSurface == EGL_NO_SURFACE) {
+ glcx->d_func()->eglSurface = glcx->d_func()->eglContext->createSurface(q);
+ eglSurfaceWindowId = currentId;
+ }
+}
+
+
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key,
+ QGLContext::BindOptions options)
+{
+ Q_Q(QGLContext);
+
+ // The EGL texture_from_pixmap has no facility to invert the y coordinate
+ if (!(options & QGLContext::CanFlipNativePixmapBindOption))
+ return 0;
+
+
+ static bool checkedForTFP = false;
+ static bool haveTFP = false;
+ static bool checkedForEglImageTFP = false;
+ static bool haveEglImageTFP = false;
+
+
+ if (!checkedForEglImageTFP) {
+ checkedForEglImageTFP = true;
+
+ // We need to be able to create an EGLImage from a native pixmap, which was split
+ // into a seperate EGL extension, EGL_KHR_image_pixmap. It is possible to have
+ // eglCreateImageKHR & eglDestroyImageKHR without support for pixmaps, so we must
+ // check we have the EGLImage from pixmap functionality.
+ if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) {
+
+ // Being able to create an EGLImage from a native pixmap is also pretty useless
+ // without the ability to bind that EGLImage as a texture, which is provided by
+ // the GL_OES_EGL_image extension, which we try to resolve here:
+ haveEglImageTFP = qt_resolve_eglimage_gl_extensions(q);
+
+ if (haveEglImageTFP)
+ qDebug("Found EGL_KHR_image_pixmap & GL_OES_EGL_image extensions (preferred method)!");
+ }
+ }
+
+ if (!checkedForTFP) {
+ // Check for texture_from_pixmap egl extension
+ checkedForTFP = true;
+ if (QEgl::hasExtension("EGL_NOKIA_texture_from_pixmap") ||
+ QEgl::hasExtension("EGL_EXT_texture_from_pixmap"))
+ {
+ qDebug("Found texture_from_pixmap EGL extension!");
+ haveTFP = true;
+ }
+ }
+
+ if (!haveTFP && !haveEglImageTFP)
+ return 0;
+
+
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data());
+ Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class);
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+ bool pixmapHasValidSurface = false;
+ bool textureIsBound = false;
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ if (haveTFP && pixmapData->gl_surface &&
+ hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
+ {
+ pixmapHasValidSurface = true;
+ }
+
+ // If we already have a valid EGL surface for the pixmap, we should use it
+ if (pixmapHasValidSurface) {
+ EGLBoolean success;
+ success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
+ if (success == EGL_FALSE) {
+ qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
+ eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
+ pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
+ } else
+ textureIsBound = true;
+ }
+
+ // If the pixmap doesn't already have a valid surface, try binding it via EGLImage
+ // first, as going through EGLImage should be faster and better supported:
+ if (!textureIsBound && haveEglImageTFP) {
+ EGLImageKHR eglImage;
+
+ EGLint attribs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE
+ };
+ eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
+ (EGLClientBuffer)QEgl::nativePixmap(pixmap), attribs);
+
+ QGLContext* ctx = q;
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage);
+
+ GLint err = glGetError();
+ if (err == GL_NO_ERROR)
+ textureIsBound = true;
+
+ // Once the egl image is bound, the texture becomes a new sibling image and we can safely
+ // destroy the EGLImage we created for the pixmap:
+ if (eglImage != EGL_NO_IMAGE_KHR)
+ QEgl::eglDestroyImageKHR(QEgl::display(), eglImage);
+ }
+
+ if (!textureIsBound && haveTFP) {
+ // Check to see if the surface is still valid
+ if (pixmapData->gl_surface &&
+ hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
+ {
+ // Surface is invalid!
+ destroyGlSurfaceForPixmap(pixmapData);
+ }
+
+ if (pixmapData->gl_surface == 0) {
+ EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap,
+ QEgl::OpenGL,
+ hasAlpha ? QEgl::Translucent : QEgl::NoOptions);
+
+ pixmapData->gl_surface = (void*)QEgl::createSurface(pixmap, config);
+ if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE)
+ return false;
+ }
+
+ EGLBoolean success;
+ success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
+ if (success == EGL_FALSE) {
+ qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
+ eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
+ pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
+ haveTFP = false; // If TFP isn't working, disable it's use
+ } else
+ textureIsBound = true;
+ }
+
+ QGLTexture *texture = 0;
+
+ if (textureIsBound) {
+ texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
+ pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
+
+ // We assume the cost of bound pixmaps is zero
+ QGLTextureCache::instance()->insert(q, key, texture, 0);
+
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ } else
+ glDeleteTextures(1, &textureId);
+
+ return texture;
+}
+
+
+void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
+{
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ EGLBoolean success;
+ success = eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
+ if (success == EGL_FALSE) {
+ qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
+ << QEgl::errorString();
+ }
+ pixmapData->gl_surface = 0;
+ }
+}
+
+void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
+{
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ EGLBoolean success;
+ success = eglReleaseTexImage(QEgl::display(),
+ (EGLSurface)pixmapData->gl_surface,
+ EGL_BACK_BUFFER);
+ if (success == EGL_FALSE) {
+ qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
+ << QEgl::errorString();
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qglpixelbuffer_wayland.cpp b/src/opengl/qglpixelbuffer_wayland.cpp
new file mode 100644
index 0000000000..32a42a2323
--- /dev/null
+++ b/src/opengl/qglpixelbuffer_wayland.cpp
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qlibrary.h>
+#include <qdebug.h>
+#include <private/qgl_p.h>
+#include <private/qt_x11_p.h>
+#include <private/qpaintengine_opengl_p.h>
+
+#include <qx11info_x11.h>
+#include <GL/glx.h>
+#include <qimage.h>
+
+#include "qglpixelbuffer.h"
+#include "qglpixelbuffer_p.h"
+
+#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
+#include <dlfcn.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef GLX_VERSION_1_3
+#define GLX_RGBA_BIT 0x00000002
+#define GLX_PBUFFER_BIT 0x00000004
+#define GLX_DRAWABLE_TYPE 0x8010
+#define GLX_RENDER_TYPE 0x8011
+#define GLX_RGBA_TYPE 0x8014
+#define GLX_PBUFFER_HEIGHT 0x8040
+#define GLX_PBUFFER_WIDTH 0x8041
+#endif
+
+#ifndef GLX_ARB_multisample
+#define GLX_SAMPLE_BUFFERS_ARB 100000
+#define GLX_SAMPLES_ARB 100001
+#endif
+
+typedef GLXFBConfig* (*_glXChooseFBConfig) (Display *dpy, int screen, const int *attrib_list, int *nelements);
+typedef int (*_glXGetFBConfigAttrib) (Display *dpy, GLXFBConfig config, int attribute, int *value);
+typedef GLXPbuffer (*_glXCreatePbuffer) (Display *dpy, GLXFBConfig config, const int *attrib_list);
+typedef void (*_glXDestroyPbuffer) (Display *dpy, GLXPbuffer pbuf);
+typedef GLXContext (*_glXCreateNewContext) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
+typedef Bool (*_glXMakeContextCurrent) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
+
+static _glXChooseFBConfig qt_glXChooseFBConfig = 0;
+static _glXCreateNewContext qt_glXCreateNewContext = 0;
+static _glXCreatePbuffer qt_glXCreatePbuffer = 0;
+static _glXDestroyPbuffer qt_glXDestroyPbuffer = 0;
+static _glXGetFBConfigAttrib qt_glXGetFBConfigAttrib = 0;
+static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0;
+
+#define glXChooseFBConfig qt_glXChooseFBConfig
+#define glXCreateNewContext qt_glXCreateNewContext
+#define glXCreatePbuffer qt_glXCreatePbuffer
+#define glXDestroyPbuffer qt_glXDestroyPbuffer
+#define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib
+#define glXMakeContextCurrent qt_glXMakeContextCurrent
+
+extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp
+
+static bool qt_resolve_pbuffer_extensions()
+{
+ static int resolved = false;
+ if (resolved && qt_glXMakeContextCurrent)
+ return true;
+ else if (resolved)
+ return false;
+
+ qt_glXChooseFBConfig = (_glXChooseFBConfig) qglx_getProcAddress("glXChooseFBConfig");
+ qt_glXCreateNewContext = (_glXCreateNewContext) qglx_getProcAddress("glXCreateNewContext");
+ qt_glXCreatePbuffer = (_glXCreatePbuffer) qglx_getProcAddress("glXCreatePbuffer");
+ qt_glXDestroyPbuffer = (_glXDestroyPbuffer) qglx_getProcAddress("glXDestroyPbuffer");
+ qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) qglx_getProcAddress("glXGetFBConfigAttrib");
+ qt_glXMakeContextCurrent = (_glXMakeContextCurrent) qglx_getProcAddress("glXMakeContextCurrent");
+
+ resolved = qt_glXMakeContextCurrent ? true : false;
+ return resolved;
+}
+
+static void qt_format_to_attrib_list(const QGLFormat &f, int attribs[])
+{
+ int i = 0;
+ attribs[i++] = GLX_RENDER_TYPE;
+ attribs[i++] = GLX_RGBA_BIT;
+ attribs[i++] = GLX_DRAWABLE_TYPE;
+ attribs[i++] = GLX_PBUFFER_BIT;
+ attribs[i++] = GLX_RED_SIZE;
+ attribs[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize();
+ attribs[i++] = GLX_GREEN_SIZE;
+ attribs[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize();
+ attribs[i++] = GLX_BLUE_SIZE;
+ attribs[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize();
+ if (f.doubleBuffer()) {
+ attribs[i++] = GLX_DOUBLEBUFFER;
+ attribs[i++] = true;
+ }
+ if (f.depth()) {
+ attribs[i++] = GLX_DEPTH_SIZE;
+ attribs[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
+ }
+ if (f.stereo()) {
+ attribs[i++] = GLX_STEREO;
+ attribs[i++] = true;
+ }
+ if (f.stencil()) {
+ attribs[i++] = GLX_STENCIL_SIZE;
+ attribs[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
+ }
+ if (f.alpha()) {
+ attribs[i++] = GLX_ALPHA_SIZE;
+ attribs[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize();
+ }
+ if (f.accum()) {
+ attribs[i++] = GLX_ACCUM_RED_SIZE;
+ attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+ attribs[i++] = GLX_ACCUM_GREEN_SIZE;
+ attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+ attribs[i++] = GLX_ACCUM_BLUE_SIZE;
+ attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+ if (f.alpha()) {
+ attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
+ attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
+ }
+ }
+ if (f.sampleBuffers()) {
+ attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
+ attribs[i++] = 1;
+ attribs[i++] = GLX_SAMPLES_ARB;
+ attribs[i++] = f.samples() == -1 ? 4 : f.samples();
+ }
+
+ attribs[i] = XNone;
+}
+
+bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidget *shareWidget)
+{
+ if (!qt_resolve_pbuffer_extensions()) {
+ qWarning("QGLPixelBuffer: pbuffers are not supported on this system.");
+ return false;
+ }
+
+ int attribs[40];
+ int num_configs = 0;
+
+ qt_format_to_attrib_list(f, attribs);
+
+ int screen = X11->defaultScreen;
+ if (shareWidget)
+ screen = shareWidget->x11Info().screen();
+
+ GLXFBConfig *configs = glXChooseFBConfig(X11->display, screen, attribs, &num_configs);
+ if (configs && num_configs) {
+ int res;
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_LEVEL, &res);
+ format.setPlane(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_DOUBLEBUFFER, &res);
+ format.setDoubleBuffer(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_DEPTH_SIZE, &res);
+ format.setDepth(res);
+ if (format.depth())
+ format.setDepthBufferSize(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_RGBA, &res);
+ format.setRgba(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_RED_SIZE, &res);
+ format.setRedBufferSize(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_GREEN_SIZE, &res);
+ format.setGreenBufferSize(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_BLUE_SIZE, &res);
+ format.setBlueBufferSize(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_ALPHA_SIZE, &res);
+ format.setAlpha(res);
+ if (format.alpha())
+ format.setAlphaBufferSize(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_ACCUM_RED_SIZE, &res);
+ format.setAccum(res);
+ if (format.accum())
+ format.setAccumBufferSize(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_STENCIL_SIZE, &res);
+ format.setStencil(res);
+ if (format.stencil())
+ format.setStencilBufferSize(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_STEREO, &res);
+ format.setStereo(res);
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_SAMPLE_BUFFERS_ARB, &res);
+ format.setSampleBuffers(res);
+ if (format.sampleBuffers()) {
+ glXGetFBConfigAttrib(X11->display, configs[0], GLX_SAMPLES_ARB, &res);
+ format.setSamples(res);
+ }
+
+ int pb_attribs[] = {GLX_PBUFFER_WIDTH, size.width(), GLX_PBUFFER_HEIGHT, size.height(), XNone};
+ GLXContext shareContext = 0;
+ if (shareWidget && shareWidget->d_func()->glcx)
+ shareContext = (GLXContext) shareWidget->d_func()->glcx->d_func()->cx;
+
+ pbuf = glXCreatePbuffer(QX11Info::display(), configs[0], pb_attribs);
+ ctx = glXCreateNewContext(QX11Info::display(), configs[0], GLX_RGBA_TYPE, shareContext, true);
+
+ XFree(configs);
+ if (!pbuf || !ctx) {
+ qWarning("QGLPixelBuffer: Unable to create a pbuffer/context - giving up.");
+ return false;
+ }
+ return true;
+ } else {
+ qWarning("QGLPixelBuffer: Unable to find a context/format match - giving up.");
+ return false;
+ }
+}
+
+bool QGLPixelBufferPrivate::cleanup()
+{
+ glXDestroyPbuffer(QX11Info::display(), pbuf);
+ return true;
+}
+
+bool QGLPixelBuffer::bindToDynamicTexture(GLuint)
+{
+ return false;
+}
+
+void QGLPixelBuffer::releaseFromDynamicTexture()
+{
+}
+
+bool QGLPixelBuffer::hasOpenGLPbuffers()
+{
+ bool ret = qt_resolve_pbuffer_extensions();
+
+ if (!ret)
+ return false;
+
+ int attribs[40];
+ int num_configs = 0;
+
+ qt_format_to_attrib_list(QGLFormat::defaultFormat(), attribs);
+
+ GLXFBConfig *configs = glXChooseFBConfig(X11->display, X11->defaultScreen, attribs, &num_configs);
+ GLXPbuffer pbuf = 0;
+ GLXContext ctx = 0;
+
+ if (configs && num_configs) {
+ int pb_attribs[] = {GLX_PBUFFER_WIDTH, 128, GLX_PBUFFER_HEIGHT, 128, XNone};
+ pbuf = glXCreatePbuffer(X11->display, configs[0], pb_attribs);
+ ctx = glXCreateNewContext(X11->display, configs[0], GLX_RGBA_TYPE, 0, true);
+ XFree(configs);
+ glXDestroyContext(X11->display, ctx);
+ glXDestroyPbuffer(X11->display, pbuf);
+ }
+ return pbuf && ctx;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_waylandgl_egl.cpp b/src/opengl/qpixmapdata_waylandgl_egl.cpp
new file mode 100644
index 0000000000..2c11a0b441
--- /dev/null
+++ b/src/opengl/qpixmapdata_waylandgl_egl.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+
+#include <QtGui/private/qt_x11_p.h>
+#include <QtGui/private/qegl_p.h>
+#include <QtGui/private/qeglproperties_p.h>
+#include <QtGui/private/qeglcontext_p.h>
+
+#if !defined(QT_OPENGL_ES_1)
+#include <QtOpenGL/private/qpaintengineex_opengl2_p.h>
+#endif
+
+#ifndef QT_OPENGL_ES_2
+#include <QtOpenGL/private/qpaintengine_opengl_p.h>
+#endif
+
+#include <QtOpenGL/private/qgl_p.h>
+#include <QtOpenGL/private/qgl_egl_p.h>
+
+#include "qpixmapdata_x11gl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+class QX11GLSharedContexts
+{
+public:
+ QX11GLSharedContexts()
+ : rgbContext(0)
+ , argbContext(0)
+ , sharedQGLContext(0)
+ , sharePixmap(0)
+ {
+ EGLint rgbConfigId;
+ EGLint argbConfigId;
+
+ do {
+ EGLConfig rgbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable);
+ EGLConfig argbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL,
+ QEgl::Renderable | QEgl::Translucent);
+
+ eglGetConfigAttrib(QEgl::display(), rgbConfig, EGL_CONFIG_ID, &rgbConfigId);
+ eglGetConfigAttrib(QEgl::display(), argbConfig, EGL_CONFIG_ID, &argbConfigId);
+
+ rgbContext = new QEglContext;
+ rgbContext->setConfig(rgbConfig);
+ rgbContext->createContext();
+
+ if (!rgbContext->isValid())
+ break;
+
+ // If the RGB & ARGB configs are the same, use the same egl context for both:
+ if (rgbConfig == argbConfig)
+ argbContext = rgbContext;
+
+ // Otherwise, create a seperate context to be used for ARGB pixmaps:
+ if (!argbContext) {
+ argbContext = new QEglContext;
+ argbContext->setConfig(argbConfig);
+ bool success = argbContext->createContext(rgbContext);
+ if (!success) {
+ qWarning("QX11GLPixmapData - RGB & ARGB contexts aren't shared");
+ success = argbContext->createContext();
+ if (!success)
+ argbContext = rgbContext; // Might work, worth a shot at least.
+ }
+ }
+
+ if (!argbContext->isValid())
+ break;
+
+ // Create the pixmap which will be used to create the egl surface for the share QGLContext
+ QX11PixmapData *rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType);
+ rgbPixmapData->resize(8, 8);
+ rgbPixmapData->fill(Qt::red);
+ sharePixmap = new QPixmap(rgbPixmapData);
+ EGLSurface sharePixmapSurface = QEgl::createSurface(sharePixmap, rgbConfig);
+ rgbPixmapData->gl_surface = (void*)sharePixmapSurface;
+
+ // Create the actual QGLContext which will be used for sharing
+ sharedQGLContext = new QGLContext(QX11GLPixmapData::glFormat());
+ sharedQGLContext->d_func()->eglContext = rgbContext;
+ sharedQGLContext->d_func()->eglSurface = sharePixmapSurface;
+ sharedQGLContext->d_func()->valid = true;
+ qt_glformat_from_eglconfig(sharedQGLContext->d_func()->glFormat, rgbConfig);
+
+
+ valid = rgbContext->makeCurrent(sharePixmapSurface);
+
+ // If the ARGB & RGB configs are different, check ARGB works too:
+ if (argbConfig != rgbConfig) {
+ QX11PixmapData *argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType);
+ argbPixmapData->resize(8, 8);
+ argbPixmapData->fill(Qt::transparent); // Force ARGB
+ QPixmap argbPixmap(argbPixmapData); // destroys pixmap data when goes out of scope
+ EGLSurface argbPixmapSurface = QEgl::createSurface(&argbPixmap, argbConfig);
+ valid = argbContext->makeCurrent(argbPixmapSurface);
+ argbContext->doneCurrent();
+ eglDestroySurface(QEgl::display(), argbPixmapSurface);
+ argbPixmapData->gl_surface = 0;
+ }
+
+ if (!valid) {
+ qWarning() << "Unable to make pixmap surface current:" << QEgl::errorString();
+ break;
+ }
+
+ // The pixmap surface destruction hooks are installed by QGLTextureCache, so we
+ // must make sure this is instanciated:
+ QGLTextureCache::instance();
+ } while(0);
+
+ if (!valid)
+ cleanup();
+ else
+ qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId);
+
+ }
+
+ ~QX11GLSharedContexts() {
+ cleanup();
+ }
+
+ void cleanup() {
+ if (sharedQGLContext) {
+ delete sharedQGLContext;
+ sharedQGLContext = 0;
+ }
+ if (argbContext && argbContext != rgbContext)
+ delete argbContext;
+ argbContext = 0;
+
+ if (rgbContext) {
+ delete rgbContext;
+ rgbContext = 0;
+ }
+
+ // Deleting the QPixmap will fire the pixmap destruction cleanup hooks which in turn
+ // will destroy the egl surface:
+ if (sharePixmap) {
+ delete sharePixmap;
+ sharePixmap = 0;
+ }
+ }
+
+ bool isValid() { return valid;}
+
+ // On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need
+ // different contexts:
+ QEglContext *rgbContext;
+ QEglContext *argbContext;
+
+ // The share context wraps the rgbContext and is used as the master of the context share
+ // group. As all other contexts will have the same egl context (or a shared one if rgb != argb)
+ // all QGLContexts will actually be sharing and can be in the same context group.
+ QGLContext *sharedQGLContext;
+private:
+ QPixmap *sharePixmap;
+ bool valid;
+};
+
+static void qt_cleanup_x11gl_share_contexts();
+
+Q_GLOBAL_STATIC_WITH_INITIALIZER(QX11GLSharedContexts, qt_x11gl_share_contexts,
+ {
+ qAddPostRoutine(qt_cleanup_x11gl_share_contexts);
+ })
+
+static void qt_cleanup_x11gl_share_contexts()
+{
+ qt_x11gl_share_contexts()->cleanup();
+}
+
+
+QX11GLSharedContexts* QX11GLPixmapData::sharedContexts()
+{
+ return qt_x11gl_share_contexts();
+}
+
+bool QX11GLPixmapData::hasX11GLPixmaps()
+{
+ static bool checkedForX11GLPixmaps = false;
+ static bool haveX11GLPixmaps = false;
+
+ if (checkedForX11GLPixmaps)
+ return haveX11GLPixmaps;
+
+ haveX11GLPixmaps = qt_x11gl_share_contexts()->isValid();
+ checkedForX11GLPixmaps = true;
+
+ return haveX11GLPixmaps;
+}
+
+QX11GLPixmapData::QX11GLPixmapData()
+ : QX11PixmapData(QPixmapData::PixmapType),
+ ctx(0)
+{
+}
+
+QX11GLPixmapData::~QX11GLPixmapData()
+{
+ if (ctx)
+ delete ctx;
+}
+
+
+void QX11GLPixmapData::fill(const QColor &color)
+{
+ if (ctx) {
+ ctx->makeCurrent();
+ glFinish();
+ eglWaitClient();
+ }
+
+ QX11PixmapData::fill(color);
+ XSync(X11->display, False);
+
+ if (ctx) {
+ ctx->makeCurrent();
+ eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+ }
+}
+
+void QX11GLPixmapData::copy(const QPixmapData *data, const QRect &rect)
+{
+ if (ctx) {
+ ctx->makeCurrent();
+ glFinish();
+ eglWaitClient();
+ }
+
+ QX11PixmapData::copy(data, rect);
+ XSync(X11->display, False);
+
+ if (ctx) {
+ ctx->makeCurrent();
+ eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+ }
+}
+
+bool QX11GLPixmapData::scroll(int dx, int dy, const QRect &rect)
+{
+ if (ctx) {
+ ctx->makeCurrent();
+ glFinish();
+ eglWaitClient();
+ }
+
+ bool success = QX11PixmapData::scroll(dx, dy, rect);
+ XSync(X11->display, False);
+
+ if (ctx) {
+ ctx->makeCurrent();
+ eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+ }
+
+ return success;
+}
+
+#if !defined(QT_OPENGL_ES_1)
+Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_pixmap_2_engine)
+#endif
+
+#ifndef QT_OPENGL_ES_2
+Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_pixmap_engine)
+#endif
+
+
+QPaintEngine* QX11GLPixmapData::paintEngine() const
+{
+ // We need to create the context before beginPaint - do it here:
+ if (!ctx) {
+ ctx = new QGLContext(glFormat());
+ Q_ASSERT(ctx->d_func()->eglContext == 0);
+ ctx->d_func()->eglContext = hasAlphaChannel() ? sharedContexts()->argbContext : sharedContexts()->rgbContext;
+
+ // While we use a seperate QGLContext for each pixmap, the underlying QEglContext is
+ // the same. So we must use a "fake" QGLContext and fool the texture cache into thinking
+ // each pixmap's QGLContext is sharing with this central one. The only place this is
+ // going to fail is where we the underlying EGL RGB and ARGB contexts aren't sharing.
+ ctx->d_func()->sharing = true;
+ QGLContextGroup::addShare(ctx, sharedContexts()->sharedQGLContext);
+
+ // Update the glFormat for the QGLContext:
+ qt_glformat_from_eglconfig(ctx->d_func()->glFormat, ctx->d_func()->eglContext->config());
+ }
+
+ QPaintEngine* engine;
+
+#if defined(QT_OPENGL_ES_1)
+ engine = qt_gl_pixmap_engine();
+#elif defined(QT_OPENGL_ES_2)
+ engine = qt_gl_pixmap_2_engine();
+#else
+ if (qt_gl_preferGL2Engine())
+ engine = qt_gl_pixmap_2_engine();
+ else
+ engine = qt_gl_pixmap_engine();
+#endif
+
+
+
+ // Support multiple painters on multiple pixmaps simultaniously
+ if (engine->isActive()) {
+ qWarning("Pixmap paint engine already active");
+
+#if defined(QT_OPENGL_ES_1)
+ engine = new QOpenGLPaintEngine;
+#elif defined(QT_OPENGL_ES_2)
+ engine = new QGL2PaintEngineEx;
+#else
+ if (qt_gl_preferGL2Engine())
+ engine = new QGL2PaintEngineEx;
+ else
+ engine = new QOpenGLPaintEngine;
+#endif
+
+ engine->setAutoDestruct(true);
+ return engine;
+ }
+
+ return engine;
+}
+
+void QX11GLPixmapData::beginPaint()
+{
+// qDebug("QX11GLPixmapData::beginPaint()");
+ // TODO: Check to see if the surface is renderable
+ if ((EGLSurface)gl_surface == EGL_NO_SURFACE) {
+ QPixmap tmpPixmap(this);
+ EGLConfig cfg = ctx->d_func()->eglContext->config();
+ Q_ASSERT(cfg != QEGL_NO_CONFIG);
+
+// qDebug("QX11GLPixmapData - using EGL Config ID %d", ctx->d_func()->eglContext->configAttrib(EGL_CONFIG_ID));
+ EGLSurface surface = QEgl::createSurface(&tmpPixmap, cfg);
+ if (surface == EGL_NO_SURFACE) {
+ qWarning() << "Error creating EGL surface for pixmap:" << QEgl::errorString();
+ return;
+ }
+ gl_surface = (void*)surface;
+ ctx->d_func()->eglSurface = surface;
+ ctx->d_func()->valid = true;
+ }
+ QGLPaintDevice::beginPaint();
+}
+
+QGLContext* QX11GLPixmapData::context() const
+{
+ return ctx;
+}
+
+QSize QX11GLPixmapData::size() const
+{
+ return QSize(w, h);
+}
+
+
+QGLFormat QX11GLPixmapData::glFormat()
+{
+ return QGLFormat::defaultFormat(); //###
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_waylandgl_p.h b/src/opengl/qpixmapdata_waylandgl_p.h
new file mode 100644
index 0000000000..2d1336bef1
--- /dev/null
+++ b/src/opengl/qpixmapdata_waylandgl_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPIXMAPDATA_X11GL_P_H
+#define QPIXMAPDATA_X11GL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qpixmapdata_p.h>
+#include <private/qpixmap_x11_p.h>
+#include <private/qglpaintdevice_p.h>
+
+#include <qgl.h>
+
+#ifndef QT_NO_EGL
+#include <QtGui/private/qeglcontext_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QX11GLSharedContexts;
+
+class QX11GLPixmapData : public QX11PixmapData, public QGLPaintDevice
+{
+public:
+ QX11GLPixmapData();
+ virtual ~QX11GLPixmapData();
+
+ // Re-implemented from QX11PixmapData:
+ void fill(const QColor &color);
+ void copy(const QPixmapData *data, const QRect &rect);
+ bool scroll(int dx, int dy, const QRect &rect);
+
+ // Re-implemented from QGLPaintDevice
+ QPaintEngine* paintEngine() const; // Also re-implements QX11PixmapData::paintEngine
+ void beginPaint();
+ QGLContext* context() const;
+ QSize size() const;
+
+ static bool hasX11GLPixmaps();
+ static QGLFormat glFormat();
+ static QX11GLSharedContexts* sharedContexts();
+
+private:
+ mutable QGLContext* ctx;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QPIXMAPDATA_X11GL_P_H
diff --git a/src/opengl/qwindowsurface_waylandgl.cpp b/src/opengl/qwindowsurface_waylandgl.cpp
new file mode 100644
index 0000000000..3de6cae056
--- /dev/null
+++ b/src/opengl/qwindowsurface_waylandgl.cpp
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QTime>
+#include <QDebug>
+
+#include <private/qt_x11_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
+
+#include "qwindowsurface_x11gl_p.h"
+#include "qpixmapdata_x11gl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QX11GLWindowSurface::QX11GLWindowSurface(QWidget* window)
+ : QWindowSurface(window), m_windowGC(0), m_pixmapGC(0), m_window(window)
+{
+}
+
+QX11GLWindowSurface::~QX11GLWindowSurface()
+{
+ if (m_windowGC)
+ XFree(m_windowGC);
+ if (m_pixmapGC)
+ XFree(m_pixmapGC);
+}
+
+QPaintDevice *QX11GLWindowSurface::paintDevice()
+{
+ return &m_backBuffer;
+}
+
+extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp
+
+void QX11GLWindowSurface::flush(QWidget *widget, const QRegion &widgetRegion, const QPoint &offset)
+{
+ // We don't need to know the widget which initiated the flush. Instead we just use the offset
+ // to translate the widgetRegion:
+ Q_UNUSED(widget);
+
+ if (m_backBuffer.isNull()) {
+ qDebug("QX11GLWindowSurface::flush() - backBuffer is null, not flushing anything");
+ return;
+ }
+
+ Q_ASSERT(window()->size() != m_backBuffer.size());
+
+ // Wait for all GL rendering to the back buffer pixmap to complete before trying to
+ // copy it to the window. We do this by making sure the pixmap's context is current
+ // and then call eglWaitClient. The EGL 1.4 spec says eglWaitClient doesn't have to
+ // block, just that "All rendering calls...are guaranteed to be executed before native
+ // rendering calls". This makes it potentially less expensive than glFinish.
+ QGLContext* ctx = static_cast<QX11GLPixmapData*>(m_backBuffer.data_ptr().data())->context();
+ if (QGLContext::currentContext() != ctx && ctx && ctx->isValid())
+ ctx->makeCurrent();
+ eglWaitClient();
+
+ if (m_windowGC == 0) {
+ XGCValues attribs;
+ attribs.graphics_exposures = False;
+ m_windowGC = XCreateGC(X11->display, m_window->handle(), GCGraphicsExposures, &attribs);
+ }
+
+ int rectCount;
+ XRectangle *rects = (XRectangle *)qt_getClipRects(widgetRegion, rectCount);
+ if (rectCount <= 0)
+ return;
+
+ XSetClipRectangles(X11->display, m_windowGC, 0, 0, rects, rectCount, YXBanded);
+
+ QRect dirtyRect = widgetRegion.boundingRect().translated(-offset);
+ XCopyArea(X11->display, m_backBuffer.handle(), m_window->handle(), m_windowGC,
+ dirtyRect.x(), dirtyRect.y(), dirtyRect.width(), dirtyRect.height(),
+ dirtyRect.x(), dirtyRect.y());
+
+ // Make sure the blit of the update from the back buffer to the window completes
+ // before allowing rendering to start again to the back buffer. Otherwise the GPU
+ // might start rendering to the back buffer again while the blit takes place.
+ eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+}
+
+void QX11GLWindowSurface::setGeometry(const QRect &rect)
+{
+ if (rect.width() > m_backBuffer.size().width() || rect.height() > m_backBuffer.size().height()) {
+ QX11GLPixmapData *pd = new QX11GLPixmapData;
+ QSize newSize = rect.size();
+ pd->resize(newSize.width(), newSize.height());
+ m_backBuffer = QPixmap(pd);
+ if (window()->testAttribute(Qt::WA_TranslucentBackground))
+ m_backBuffer.fill(Qt::transparent);
+ if (m_pixmapGC) {
+ XFreeGC(X11->display, m_pixmapGC);
+ m_pixmapGC = 0;
+ }
+ }
+
+ QWindowSurface::setGeometry(rect);
+}
+
+bool QX11GLWindowSurface::scroll(const QRegion &area, int dx, int dy)
+{
+ if (m_backBuffer.isNull())
+ return false;
+
+ Q_ASSERT(m_backBuffer.data_ptr()->classId() == QPixmapData::X11Class);
+
+ // Make sure all GL rendering is complete before starting the scroll operation:
+ QGLContext* ctx = static_cast<QX11GLPixmapData*>(m_backBuffer.data_ptr().data())->context();
+ if (QGLContext::currentContext() != ctx && ctx && ctx->isValid())
+ ctx->makeCurrent();
+ eglWaitClient();
+
+ if (!m_pixmapGC)
+ m_pixmapGC = XCreateGC(X11->display, m_backBuffer.handle(), 0, 0);
+
+ foreach (const QRect& rect, area.rects()) {
+ XCopyArea(X11->display, m_backBuffer.handle(), m_backBuffer.handle(), m_pixmapGC,
+ rect.x(), rect.y(), rect.width(), rect.height(),
+ rect.x()+dx, rect.y()+dy);
+ }
+
+ // Make sure the scroll operation is complete before allowing GL rendering to resume
+ eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+
+ return true;
+}
+
+
+QPixmap QX11GLWindowSurface::grabWidget(const QWidget *widget, const QRect& rect) const
+{
+ if (!widget || m_backBuffer.isNull())
+ return QPixmap();
+
+ QRect srcRect;
+
+ // make sure the rect is inside the widget & clip to widget's rect
+ if (!rect.isEmpty())
+ srcRect = rect & widget->rect();
+ else
+ srcRect = widget->rect();
+
+ if (srcRect.isEmpty())
+ return QPixmap();
+
+ // If it's a child widget we have to translate the coordinates
+ if (widget != window())
+ srcRect.translate(widget->mapTo(window(), QPoint(0, 0)));
+
+ QPixmap::x11SetDefaultScreen(widget->x11Info().screen());
+
+ QX11PixmapData *pmd = new QX11PixmapData(QPixmapData::PixmapType);
+ pmd->resize(srcRect.width(), srcRect.height());
+ QPixmap px(pmd);
+
+ GC tmpGc = XCreateGC(X11->display, m_backBuffer.handle(), 0, 0);
+
+ // Make sure all GL rendering is complete before copying the window
+ QGLContext* ctx = static_cast<QX11GLPixmapData*>(m_backBuffer.pixmapData())->context();
+ if (QGLContext::currentContext() != ctx && ctx && ctx->isValid())
+ ctx->makeCurrent();
+ eglWaitClient();
+
+ // Copy srcRect from the backing store to the new pixmap
+ XSetGraphicsExposures(X11->display, tmpGc, False);
+ XCopyArea(X11->display, m_backBuffer.handle(), px.handle(), tmpGc,
+ srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), 0, 0);
+ XFreeGC(X11->display, tmpGc);
+
+ // Wait until the copy has finised before allowing more rendering into the back buffer
+ eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+
+ return px;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qwindowsurface_waylandgl_p.h b/src/opengl/qwindowsurface_waylandgl_p.h
new file mode 100644
index 0000000000..4d493d0b8f
--- /dev/null
+++ b/src/opengl/qwindowsurface_waylandgl_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSURFACE_X11GL_P_H
+#define QWINDOWSURFACE_X11GL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qwindowsurface_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QX11GLWindowSurface : public QWindowSurface
+{
+public:
+ QX11GLWindowSurface(QWidget* window);
+ virtual ~QX11GLWindowSurface();
+
+ // Inherreted from QWindowSurface
+ QPaintDevice *paintDevice();
+ void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
+ void setGeometry(const QRect &rect);
+ bool scroll(const QRegion &area, int dx, int dy);
+ QPixmap grabWidget(const QWidget *widget, const QRect& rectangle = QRect()) const;
+
+private:
+ GC m_windowGC;
+ GC m_pixmapGC;
+ QPixmap m_backBuffer;
+ QWidget *m_window;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSURFACE_X11GL_P_H