summaryrefslogtreecommitdiffstats
path: root/src/widgets/platforms/x11
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/platforms/x11')
-rw-r--r--src/widgets/platforms/x11/qapplication_x11.cpp6239
-rw-r--r--src/widgets/platforms/x11/qclipboard_x11.cpp1539
-rw-r--r--src/widgets/platforms/x11/qcolormap_x11.cpp670
-rw-r--r--src/widgets/platforms/x11/qcursor_x11.cpp637
-rw-r--r--src/widgets/platforms/x11/qdesktopwidget_x11.cpp406
-rw-r--r--src/widgets/platforms/x11/qdnd_x11.cpp2072
-rw-r--r--src/widgets/platforms/x11/qeventdispatcher_x11.cpp191
-rw-r--r--src/widgets/platforms/x11/qeventdispatcher_x11_p.h86
-rw-r--r--src/widgets/platforms/x11/qfont_x11.cpp368
-rw-r--r--src/widgets/platforms/x11/qfontdatabase_x11.cpp2146
-rw-r--r--src/widgets/platforms/x11/qfontengine_x11.cpp1215
-rw-r--r--src/widgets/platforms/x11/qfontengine_x11_p.h180
-rw-r--r--src/widgets/platforms/x11/qkde.cpp176
-rw-r--r--src/widgets/platforms/x11/qkde_p.h81
-rw-r--r--src/widgets/platforms/x11/qkeymapper_x11.cpp1869
-rw-r--r--src/widgets/platforms/x11/qkeymapper_x11_p.cpp489
-rw-r--r--src/widgets/platforms/x11/qmotifdnd_x11.cpp1031
-rw-r--r--src/widgets/platforms/x11/qpaintdevice_x11.cpp84
-rw-r--r--src/widgets/platforms/x11/qpaintengine_x11.cpp2507
-rw-r--r--src/widgets/platforms/x11/qpaintengine_x11_p.h246
-rw-r--r--src/widgets/platforms/x11/qpixmap_x11.cpp2419
-rw-r--r--src/widgets/platforms/x11/qpixmap_x11_p.h156
-rw-r--r--src/widgets/platforms/x11/qregion_x11.cpp92
-rw-r--r--src/widgets/platforms/x11/qsound_x11.cpp296
-rw-r--r--src/widgets/platforms/x11/qt_x11_p.h757
-rw-r--r--src/widgets/platforms/x11/qwidget_x11.cpp3146
-rw-r--r--src/widgets/platforms/x11/qwidgetcreate_x11.cpp79
-rw-r--r--src/widgets/platforms/x11/qx11embed_x11.cpp1808
-rw-r--r--src/widgets/platforms/x11/qx11embed_x11.h132
-rw-r--r--src/widgets/platforms/x11/qx11info_x11.cpp543
-rw-r--r--src/widgets/platforms/x11/qx11info_x11.h123
31 files changed, 31783 insertions, 0 deletions
diff --git a/src/widgets/platforms/x11/qapplication_x11.cpp b/src/widgets/platforms/x11/qapplication_x11.cpp
new file mode 100644
index 0000000000..20542ea328
--- /dev/null
+++ b/src/widgets/platforms/x11/qapplication_x11.cpp
@@ -0,0 +1,6239 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+// ### 4.0: examine Q_EXPORT's below. The respective symbols had all
+// been in use (e.g. in the KDE wm) before the introduction of a version
+// map. One might want to turn some of them into proper public API and
+// provide a proper alternative for others. See also the exports in
+// qapplication_win.cpp, which suggest a unification.
+
+#include "qplatformdefs.h"
+
+#include "qcolormap.h"
+#include "qdesktopwidget.h"
+#include "qapplication.h"
+#include "qapplication_p.h"
+#include "qcursor.h"
+#include "qwidget.h"
+#include "qbitarray.h"
+#include "qpainter.h"
+#include "qfile.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 "qwhatsthis.h"
+#include "qsettings.h"
+#include "qstylefactory.h"
+#include "qfileinfo.h"
+#include "qdir.h"
+#include "qhash.h"
+#include "qevent.h"
+#include "qevent_p.h"
+#include "qvarlengtharray.h"
+#include "qdebug.h"
+#include <private/qcrashhandler_p.h>
+#include <private/qcolor_p.h>
+#include <private/qcursor_p.h>
+#include <private/qiconloader_p.h>
+#include <qgtkstyle.h>
+#include "qstyle.h"
+#include "qmetaobject.h"
+#include "qtimer.h"
+#include "qlibrary.h"
+#include <private/qgraphicssystemfactory_p.h>
+#include "qguiplatformplugin_p.h"
+#include "qkde_p.h"
+
+#if !defined (QT_NO_TABLET)
+extern "C" {
+# define class c_class //XIproto.h has a name member named 'class' which the c++ compiler doesn't like
+# include <wacomcfg.h>
+# undef class
+}
+#endif
+
+#ifndef QT_GUI_DOUBLE_CLICK_RADIUS
+#define QT_GUI_DOUBLE_CLICK_RADIUS 5
+#endif
+
+
+//#define ALIEN_DEBUG
+
+#if !defined(QT_NO_GLIB)
+# include "qguieventdispatcher_glib_p.h"
+#endif
+#include "qeventdispatcher_x11_p.h"
+#include <private/qpaintengine_x11_p.h>
+
+#include <private/qkeymapper_p.h>
+
+// Input method stuff
+#ifndef QT_NO_IM
+#include "qinputcontext.h"
+#include "qinputcontextfactory.h"
+#endif // QT_NO_IM
+
+#ifndef QT_NO_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif // QT_NO_XFIXES
+
+#include "qt_x11_p.h"
+#include "qx11info_x11.h"
+
+#define XK_MISCELLANY
+#include <X11/keysymdef.h>
+#if !defined(QT_NO_XINPUT)
+#include <X11/extensions/XI.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <locale.h>
+
+#include "qwidget_p.h"
+
+#include <private/qbackingstore_p.h>
+
+#ifdef QT_RX71_MULTITOUCH
+# include <qsocketnotifier.h>
+# include <linux/input.h>
+# include <errno.h>
+#endif
+
+#if _POSIX_VERSION+0 < 200112L && !defined(Q_OS_BSD4)
+# define QT_NO_UNSETENV
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//#define X_NOT_BROKEN
+#ifdef X_NOT_BROKEN
+// Some X libraries are built with setlocale #defined to _Xsetlocale,
+// even though library users are then built WITHOUT such a definition.
+// This creates a problem - Qt might setlocale() one value, but then
+// X looks and doesn't see the value Qt set. The solution here is to
+// implement _Xsetlocale just in case X calls it - redirecting it to
+// the real libC version.
+//
+# ifndef setlocale
+extern "C" char *_Xsetlocale(int category, const char *locale);
+char *_Xsetlocale(int category, const char *locale)
+{
+ //qDebug("_Xsetlocale(%d,%s),category,locale");
+ return setlocale(category,locale);
+}
+# endif // setlocale
+#endif // X_NOT_BROKEN
+
+/* Warning: if you modify this string, modify the list of atoms in qt_x11_p.h as well! */
+static const char * x11_atomnames = {
+ // window-manager <-> client protocols
+ "WM_PROTOCOLS\0"
+ "WM_DELETE_WINDOW\0"
+ "WM_TAKE_FOCUS\0"
+ "_NET_WM_PING\0"
+ "_NET_WM_CONTEXT_HELP\0"
+ "_NET_WM_SYNC_REQUEST\0"
+ "_NET_WM_SYNC_REQUEST_COUNTER\0"
+
+ // ICCCM window state
+ "WM_STATE\0"
+ "WM_CHANGE_STATE\0"
+
+ // Session management
+ "WM_CLIENT_LEADER\0"
+ "WM_WINDOW_ROLE\0"
+ "SM_CLIENT_ID\0"
+
+ // Clipboard
+ "CLIPBOARD\0"
+ "INCR\0"
+ "TARGETS\0"
+ "MULTIPLE\0"
+ "TIMESTAMP\0"
+ "SAVE_TARGETS\0"
+ "CLIP_TEMPORARY\0"
+ "_QT_SELECTION\0"
+ "_QT_CLIPBOARD_SENTINEL\0"
+ "_QT_SELECTION_SENTINEL\0"
+ "CLIPBOARD_MANAGER\0"
+
+ "RESOURCE_MANAGER\0"
+
+ "_XSETROOT_ID\0"
+
+ "_QT_SCROLL_DONE\0"
+ "_QT_INPUT_ENCODING\0"
+
+ "_MOTIF_WM_HINTS\0"
+
+ "DTWM_IS_RUNNING\0"
+ "ENLIGHTENMENT_DESKTOP\0"
+ "_DT_SAVE_MODE\0"
+ "_SGI_DESKS_MANAGER\0"
+
+ // EWMH (aka NETWM)
+ "_NET_SUPPORTED\0"
+ "_NET_VIRTUAL_ROOTS\0"
+ "_NET_WORKAREA\0"
+
+ "_NET_MOVERESIZE_WINDOW\0"
+ "_NET_WM_MOVERESIZE\0"
+
+ "_NET_WM_NAME\0"
+ "_NET_WM_ICON_NAME\0"
+ "_NET_WM_ICON\0"
+
+ "_NET_WM_PID\0"
+
+ "_NET_WM_WINDOW_OPACITY\0"
+
+ "_NET_WM_STATE\0"
+ "_NET_WM_STATE_ABOVE\0"
+ "_NET_WM_STATE_BELOW\0"
+ "_NET_WM_STATE_FULLSCREEN\0"
+ "_NET_WM_STATE_MAXIMIZED_HORZ\0"
+ "_NET_WM_STATE_MAXIMIZED_VERT\0"
+ "_NET_WM_STATE_MODAL\0"
+ "_NET_WM_STATE_STAYS_ON_TOP\0"
+ "_NET_WM_STATE_DEMANDS_ATTENTION\0"
+
+ "_NET_WM_USER_TIME\0"
+ "_NET_WM_USER_TIME_WINDOW\0"
+ "_NET_WM_FULL_PLACEMENT\0"
+
+ "_NET_WM_WINDOW_TYPE\0"
+ "_NET_WM_WINDOW_TYPE_DESKTOP\0"
+ "_NET_WM_WINDOW_TYPE_DOCK\0"
+ "_NET_WM_WINDOW_TYPE_TOOLBAR\0"
+ "_NET_WM_WINDOW_TYPE_MENU\0"
+ "_NET_WM_WINDOW_TYPE_UTILITY\0"
+ "_NET_WM_WINDOW_TYPE_SPLASH\0"
+ "_NET_WM_WINDOW_TYPE_DIALOG\0"
+ "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0"
+ "_NET_WM_WINDOW_TYPE_POPUP_MENU\0"
+ "_NET_WM_WINDOW_TYPE_TOOLTIP\0"
+ "_NET_WM_WINDOW_TYPE_NOTIFICATION\0"
+ "_NET_WM_WINDOW_TYPE_COMBO\0"
+ "_NET_WM_WINDOW_TYPE_DND\0"
+ "_NET_WM_WINDOW_TYPE_NORMAL\0"
+ "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0"
+
+ "_KDE_NET_WM_FRAME_STRUT\0"
+
+ "_NET_STARTUP_INFO\0"
+ "_NET_STARTUP_INFO_BEGIN\0"
+
+ "_NET_SUPPORTING_WM_CHECK\0"
+
+ "_NET_WM_CM_S0\0"
+
+ "_NET_SYSTEM_TRAY_VISUAL\0"
+
+ "_NET_ACTIVE_WINDOW\0"
+
+ // Property formats
+ "COMPOUND_TEXT\0"
+ "TEXT\0"
+ "UTF8_STRING\0"
+
+ // xdnd
+ "XdndEnter\0"
+ "XdndPosition\0"
+ "XdndStatus\0"
+ "XdndLeave\0"
+ "XdndDrop\0"
+ "XdndFinished\0"
+ "XdndTypeList\0"
+ "XdndActionList\0"
+
+ "XdndSelection\0"
+
+ "XdndAware\0"
+ "XdndProxy\0"
+
+ "XdndActionCopy\0"
+ "XdndActionLink\0"
+ "XdndActionMove\0"
+ "XdndActionPrivate\0"
+
+ // Motif DND
+ "_MOTIF_DRAG_AND_DROP_MESSAGE\0"
+ "_MOTIF_DRAG_INITIATOR_INFO\0"
+ "_MOTIF_DRAG_RECEIVER_INFO\0"
+ "_MOTIF_DRAG_WINDOW\0"
+ "_MOTIF_DRAG_TARGETS\0"
+
+ "XmTRANSFER_SUCCESS\0"
+ "XmTRANSFER_FAILURE\0"
+
+ // Xkb
+ "_XKB_RULES_NAMES\0"
+
+ // XEMBED
+ "_XEMBED\0"
+ "_XEMBED_INFO\0"
+
+ // Wacom old. (before version 0.10)
+ "Wacom Stylus\0"
+ "Wacom Cursor\0"
+ "Wacom Eraser\0"
+
+ // Tablet
+ "STYLUS\0"
+ "ERASER\0"
+};
+
+Q_GUI_EXPORT QX11Data *qt_x11Data = 0;
+
+/*****************************************************************************
+ Internal variables and functions
+ *****************************************************************************/
+static const char *appName = 0; // application name
+static const char *appClass = 0; // application class
+static const char *appFont = 0; // application font
+static const char *appBGCol = 0; // application bg color
+static const char *appFGCol = 0; // application fg color
+static const char *appBTNCol = 0; // application btn color
+static const char *mwGeometry = 0; // main widget geometry
+static const char *mwTitle = 0; // main widget title
+char *qt_ximServer = 0; // XIM Server will connect to
+static bool appSync = false; // X11 synchronization
+#if defined(QT_DEBUG)
+static bool appNoGrab = false; // X11 grabbing enabled
+static bool appDoGrab = false; // X11 grabbing override (gdb)
+#endif
+static bool app_save_rootinfo = false; // save root info
+static bool app_do_modal = false; // modal mode
+static Window curWin = 0; // current window
+
+
+// function to update the workarea of the screen - in qdesktopwidget_x11.cpp
+extern void qt_desktopwidget_update_workarea();
+
+// Function to change the window manager state (from qwidget_x11.cpp)
+extern void qt_change_net_wm_state(const QWidget *w, bool set, Atom one, Atom two = 0);
+
+// modifier masks for alt, meta, super, hyper, and mode_switch - detected when the application starts
+// and/or keyboard layout changes
+uchar qt_alt_mask = 0;
+uchar qt_meta_mask = 0;
+uchar qt_super_mask = 0;
+uchar qt_hyper_mask = 0;
+uchar qt_mode_switch_mask = 0;
+
+// flags for extensions for special Languages, currently only for RTL languages
+bool qt_use_rtl_extensions = false;
+
+static Window mouseActWindow = 0; // window where mouse is
+static Qt::MouseButton mouseButtonPressed = Qt::NoButton; // last mouse button pressed
+static Qt::MouseButtons mouseButtonState = Qt::NoButton; // mouse button state
+static Time mouseButtonPressTime = 0; // when was a button pressed
+static short mouseXPos, mouseYPos; // mouse pres position in act window
+static short mouseGlobalXPos, mouseGlobalYPos; // global mouse press position
+
+extern QWidgetList *qt_modal_stack; // stack of modal widgets
+
+// window where mouse buttons have been pressed
+static Window pressed_window = XNone;
+
+// popup control
+static bool replayPopupMouseEvent = false;
+static bool popupGrabOk;
+
+bool qt_sm_blockUserInput = false; // session management
+
+Q_GUI_EXPORT int qt_xfocusout_grab_counter = 0;
+
+#if !defined (QT_NO_TABLET)
+Q_GLOBAL_STATIC(QTabletDeviceDataList, tablet_devices)
+QTabletDeviceDataList *qt_tablet_devices()
+{
+ return tablet_devices();
+}
+
+extern bool qt_tabletChokeMouse;
+#endif
+
+typedef bool(*QX11FilterFunction)(XEvent *event);
+
+Q_GLOBAL_STATIC(QList<QX11FilterFunction>, x11Filters)
+
+Q_GUI_EXPORT void qt_installX11EventFilter(QX11FilterFunction func)
+{
+ Q_ASSERT(func);
+
+ if (QList<QX11FilterFunction> *list = x11Filters())
+ list->append(func);
+}
+
+Q_GUI_EXPORT void qt_removeX11EventFilter(QX11FilterFunction func)
+{
+ Q_ASSERT(func);
+
+ if (QList<QX11FilterFunction> *list = x11Filters())
+ list->removeOne(func);
+}
+
+
+static bool qt_x11EventFilter(XEvent* ev)
+{
+ long unused;
+ if (qApp->filterEvent(ev, &unused))
+ return true;
+ if (const QList<QX11FilterFunction> *list = x11Filters()) {
+ for (QList<QX11FilterFunction>::const_iterator it = list->constBegin(); it != list->constEnd(); ++it) {
+ if ((*it)(ev))
+ return true;
+ }
+ }
+
+ return qApp->x11EventFilter(ev);
+}
+
+#if !defined(QT_NO_XIM)
+XIMStyle qt_xim_preferred_style = 0;
+#endif
+int qt_ximComposingKeycode=0;
+QTextCodec * qt_input_mapper = 0;
+
+extern bool qt_check_clipboard_sentinel(); //def in qclipboard_x11.cpp
+extern bool qt_check_selection_sentinel(); //def in qclipboard_x11.cpp
+extern bool qt_xfixes_clipboard_changed(Window clipboardOwner, Time timestamp); //def in qclipboard_x11.cpp
+extern bool qt_xfixes_selection_changed(Window selectionOwner, Time timestamp); //def in qclipboard_x11.cpp
+
+static void qt_save_rootinfo();
+Q_GUI_EXPORT bool qt_try_modal(QWidget *, XEvent *);
+
+QWidget *qt_button_down = 0; // last widget to be pressed with the mouse
+QPointer<QWidget> qt_last_mouse_receiver = 0;
+static QWidget *qt_popup_down = 0; // popup that contains the pressed widget
+
+extern bool qt_xdnd_dragging;
+
+// gui or non-gui from qapplication.cpp
+extern bool qt_is_gui_used;
+
+/*!
+ \internal
+ Try to resolve a \a symbol from \a library with the version specified
+ by \a vernum.
+
+ Note that, in the case of the Xfixes library, \a vernum is not the same as
+ \c XFIXES_MAJOR - it is a part of soname and may differ from the Xfixes
+ version.
+*/
+static void* qt_load_library_runtime(const char *library, int vernum,
+ int highestVernum, const char *symbol)
+{
+ QList<int> versions;
+ // we try to load in the following order:
+ // explicit version -> the default one -> (from the highest (highestVernum) to the lowest (vernum) )
+ if (vernum != -1)
+ versions << vernum;
+ versions << -1;
+ if (vernum != -1) {
+ for(int i = highestVernum; i > vernum; --i)
+ versions << i;
+ }
+ Q_FOREACH(int version, versions) {
+ QLatin1String libName(library);
+ QLibrary xfixesLib(libName, version);
+ void *ptr = xfixesLib.resolve(symbol);
+ if (ptr)
+ return ptr;
+ }
+ return 0;
+}
+
+#ifndef QT_NO_XINPUT
+# ifdef QT_RUNTIME_XINPUT
+# define XINPUT_LOAD_RUNTIME(vernum, symbol, symbol_type) \
+ (symbol_type)qt_load_library_runtime("libXi", vernum, 6, #symbol);
+# define XINPUT_LOAD(symbol) \
+ XINPUT_LOAD_RUNTIME(1, symbol, Ptr##symbol)
+# else // not runtime XInput
+# define XINPUT_LOAD(symbol) symbol
+# endif // QT_RUNTIME_XINPUT
+#else // not using Xinput at all
+# define XINPUT_LOAD(symbol) 0
+#endif // QT_NO_XINPUT
+
+#ifndef QT_NO_XFIXES
+# ifdef QT_RUNTIME_XFIXES
+# define XFIXES_LOAD_RUNTIME(vernum, symbol, symbol_type) \
+ (symbol_type)qt_load_library_runtime("libXfixes", vernum, 4, #symbol);
+# define XFIXES_LOAD_V1(symbol) \
+ XFIXES_LOAD_RUNTIME(1, symbol, Ptr##symbol)
+# define XFIXES_LOAD_V2(symbol) \
+ XFIXES_LOAD_RUNTIME(2, symbol, Ptr##symbol)
+
+# else // not runtime Xfixes
+
+# if XFIXES_MAJOR >= 2
+# define XFIXES_LOAD_V1(symbol) symbol
+# define XFIXES_LOAD_V2(symbol) symbol
+# elif XFIXES_MAJOR >= 1
+# define XFIXES_LOAD_V1(symbol) symbol
+# define XFIXES_LOAD_V2(symbol) 0
+# else
+# error Unsupported version of Xfixes
+# endif
+# endif // QT_RUNTIME_XFIXES
+#else // not using Xfixes at all
+# define XFIXES_LOAD_V1(symbol) 0
+# define XFIXES_LOAD_V2(symbol) 0
+#endif // QT_NO_XFIXES
+
+#ifndef QT_NO_XFIXES
+
+struct qt_xfixes_selection_event_data
+{
+ // which selection to filter out.
+ Atom selection;
+};
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static Bool qt_xfixes_scanner(Display*, XEvent *event, XPointer arg)
+{
+ qt_xfixes_selection_event_data *data =
+ reinterpret_cast<qt_xfixes_selection_event_data*>(arg);
+ if (event->type == X11->xfixes_eventbase + XFixesSelectionNotify) {
+ XFixesSelectionNotifyEvent *xfixes_event = reinterpret_cast<XFixesSelectionNotifyEvent*>(event);
+ if (xfixes_event->selection == data->selection)
+ return true;
+ }
+ return false;
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+#endif // QT_NO_XFIXES
+
+class QETWidget : public QWidget // event translator widget
+{
+public:
+ QWidgetPrivate* d_func() { return QWidget::d_func(); }
+ bool translateMouseEvent(const XEvent *);
+ void translatePaintEvent(const XEvent *);
+ bool translateConfigEvent(const XEvent *);
+ bool translateCloseEvent(const XEvent *);
+ bool translateScrollDoneEvent(const XEvent *);
+ bool translateWheelEvent(int global_x, int global_y, int delta, Qt::MouseButtons buttons,
+ Qt::KeyboardModifiers modifiers, Qt::Orientation orient);
+#if !defined (QT_NO_TABLET)
+ bool translateXinputEvent(const XEvent*, QTabletDeviceData *tablet);
+#endif
+ bool translatePropertyEvent(const XEvent *);
+
+ void doDeferredMap()
+ {
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ if (!testAttribute(Qt::WA_Resized)) {
+ adjustSize();
+ setAttribute(Qt::WA_Resized, false);
+ }
+
+ /*
+ workaround for WM's that throw away ConfigureRequests from the following:
+
+ window->hide();
+ window->move(x, y); // could also be resize(), move()+resize(), or setGeometry()
+ window->show();
+ */
+ QRect r = geometry();
+
+ XMoveResizeWindow(X11->display,
+ internalWinId(),
+ r.x(),
+ r.y(),
+ r.width(),
+ r.height());
+
+ // static gravity!
+ XSizeHints sh;
+ long unused;
+ XGetWMNormalHints(X11->display, internalWinId(), &sh, &unused);
+ sh.flags |= USPosition | PPosition | USSize | PSize | PWinGravity;
+ sh.x = r.x();
+ sh.y = r.y();
+ sh.width = r.width();
+ sh.height = r.height();
+ sh.win_gravity = StaticGravity;
+ XSetWMNormalHints(X11->display, internalWinId(), &sh);
+
+ setAttribute(Qt::WA_Mapped);
+ if (testAttribute(Qt::WA_DontShowOnScreen))
+ return;
+ d_func()->topData()->waitingForMapNotify = 1;
+ XMapWindow(X11->display, internalWinId());
+ }
+};
+
+
+void QApplicationPrivate::createEventDispatcher()
+{
+ Q_Q(QApplication);
+#if !defined(QT_NO_GLIB)
+ if (qgetenv("QT_NO_GLIB").isEmpty() && QEventDispatcherGlib::versionSupported())
+ eventDispatcher = (q->type() != QApplication::Tty
+ ? new QGuiEventDispatcherGlib(q)
+ : new QEventDispatcherGlib(q));
+ else
+#endif
+ eventDispatcher = (q->type() != QApplication::Tty
+ ? new QEventDispatcherX11(q)
+ : new QEventDispatcherUNIX(q));
+}
+
+/*****************************************************************************
+ Default X error handlers
+ *****************************************************************************/
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static int (*original_x_errhandler)(Display *dpy, XErrorEvent *);
+static int (*original_xio_errhandler)(Display *dpy);
+
+static int qt_x_errhandler(Display *dpy, XErrorEvent *err)
+{
+ if (X11->display != dpy) {
+ // only handle X errors for our display
+ return 0;
+ }
+
+ switch (err->error_code) {
+ case BadAtom:
+ if (err->request_code == 20 /* X_GetProperty */
+ && (err->resourceid == XA_RESOURCE_MANAGER
+ || err->resourceid == XA_RGB_DEFAULT_MAP
+ || err->resourceid == ATOM(_NET_SUPPORTED)
+ || err->resourceid == ATOM(_NET_SUPPORTING_WM_CHECK)
+ || err->resourceid == ATOM(XdndProxy)
+ || err->resourceid == ATOM(XdndAware))) {
+ // Perhaps we're running under SECURITY reduction? :/
+ return 0;
+ }
+ break;
+
+ case BadWindow:
+ if (err->request_code == 2 /* X_ChangeWindowAttributes */
+ || err->request_code == 38 /* X_QueryPointer */) {
+ for (int i = 0; i < ScreenCount(dpy); ++i) {
+ if (err->resourceid == RootWindow(dpy, i)) {
+ // Perhaps we're running under SECURITY reduction? :/
+ return 0;
+ }
+ }
+ }
+ X11->seen_badwindow = true;
+ if (err->request_code == 25 /* X_SendEvent */) {
+ for (int i = 0; i < ScreenCount(dpy); ++i) {
+ if (err->resourceid == RootWindow(dpy, i)) {
+ // Perhaps we're running under SECURITY reduction? :/
+ return 0;
+ }
+ }
+ if (X11->xdndHandleBadwindow()) {
+ qDebug("xdndHandleBadwindow returned true");
+ return 0;
+ }
+ }
+ if (X11->ignore_badwindow)
+ return 0;
+ break;
+
+ default:
+#if !defined(QT_NO_XINPUT)
+ if (err->request_code == X11->xinput_major
+ && err->error_code == (X11->xinput_errorbase + XI_BadDevice)
+ && err->minor_code == 3 /* X_OpenDevice */) {
+ return 0;
+ }
+#endif
+ break;
+ }
+
+ char errstr[256];
+ XGetErrorText( dpy, err->error_code, errstr, 256 );
+ char buffer[256];
+ char request_str[256];
+ qsnprintf(buffer, 256, "%d", err->request_code);
+ XGetErrorDatabaseText(dpy, "XRequest", buffer, "", request_str, 256);
+ if (err->request_code < 128) {
+ // X error for a normal protocol request
+ qWarning( "X Error: %s %d\n"
+ " Major opcode: %d (%s)\n"
+ " Resource id: 0x%lx",
+ errstr, err->error_code,
+ err->request_code,
+ request_str,
+ err->resourceid );
+ } else {
+ // X error for an extension request
+ const char *extensionName = 0;
+ if (err->request_code == X11->xrender_major)
+ extensionName = "RENDER";
+ else if (err->request_code == X11->xrandr_major)
+ extensionName = "RANDR";
+ else if (err->request_code == X11->xinput_major)
+ extensionName = "XInputExtension";
+ else if (err->request_code == X11->mitshm_major)
+ extensionName = "MIT-SHM";
+#ifndef QT_NO_XKB
+ else if(err->request_code == X11->xkb_major)
+ extensionName = "XKEYBOARD";
+#endif
+
+ char minor_str[256];
+ if (extensionName) {
+ qsnprintf(buffer, 256, "%s.%d", extensionName, err->minor_code);
+ XGetErrorDatabaseText(dpy, "XRequest", buffer, "", minor_str, 256);
+ } else {
+ extensionName = "Uknown extension";
+ qsnprintf(minor_str, 256, "Unknown request");
+ }
+ qWarning( "X Error: %s %d\n"
+ " Extension: %d (%s)\n"
+ " Minor opcode: %d (%s)\n"
+ " Resource id: 0x%lx",
+ errstr, err->error_code,
+ err->request_code,
+ extensionName,
+ err->minor_code,
+ minor_str,
+ err->resourceid );
+ }
+
+ // ### we really should distinguish between severe, non-severe and
+ // ### application specific errors
+
+ return 0;
+}
+
+
+static int qt_xio_errhandler(Display *)
+{
+ qWarning("%s: Fatal IO error: client killed", appName);
+ QApplicationPrivate::reset_instance_pointer();
+ exit(1);
+ //### give the application a chance for a proper shutdown instead,
+ //### exit(1) doesn't help.
+ return 0;
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+#ifndef QT_NO_XSYNC
+struct qt_sync_request_event_data
+{
+ WId window;
+};
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static Bool qt_sync_request_scanner(Display*, XEvent *event, XPointer arg)
+{
+ qt_sync_request_event_data *data =
+ reinterpret_cast<qt_sync_request_event_data*>(arg);
+ if (event->type == ClientMessage &&
+ event->xany.window == data->window &&
+ event->xclient.message_type == ATOM(WM_PROTOCOLS) &&
+ (Atom)event->xclient.data.l[0] == ATOM(_NET_WM_SYNC_REQUEST)) {
+ QWidget *w = QWidget::find(event->xany.window);
+ if (QTLWExtra *tlw = ((QETWidget*)w)->d_func()->maybeTopData()) {
+ const ulong timestamp = (const ulong) event->xclient.data.l[1];
+ if (timestamp > X11->time)
+ X11->time = timestamp;
+ if (timestamp == CurrentTime || timestamp > tlw->syncRequestTimestamp) {
+ tlw->syncRequestTimestamp = timestamp;
+ tlw->newCounterValueLo = event->xclient.data.l[2];
+ tlw->newCounterValueHi = event->xclient.data.l[3];
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+#endif // QT_NO_XSYNC
+
+static void qt_x11_create_intern_atoms()
+{
+ const char *names[QX11Data::NAtoms];
+ const char *ptr = x11_atomnames;
+
+ int i = 0;
+ while (*ptr) {
+ names[i++] = ptr;
+ while (*ptr)
+ ++ptr;
+ ++ptr;
+ }
+
+ Q_ASSERT(i == QX11Data::NPredefinedAtoms);
+
+ QByteArray settings_atom_name("_QT_SETTINGS_TIMESTAMP_");
+ settings_atom_name += XDisplayName(X11->displayName);
+ names[i++] = settings_atom_name;
+
+ Q_ASSERT(i == QX11Data::NAtoms);
+#if defined(XlibSpecificationRelease) && (XlibSpecificationRelease >= 6)
+ XInternAtoms(X11->display, (char **)names, i, False, X11->atoms);
+#else
+ for (i = 0; i < QX11Data::NAtoms; ++i)
+ X11->atoms[i] = XInternAtom(X11->display, (char *)names[i], False);
+#endif
+}
+
+Q_GUI_EXPORT void qt_x11_apply_settings_in_all_apps()
+{
+ QByteArray stamp;
+ QDataStream s(&stamp, QIODevice::WriteOnly);
+ s << QDateTime::currentDateTime();
+
+ XChangeProperty(QX11Info::display(), QX11Info::appRootWindow(0),
+ ATOM(_QT_SETTINGS_TIMESTAMP), ATOM(_QT_SETTINGS_TIMESTAMP), 8,
+ PropModeReplace, (unsigned char *)stamp.data(), stamp.size());
+}
+
+/*! \internal
+ apply the settings to the application
+*/
+bool QApplicationPrivate::x11_apply_settings()
+{
+ QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
+
+ settings.beginGroup(QLatin1String("Qt"));
+
+ /*
+ Qt settings. This is now they are written into the datastream.
+
+ Palette / * - QPalette
+ font - QFont
+ libraryPath - QStringList
+ style - QString
+ doubleClickInterval - int
+ keyboardInputInterval - int
+ cursorFlashTime - int
+ wheelScrollLines - int
+ colorSpec - QString
+ defaultCodec - QString
+ globalStrut/width - int
+ globalStrut/height - int
+ GUIEffects - QStringList
+ Font Substitutions/ * - QStringList
+ Font Substitutions/... - QStringList
+ */
+
+ QStringList strlist;
+ int i;
+ QPalette pal(Qt::black);
+ int groupCount = 0;
+ strlist = settings.value(QLatin1String("Palette/active")).toStringList();
+ if (!strlist.isEmpty()) {
+ ++groupCount;
+ for (i = 0; i < qMin(strlist.count(), int(QPalette::NColorRoles)); i++)
+ pal.setColor(QPalette::Active, (QPalette::ColorRole) i,
+ QColor(strlist[i]));
+ }
+ strlist = settings.value(QLatin1String("Palette/inactive")).toStringList();
+ if (!strlist.isEmpty()) {
+ ++groupCount;
+ for (i = 0; i < qMin(strlist.count(), int(QPalette::NColorRoles)); i++)
+ pal.setColor(QPalette::Inactive, (QPalette::ColorRole) i,
+ QColor(strlist[i]));
+ }
+ strlist = settings.value(QLatin1String("Palette/disabled")).toStringList();
+ if (!strlist.isEmpty()) {
+ ++groupCount;
+ for (i = 0; i < qMin(strlist.count(), int(QPalette::NColorRoles)); i++)
+ pal.setColor(QPalette::Disabled, (QPalette::ColorRole) i,
+ QColor(strlist[i]));
+ }
+
+ // ### Fix properly for 4.6
+ bool usingGtkSettings = QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle");
+ if (!usingGtkSettings) {
+ if (groupCount == QPalette::NColorGroups)
+ QApplicationPrivate::setSystemPalette(pal);
+ }
+
+ if (!appFont) {
+ // ### Fix properly for 4.6
+ if (!usingGtkSettings) {
+ QFont font(QApplication::font());
+ QString fontDescription;
+ // Override Qt font if KDE4 settings can be used
+ if (X11->desktopVersion == 4) {
+ QSettings kdeSettings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat);
+ fontDescription = kdeSettings.value(QLatin1String("font")).toString();
+ if (fontDescription.isEmpty()) {
+ // KDE stores fonts without quotes
+ fontDescription = kdeSettings.value(QLatin1String("font")).toStringList().join(QLatin1String(","));
+ }
+ }
+ if (fontDescription.isEmpty())
+ fontDescription = settings.value(QLatin1String("font")).toString();
+ if (!fontDescription .isEmpty()) {
+ font.fromString(fontDescription );
+ QApplicationPrivate::setSystemFont(font);
+ }
+ }
+ }
+
+ // read library (ie. plugin) path list
+ QString libpathkey =
+ QString::fromLatin1("%1.%2/libraryPath")
+ .arg(QT_VERSION >> 16)
+ .arg((QT_VERSION & 0xff00) >> 8);
+ QStringList pathlist = settings.value(libpathkey).toString().split(QLatin1Char(':'));
+ if (! pathlist.isEmpty()) {
+ QStringList::ConstIterator it = pathlist.constBegin();
+ while (it != pathlist.constEnd())
+ QApplication::addLibraryPath(*it++);
+ }
+
+ // read new QStyle
+ QString stylename = settings.value(QLatin1String("style")).toString();
+
+ if (stylename.isEmpty() && QApplicationPrivate::styleOverride.isNull() && X11->use_xrender) {
+ stylename = qt_guiPlatformPlugin()->styleName();
+ }
+
+ static QString currentStyleName = stylename;
+ if (QCoreApplication::startingUp()) {
+ if (!stylename.isEmpty() && QApplicationPrivate::styleOverride.isNull())
+ QApplicationPrivate::styleOverride = stylename;
+ } else {
+ if (currentStyleName != stylename) {
+ currentStyleName = stylename;
+ QApplication::setStyle(stylename);
+ }
+ }
+
+ int num =
+ settings.value(QLatin1String("doubleClickInterval"),
+ QApplication::doubleClickInterval()).toInt();
+ QApplication::setDoubleClickInterval(num);
+
+ num =
+ settings.value(QLatin1String("cursorFlashTime"),
+ QApplication::cursorFlashTime()).toInt();
+ QApplication::setCursorFlashTime(num);
+
+#ifndef QT_NO_WHEELEVENT
+ num =
+ settings.value(QLatin1String("wheelScrollLines"),
+ QApplication::wheelScrollLines()).toInt();
+ QApplication::setWheelScrollLines(num);
+#endif
+
+ QString colorspec = settings.value(QLatin1String("colorSpec"),
+ QVariant(QLatin1String("default"))).toString();
+ if (colorspec == QLatin1String("normal"))
+ QApplication::setColorSpec(QApplication::NormalColor);
+ else if (colorspec == QLatin1String("custom"))
+ QApplication::setColorSpec(QApplication::CustomColor);
+ else if (colorspec == QLatin1String("many"))
+ QApplication::setColorSpec(QApplication::ManyColor);
+ else if (colorspec != QLatin1String("default"))
+ colorspec = QLatin1String("default");
+
+ QString defaultcodec = settings.value(QLatin1String("defaultCodec"),
+ QVariant(QLatin1String("none"))).toString();
+ if (defaultcodec != QLatin1String("none")) {
+ QTextCodec *codec = QTextCodec::codecForName(defaultcodec.toLatin1());
+ if (codec)
+ QTextCodec::setCodecForTr(codec);
+ }
+
+ int w = settings.value(QLatin1String("globalStrut/width")).toInt();
+ int h = settings.value(QLatin1String("globalStrut/height")).toInt();
+ QSize strut(w, h);
+ if (strut.isValid())
+ QApplication::setGlobalStrut(strut);
+
+ QStringList effects = settings.value(QLatin1String("GUIEffects")).toStringList();
+ QApplication::setEffectEnabled(Qt::UI_General,
+ effects.contains(QLatin1String("general")));
+ QApplication::setEffectEnabled(Qt::UI_AnimateMenu,
+ effects.contains(QLatin1String("animatemenu")));
+ QApplication::setEffectEnabled(Qt::UI_FadeMenu,
+ effects.contains(QLatin1String("fademenu")));
+ QApplication::setEffectEnabled(Qt::UI_AnimateCombo,
+ effects.contains(QLatin1String("animatecombo")));
+ QApplication::setEffectEnabled(Qt::UI_AnimateTooltip,
+ effects.contains(QLatin1String("animatetooltip")));
+ QApplication::setEffectEnabled(Qt::UI_FadeTooltip,
+ effects.contains(QLatin1String("fadetooltip")));
+ QApplication::setEffectEnabled(Qt::UI_AnimateToolBox,
+ effects.contains(QLatin1String("animatetoolbox")));
+
+ if (!X11->has_fontconfig) {
+ settings.beginGroup(QLatin1String("Font Substitutions"));
+ QStringList fontsubs = settings.childKeys();
+ if (!fontsubs.isEmpty()) {
+ QStringList::Iterator it = fontsubs.begin();
+ for (; it != fontsubs.end(); ++it) {
+ QString fam = *it;
+ QStringList subs = settings.value(fam).toStringList();
+ QFont::insertSubstitutions(fam, subs);
+ }
+ }
+ settings.endGroup();
+ }
+
+ qt_use_rtl_extensions =
+ settings.value(QLatin1String("useRtlExtensions"), false).toBool();
+
+#ifndef QT_NO_XIM
+ if (qt_xim_preferred_style == 0) {
+ QString ximInputStyle = settings.value(QLatin1String("XIMInputStyle"),
+ QVariant(QLatin1String("on the spot"))).toString().toLower();
+ if (ximInputStyle == QLatin1String("on the spot"))
+ qt_xim_preferred_style = XIMPreeditCallbacks | XIMStatusNothing;
+ else if (ximInputStyle == QLatin1String("over the spot"))
+ qt_xim_preferred_style = XIMPreeditPosition | XIMStatusNothing;
+ else if (ximInputStyle == QLatin1String("off the spot"))
+ qt_xim_preferred_style = XIMPreeditArea | XIMStatusArea;
+ else if (ximInputStyle == QLatin1String("root"))
+ qt_xim_preferred_style = XIMPreeditNothing | XIMStatusNothing;
+ }
+#endif
+ QStringList inputMethods = QInputContextFactory::keys();
+ if (inputMethods.size() > 2 && inputMethods.contains(QLatin1String("imsw-multi"))) {
+ X11->default_im = QLatin1String("imsw-multi");
+ } else {
+ X11->default_im = settings.value(QLatin1String("DefaultInputMethod"),
+ QLatin1String("xim")).toString();
+ }
+
+ settings.endGroup(); // Qt
+
+ return true;
+}
+
+
+/*! \internal
+ Resets the QApplication::instance() pointer to zero
+*/
+void QApplicationPrivate::reset_instance_pointer()
+{ QApplication::self = 0; }
+
+
+// read the _QT_INPUT_ENCODING property and apply the settings to
+// the application
+static void qt_set_input_encoding()
+{
+ Atom type;
+ int format;
+ ulong nitems, after = 1;
+ unsigned char *data = 0;
+
+ int e = XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
+ ATOM(_QT_INPUT_ENCODING), 0, 1024,
+ False, XA_STRING, &type, &format, &nitems,
+ &after, &data);
+ if (e != Success || !nitems || type == XNone) {
+ // Always use the locale codec, since we have no examples of non-local
+ // XIMs, and since we cannot get a sensible answer about the encoding
+ // from the XIM.
+ qt_input_mapper = QTextCodec::codecForLocale();
+
+ } else {
+ if (!qstricmp((char *)data, "locale"))
+ qt_input_mapper = QTextCodec::codecForLocale();
+ else
+ qt_input_mapper = QTextCodec::codecForName((char *)data);
+ // make sure we have an input codec
+ if(!qt_input_mapper)
+ qt_input_mapper = QTextCodec::codecForName("ISO 8859-1");
+ }
+ if (qt_input_mapper && qt_input_mapper->mibEnum() == 11) // 8859-8
+ qt_input_mapper = QTextCodec::codecForName("ISO 8859-8-I");
+ if(data)
+ XFree((char *)data);
+}
+
+// set font, foreground and background from x11 resources. The
+// arguments may override the resource settings.
+static void qt_set_x11_resources(const char* font = 0, const char* fg = 0,
+ const char* bg = 0, const char* button = 0)
+{
+
+ QString resFont, resFG, resBG, resButton, resEF, sysFont, selectBackground, selectForeground;
+
+ QApplication::setEffectEnabled(Qt::UI_General, false);
+ QApplication::setEffectEnabled(Qt::UI_AnimateMenu, false);
+ QApplication::setEffectEnabled(Qt::UI_FadeMenu, false);
+ QApplication::setEffectEnabled(Qt::UI_AnimateCombo, false);
+ QApplication::setEffectEnabled(Qt::UI_AnimateTooltip, false);
+ QApplication::setEffectEnabled(Qt::UI_FadeTooltip, false);
+ QApplication::setEffectEnabled(Qt::UI_AnimateToolBox, false);
+
+ bool paletteAlreadySet = false;
+ if (QApplication::desktopSettingsAware()) {
+ // first, read from settings
+ QApplicationPrivate::x11_apply_settings();
+ // the call to QApplication::style() below creates the system
+ // palette, which breaks the logic after the RESOURCE_MANAGER
+ // loop... so I have to save this value to be able to use it later
+ paletteAlreadySet = (QApplicationPrivate::sys_pal != 0);
+
+ // second, parse the RESOURCE_MANAGER property
+ int format;
+ ulong nitems, after = 1;
+ QString res;
+ long offset = 0;
+ Atom type = XNone;
+
+ while (after > 0) {
+ uchar *data = 0;
+ if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(0),
+ ATOM(RESOURCE_MANAGER),
+ offset, 8192, False, AnyPropertyType,
+ &type, &format, &nitems, &after,
+ &data) != Success) {
+ res = QString();
+ break;
+ }
+ if (type == XA_STRING)
+ res += QString::fromLatin1((char*)data);
+ else
+ res += QString::fromLocal8Bit((char*)data);
+ offset += 2048; // offset is in 32bit quantities... 8192/4 == 2048
+ if (data)
+ XFree((char *)data);
+ }
+
+ QString key, value;
+ int l = 0, r;
+ QString apn = QString::fromLocal8Bit(appName);
+ QString apc = QString::fromLocal8Bit(appClass);
+ int apnl = apn.length();
+ int apcl = apc.length();
+ int resl = res.length();
+
+ while (l < resl) {
+ r = res.indexOf(QLatin1Char('\n'), l);
+ if (r < 0)
+ r = resl;
+ while (res.at(l).isSpace())
+ l++;
+ bool mine = false;
+ QChar sc = res.at(l + 1);
+ if (res.at(l) == QLatin1Char('*') &&
+ (sc == QLatin1Char('f') || sc == QLatin1Char('b') || sc == QLatin1Char('g') ||
+ sc == QLatin1Char('F') || sc == QLatin1Char('B') || sc == QLatin1Char('G') ||
+ sc == QLatin1Char('s') || sc == QLatin1Char('S')
+ // capital T only, since we're looking for "Text.selectSomething"
+ || sc == QLatin1Char('T'))) {
+ // OPTIMIZED, since we only want "*[fbgsT].."
+ QString item = res.mid(l, r - l).simplified();
+ int i = item.indexOf(QLatin1Char(':'));
+ key = item.left(i).trimmed().mid(1).toLower();
+ value = item.right(item.length() - i - 1).trimmed();
+ mine = true;
+ } else if ((apnl && res.at(l) == apn.at(0)) || (appClass && apcl && res.at(l) == apc.at(0))) {
+ if (res.mid(l,apnl) == apn && (res.at(l+apnl) == QLatin1Char('.')
+ || res.at(l+apnl) == QLatin1Char('*'))) {
+ QString item = res.mid(l, r - l).simplified();
+ int i = item.indexOf(QLatin1Char(':'));
+ key = item.left(i).trimmed().mid(apnl+1).toLower();
+ value = item.right(item.length() - i - 1).trimmed();
+ mine = true;
+ } else if (res.mid(l,apcl) == apc && (res.at(l+apcl) == QLatin1Char('.')
+ || res.at(l+apcl) == QLatin1Char('*'))) {
+ QString item = res.mid(l, r - l).simplified();
+ int i = item.indexOf(QLatin1Char(':'));
+ key = item.left(i).trimmed().mid(apcl+1).toLower();
+ value = item.right(item.length() - i - 1).trimmed();
+ mine = true;
+ }
+ }
+
+ if (mine) {
+ if (!font && key == QLatin1String("systemfont"))
+ sysFont = value.left(value.lastIndexOf(QLatin1Char(':')));
+ if (!font && key == QLatin1String("font"))
+ resFont = value;
+ else if (!fg && !paletteAlreadySet) {
+ if (key == QLatin1String("foreground"))
+ resFG = value;
+ else if (!bg && key == QLatin1String("background"))
+ resBG = value;
+ else if (!bg && !button && key == QLatin1String("button.background"))
+ resButton = value;
+ else if (key == QLatin1String("text.selectbackground")) {
+ selectBackground = value;
+ } else if (key == QLatin1String("text.selectforeground")) {
+ selectForeground = value;
+ }
+ } else if (key == QLatin1String("guieffects"))
+ resEF = value;
+ // NOTE: if you add more, change the [fbg] stuff above
+ }
+
+ l = r + 1;
+ }
+ }
+ if (!sysFont.isEmpty())
+ resFont = sysFont;
+ if (resFont.isEmpty())
+ resFont = QString::fromLocal8Bit(font);
+ if (resFG.isEmpty())
+ resFG = QString::fromLocal8Bit(fg);
+ if (resBG.isEmpty())
+ resBG = QString::fromLocal8Bit(bg);
+ if (resButton.isEmpty())
+ resButton = QString::fromLocal8Bit(button);
+ if (!resFont.isEmpty()
+ && !X11->has_fontconfig
+ && !QApplicationPrivate::sys_font) {
+ // set application font
+ QFont fnt;
+ fnt.setRawName(resFont);
+
+ // the font we get may actually be an alias for another font,
+ // so we reset the application font to the real font info.
+ if (! fnt.exactMatch()) {
+ QFontInfo fontinfo(fnt);
+ fnt.setFamily(fontinfo.family());
+ fnt.setRawMode(fontinfo.rawMode());
+
+ if (! fnt.rawMode()) {
+ fnt.setItalic(fontinfo.italic());
+ fnt.setWeight(fontinfo.weight());
+ fnt.setUnderline(fontinfo.underline());
+ fnt.setStrikeOut(fontinfo.strikeOut());
+ fnt.setStyleHint(fontinfo.styleHint());
+
+ if (fnt.pointSize() <= 0 && fnt.pixelSize() <= 0) {
+ // size is all wrong... fix it
+ qreal pointSize = fontinfo.pixelSize() * 72. / (float) QX11Info::appDpiY();
+ if (pointSize <= 0)
+ pointSize = 12;
+ fnt.setPointSize(qRound(pointSize));
+ }
+ }
+ }
+
+ QApplicationPrivate::setSystemFont(fnt);
+ }
+ // QGtkStyle sets it's own system palette
+ bool gtkStyle = QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle");
+ bool kdeColors = (QApplication::desktopSettingsAware() && X11->desktopEnvironment == DE_KDE);
+ if (!gtkStyle && (kdeColors || (button || !resBG.isEmpty() || !resFG.isEmpty()))) {// set app colors
+ bool allowX11ColorNames = QColor::allowX11ColorNames();
+ QColor::setAllowX11ColorNames(true);
+
+ (void) QApplication::style(); // trigger creation of application style and system palettes
+ QColor btn;
+ QColor bg;
+ QColor fg;
+ QColor bfg;
+ QColor wfg;
+ if (!resBG.isEmpty())
+ bg = QColor(resBG);
+ if (!bg.isValid())
+ bg = QApplicationPrivate::sys_pal->color(QPalette::Active, QPalette::Window);
+
+ if (!resFG.isEmpty())
+ fg = QColor(resFG);
+ if (!fg.isValid())
+ fg = QApplicationPrivate::sys_pal->color(QPalette::Active, QPalette::WindowText);
+
+ if (!resButton.isEmpty())
+ btn = QColor(resButton);
+ else if (!resBG.isEmpty())
+ btn = bg;
+ if (!btn.isValid())
+ btn = QApplicationPrivate::sys_pal->color(QPalette::Active, QPalette::Button);
+
+ int h,s,v;
+ fg.getHsv(&h,&s,&v);
+ QColor base = Qt::white;
+ bool bright_mode = false;
+ if (v >= 255 - 50) {
+ base = btn.darker(150);
+ bright_mode = true;
+ }
+
+ QPalette pal(fg, btn, btn.lighter(125), btn.darker(130), btn.darker(120), wfg.isValid() ? wfg : fg, Qt::white, base, bg);
+ QColor disabled((fg.red() + btn.red()) / 2,
+ (fg.green() + btn.green())/ 2,
+ (fg.blue() + btn.blue()) / 2);
+ pal.setColorGroup(QPalette::Disabled, disabled, btn, btn.lighter(125),
+ btn.darker(130), btn.darker(150), disabled, Qt::white, Qt::white, bg);
+
+ QColor highlight, highlightText;
+ if (!selectBackground.isEmpty() && !selectForeground.isEmpty()) {
+ highlight = QColor(selectBackground);
+ highlightText = QColor(selectForeground);
+ }
+
+ if (highlight.isValid() && highlightText.isValid()) {
+ pal.setColor(QPalette::Highlight, highlight);
+ pal.setColor(QPalette::HighlightedText, highlightText);
+
+ // calculate disabled colors by removing saturation
+ highlight.setHsv(highlight.hue(), 0, highlight.value(), highlight.alpha());
+ highlightText.setHsv(highlightText.hue(), 0, highlightText.value(), highlightText.alpha());
+ pal.setColor(QPalette::Disabled, QPalette::Highlight, highlight);
+ pal.setColor(QPalette::Disabled, QPalette::HighlightedText, highlightText);
+ } else if (bright_mode) {
+ pal.setColor(QPalette::HighlightedText, base);
+ pal.setColor(QPalette::Highlight, Qt::white);
+ pal.setColor(QPalette::Disabled, QPalette::HighlightedText, base);
+ pal.setColor(QPalette::Disabled, QPalette::Highlight, Qt::white);
+ } else {
+ pal.setColor(QPalette::HighlightedText, Qt::white);
+ pal.setColor(QPalette::Highlight, Qt::darkBlue);
+ pal.setColor(QPalette::Disabled, QPalette::HighlightedText, Qt::white);
+ pal.setColor(QPalette::Disabled, QPalette::Highlight, Qt::darkBlue);
+ }
+
+ pal = qt_guiPlatformPlugin()->palette().resolve(pal);
+ QApplicationPrivate::setSystemPalette(pal);
+ QColor::setAllowX11ColorNames(allowX11ColorNames);
+ }
+
+ if (!resEF.isEmpty()) {
+ QStringList effects = resEF.split(QLatin1Char(' '));
+ QApplication::setEffectEnabled(Qt::UI_General, effects.contains(QLatin1String("general")));
+ QApplication::setEffectEnabled(Qt::UI_AnimateMenu,
+ effects.contains(QLatin1String("animatemenu")));
+ QApplication::setEffectEnabled(Qt::UI_FadeMenu,
+ effects.contains(QLatin1String("fademenu")));
+ QApplication::setEffectEnabled(Qt::UI_AnimateCombo,
+ effects.contains(QLatin1String("animatecombo")));
+ QApplication::setEffectEnabled(Qt::UI_AnimateTooltip,
+ effects.contains(QLatin1String("animatetooltip")));
+ QApplication::setEffectEnabled(Qt::UI_FadeTooltip,
+ effects.contains(QLatin1String("fadetooltip")));
+ QApplication::setEffectEnabled(Qt::UI_AnimateToolBox,
+ effects.contains(QLatin1String("animatetoolbox")));
+ }
+
+ QIconLoader::instance()->updateSystemTheme();
+}
+
+
+// update the supported array
+static void qt_get_net_supported()
+{
+ Atom type;
+ int format;
+ long offset = 0;
+ unsigned long nitems, after;
+ unsigned char *data = 0;
+
+ int e = XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
+ ATOM(_NET_SUPPORTED), 0, 0,
+ False, XA_ATOM, &type, &format, &nitems, &after, &data);
+ if (data)
+ XFree(data);
+
+ if (X11->net_supported_list)
+ delete [] X11->net_supported_list;
+ X11->net_supported_list = 0;
+
+ if (e == Success && type == XA_ATOM && format == 32) {
+ QBuffer ts;
+ ts.open(QIODevice::WriteOnly);
+
+ while (after > 0) {
+ XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
+ ATOM(_NET_SUPPORTED), offset, 1024,
+ False, XA_ATOM, &type, &format, &nitems, &after, &data);
+
+ if (type == XA_ATOM && format == 32) {
+ ts.write(reinterpret_cast<char *>(data), nitems * sizeof(long));
+ offset += nitems;
+ } else
+ after = 0;
+ if (data)
+ XFree(data);
+ }
+
+ // compute nitems
+ QByteArray buffer(ts.buffer());
+ nitems = buffer.size() / sizeof(Atom);
+ X11->net_supported_list = new Atom[nitems + 1];
+ Atom *a = (Atom *) buffer.data();
+ uint i;
+ for (i = 0; i < nitems; i++)
+ X11->net_supported_list[i] = a[i];
+ X11->net_supported_list[nitems] = 0;
+ }
+}
+
+
+bool QX11Data::isSupportedByWM(Atom atom)
+{
+ if (!X11->net_supported_list)
+ return false;
+
+ bool supported = false;
+ int i = 0;
+ while (X11->net_supported_list[i] != 0) {
+ if (X11->net_supported_list[i++] == atom) {
+ supported = true;
+ break;
+ }
+ }
+
+ return supported;
+}
+
+
+// update the virtual roots array
+static void qt_get_net_virtual_roots()
+{
+ if (X11->net_virtual_root_list)
+ delete [] X11->net_virtual_root_list;
+ X11->net_virtual_root_list = 0;
+
+ if (!X11->isSupportedByWM(ATOM(_NET_VIRTUAL_ROOTS)))
+ return;
+
+ Atom type;
+ int format;
+ long offset = 0;
+ unsigned long nitems, after;
+ unsigned char *data;
+
+ int e = XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
+ ATOM(_NET_VIRTUAL_ROOTS), 0, 0,
+ False, XA_ATOM, &type, &format, &nitems, &after, &data);
+ if (data)
+ XFree(data);
+
+ if (e == Success && type == XA_ATOM && format == 32) {
+ QBuffer ts;
+ ts.open(QIODevice::WriteOnly);
+
+ while (after > 0) {
+ XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
+ ATOM(_NET_VIRTUAL_ROOTS), offset, 1024,
+ False, XA_ATOM, &type, &format, &nitems, &after, &data);
+
+ if (type == XA_ATOM && format == 32) {
+ ts.write(reinterpret_cast<char *>(data), nitems * 4);
+ offset += nitems;
+ } else
+ after = 0;
+ if (data)
+ XFree(data);
+ }
+
+ // compute nitems
+ QByteArray buffer(ts.buffer());
+ nitems = buffer.size() / sizeof(Window);
+ X11->net_virtual_root_list = new Window[nitems + 1];
+ Window *a = (Window *) buffer.data();
+ uint i;
+ for (i = 0; i < nitems; i++)
+ X11->net_virtual_root_list[i] = a[i];
+ X11->net_virtual_root_list[nitems] = 0;
+ }
+}
+
+void qt_net_remove_user_time(QWidget *tlw)
+{
+ Q_ASSERT(tlw);
+ QTLWExtra *extra = tlw->d_func()->maybeTopData();
+ if (extra && extra->userTimeWindow) {
+ Q_ASSERT(tlw->internalWinId());
+ XDeleteProperty(X11->display, tlw->internalWinId(), ATOM(_NET_WM_USER_TIME_WINDOW));
+ XDestroyWindow(X11->display, extra->userTimeWindow);
+ extra->userTimeWindow = 0;
+ }
+}
+
+void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp)
+{
+ Q_ASSERT(tlw);
+ Q_ASSERT(tlw->isWindow());
+ Q_ASSERT(tlw->testAttribute(Qt::WA_WState_Created));
+ QTLWExtra *extra = tlw->d_func()->topData();
+ WId wid = tlw->internalWinId();
+ const bool isSupportedByWM = X11->isSupportedByWM(ATOM(_NET_WM_USER_TIME_WINDOW));
+ if (extra->userTimeWindow || isSupportedByWM) {
+ if (!extra->userTimeWindow) {
+ extra->userTimeWindow = XCreateSimpleWindow(X11->display,
+ tlw->internalWinId(),
+ -1, -1, 1, 1, 0, 0, 0);
+ wid = extra->userTimeWindow;
+ XChangeProperty(X11->display, tlw->internalWinId(), ATOM(_NET_WM_USER_TIME_WINDOW),
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)&wid, 1);
+ XDeleteProperty(X11->display, tlw->internalWinId(), ATOM(_NET_WM_USER_TIME));
+ } else if (!isSupportedByWM) {
+ // WM no longer supports it, then we should remove the
+ // _NET_WM_USER_TIME_WINDOW atom.
+ qt_net_remove_user_time(tlw);
+ } else {
+ wid = extra->userTimeWindow;
+ }
+ }
+ XChangeProperty(X11->display, wid, ATOM(_NET_WM_USER_TIME),
+ XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &timestamp, 1);
+}
+
+static void qt_check_focus_model()
+{
+ Window fw = XNone;
+ int unused;
+ XGetInputFocus(X11->display, &fw, &unused);
+ if (fw == PointerRoot)
+ X11->focus_model = QX11Data::FM_PointerRoot;
+ else
+ X11->focus_model = QX11Data::FM_Other;
+}
+
+#ifndef QT_NO_TABLET
+
+#if !defined (Q_OS_IRIX)
+// from include/Xwacom.h
+# define XWACOM_PARAM_TOOLID 322
+# define XWACOM_PARAM_TOOLSERIAL 323
+
+typedef WACOMCONFIG * (*PtrWacomConfigInit) (Display*, WACOMERRORFUNC);
+typedef WACOMDEVICE * (*PtrWacomConfigOpenDevice) (WACOMCONFIG*, const char*);
+typedef int *(*PtrWacomConfigGetRawParam) (WACOMDEVICE*, int, int*, int, unsigned*);
+typedef int (*PtrWacomConfigCloseDevice) (WACOMDEVICE *);
+typedef void (*PtrWacomConfigTerm) (WACOMCONFIG *);
+
+static PtrWacomConfigInit ptrWacomConfigInit = 0;
+static PtrWacomConfigOpenDevice ptrWacomConfigOpenDevice = 0;
+static PtrWacomConfigGetRawParam ptrWacomConfigGetRawParam = 0;
+static PtrWacomConfigCloseDevice ptrWacomConfigCloseDevice = 0;
+static PtrWacomConfigTerm ptrWacomConfigTerm = 0;
+Q_GLOBAL_STATIC(QByteArray, wacomDeviceName)
+#endif
+
+#endif
+
+/*****************************************************************************
+ qt_init() - initializes Qt for X11
+ *****************************************************************************/
+
+#if !defined(QT_NO_FONTCONFIG)
+static void getXDefault(const char *group, const char *key, int *val)
+{
+ char *str = XGetDefault(X11->display, group, key);
+ if (str) {
+ char *end = 0;
+ int v = strtol(str, &end, 0);
+ if (str != end)
+ *val = v;
+ // otherwise use fontconfig to convert the string to integer
+ else
+ FcNameConstant((FcChar8 *) str, val);
+ }
+}
+
+static void getXDefault(const char *group, const char *key, double *val)
+{
+ char *str = XGetDefault(X11->display, group, key);
+ if (str) {
+ bool ok;
+ double v = QByteArray(str).toDouble(&ok);
+ if (ok)
+ *val = v;
+ }
+}
+
+static void getXDefault(const char *group, const char *key, bool *val)
+{
+ char *str = XGetDefault(X11->display, group, key);
+ if (str) {
+ char c = str[0];
+ if (isupper((int)c))
+ c = tolower(c);
+ if (c == 't' || c == 'y' || c == '1')
+ *val = true;
+ else if (c == 'f' || c == 'n' || c == '0')
+ *val = false;
+ if (c == 'o') {
+ c = str[1];
+ if (isupper((int)c))
+ c = tolower(c);
+ if (c == 'n')
+ *val = true;
+ if (c == 'f')
+ *val = false;
+ }
+ }
+}
+#endif
+
+// ### This should be static but it isn't because of the friend declaration
+// ### in qpaintdevice.h which then should have a static too but can't have
+// ### it because "storage class specifiers invalid in friend function
+// ### declarations" :-) Ideas anyone?
+void qt_init(QApplicationPrivate *priv, int,
+ Display *display, Qt::HANDLE visual, Qt::HANDLE colormap)
+{
+ X11 = new QX11Data;
+ X11->display = display;
+ X11->displayName = 0;
+ X11->foreignDisplay = (display != 0);
+ X11->focus_model = -1;
+
+ // RANDR
+ X11->use_xrandr = false;
+ X11->xrandr_major = 0;
+ X11->xrandr_eventbase = 0;
+ X11->xrandr_errorbase = 0;
+
+ // RENDER
+ X11->use_xrender = false;
+ X11->xrender_major = 0;
+ X11->xrender_version = 0;
+
+ // XFIXES
+ X11->use_xfixes = false;
+ X11->xfixes_major = 0;
+ X11->xfixes_eventbase = 0;
+ X11->xfixes_errorbase = 0;
+
+ // XInputExtension
+ X11->use_xinput = false;
+ X11->xinput_major = 0;
+ X11->xinput_eventbase = 0;
+ X11->xinput_errorbase = 0;
+
+ X11->use_xkb = false;
+ X11->xkb_major = 0;
+ X11->xkb_eventbase = 0;
+ X11->xkb_errorbase = 0;
+
+ // MIT-SHM
+ X11->use_mitshm = false;
+ X11->use_mitshm_pixmaps = false;
+ X11->mitshm_major = 0;
+
+ X11->sip_serial = 0;
+ X11->net_supported_list = 0;
+ X11->net_virtual_root_list = 0;
+ X11->wm_client_leader = 0;
+ X11->screens = 0;
+ X11->argbVisuals = 0;
+ X11->argbColormaps = 0;
+ X11->screenCount = 0;
+ X11->time = CurrentTime;
+ X11->userTime = CurrentTime;
+ X11->ignore_badwindow = false;
+ X11->seen_badwindow = false;
+
+ X11->motifdnd_active = false;
+
+ X11->default_im = QLatin1String("imsw-multi");
+ priv->inputContext = 0;
+
+ // colormap control
+ X11->visual_class = -1;
+ X11->visual_id = -1;
+ X11->color_count = 0;
+ X11->custom_cmap = false;
+
+ // outside visual/colormap
+ X11->visual = reinterpret_cast<Visual *>(visual);
+ X11->colormap = colormap;
+
+ // Fontconfig
+ X11->has_fontconfig = false;
+#if !defined(QT_NO_FONTCONFIG)
+ if (qgetenv("QT_X11_NO_FONTCONFIG").isNull())
+ X11->has_fontconfig = FcInit();
+ X11->fc_antialias = true;
+#endif
+
+#ifndef QT_NO_XRENDER
+ memset(X11->solid_fills, 0, sizeof(X11->solid_fills));
+ for (int i = 0; i < X11->solid_fill_count; ++i)
+ X11->solid_fills[i].screen = -1;
+ memset(X11->pattern_fills, 0, sizeof(X11->pattern_fills));
+ for (int i = 0; i < X11->pattern_fill_count; ++i)
+ X11->pattern_fills[i].screen = -1;
+#endif
+
+ X11->startupId = 0;
+
+ int argc = priv->argc;
+ char **argv = priv->argv;
+
+ if (X11->display) {
+ // Qt part of other application
+
+ // Set application name and class
+ appName = qstrdup("Qt-subapplication");
+ char *app_class = 0;
+ if (argv) {
+ const char* p = strrchr(argv[0], '/');
+ app_class = qstrdup(p ? p + 1 : argv[0]);
+ if (app_class[0])
+ app_class[0] = toupper(app_class[0]);
+ }
+ appClass = app_class;
+ } else {
+ // Qt controls everything (default)
+
+ if (QApplication::testAttribute(Qt::AA_X11InitThreads))
+ XInitThreads();
+
+ // Set application name and class
+ char *app_class = 0;
+ if (argv && argv[0]) {
+ const char *p = strrchr(argv[0], '/');
+ appName = p ? p + 1 : argv[0];
+ app_class = qstrdup(appName);
+ if (app_class[0])
+ app_class[0] = toupper(app_class[0]);
+ }
+ appClass = app_class;
+ }
+
+ // Install default error handlers
+ original_x_errhandler = XSetErrorHandler(qt_x_errhandler);
+ original_xio_errhandler = XSetIOErrorHandler(qt_xio_errhandler);
+
+ // Get command line params
+ int j = argc ? 1 : 0;
+ for (int i=1; i<argc; i++) {
+ if (argv[i] && *argv[i] != '-') {
+ argv[j++] = argv[i];
+ continue;
+ }
+ QByteArray arg(argv[i]);
+ if (arg == "-display") {
+ if (++i < argc && !X11->display)
+ X11->displayName = argv[i];
+ } else if (arg == "-fn" || arg == "-font") {
+ if (++i < argc)
+ appFont = argv[i];
+ } else if (arg == "-bg" || arg == "-background") {
+ if (++i < argc)
+ appBGCol = argv[i];
+ } else if (arg == "-btn" || arg == "-button") {
+ if (++i < argc)
+ appBTNCol = argv[i];
+ } else if (arg == "-fg" || arg == "-foreground") {
+ if (++i < argc)
+ appFGCol = argv[i];
+ } else if (arg == "-name") {
+ if (++i < argc)
+ appName = argv[i];
+ } else if (arg == "-title") {
+ if (++i < argc)
+ mwTitle = argv[i];
+ } else if (arg == "-geometry") {
+ if (++i < argc)
+ mwGeometry = argv[i];
+ } else if (arg == "-im") {
+ if (++i < argc)
+ qt_ximServer = argv[i];
+ } else if (arg == "-ncols") { // xv and netscape use this name
+ if (++i < argc)
+ X11->color_count = qMax(0,atoi(argv[i]));
+ } else if (arg == "-visual") { // xv and netscape use this name
+ if (++i < argc && !X11->visual) {
+ QString s = QString::fromLocal8Bit(argv[i]).toLower();
+ if (s == QLatin1String("staticgray"))
+ X11->visual_class = StaticGray;
+ else if (s == QLatin1String("grayscale"))
+ X11->visual_class = XGrayScale;
+ else if (s == QLatin1String("staticcolor"))
+ X11->visual_class = StaticColor;
+ else if (s == QLatin1String("pseudocolor"))
+ X11->visual_class = PseudoColor;
+ else if (s == QLatin1String("truecolor"))
+ X11->visual_class = TrueColor;
+ else if (s == QLatin1String("directcolor"))
+ X11->visual_class = DirectColor;
+ else
+ X11->visual_id = static_cast<int>(strtol(argv[i], 0, 0));
+ }
+#ifndef QT_NO_XIM
+ } else if (arg == "-inputstyle") {
+ if (++i < argc) {
+ QString s = QString::fromLocal8Bit(argv[i]).toLower();
+ if (s == QLatin1String("onthespot"))
+ qt_xim_preferred_style = XIMPreeditCallbacks |
+ XIMStatusNothing;
+ else if (s == QLatin1String("overthespot"))
+ qt_xim_preferred_style = XIMPreeditPosition |
+ XIMStatusNothing;
+ else if (s == QLatin1String("offthespot"))
+ qt_xim_preferred_style = XIMPreeditArea |
+ XIMStatusArea;
+ else if (s == QLatin1String("root"))
+ qt_xim_preferred_style = XIMPreeditNothing |
+ XIMStatusNothing;
+ }
+#endif
+ } else if (arg == "-cmap") { // xv uses this name
+ if (!X11->colormap)
+ X11->custom_cmap = true;
+ }
+ else if (arg == "-sync")
+ appSync = !appSync;
+#if defined(QT_DEBUG)
+ else if (arg == "-nograb")
+ appNoGrab = !appNoGrab;
+ else if (arg == "-dograb")
+ appDoGrab = !appDoGrab;
+#endif
+ else
+ argv[j++] = argv[i];
+ }
+
+ priv->argc = j;
+
+#if defined(QT_DEBUG) && defined(Q_OS_LINUX)
+ if (!appNoGrab && !appDoGrab) {
+ QString s;
+ s.sprintf("/proc/%d/cmdline", getppid());
+ QFile f(s);
+ if (f.open(QIODevice::ReadOnly)) {
+ s.clear();
+ char c;
+ while (f.getChar(&c) && c) {
+ if (c == '/')
+ s.clear();
+ else
+ s += QLatin1Char(c);
+ }
+ if (s == QLatin1String("gdb")) {
+ appNoGrab = true;
+ qDebug("Qt: gdb: -nograb added to command-line options.\n"
+ "\t Use the -dograb option to enforce grabbing.");
+ }
+ f.close();
+ }
+ }
+#endif
+
+ // Connect to X server
+ if (qt_is_gui_used && !X11->display) {
+ if ((X11->display = XOpenDisplay(X11->displayName)) == 0) {
+ qWarning("%s: cannot connect to X server %s", appName,
+ XDisplayName(X11->displayName));
+ QApplicationPrivate::reset_instance_pointer();
+ exit(1);
+ }
+
+ if (appSync) // if "-sync" argument
+ XSynchronize(X11->display, true);
+ }
+
+ // Common code, regardless of whether display is foreign.
+
+ // Get X parameters
+
+ if (qt_is_gui_used) {
+ X11->defaultScreen = DefaultScreen(X11->display);
+ X11->screenCount = ScreenCount(X11->display);
+
+ X11->screens = new QX11InfoData[X11->screenCount];
+ X11->argbVisuals = new Visual *[X11->screenCount];
+ X11->argbColormaps = new Colormap[X11->screenCount];
+
+ for (int s = 0; s < X11->screenCount; s++) {
+ QX11InfoData *screen = X11->screens + s;
+ screen->ref = 1; // ensures it doesn't get deleted
+ screen->screen = s;
+
+ int widthMM = DisplayWidthMM(X11->display, s);
+ if (widthMM != 0) {
+ screen->dpiX = (DisplayWidth(X11->display, s) * 254 + widthMM * 5) / (widthMM * 10);
+ } else {
+ screen->dpiX = 72;
+ }
+
+ int heightMM = DisplayHeightMM(X11->display, s);
+ if (heightMM != 0) {
+ screen->dpiY = (DisplayHeight(X11->display, s) * 254 + heightMM * 5) / (heightMM * 10);
+ } else {
+ screen->dpiY = 72;
+ }
+
+ X11->argbVisuals[s] = 0;
+ X11->argbColormaps[s] = 0;
+ }
+
+
+#ifndef QT_NO_XRENDER
+ int xrender_eventbase, xrender_errorbase;
+ // See if XRender is supported on the connected display
+ if (XQueryExtension(X11->display, "RENDER", &X11->xrender_major,
+ &xrender_eventbase, &xrender_errorbase)
+ && XRenderQueryExtension(X11->display, &xrender_eventbase,
+ &xrender_errorbase)) {
+ // Check the version as well - we need v0.4 or higher
+ int major = 0;
+ int minor = 0;
+ XRenderQueryVersion(X11->display, &major, &minor);
+ if (qgetenv("QT_X11_NO_XRENDER").isNull()) {
+ X11->use_xrender = (major >= 0 && minor >= 5);
+ X11->xrender_version = major*100+minor;
+ // workaround for broken XServer on Ubuntu Breezy (6.8 compiled with 7.0
+ // protocol headers)
+ if (X11->xrender_version == 10
+ && VendorRelease(X11->display) < 60900000
+ && QByteArray(ServerVendor(X11->display)).contains("X.Org"))
+ X11->xrender_version = 9;
+ }
+ }
+#endif // QT_NO_XRENDER
+
+#ifndef QT_NO_MITSHM
+ int mitshm_minor;
+ int mitshm_major;
+ int mitshm_eventbase;
+ int mitshm_errorbase;
+ int mitshm_pixmaps;
+ if (XQueryExtension(X11->display, "MIT-SHM", &X11->mitshm_major,
+ &mitshm_eventbase, &mitshm_errorbase)
+ && XShmQueryVersion(X11->display, &mitshm_major, &mitshm_minor,
+ &mitshm_pixmaps))
+ {
+ QString displayName = QLatin1String(XDisplayName(NULL));
+
+ // MITSHM only works for local displays, so do a quick check here
+ // to determine whether the display is local or not (not 100 % accurate).
+ // BGR server layouts are not supported either, since it requires the raster
+ // engine to work on a QImage with BGR layout.
+ bool local = displayName.isEmpty() || displayName.lastIndexOf(QLatin1Char(':')) == 0;
+ if (local && (qgetenv("QT_X11_NO_MITSHM").toInt() == 0)) {
+ Visual *defaultVisual = DefaultVisual(X11->display, DefaultScreen(X11->display));
+ X11->use_mitshm = ((defaultVisual->red_mask == 0xff0000
+ || defaultVisual->red_mask == 0xf800)
+ && (defaultVisual->green_mask == 0xff00
+ || defaultVisual->green_mask == 0x7e0)
+ && (defaultVisual->blue_mask == 0xff
+ || defaultVisual->blue_mask == 0x1f));
+ X11->use_mitshm_pixmaps = X11->use_mitshm && mitshm_pixmaps;
+ }
+ }
+#endif // QT_NO_MITSHM
+
+ // initialize the graphics system - order is imporant here - it must be done before
+ // the QColormap::initialize() call
+ QApplicationPrivate::graphics_system = QGraphicsSystemFactory::create(QApplicationPrivate::graphics_system_name);
+ QColormap::initialize();
+
+ // Support protocols
+ X11->xdndSetup();
+
+ // Finally create all atoms
+ qt_x11_create_intern_atoms();
+
+ // initialize NET lists
+ qt_get_net_supported();
+ qt_get_net_virtual_roots();
+
+#ifndef QT_NO_XRANDR
+ // See if XRandR is supported on the connected display
+ if (XQueryExtension(X11->display, "RANDR", &X11->xrandr_major,
+ &X11->xrandr_eventbase, &X11->xrandr_errorbase)) {
+
+# ifdef QT_RUNTIME_XRANDR
+ X11->ptrXRRSelectInput = 0;
+ X11->ptrXRRUpdateConfiguration = 0;
+ X11->ptrXRRRootToScreen = 0;
+ X11->ptrXRRQueryExtension = 0;
+ QLibrary xrandrLib(QLatin1String("Xrandr"), 2);
+ if (!xrandrLib.load()) { // try without the version number
+ xrandrLib.setFileName(QLatin1String("Xrandr"));
+ xrandrLib.load();
+ }
+ if (xrandrLib.isLoaded()) {
+ X11->ptrXRRSelectInput =
+ (PtrXRRSelectInput) xrandrLib.resolve("XRRSelectInput");
+ X11->ptrXRRUpdateConfiguration =
+ (PtrXRRUpdateConfiguration) xrandrLib.resolve("XRRUpdateConfiguration");
+ X11->ptrXRRRootToScreen =
+ (PtrXRRRootToScreen) xrandrLib.resolve("XRRRootToScreen");
+ X11->ptrXRRQueryExtension =
+ (PtrXRRQueryExtension) xrandrLib.resolve("XRRQueryExtension");
+ X11->ptrXRRSizes =
+ (PtrXRRSizes) xrandrLib.resolve("XRRSizes");
+ }
+# else
+ X11->ptrXRRSelectInput = XRRSelectInput;
+ X11->ptrXRRUpdateConfiguration = XRRUpdateConfiguration;
+ X11->ptrXRRRootToScreen = XRRRootToScreen;
+ X11->ptrXRRQueryExtension = XRRQueryExtension;
+ X11->ptrXRRSizes = XRRSizes;
+# endif
+
+ if (X11->ptrXRRQueryExtension
+ && X11->ptrXRRQueryExtension(X11->display, &X11->xrandr_eventbase, &X11->xrandr_errorbase)) {
+ // XRandR is supported
+ X11->use_xrandr = true;
+ }
+ }
+#endif // QT_NO_XRANDR
+
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender) {
+ // XRender is supported, let's see if we have a PictFormat for the
+ // default visual
+ XRenderPictFormat *format =
+ XRenderFindVisualFormat(X11->display,
+ (Visual *) QX11Info::appVisual(X11->defaultScreen));
+
+ if (!format) {
+ X11->use_xrender = false;
+ }
+ }
+#endif // QT_NO_XRENDER
+
+#ifndef QT_NO_XFIXES
+ // See if Xfixes is supported on the connected display
+ if (XQueryExtension(X11->display, "XFIXES", &X11->xfixes_major,
+ &X11->xfixes_eventbase, &X11->xfixes_errorbase)) {
+ X11->ptrXFixesQueryExtension = XFIXES_LOAD_V1(XFixesQueryExtension);
+ X11->ptrXFixesQueryVersion = XFIXES_LOAD_V1(XFixesQueryVersion);
+ X11->ptrXFixesSetCursorName = XFIXES_LOAD_V2(XFixesSetCursorName);
+ X11->ptrXFixesSelectSelectionInput = XFIXES_LOAD_V2(XFixesSelectSelectionInput);
+
+ if(X11->ptrXFixesQueryExtension && X11->ptrXFixesQueryVersion
+ && X11->ptrXFixesQueryExtension(X11->display, &X11->xfixes_eventbase,
+ &X11->xfixes_errorbase)) {
+ // Xfixes is supported.
+ // Note: the XFixes protocol version is negotiated using QueryVersion.
+ // We supply the highest version we support, the X server replies with
+ // the highest version it supports, but no higher than the version we
+ // asked for. The version sent back is the protocol version the X server
+ // will use to talk us. If this call is removed, the behavior of the
+ // X server when it receives an XFixes request is undefined.
+ int major = 3;
+ int minor = 0;
+ X11->ptrXFixesQueryVersion(X11->display, &major, &minor);
+ X11->use_xfixes = (major >= 1);
+ X11->xfixes_major = major;
+ }
+ }
+#endif // QT_NO_XFIXES
+
+#ifndef QT_NO_XCURSOR
+#ifdef QT_RUNTIME_XCURSOR
+ X11->ptrXcursorLibraryLoadCursor = 0;
+ QLibrary xcursorLib(QLatin1String("Xcursor"), 1);
+ bool xcursorFound = xcursorLib.load();
+ if (!xcursorFound) { //try without the version number
+ xcursorLib.setFileName(QLatin1String("Xcursor"));
+ xcursorFound = xcursorLib.load();
+ }
+ if (xcursorFound) {
+ X11->ptrXcursorLibraryLoadCursor =
+ (PtrXcursorLibraryLoadCursor) xcursorLib.resolve("XcursorLibraryLoadCursor");
+ }
+#else
+ X11->ptrXcursorLibraryLoadCursor = XcursorLibraryLoadCursor;
+#endif // QT_RUNTIME_XCURSOR
+#endif // QT_NO_XCURSOR
+
+#ifndef QT_NO_XSYNC
+ int xsync_evbase, xsync_errbase;
+ int major, minor;
+ if (XSyncQueryExtension(X11->display, &xsync_evbase, &xsync_errbase))
+ XSyncInitialize(X11->display, &major, &minor);
+#endif // QT_NO_XSYNC
+
+#ifndef QT_NO_XINERAMA
+#ifdef QT_RUNTIME_XINERAMA
+ X11->ptrXineramaQueryExtension = 0;
+ X11->ptrXineramaIsActive = 0;
+ X11->ptrXineramaQueryScreens = 0;
+ QLibrary xineramaLib(QLatin1String("Xinerama"), 1);
+ bool xineramaFound = xineramaLib.load();
+ if (!xineramaFound) { //try without the version number
+ xineramaLib.setFileName(QLatin1String("Xinerama"));
+ xineramaFound = xineramaLib.load();
+ }
+ if (xineramaFound) {
+ X11->ptrXineramaQueryExtension =
+ (PtrXineramaQueryExtension) xineramaLib.resolve("XineramaQueryExtension");
+ X11->ptrXineramaIsActive =
+ (PtrXineramaIsActive) xineramaLib.resolve("XineramaIsActive");
+ X11->ptrXineramaQueryScreens =
+ (PtrXineramaQueryScreens) xineramaLib.resolve("XineramaQueryScreens");
+ }
+#else
+ X11->ptrXineramaQueryScreens = XineramaQueryScreens;
+ X11->ptrXineramaIsActive = XineramaIsActive;
+ X11->ptrXineramaQueryExtension = XineramaQueryExtension;
+#endif // QT_RUNTIME_XINERAMA
+#endif // QT_NO_XINERAMA
+
+#ifndef QT_NO_XINPUT
+ // See if Xinput is supported on the connected display
+ X11->ptrXCloseDevice = 0;
+ X11->ptrXListInputDevices = 0;
+ X11->ptrXOpenDevice = 0;
+ X11->ptrXFreeDeviceList = 0;
+ X11->ptrXSelectExtensionEvent = 0;
+ X11->use_xinput = XQueryExtension(X11->display, "XInputExtension", &X11->xinput_major,
+ &X11->xinput_eventbase, &X11->xinput_errorbase);
+ if (X11->use_xinput) {
+ X11->ptrXCloseDevice = XINPUT_LOAD(XCloseDevice);
+ X11->ptrXListInputDevices = XINPUT_LOAD(XListInputDevices);
+ X11->ptrXOpenDevice = XINPUT_LOAD(XOpenDevice);
+ X11->ptrXFreeDeviceList = XINPUT_LOAD(XFreeDeviceList);
+ X11->ptrXSelectExtensionEvent = XINPUT_LOAD(XSelectExtensionEvent);
+ }
+#endif // QT_NO_XINPUT
+
+#ifndef QT_NO_XKB
+ int xkblibMajor = XkbMajorVersion;
+ int xkblibMinor = XkbMinorVersion;
+ X11->use_xkb = XkbQueryExtension(X11->display,
+ &X11->xkb_major,
+ &X11->xkb_eventbase,
+ &X11->xkb_errorbase,
+ &xkblibMajor,
+ &xkblibMinor);
+ if (X11->use_xkb) {
+ // If XKB is detected, set the GrabsUseXKBState option so input method
+ // compositions continue to work (ie. deadkeys)
+ unsigned int state = XkbPCF_GrabsUseXKBStateMask;
+ (void) XkbSetPerClientControls(X11->display, state, &state);
+
+ // select for group change events
+ XkbSelectEventDetails(X11->display,
+ XkbUseCoreKbd,
+ XkbStateNotify,
+ XkbAllStateComponentsMask,
+ XkbGroupStateMask);
+
+ // current group state is queried when creating the keymapper, no need to do it here
+ }
+#endif
+
+
+#if !defined(QT_NO_FONTCONFIG)
+ int dpi = 0;
+ getXDefault("Xft", FC_DPI, &dpi);
+ if (dpi) {
+ for (int s = 0; s < ScreenCount(X11->display); ++s) {
+ QX11Info::setAppDpiX(s, dpi);
+ QX11Info::setAppDpiY(s, dpi);
+ }
+ }
+ double fc_scale = 1.;
+ getXDefault("Xft", FC_SCALE, &fc_scale);
+ X11->fc_scale = fc_scale;
+ for (int s = 0; s < ScreenCount(X11->display); ++s) {
+ int subpixel = FC_RGBA_UNKNOWN;
+#if !defined(QT_NO_XRENDER) && (RENDER_MAJOR > 0 || RENDER_MINOR >= 6)
+ if (X11->use_xrender) {
+ int rsp = XRenderQuerySubpixelOrder(X11->display, s);
+ switch (rsp) {
+ default:
+ case SubPixelUnknown:
+ subpixel = FC_RGBA_UNKNOWN;
+ break;
+ case SubPixelHorizontalRGB:
+ subpixel = FC_RGBA_RGB;
+ break;
+ case SubPixelHorizontalBGR:
+ subpixel = FC_RGBA_BGR;
+ break;
+ case SubPixelVerticalRGB:
+ subpixel = FC_RGBA_VRGB;
+ break;
+ case SubPixelVerticalBGR:
+ subpixel = FC_RGBA_VBGR;
+ break;
+ case SubPixelNone:
+ subpixel = FC_RGBA_NONE;
+ break;
+ }
+ }
+#endif
+
+ char *rgba = XGetDefault(X11->display, "Xft", FC_RGBA);
+ if (rgba) {
+ char *end = 0;
+ int v = strtol(rgba, &end, 0);
+ if (rgba != end) {
+ subpixel = v;
+ } else if (qstrncmp(rgba, "unknown", 7) == 0) {
+ subpixel = FC_RGBA_UNKNOWN;
+ } else if (qstrncmp(rgba, "rgb", 3) == 0) {
+ subpixel = FC_RGBA_RGB;
+ } else if (qstrncmp(rgba, "bgr", 3) == 0) {
+ subpixel = FC_RGBA_BGR;
+ } else if (qstrncmp(rgba, "vrgb", 4) == 0) {
+ subpixel = FC_RGBA_VRGB;
+ } else if (qstrncmp(rgba, "vbgr", 4) == 0) {
+ subpixel = FC_RGBA_VBGR;
+ } else if (qstrncmp(rgba, "none", 4) == 0) {
+ subpixel = FC_RGBA_NONE;
+ }
+ }
+ X11->screens[s].subpixel = subpixel;
+ }
+ getXDefault("Xft", FC_ANTIALIAS, &X11->fc_antialias);
+#ifdef FC_HINT_STYLE
+ X11->fc_hint_style = -1;
+ getXDefault("Xft", FC_HINT_STYLE, &X11->fc_hint_style);
+#endif
+#if 0
+ // ###### these are implemented by Xft, not sure we need them
+ getXDefault("Xft", FC_AUTOHINT, &X11->fc_autohint);
+ getXDefault("Xft", FC_HINTING, &X11->fc_autohint);
+ getXDefault("Xft", FC_MINSPACE, &X11->fc_autohint);
+#endif
+#endif // QT_NO_XRENDER
+
+ // initialize key mapper
+ QKeyMapper::changeKeyboard();
+
+ // Misc. initialization
+#if 0 //disabled for now..
+ QSegfaultHandler::initialize(priv->argv, priv->argc);
+#endif
+ QCursorData::initialize();
+ }
+ QFont::initialize();
+
+ if(qt_is_gui_used) {
+ qApp->setObjectName(QString::fromLocal8Bit(appName));
+
+ int screen;
+ for (screen = 0; screen < X11->screenCount; ++screen) {
+ XSelectInput(X11->display, QX11Info::appRootWindow(screen),
+ KeymapStateMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask);
+
+#ifndef QT_NO_XRANDR
+ if (X11->use_xrandr)
+ X11->ptrXRRSelectInput(X11->display, QX11Info::appRootWindow(screen), True);
+#endif // QT_NO_XRANDR
+ }
+ }
+
+ if (qt_is_gui_used) {
+ // Attempt to determine the current running X11 Desktop Enviornment
+ // Use dbus if/when we can, but fall back to using windowManagerName() for now
+
+#ifndef QT_NO_XFIXES
+ if (X11->ptrXFixesSelectSelectionInput)
+ X11->ptrXFixesSelectSelectionInput(X11->display, QX11Info::appRootWindow(), ATOM(_NET_WM_CM_S0),
+ XFixesSetSelectionOwnerNotifyMask
+ | XFixesSelectionWindowDestroyNotifyMask
+ | XFixesSelectionClientCloseNotifyMask);
+#endif // QT_NO_XFIXES
+ X11->compositingManagerRunning = XGetSelectionOwner(X11->display,
+ ATOM(_NET_WM_CM_S0));
+ X11->desktopEnvironment = DE_UNKNOWN;
+ X11->desktopVersion = 0;
+
+ Atom type;
+ int format;
+ unsigned long length, after;
+ uchar *data = 0;
+ int rc;
+
+ do {
+ if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
+ X11->desktopEnvironment = DE_KDE;
+ X11->desktopVersion = qgetenv("KDE_SESSION_VERSION").toInt();
+ break;
+ }
+
+ if (qgetenv("DESKTOP_SESSION") == "gnome") {
+ X11->desktopEnvironment = DE_GNOME;
+ break;
+ }
+
+ // GNOME_DESKTOP_SESSION_ID is deprecated for some reason, but still check it
+ if (!qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty()) {
+ X11->desktopEnvironment = DE_GNOME;
+ break;
+ }
+
+ rc = XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(_DT_SAVE_MODE),
+ 0, 2, False, XA_STRING, &type, &format, &length,
+ &after, &data);
+ if (rc == Success && length) {
+ if (!strcmp(reinterpret_cast<char *>(data), "xfce4")) {
+ // Pretend that xfce4 is gnome, as it uses the same libraries.
+ // The detection above is stolen from xdg-open.
+ X11->desktopEnvironment = DE_GNOME;
+ break;
+ }
+
+ // We got the property but it wasn't xfce4. Free data before it gets overwritten.
+ XFree(data);
+ data = 0;
+ }
+
+ rc = XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(DTWM_IS_RUNNING),
+ 0, 1, False, AnyPropertyType, &type, &format, &length,
+ &after, &data);
+ if (rc == Success && length) {
+ // DTWM is running, meaning most likely CDE is running...
+ X11->desktopEnvironment = DE_CDE;
+ break;
+ }
+
+ rc = XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
+ ATOM(_SGI_DESKS_MANAGER), 0, 1, False, XA_WINDOW,
+ &type, &format, &length, &after, &data);
+ if (rc == Success && length) {
+ X11->desktopEnvironment = DE_4DWM;
+ break;
+ }
+
+ if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
+ ATOM(_NET_SUPPORTING_WM_CHECK),
+ 0, 1024, False, XA_WINDOW, &type,
+ &format, &length, &after, &data) == Success) {
+ if (type == XA_WINDOW && format == 32) {
+ Window windowManagerWindow = *((Window*) data);
+ XFree(data);
+ data = 0;
+
+ if (windowManagerWindow != XNone) {
+ Atom utf8atom = ATOM(UTF8_STRING);
+ if (XGetWindowProperty(QX11Info::display(), windowManagerWindow, ATOM(_NET_WM_NAME),
+ 0, 1024, False, utf8atom, &type,
+ &format, &length, &after, &data) == Success) {
+ if (type == utf8atom && format == 8) {
+ if (qstrcmp((const char *)data, "MCompositor") == 0)
+ X11->desktopEnvironment = DE_MEEGO_COMPOSITOR;
+ }
+ }
+ }
+ }
+ }
+
+ } while(0);
+
+ if (data)
+ XFree((char *)data);
+
+#if !defined(QT_NO_STYLE_GTK)
+ if (X11->desktopEnvironment == DE_GNOME) {
+ static bool menusHaveIcons = QGtkStyle::getGConfBool(QLatin1String("/desktop/gnome/interface/menus_have_icons"), true);
+ QApplication::setAttribute(Qt::AA_DontShowIconsInMenus, !menusHaveIcons);
+ }
+#endif
+ qt_set_input_encoding();
+
+ qt_set_x11_resources(appFont, appFGCol, appBGCol, appBTNCol);
+
+ // be smart about the size of the default font. most X servers have helvetica
+ // 12 point available at 2 resolutions:
+ // 75dpi (12 pixels) and 100dpi (17 pixels).
+ // At 95 DPI, a 12 point font should be 16 pixels tall - in which case a 17
+ // pixel font is a closer match than a 12 pixel font
+ int ptsz = (X11->use_xrender
+ ? 9
+ : (int) (((QX11Info::appDpiY() >= 95 ? 17. : 12.) *
+ 72. / (float) QX11Info::appDpiY()) + 0.5));
+
+ if (!QApplicationPrivate::sys_font) {
+ // no font from settings or RESOURCE_MANAGER, provide a fallback
+ QFont f(X11->has_fontconfig ? QLatin1String("Sans Serif") : QLatin1String("Helvetica"),
+ ptsz);
+ QApplicationPrivate::setSystemFont(f);
+ }
+
+#if !defined (QT_NO_TABLET)
+ if (X11->use_xinput) {
+ int ndev,
+ i,
+ j;
+ bool gotStylus,
+ gotEraser;
+ XDeviceInfo *devices = 0, *devs;
+ XInputClassInfo *ip;
+ XAnyClassPtr any;
+ XValuatorInfoPtr v;
+ XAxisInfoPtr a;
+ XDevice *dev = 0;
+
+ if (X11->ptrXListInputDevices) {
+ devices = X11->ptrXListInputDevices(X11->display, &ndev);
+ if (!devices)
+ qWarning("QApplication: Failed to get list of tablet devices");
+ }
+ if (!devices)
+ ndev = -1;
+ QTabletEvent::TabletDevice deviceType;
+ for (devs = devices, i = 0; i < ndev && devs; i++, devs++) {
+ dev = 0;
+ deviceType = QTabletEvent::NoDevice;
+ gotStylus = false;
+ gotEraser = false;
+
+#if defined(Q_OS_IRIX)
+ QString devName = QString::fromLocal8Bit(devs->name).toLower();
+ if (devName == QLatin1String(WACOM_NAME)) {
+ deviceType = QTabletEvent::Stylus;
+ gotStylus = true;
+ }
+#else
+ if (devs->type == ATOM(XWacomStylus) || devs->type == ATOM(XTabletStylus)) {
+ deviceType = QTabletEvent::Stylus;
+ if (wacomDeviceName()->isEmpty())
+ wacomDeviceName()->append(devs->name);
+ gotStylus = true;
+ } else if (devs->type == ATOM(XWacomEraser) || devs->type == ATOM(XTabletEraser)) {
+ deviceType = QTabletEvent::XFreeEraser;
+ gotEraser = true;
+ }
+#endif
+ if (deviceType == QTabletEvent::NoDevice)
+ continue;
+
+ if (gotStylus || gotEraser) {
+ if (X11->ptrXOpenDevice)
+ dev = X11->ptrXOpenDevice(X11->display, devs->id);
+
+ if (!dev)
+ continue;
+
+ QTabletDeviceData device_data;
+ device_data.deviceType = deviceType;
+ device_data.eventCount = 0;
+ device_data.device = dev;
+ device_data.xinput_motion = -1;
+ device_data.xinput_key_press = -1;
+ device_data.xinput_key_release = -1;
+ device_data.xinput_button_press = -1;
+ device_data.xinput_button_release = -1;
+ device_data.xinput_proximity_in = -1;
+ device_data.xinput_proximity_out = -1;
+ device_data.widgetToGetPress = 0;
+
+ if (dev->num_classes > 0) {
+ for (ip = dev->classes, j = 0; j < dev->num_classes;
+ ip++, j++) {
+ switch (ip->input_class) {
+ case KeyClass:
+ DeviceKeyPress(dev, device_data.xinput_key_press,
+ device_data.eventList[device_data.eventCount]);
+ if (device_data.eventList[device_data.eventCount])
+ ++device_data.eventCount;
+ DeviceKeyRelease(dev, device_data.xinput_key_release,
+ device_data.eventList[device_data.eventCount]);
+ if (device_data.eventList[device_data.eventCount])
+ ++device_data.eventCount;
+ break;
+ case ButtonClass:
+ DeviceButtonPress(dev, device_data.xinput_button_press,
+ device_data.eventList[device_data.eventCount]);
+ if (device_data.eventList[device_data.eventCount])
+ ++device_data.eventCount;
+ DeviceButtonRelease(dev, device_data.xinput_button_release,
+ device_data.eventList[device_data.eventCount]);
+ if (device_data.eventList[device_data.eventCount])
+ ++device_data.eventCount;
+ break;
+ case ValuatorClass:
+ // I'm only going to be interested in motion when the
+ // stylus is already down anyway!
+ DeviceMotionNotify(dev, device_data.xinput_motion,
+ device_data.eventList[device_data.eventCount]);
+ if (device_data.eventList[device_data.eventCount])
+ ++device_data.eventCount;
+ ProximityIn(dev, device_data.xinput_proximity_in, device_data.eventList[device_data.eventCount]);
+ if (device_data.eventList[device_data.eventCount])
+ ++device_data.eventCount;
+ ProximityOut(dev, device_data.xinput_proximity_out, device_data.eventList[device_data.eventCount]);
+ if (device_data.eventList[device_data.eventCount])
+ ++device_data.eventCount;
+ default:
+ break;
+ }
+ }
+ }
+
+ // get the min/max value for pressure!
+ any = (XAnyClassPtr) (devs->inputclassinfo);
+ for (j = 0; j < devs->num_classes; j++) {
+ if (any->c_class == ValuatorClass) {
+ v = (XValuatorInfoPtr) any;
+ a = (XAxisInfoPtr) ((char *) v +
+ sizeof (XValuatorInfo));
+#if defined (Q_OS_IRIX)
+ // I'm not exaclty wild about this, but the
+ // dimensions of the tablet are more relevant here
+ // than the min and max values from the axis
+ // (actually it seems to be 2/3 or what is in the
+ // axis. So we'll try to parse it from this
+ // string. --tws
+ char returnString[SGIDeviceRtrnLen];
+ int tmp;
+ if (XSGIMiscQueryExtension(X11->display, &tmp, &tmp)
+ && XSGIDeviceQuery(X11->display, devs->id,
+ "dimensions", returnString)) {
+ QString str = QLatin1String(returnString);
+ int comma = str.indexOf(',');
+ device_data.minX = 0;
+ device_data.minY = 0;
+ device_data.maxX = str.left(comma).toInt();
+ device_data.maxY = str.mid(comma + 1).toInt();
+ } else {
+ device_data.minX = a[WAC_XCOORD_I].min_value;
+ device_data.maxX = a[WAC_XCOORD_I].max_value;
+ device_data.minY = a[WAC_YCOORD_I].min_value;
+ device_data.maxY = a[WAC_YCOORD_I].max_value;
+ }
+ device_data.minPressure = a[WAC_PRESSURE_I].min_value;
+ device_data.maxPressure = a[WAC_PRESSURE_I].max_value;
+ device_data.minTanPressure = a[WAC_TAN_PRESSURE_I].min_value;
+ device_data.maxTanPressure = a[WAC_TAN_PRESSURE_I].max_value;
+ device_data.minZ = a[WAC_ZCOORD_I].min_value;
+ device_data.maxZ = a[WAC_ZCOORD_I].max_value;
+#else
+ device_data.minX = a[0].min_value;
+ device_data.maxX = a[0].max_value;
+ device_data.minY = a[1].min_value;
+ device_data.maxY = a[1].max_value;
+ device_data.minPressure = a[2].min_value;
+ device_data.maxPressure = a[2].max_value;
+ device_data.minTanPressure = 0;
+ device_data.maxTanPressure = 0;
+ device_data.minZ = 0;
+ device_data.maxZ = 0;
+#endif
+
+ // got the max pressure no need to go further...
+ break;
+ }
+ any = (XAnyClassPtr) ((char *) any + any->length);
+ } // end of for loop
+
+ tablet_devices()->append(device_data);
+ } // if (gotStylus || gotEraser)
+ }
+ if (X11->ptrXFreeDeviceList)
+ X11->ptrXFreeDeviceList(devices);
+ }
+#endif // QT_NO_TABLET
+
+ X11->startupId = getenv("DESKTOP_STARTUP_ID");
+ if (X11->startupId) {
+#ifndef QT_NO_UNSETENV
+ unsetenv("DESKTOP_STARTUP_ID");
+#else
+ // it's a small memory leak, however we won't crash if Qt is
+ // unloaded and someones tries to use the envoriment.
+ putenv(strdup("DESKTOP_STARTUP_ID="));
+#endif
+ }
+ } else {
+ // read some non-GUI settings when not using the X server...
+
+ if (QApplication::desktopSettingsAware()) {
+ QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
+ settings.beginGroup(QLatin1String("Qt"));
+
+ // read library (ie. plugin) path list
+ QString libpathkey = QString::fromLatin1("%1.%2/libraryPath")
+ .arg(QT_VERSION >> 16)
+ .arg((QT_VERSION & 0xff00) >> 8);
+ QStringList pathlist =
+ settings.value(libpathkey).toString().split(QLatin1Char(':'));
+ if (! pathlist.isEmpty()) {
+ QStringList::ConstIterator it = pathlist.constBegin();
+ while (it != pathlist.constEnd())
+ QApplication::addLibraryPath(*it++);
+ }
+
+ QString defaultcodec = settings.value(QLatin1String("defaultCodec"),
+ QVariant(QLatin1String("none"))).toString();
+ if (defaultcodec != QLatin1String("none")) {
+ QTextCodec *codec = QTextCodec::codecForName(defaultcodec.toLatin1());
+ if (codec)
+ QTextCodec::setCodecForTr(codec);
+ }
+
+ settings.endGroup(); // Qt
+ }
+ }
+
+#if !defined (Q_OS_IRIX) && !defined (QT_NO_TABLET)
+ QLibrary wacom(QString::fromLatin1("wacomcfg"), 0); // version 0 is the latest release at time of writing this.
+ // NOTE: C casts instead of reinterpret_cast for GCC 3.3.x
+ ptrWacomConfigInit = (PtrWacomConfigInit)wacom.resolve("WacomConfigInit");
+ ptrWacomConfigOpenDevice = (PtrWacomConfigOpenDevice)wacom.resolve("WacomConfigOpenDevice");
+ ptrWacomConfigGetRawParam = (PtrWacomConfigGetRawParam)wacom.resolve("WacomConfigGetRawParam");
+ ptrWacomConfigCloseDevice = (PtrWacomConfigCloseDevice)wacom.resolve("WacomConfigCloseDevice");
+ ptrWacomConfigTerm = (PtrWacomConfigTerm)wacom.resolve("WacomConfigTerm");
+
+ if (ptrWacomConfigInit == 0 || ptrWacomConfigOpenDevice == 0 || ptrWacomConfigGetRawParam == 0
+ || ptrWacomConfigCloseDevice == 0 || ptrWacomConfigTerm == 0) { // either we have all, or we have none.
+ ptrWacomConfigInit = 0;
+ ptrWacomConfigOpenDevice = 0;
+ ptrWacomConfigGetRawParam = 0;
+ ptrWacomConfigCloseDevice = 0;
+ ptrWacomConfigTerm = 0;
+ }
+#endif
+}
+
+void QApplicationPrivate::initializeWidgetPaletteHash()
+{
+}
+
+/*****************************************************************************
+ qt_cleanup() - cleans up when the application is finished
+ *****************************************************************************/
+
+void qt_cleanup()
+{
+ if (app_save_rootinfo) // root window must keep state
+ qt_save_rootinfo();
+
+ if (qt_is_gui_used) {
+ QPixmapCache::clear();
+ QCursorData::cleanup();
+ QFont::cleanup();
+ QColormap::cleanup();
+
+#if !defined (QT_NO_TABLET)
+ QTabletDeviceDataList *devices = qt_tablet_devices();
+ if (X11->ptrXCloseDevice)
+ for (int i = 0; i < devices->size(); ++i)
+ X11->ptrXCloseDevice(X11->display, (XDevice*)devices->at(i).device);
+ devices->clear();
+#endif
+ }
+
+#ifndef QT_NO_XRENDER
+ for (int i = 0; i < X11->solid_fill_count; ++i) {
+ if (X11->solid_fills[i].picture)
+ XRenderFreePicture(X11->display, X11->solid_fills[i].picture);
+ }
+ for (int i = 0; i < X11->pattern_fill_count; ++i) {
+ if (X11->pattern_fills[i].picture)
+ XRenderFreePicture(X11->display, X11->pattern_fills[i].picture);
+ }
+#endif
+
+#if !defined(QT_NO_IM)
+ delete QApplicationPrivate::inputContext;
+ QApplicationPrivate::inputContext = 0;
+#endif
+
+ // Reset the error handlers
+ if (qt_is_gui_used)
+ XSync(X11->display, False); // sync first to process all possible errors
+ XSetErrorHandler(original_x_errhandler);
+ XSetIOErrorHandler(original_xio_errhandler);
+
+ if (X11->argbColormaps) {
+ for (int s = 0; s < X11->screenCount; s++) {
+ if (X11->argbColormaps[s])
+ XFreeColormap(X11->display, X11->argbColormaps[s]);
+ }
+ }
+
+ if (qt_is_gui_used && !X11->foreignDisplay)
+ XCloseDisplay(X11->display); // close X display
+ X11->display = 0;
+
+ delete [] X11->screens;
+ delete [] X11->argbVisuals;
+ delete [] X11->argbColormaps;
+
+ if (X11->foreignDisplay) {
+ delete [] (char *)appName;
+ appName = 0;
+ }
+
+ delete [] (char *)appClass;
+ appClass = 0;
+
+ if (X11->net_supported_list)
+ delete [] X11->net_supported_list;
+ X11->net_supported_list = 0;
+
+ if (X11->net_virtual_root_list)
+ delete [] X11->net_virtual_root_list;
+ X11->net_virtual_root_list = 0;
+
+ delete X11;
+ X11 = 0;
+}
+
+
+/*****************************************************************************
+ Platform specific global and internal functions
+ *****************************************************************************/
+
+void qt_save_rootinfo() // save new root info
+{
+ Atom type;
+ int format;
+ unsigned long length, after;
+ uchar *data = 0;
+
+ if (ATOM(_XSETROOT_ID)) { // kill old pixmap
+ if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
+ ATOM(_XSETROOT_ID), 0, 1,
+ True, AnyPropertyType, &type, &format,
+ &length, &after, &data) == Success) {
+ if (type == XA_PIXMAP && format == 32 && length == 1 &&
+ after == 0 && data) {
+ XKillClient(X11->display, *((Pixmap*)data));
+ }
+ Pixmap dummy = XCreatePixmap(X11->display, QX11Info::appRootWindow(),
+ 1, 1, 1);
+ XChangeProperty(X11->display, QX11Info::appRootWindow(),
+ ATOM(_XSETROOT_ID), XA_PIXMAP, 32,
+ PropModeReplace, (uchar *)&dummy, 1);
+ XSetCloseDownMode(X11->display, RetainPermanent);
+ }
+ }
+ if (data)
+ XFree((char *)data);
+}
+
+void qt_updated_rootinfo()
+{
+ app_save_rootinfo = true;
+}
+
+// ### Cleanup, this function is not in use!
+bool qt_wstate_iconified(WId winid)
+{
+ Atom type;
+ int format;
+ unsigned long length, after;
+ uchar *data = 0;
+ int r = XGetWindowProperty(X11->display, winid, ATOM(WM_STATE), 0, 2,
+ False, AnyPropertyType, &type, &format,
+ &length, &after, &data);
+ bool iconic = false;
+ if (r == Success && data && format == 32) {
+ // quint32 *wstate = (quint32*)data;
+ unsigned long *wstate = (unsigned long *) data;
+ iconic = (*wstate == IconicState);
+ XFree((char *)data);
+ }
+ return iconic;
+}
+
+QString QApplicationPrivate::appName() const
+{
+ return QString::fromLocal8Bit(QT_PREPEND_NAMESPACE(appName));
+}
+
+const char *QX11Info::appClass() // get application class
+{
+ return QT_PREPEND_NAMESPACE(appClass);
+}
+
+bool qt_nograb() // application no-grab option
+{
+#if defined(QT_DEBUG)
+ return appNoGrab;
+#else
+ return false;
+#endif
+}
+
+
+/*****************************************************************************
+ Platform specific QApplication members
+ *****************************************************************************/
+
+#ifdef QT3_SUPPORT
+void QApplication::setMainWidget(QWidget *mainWidget)
+{
+#ifndef QT_NO_DEBUG
+ if (mainWidget && mainWidget->parentWidget() && mainWidget->isWindow())
+ qWarning("QApplication::setMainWidget: New main widget (%s/%s) "
+ "has a parent",
+ mainWidget->metaObject()->className(), mainWidget->objectName().toLocal8Bit().constData());
+#endif
+ if (mainWidget)
+ mainWidget->d_func()->createWinId();
+ QApplicationPrivate::main_widget = mainWidget;
+ if (QApplicationPrivate::main_widget) // give WM command line
+ QApplicationPrivate::applyX11SpecificCommandLineArguments(QApplicationPrivate::main_widget);
+}
+#endif
+
+void QApplicationPrivate::applyX11SpecificCommandLineArguments(QWidget *main_widget)
+{
+ static bool beenHereDoneThat = false;
+ if (beenHereDoneThat)
+ return;
+ beenHereDoneThat = true;
+ Q_ASSERT(main_widget->testAttribute(Qt::WA_WState_Created));
+ if (mwTitle) {
+ XStoreName(X11->display, main_widget->effectiveWinId(), (char*)mwTitle);
+ QByteArray net_wm_name = QString::fromLocal8Bit(mwTitle).toUtf8();
+ XChangeProperty(X11->display, main_widget->effectiveWinId(), ATOM(_NET_WM_NAME), ATOM(UTF8_STRING), 8,
+ PropModeReplace, (unsigned char *)net_wm_name.data(), net_wm_name.size());
+ }
+ if (mwGeometry) { // parse geometry
+ int x, y;
+ int w, h;
+ int m = XParseGeometry((char*)mwGeometry, &x, &y, (uint*)&w, (uint*)&h);
+ QSize minSize = main_widget->minimumSize();
+ QSize maxSize = main_widget->maximumSize();
+ if ((m & XValue) == 0)
+ x = main_widget->geometry().x();
+ if ((m & YValue) == 0)
+ y = main_widget->geometry().y();
+ if ((m & WidthValue) == 0)
+ w = main_widget->width();
+ if ((m & HeightValue) == 0)
+ h = main_widget->height();
+ w = qMin(w,maxSize.width());
+ h = qMin(h,maxSize.height());
+ w = qMax(w,minSize.width());
+ h = qMax(h,minSize.height());
+ if ((m & XNegative)) {
+ x = QApplication::desktop()->width() + x - w;
+ }
+ if ((m & YNegative)) {
+ y = QApplication::desktop()->height() + y - h;
+ }
+ main_widget->setGeometry(x, y, w, h);
+ }
+}
+
+#ifndef QT_NO_CURSOR
+
+/*****************************************************************************
+ QApplication cursor stack
+ *****************************************************************************/
+
+void QApplication::setOverrideCursor(const QCursor &cursor)
+{
+ qApp->d_func()->cursor_list.prepend(cursor);
+
+ QWidgetList all = allWidgets();
+ for (QWidgetList::ConstIterator it = all.constBegin(); it != all.constEnd(); ++it) {
+ register QWidget *w = *it;
+ if ((w->testAttribute(Qt::WA_SetCursor) || w->isWindow()) && (w->windowType() != Qt::Desktop))
+ qt_x11_enforce_cursor(w);
+ }
+ XFlush(X11->display); // make X execute it NOW
+}
+
+void QApplication::restoreOverrideCursor()
+{
+ if (qApp->d_func()->cursor_list.isEmpty())
+ return;
+ qApp->d_func()->cursor_list.removeFirst();
+
+ if (QWidgetPrivate::mapper != 0 && !closingDown()) {
+ QWidgetList all = allWidgets();
+ for (QWidgetList::ConstIterator it = all.constBegin(); it != all.constEnd(); ++it) {
+ register QWidget *w = *it;
+ if ((w->testAttribute(Qt::WA_SetCursor) || w->isWindow()) && (w->windowType() != Qt::Desktop))
+ qt_x11_enforce_cursor(w);
+ }
+ XFlush(X11->display);
+ }
+}
+
+#endif
+
+
+/*****************************************************************************
+ Routines to find a Qt widget from a screen position
+ *****************************************************************************/
+
+Window QX11Data::findClientWindow(Window win, Atom property, bool leaf)
+{
+ Atom type = XNone;
+ int format, i;
+ ulong nitems, after;
+ uchar *data = 0;
+ Window root, parent, target=0, *children=0;
+ uint nchildren;
+ if (XGetWindowProperty(X11->display, win, property, 0, 0, false, AnyPropertyType,
+ &type, &format, &nitems, &after, &data) == Success) {
+ if (data)
+ XFree((char *)data);
+ if (type)
+ return win;
+ }
+ if (!XQueryTree(X11->display,win,&root,&parent,&children,&nchildren)) {
+ if (children)
+ XFree((char *)children);
+ return 0;
+ }
+ for (i=nchildren-1; !target && i >= 0; i--)
+ target = X11->findClientWindow(children[i], property, leaf);
+ if (children)
+ XFree((char *)children);
+ return target;
+}
+
+QWidget *QApplication::topLevelAt(const QPoint &p)
+{
+#ifdef QT_NO_CURSOR
+ Q_UNUSED(p);
+ return 0;
+#else
+ int screen = QCursor::x11Screen();
+ int unused;
+
+ int x = p.x();
+ int y = p.y();
+ Window target;
+ if (!XTranslateCoordinates(X11->display,
+ QX11Info::appRootWindow(screen),
+ QX11Info::appRootWindow(screen),
+ x, y, &unused, &unused, &target)) {
+ return 0;
+ }
+ if (!target || target == QX11Info::appRootWindow(screen))
+ return 0;
+ QWidget *w;
+ w = QWidget::find((WId)target);
+
+ if (!w) {
+ X11->ignoreBadwindow();
+ target = X11->findClientWindow(target, ATOM(WM_STATE), true);
+ if (X11->badwindow())
+ return 0;
+ w = QWidget::find((WId)target);
+ if (!w) {
+ // Perhaps the widget at (x,y) is inside a foreign application?
+ // Search all toplevel widgets to see if one is within target
+ QWidgetList list = QApplication::topLevelWidgets();
+ for (int i = 0; i < list.count(); ++i) {
+ QWidget *widget = list.at(i);
+ Window ctarget = target;
+ if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) {
+ Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
+ Window wid = widget->internalWinId();
+ while (ctarget && !w) {
+ X11->ignoreBadwindow();
+ if (!XTranslateCoordinates(X11->display,
+ QX11Info::appRootWindow(screen),
+ ctarget, x, y, &unused, &unused, &ctarget)
+ || X11->badwindow())
+ break;
+ if (ctarget == wid) {
+ // Found!
+ w = widget;
+ break;
+ }
+ }
+ }
+ if (w)
+ break;
+ }
+ }
+ }
+ return w ? w->window() : 0;
+#endif
+}
+
+void QApplication::syncX()
+{
+ if (X11->display)
+ XSync(X11->display, False); // don't discard events
+}
+
+
+void QApplication::beep()
+{
+ if (X11->display)
+ XBell(X11->display, 0);
+ else
+ printf("\7");
+}
+
+void QApplication::alert(QWidget *widget, int msec)
+{
+ if (!QApplicationPrivate::checkInstance("alert"))
+ return;
+
+ QWidgetList windowsToMark;
+ if (!widget) {
+ windowsToMark += topLevelWidgets();
+ } else {
+ windowsToMark.append(widget->window());
+ }
+
+ for (int i = 0; i < windowsToMark.size(); ++i) {
+ QWidget *window = windowsToMark.at(i);
+ if (!window->isActiveWindow()) {
+ qt_change_net_wm_state(window, true, ATOM(_NET_WM_STATE_DEMANDS_ATTENTION));
+ if (msec != 0) {
+ QTimer *timer = new QTimer(qApp);
+ timer->setSingleShot(true);
+ connect(timer, SIGNAL(timeout()), qApp, SLOT(_q_alertTimeOut()));
+ if (QTimer *oldTimer = qApp->d_func()->alertTimerHash.value(window)) {
+ qApp->d_func()->alertTimerHash.remove(window);
+ delete oldTimer;
+ }
+ qApp->d_func()->alertTimerHash.insert(window, timer);
+ timer->start(msec);
+ }
+ }
+ }
+}
+
+void QApplicationPrivate::_q_alertTimeOut()
+{
+ if (QTimer *timer = qobject_cast<QTimer *>(q_func()->sender())) {
+ QHash<QWidget *, QTimer *>::iterator it = alertTimerHash.begin();
+ while (it != alertTimerHash.end()) {
+ if (it.value() == timer) {
+ QWidget *window = it.key();
+ qt_change_net_wm_state(window, false, ATOM(_NET_WM_STATE_DEMANDS_ATTENTION));
+ alertTimerHash.erase(it);
+ timer->deleteLater();
+ break;
+ }
+ ++it;
+ }
+ }
+}
+
+/*****************************************************************************
+ Special lookup functions for windows that have been reparented recently
+ *****************************************************************************/
+
+static QWidgetMapper *wPRmapper = 0; // alternative widget mapper
+
+void qPRCreate(const QWidget *widget, Window oldwin)
+{ // QWidget::reparent mechanism
+ if (!wPRmapper)
+ wPRmapper = new QWidgetMapper;
+
+ QETWidget *w = static_cast<QETWidget *>(const_cast<QWidget *>(widget));
+ wPRmapper->insert((int)oldwin, w); // add old window to mapper
+ w->setAttribute(Qt::WA_WState_Reparented); // set reparented flag
+}
+
+void qPRCleanup(QWidget *widget)
+{
+ QETWidget *etw = static_cast<QETWidget *>(const_cast<QWidget *>(widget));
+ if (!(wPRmapper && widget->testAttribute(Qt::WA_WState_Reparented)))
+ return; // not a reparented widget
+ QWidgetMapper::Iterator it = wPRmapper->begin();
+ while (it != wPRmapper->constEnd()) {
+ QWidget *w = *it;
+ if (w == etw) { // found widget
+ etw->setAttribute(Qt::WA_WState_Reparented, false); // clear flag
+ it = wPRmapper->erase(it);// old window no longer needed
+ } else {
+ ++it;
+ }
+ }
+ if (wPRmapper->size() == 0) { // became empty
+ delete wPRmapper; // then reset alt mapper
+ wPRmapper = 0;
+ }
+}
+
+static QETWidget *qPRFindWidget(Window oldwin)
+{
+ return wPRmapper ? (QETWidget*)wPRmapper->value((int)oldwin, 0) : 0;
+}
+
+int QApplication::x11ClientMessage(QWidget* w, XEvent* event, bool passive_only)
+{
+ if (w && !w->internalWinId())
+ return 0;
+ QETWidget *widget = (QETWidget*)w;
+ if (event->xclient.format == 32 && event->xclient.message_type) {
+ if (event->xclient.message_type == ATOM(WM_PROTOCOLS)) {
+ Atom a = event->xclient.data.l[0];
+ if (a == ATOM(WM_DELETE_WINDOW)) {
+ if (passive_only) return 0;
+ widget->translateCloseEvent(event);
+ }
+ else if (a == ATOM(WM_TAKE_FOCUS)) {
+ if ((ulong) event->xclient.data.l[1] > X11->time)
+ X11->time = event->xclient.data.l[1];
+ QWidget *amw = activeModalWidget();
+ if (amw && amw->testAttribute(Qt::WA_X11DoNotAcceptFocus))
+ amw = 0;
+ if (amw && !QApplicationPrivate::tryModalHelper(widget, 0)) {
+ QWidget *p = amw->parentWidget();
+ while (p && p != widget)
+ p = p->parentWidget();
+ if (!p || !X11->net_supported_list)
+ amw->raise(); // help broken window managers
+ amw->activateWindow();
+ }
+#ifndef QT_NO_WHATSTHIS
+ } else if (a == ATOM(_NET_WM_CONTEXT_HELP)) {
+ QWhatsThis::enterWhatsThisMode();
+#endif // QT_NO_WHATSTHIS
+ } else if (a == ATOM(_NET_WM_PING)) {
+ // avoid send/reply loops
+ Window root = RootWindow(X11->display, w->x11Info().screen());
+ if (event->xclient.window != root) {
+ event->xclient.window = root;
+ XSendEvent(event->xclient.display, event->xclient.window,
+ False, SubstructureNotifyMask|SubstructureRedirectMask, event);
+ }
+#ifndef QT_NO_XSYNC
+ } else if (a == ATOM(_NET_WM_SYNC_REQUEST)) {
+ const ulong timestamp = (const ulong) event->xclient.data.l[1];
+ if (timestamp > X11->time)
+ X11->time = timestamp;
+ if (QTLWExtra *tlw = w->d_func()->maybeTopData()) {
+ if (timestamp == CurrentTime || timestamp > tlw->syncRequestTimestamp) {
+ tlw->syncRequestTimestamp = timestamp;
+ tlw->newCounterValueLo = event->xclient.data.l[2];
+ tlw->newCounterValueHi = event->xclient.data.l[3];
+ }
+ }
+#endif
+ }
+ } else if (event->xclient.message_type == ATOM(_QT_SCROLL_DONE)) {
+ widget->translateScrollDoneEvent(event);
+ } else if (event->xclient.message_type == ATOM(XdndPosition)) {
+ X11->xdndHandlePosition(widget, event, passive_only);
+ } else if (event->xclient.message_type == ATOM(XdndEnter)) {
+ X11->xdndHandleEnter(widget, event, passive_only);
+ } else if (event->xclient.message_type == ATOM(XdndStatus)) {
+ X11->xdndHandleStatus(widget, event, passive_only);
+ } else if (event->xclient.message_type == ATOM(XdndLeave)) {
+ X11->xdndHandleLeave(widget, event, passive_only);
+ } else if (event->xclient.message_type == ATOM(XdndDrop)) {
+ X11->xdndHandleDrop(widget, event, passive_only);
+ } else if (event->xclient.message_type == ATOM(XdndFinished)) {
+ X11->xdndHandleFinished(widget, event, passive_only);
+ } else {
+ if (passive_only) return 0;
+ // All other are interactions
+ }
+ } else {
+ X11->motifdndHandle(widget, event, passive_only);
+ }
+
+ return 0;
+}
+
+int QApplication::x11ProcessEvent(XEvent* event)
+{
+ Q_D(QApplication);
+ QScopedLoopLevelCounter loopLevelCounter(d->threadData);
+
+#ifdef ALIEN_DEBUG
+ //qDebug() << "QApplication::x11ProcessEvent:" << event->type;
+#endif
+ switch (event->type) {
+ case ButtonPress:
+ pressed_window = event->xbutton.window;
+ X11->userTime = event->xbutton.time;
+ // fallthrough intended
+ case ButtonRelease:
+ X11->time = event->xbutton.time;
+ break;
+ case MotionNotify:
+ X11->time = event->xmotion.time;
+ break;
+ case XKeyPress:
+ X11->userTime = event->xkey.time;
+ // fallthrough intended
+ case XKeyRelease:
+ X11->time = event->xkey.time;
+ break;
+ case PropertyNotify:
+ X11->time = event->xproperty.time;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ X11->time = event->xcrossing.time;
+ break;
+ case SelectionClear:
+ X11->time = event->xselectionclear.time;
+ break;
+ default:
+ break;
+ }
+#ifndef QT_NO_XFIXES
+ if (X11->use_xfixes && event->type == (X11->xfixes_eventbase + XFixesSelectionNotify)) {
+ XFixesSelectionNotifyEvent *req =
+ reinterpret_cast<XFixesSelectionNotifyEvent *>(event);
+ X11->time = req->selection_timestamp;
+ if (req->selection == ATOM(_NET_WM_CM_S0))
+ X11->compositingManagerRunning = req->owner;
+ }
+#endif
+
+ QETWidget *widget = (QETWidget*)QWidget::find((WId)event->xany.window);
+
+ if (wPRmapper) { // just did a widget reparent?
+ if (widget == 0) { // not in std widget mapper
+ switch (event->type) { // only for mouse/key events
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ case XKeyPress:
+ case XKeyRelease:
+ widget = qPRFindWidget(event->xany.window);
+ break;
+ }
+ }
+ else if (widget->testAttribute(Qt::WA_WState_Reparented))
+ qPRCleanup(widget); // remove from alt mapper
+ }
+
+ QETWidget *keywidget=0;
+ bool grabbed=false;
+ if (event->type==XKeyPress || event->type==XKeyRelease) {
+ keywidget = (QETWidget*)QWidget::keyboardGrabber();
+ if (keywidget) {
+ grabbed = true;
+ } else if (!keywidget) {
+ if (d->inPopupMode()) // no focus widget, see if we have a popup
+ keywidget = (QETWidget*) (activePopupWidget()->focusWidget() ? activePopupWidget()->focusWidget() : activePopupWidget());
+ else if (QApplicationPrivate::focus_widget)
+ keywidget = (QETWidget*)QApplicationPrivate::focus_widget;
+ else if (widget)
+ keywidget = (QETWidget*)widget->window();
+ }
+ }
+
+#ifndef QT_NO_IM
+ // Filtering input events by the input context. It has to be taken
+ // place before any other key event consumers such as eventfilters
+ // and accelerators because some input methods require quite
+ // various key combination and sequences. It often conflicts with
+ // accelerators and so on, so we must give the input context the
+ // filtering opportunity first to ensure all input methods work
+ // properly regardless of application design.
+
+ if(keywidget && keywidget->isEnabled() && keywidget->testAttribute(Qt::WA_InputMethodEnabled)) {
+ // block user interaction during session management
+ if((event->type==XKeyPress || event->type==XKeyRelease) && qt_sm_blockUserInput)
+ return true;
+
+ // for XIM handling
+ QInputContext *qic = keywidget->inputContext();
+ if(qic && qic->x11FilterEvent(keywidget, event))
+ return true;
+
+ // filterEvent() accepts QEvent *event rather than preexpanded
+ // key event attribute values. This is intended to pass other
+ // QInputEvent in future. Other non IM-related events should
+ // not be forwarded to input contexts to prevent weird event
+ // handling.
+ if ((event->type == XKeyPress || event->type == XKeyRelease)) {
+ int code = -1;
+ int count = 0;
+ Qt::KeyboardModifiers modifiers;
+ QEvent::Type type;
+ QString text;
+ KeySym keySym;
+
+ qt_keymapper_private()->translateKeyEventInternal(keywidget, event, keySym, count,
+ text, modifiers, code, type, false);
+
+ // both key press/release is required for some complex
+ // input methods. don't eliminate anything.
+ QKeyEventEx keyevent(type, code, modifiers, text, false, qMax(qMax(count, 1), text.length()),
+ event->xkey.keycode, keySym, event->xkey.state);
+ if(qic && qic->filterEvent(&keyevent))
+ return true;
+ }
+ } else
+#endif // QT_NO_IM
+ {
+ if (XFilterEvent(event, XNone))
+ return true;
+ }
+
+ if (qt_x11EventFilter(event)) // send through app filter
+ return 1;
+
+ if (event->type == MappingNotify) {
+ // keyboard mapping changed
+ XRefreshKeyboardMapping(&event->xmapping);
+
+ QKeyMapper::changeKeyboard();
+ return 0;
+ }
+#ifndef QT_NO_XKB
+ else if (X11->use_xkb && event->type == X11->xkb_eventbase) {
+ XkbAnyEvent *xkbevent = (XkbAnyEvent *) event;
+ switch (xkbevent->xkb_type) {
+ case XkbStateNotify:
+ {
+ XkbStateNotifyEvent *xkbstateevent = (XkbStateNotifyEvent *) xkbevent;
+ if ((xkbstateevent->changed & XkbGroupStateMask) != 0) {
+ qt_keymapper_private()->xkb_currentGroup = xkbstateevent->group;
+ QKeyMapper::changeKeyboard();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+#endif
+
+ if (!widget) { // don't know this windows
+ QWidget* popup = QApplication::activePopupWidget();
+ if (popup) {
+
+ /*
+ That is more than suboptimal. The real solution should
+ do some keyevent and buttonevent translation, so that
+ the popup still continues to work as the user expects.
+ Unfortunately this translation is currently only
+ possible with a known widget. I'll change that soon
+ (Matthias).
+ */
+
+ // Danger - make sure we don't lock the server
+ switch (event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ case XKeyPress:
+ case XKeyRelease:
+ do {
+ popup->close();
+ } while ((popup = qApp->activePopupWidget()));
+ return 1;
+ }
+ }
+ return -1;
+ }
+
+ if (event->type == XKeyPress || event->type == XKeyRelease)
+ widget = keywidget; // send XKeyEvents through keywidget->x11Event()
+
+ if (app_do_modal) // modal event handling
+ if (!qt_try_modal(widget, event)) {
+ if (event->type == ClientMessage && !widget->x11Event(event))
+ x11ClientMessage(widget, event, true);
+ return 1;
+ }
+
+
+ if (widget->x11Event(event)) // send through widget filter
+ return 1;
+#if !defined (QT_NO_TABLET)
+ if (!qt_xdnd_dragging) {
+ QTabletDeviceDataList *tablets = qt_tablet_devices();
+ for (int i = 0; i < tablets->size(); ++i) {
+ QTabletDeviceData &tab = tablets->operator [](i);
+ if (event->type == tab.xinput_motion
+ || event->type == tab.xinput_button_release
+ || event->type == tab.xinput_button_press
+ || event->type == tab.xinput_proximity_in
+ || event->type == tab.xinput_proximity_out) {
+ widget->translateXinputEvent(event, &tab);
+ return 0;
+ }
+ }
+ }
+#endif
+
+#ifndef QT_NO_XRANDR
+ if (X11->use_xrandr && event->type == (X11->xrandr_eventbase + RRScreenChangeNotify)) {
+ // update Xlib internals with the latest screen configuration
+ X11->ptrXRRUpdateConfiguration(event);
+
+ // update the size for desktop widget
+ int scr = X11->ptrXRRRootToScreen(X11->display, event->xany.window);
+ QDesktopWidget *desktop = QApplication::desktop();
+ QWidget *w = desktop->screen(scr);
+ QSize oldSize(w->size());
+ w->data->crect.setWidth(DisplayWidth(X11->display, scr));
+ w->data->crect.setHeight(DisplayHeight(X11->display, scr));
+ QResizeEvent e(w->size(), oldSize);
+ QApplication::sendEvent(w, &e);
+ if (w != desktop)
+ QApplication::sendEvent(desktop, &e);
+ }
+#endif // QT_NO_XRANDR
+
+#ifndef QT_NO_XFIXES
+ if (X11->use_xfixes && event->type == (X11->xfixes_eventbase + XFixesSelectionNotify)) {
+ XFixesSelectionNotifyEvent *req = reinterpret_cast<XFixesSelectionNotifyEvent *>(event);
+
+ // compress all XFixes events related to this selection
+ // we don't want to handle old SelectionNotify events.
+ qt_xfixes_selection_event_data xfixes_event;
+ xfixes_event.selection = req->selection;
+ for (XEvent ev;;) {
+ if (!XCheckIfEvent(X11->display, &ev, &qt_xfixes_scanner, (XPointer)&xfixes_event))
+ break;
+ }
+
+ if (req->selection == ATOM(CLIPBOARD)) {
+ if (qt_xfixes_clipboard_changed(req->owner, req->selection_timestamp)) {
+ emit clipboard()->changed(QClipboard::Clipboard);
+ emit clipboard()->dataChanged();
+ }
+ } else if (req->selection == XA_PRIMARY) {
+ if (qt_xfixes_selection_changed(req->owner, req->selection_timestamp)) {
+ emit clipboard()->changed(QClipboard::Selection);
+ emit clipboard()->selectionChanged();
+ }
+ }
+ }
+#endif // QT_NO_XFIXES
+
+ switch (event->type) {
+
+ case ButtonRelease: // mouse event
+ if (!d->inPopupMode() && !QWidget::mouseGrabber() && pressed_window != widget->internalWinId()
+ && (widget = (QETWidget*) QWidget::find((WId)pressed_window)) == 0)
+ break;
+ // fall through intended
+ case ButtonPress:
+ if (event->xbutton.root != RootWindow(X11->display, widget->x11Info().screen())
+ && ! qt_xdnd_dragging) {
+ while (activePopupWidget())
+ activePopupWidget()->close();
+ return 1;
+ }
+ if (event->type == ButtonPress)
+ qt_net_update_user_time(widget->window(), X11->userTime);
+ // fall through intended
+ case MotionNotify:
+#if !defined(QT_NO_TABLET)
+ if (!qt_tabletChokeMouse) {
+#endif
+ if (widget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
+ QPoint pos(event->xbutton.x, event->xbutton.y);
+ pos = widget->d_func()->mapFromWS(pos);
+ QWidget *window = widget->window();
+ pos = widget->mapTo(window, pos);
+ if (QWidget *child = window->childAt(pos)) {
+ widget = static_cast<QETWidget *>(child);
+ pos = child->mapFrom(window, pos);
+ event->xbutton.x = pos.x();
+ event->xbutton.y = pos.y();
+ }
+ }
+ widget->translateMouseEvent(event);
+#if !defined(QT_NO_TABLET)
+ } else {
+ qt_tabletChokeMouse = false;
+ }
+#endif
+ break;
+
+ case XKeyPress: // keyboard event
+ qt_net_update_user_time(widget->window(), X11->userTime);
+ // fallthrough intended
+ case XKeyRelease:
+ {
+ if (keywidget && keywidget->isEnabled()) { // should always exist
+ // qDebug("sending key event");
+ qt_keymapper_private()->translateKeyEvent(keywidget, event, grabbed);
+ }
+ break;
+ }
+
+ case GraphicsExpose:
+ case Expose: // paint event
+ widget->translatePaintEvent(event);
+ break;
+
+ case ConfigureNotify: // window move/resize event
+ if (event->xconfigure.event == event->xconfigure.window)
+ widget->translateConfigEvent(event);
+ break;
+
+ case XFocusIn: { // got focus
+ if ((widget->windowType() == Qt::Desktop))
+ break;
+ if (d->inPopupMode()) // some delayed focus event to ignore
+ break;
+ if (!widget->isWindow())
+ break;
+ if (event->xfocus.detail != NotifyAncestor &&
+ event->xfocus.detail != NotifyInferior &&
+ event->xfocus.detail != NotifyNonlinear)
+ break;
+ setActiveWindow(widget);
+ if (X11->focus_model == QX11Data::FM_PointerRoot) {
+ // We got real input focus from somewhere, but we were in PointerRoot
+ // mode, so we don't trust this event. Check the focus model to make
+ // sure we know what focus mode we are using...
+ qt_check_focus_model();
+ }
+ }
+ break;
+
+ case XFocusOut: // lost focus
+ if ((widget->windowType() == Qt::Desktop))
+ break;
+ if (!widget->isWindow())
+ break;
+ if (event->xfocus.mode == NotifyGrab) {
+ qt_xfocusout_grab_counter++;
+ break;
+ }
+ if (event->xfocus.detail != NotifyAncestor &&
+ event->xfocus.detail != NotifyNonlinearVirtual &&
+ event->xfocus.detail != NotifyNonlinear)
+ break;
+ if (!d->inPopupMode() && widget == QApplicationPrivate::active_window) {
+ XEvent ev;
+ bool focus_will_change = false;
+ if (XCheckTypedEvent(X11->display, XFocusIn, &ev)) {
+ // we're about to get an XFocusIn, if we know we will
+ // get a new active window, we don't want to set the
+ // active window to 0 now
+ QWidget *w2 = QWidget::find(ev.xany.window);
+ if (w2
+ && w2->windowType() != Qt::Desktop
+ && !d->inPopupMode() // some delayed focus event to ignore
+ && w2->isWindow()
+ && (ev.xfocus.detail == NotifyAncestor
+ || ev.xfocus.detail == NotifyInferior
+ || ev.xfocus.detail == NotifyNonlinear))
+ focus_will_change = true;
+
+ XPutBackEvent(X11->display, &ev);
+ }
+ if (!focus_will_change)
+ setActiveWindow(0);
+ }
+ break;
+
+ case EnterNotify: { // enter window
+ if (QWidget::mouseGrabber() && (!d->inPopupMode() || widget->window() != activePopupWidget()))
+ break;
+ if ((event->xcrossing.mode != NotifyNormal
+ && event->xcrossing.mode != NotifyUngrab)
+ || event->xcrossing.detail == NotifyVirtual
+ || event->xcrossing.detail == NotifyNonlinearVirtual)
+ break;
+ if (event->xcrossing.focus &&
+ !(widget->windowType() == Qt::Desktop) && !widget->isActiveWindow()) {
+ if (X11->focus_model == QX11Data::FM_Unknown) // check focus model
+ qt_check_focus_model();
+ if (X11->focus_model == QX11Data::FM_PointerRoot) // PointerRoot mode
+ setActiveWindow(widget);
+ }
+
+ if (qt_button_down && !d->inPopupMode())
+ break;
+
+ QWidget *alien = widget->childAt(widget->d_func()->mapFromWS(QPoint(event->xcrossing.x,
+ event->xcrossing.y)));
+ QWidget *enter = alien ? alien : widget;
+ QWidget *leave = 0;
+ if (qt_last_mouse_receiver && !qt_last_mouse_receiver->internalWinId())
+ leave = qt_last_mouse_receiver;
+ else
+ leave = QWidget::find(curWin);
+
+ // ### Alien: enter/leave might be wrong here with overlapping siblings
+ // if the enter widget is native and stacked under a non-native widget.
+ QApplicationPrivate::dispatchEnterLeave(enter, leave);
+ curWin = widget->internalWinId();
+ qt_last_mouse_receiver = enter;
+ if (!d->inPopupMode() || widget->window() == activePopupWidget())
+ widget->translateMouseEvent(event); //we don't get MotionNotify, emulate it
+ }
+ break;
+ case LeaveNotify: { // leave window
+ QWidget *mouseGrabber = QWidget::mouseGrabber();
+ if (mouseGrabber && !d->inPopupMode())
+ break;
+ if (curWin && widget->internalWinId() != curWin)
+ break;
+ if ((event->xcrossing.mode != NotifyNormal
+ && event->xcrossing.mode != NotifyUngrab)
+ || event->xcrossing.detail == NotifyInferior)
+ break;
+ if (!(widget->windowType() == Qt::Desktop))
+ widget->translateMouseEvent(event); //we don't get MotionNotify, emulate it
+
+ QWidget* enter = 0;
+ QPoint enterPoint;
+ XEvent ev;
+ while (XCheckMaskEvent(X11->display, EnterWindowMask | LeaveWindowMask , &ev)
+ && !qt_x11EventFilter(&ev)) {
+ QWidget* event_widget = QWidget::find(ev.xcrossing.window);
+ if(event_widget && event_widget->x11Event(&ev))
+ break;
+ if (ev.type == LeaveNotify
+ || (ev.xcrossing.mode != NotifyNormal
+ && ev.xcrossing.mode != NotifyUngrab)
+ || ev.xcrossing.detail == NotifyVirtual
+ || ev.xcrossing.detail == NotifyNonlinearVirtual)
+ continue;
+ enter = event_widget;
+ if (enter)
+ enterPoint = enter->d_func()->mapFromWS(QPoint(ev.xcrossing.x, ev.xcrossing.y));
+ if (ev.xcrossing.focus &&
+ enter && !(enter->windowType() == Qt::Desktop) && !enter->isActiveWindow()) {
+ if (X11->focus_model == QX11Data::FM_Unknown) // check focus model
+ qt_check_focus_model();
+ if (X11->focus_model == QX11Data::FM_PointerRoot) // PointerRoot mode
+ setActiveWindow(enter);
+ }
+ break;
+ }
+
+ if ((! enter || (enter->windowType() == Qt::Desktop)) &&
+ event->xcrossing.focus && widget == QApplicationPrivate::active_window &&
+ X11->focus_model == QX11Data::FM_PointerRoot // PointerRoot mode
+ ) {
+ setActiveWindow(0);
+ }
+
+ if (qt_button_down && !d->inPopupMode())
+ break;
+
+ if (!curWin)
+ QApplicationPrivate::dispatchEnterLeave(widget, 0);
+
+ if (enter) {
+ QWidget *alienEnter = enter->childAt(enterPoint);
+ if (alienEnter)
+ enter = alienEnter;
+ }
+
+ QWidget *leave = qt_last_mouse_receiver ? qt_last_mouse_receiver : widget;
+ QWidget *activePopupWidget = qApp->activePopupWidget();
+
+ if (mouseGrabber && activePopupWidget && leave == activePopupWidget)
+ enter = mouseGrabber;
+ else if (enter != widget && mouseGrabber) {
+ if (!widget->rect().contains(widget->d_func()->mapFromWS(QPoint(event->xcrossing.x,
+ event->xcrossing.y))))
+ break;
+ }
+
+ QApplicationPrivate::dispatchEnterLeave(enter, leave);
+ qt_last_mouse_receiver = enter;
+
+ if (enter && QApplicationPrivate::tryModalHelper(enter, 0)) {
+ QWidget *nativeEnter = enter->internalWinId() ? enter : enter->nativeParentWidget();
+ curWin = nativeEnter->internalWinId();
+ static_cast<QETWidget *>(nativeEnter)->translateMouseEvent(&ev); //we don't get MotionNotify, emulate it
+ } else {
+ curWin = 0;
+ qt_last_mouse_receiver = 0;
+ }
+ }
+ break;
+
+ case UnmapNotify: // window hidden
+ if (widget->isWindow()) {
+ Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
+ widget->d_func()->topData()->waitingForMapNotify = 0;
+
+ if (widget->windowType() != Qt::Popup && !widget->testAttribute(Qt::WA_DontShowOnScreen)) {
+ widget->setAttribute(Qt::WA_Mapped, false);
+ if (widget->isVisible()) {
+ widget->d_func()->topData()->spont_unmapped = 1;
+ QHideEvent e;
+ QApplication::sendSpontaneousEvent(widget, &e);
+ widget->d_func()->hideChildren(true);
+ }
+ }
+
+ if (!widget->d_func()->topData()->validWMState && X11->deferred_map.removeAll(widget))
+ widget->doDeferredMap();
+ }
+ break;
+
+ case MapNotify: // window shown
+ if (widget->isWindow()) {
+ // if we got a MapNotify when we were not waiting for it, it most
+ // likely means the user has already asked to hide the window before
+ // it ever being shown, so we try to withdraw a window after sending
+ // the QShowEvent.
+ bool pendingHide = widget->testAttribute(Qt::WA_WState_ExplicitShowHide) && widget->testAttribute(Qt::WA_WState_Hidden);
+ widget->d_func()->topData()->waitingForMapNotify = 0;
+
+ if (widget->windowType() != Qt::Popup) {
+ widget->setAttribute(Qt::WA_Mapped);
+ if (widget->d_func()->topData()->spont_unmapped) {
+ widget->d_func()->topData()->spont_unmapped = 0;
+ widget->d_func()->showChildren(true);
+ QShowEvent e;
+ QApplication::sendSpontaneousEvent(widget, &e);
+
+ // show() must have been called on this widget in
+ // order to reach this point, but we could have
+ // cleared these 2 attributes in case something
+ // previously forced us into WithdrawnState
+ // (e.g. kdocker)
+ widget->setAttribute(Qt::WA_WState_ExplicitShowHide, true);
+ widget->setAttribute(Qt::WA_WState_Visible, true);
+ }
+ }
+ if (pendingHide) // hide the window
+ XWithdrawWindow(X11->display, widget->internalWinId(), widget->x11Info().screen());
+ }
+ break;
+
+ case ClientMessage: // client message
+ return x11ClientMessage(widget,event,False);
+
+ case ReparentNotify: { // window manager reparents
+ // compress old reparent events to self
+ XEvent ev;
+ while (XCheckTypedWindowEvent(X11->display,
+ widget->effectiveWinId(),
+ ReparentNotify,
+ &ev)) {
+ if (ev.xreparent.window != ev.xreparent.event) {
+ XPutBackEvent(X11->display, &ev);
+ break;
+ }
+ }
+ if (widget->isWindow()) {
+ QTLWExtra *topData = widget->d_func()->topData();
+
+ // store the parent. Useful for many things, embedding for instance.
+ topData->parentWinId = event->xreparent.parent;
+
+ // the widget frame strut should also be invalidated
+ widget->data->fstrut_dirty = 1;
+
+ // work around broken window managers... if we get a
+ // ReparentNotify before the MapNotify, we assume that
+ // we're being managed by a reparenting window
+ // manager.
+ //
+ // however, the WM_STATE property may not have been set
+ // yet, but we are going to assume that it will
+ // be... otherwise we could try to map again after getting
+ // an UnmapNotify... which could then, in turn, trigger a
+ // race in the window manager which causes the window to
+ // disappear when it really should be hidden.
+ if (topData->waitingForMapNotify && !topData->validWMState) {
+ topData->waitingForMapNotify = 0;
+ topData->validWMState = 1;
+ }
+
+ if (X11->focus_model != QX11Data::FM_Unknown) {
+ // toplevel reparented...
+ QWidget *newparent = QWidget::find(event->xreparent.parent);
+ if (! newparent || (newparent->windowType() == Qt::Desktop)) {
+ // we don't know about the new parent (or we've been
+ // reparented to root), perhaps a window manager
+ // has been (re)started? reset the focus model to unknown
+ X11->focus_model = QX11Data::FM_Unknown;
+ }
+ }
+ }
+ break;
+ }
+ case SelectionRequest: {
+ XSelectionRequestEvent *req = &event->xselectionrequest;
+ if (! req)
+ break;
+
+ if (ATOM(XdndSelection) && req->selection == ATOM(XdndSelection)) {
+ X11->xdndHandleSelectionRequest(req);
+
+ } else if (qt_clipboard) {
+ QClipboardEvent e(reinterpret_cast<QEventPrivate*>(event));
+ QApplication::sendSpontaneousEvent(qt_clipboard, &e);
+ }
+ break;
+ }
+ case SelectionClear: {
+ XSelectionClearEvent *req = &event->xselectionclear;
+ // don't deliver dnd events to the clipboard, it gets confused
+ if (! req || (ATOM(XdndSelection) && req->selection == ATOM(XdndSelection)))
+ break;
+
+ if (qt_clipboard && !X11->use_xfixes) {
+ QClipboardEvent e(reinterpret_cast<QEventPrivate*>(event));
+ QApplication::sendSpontaneousEvent(qt_clipboard, &e);
+ }
+ break;
+ }
+
+ case SelectionNotify: {
+ XSelectionEvent *req = &event->xselection;
+ // don't deliver dnd events to the clipboard, it gets confused
+ if (! req || (ATOM(XdndSelection) && req->selection == ATOM(XdndSelection)))
+ break;
+
+ if (qt_clipboard) {
+ QClipboardEvent e(reinterpret_cast<QEventPrivate*>(event));
+ QApplication::sendSpontaneousEvent(qt_clipboard, &e);
+ }
+ break;
+ }
+ case PropertyNotify:
+ // some properties changed
+ if (event->xproperty.window == QX11Info::appRootWindow(0)) {
+ // root properties for the first screen
+ if (!X11->use_xfixes && event->xproperty.atom == ATOM(_QT_CLIPBOARD_SENTINEL)) {
+ if (qt_check_clipboard_sentinel()) {
+ emit clipboard()->changed(QClipboard::Clipboard);
+ emit clipboard()->dataChanged();
+ }
+ } else if (!X11->use_xfixes && event->xproperty.atom == ATOM(_QT_SELECTION_SENTINEL)) {
+ if (qt_check_selection_sentinel()) {
+ emit clipboard()->changed(QClipboard::Selection);
+ emit clipboard()->selectionChanged();
+ }
+ } else if (QApplicationPrivate::obey_desktop_settings) {
+ if (event->xproperty.atom == ATOM(RESOURCE_MANAGER))
+ qt_set_x11_resources();
+ else if (event->xproperty.atom == ATOM(_QT_SETTINGS_TIMESTAMP))
+ qt_set_x11_resources();
+ }
+ }
+ if (event->xproperty.window == QX11Info::appRootWindow()) {
+ // root properties for the default screen
+ if (event->xproperty.atom == ATOM(_QT_INPUT_ENCODING)) {
+ qt_set_input_encoding();
+ } else if (event->xproperty.atom == ATOM(_NET_SUPPORTED)) {
+ qt_get_net_supported();
+ } else if (event->xproperty.atom == ATOM(_NET_VIRTUAL_ROOTS)) {
+ qt_get_net_virtual_roots();
+ } else if (event->xproperty.atom == ATOM(_NET_WORKAREA)) {
+ qt_desktopwidget_update_workarea();
+
+ // emit the workAreaResized() signal
+ QDesktopWidget *desktop = QApplication::desktop();
+ int numScreens = desktop->numScreens();
+ for (int i = 0; i < numScreens; ++i)
+ emit desktop->workAreaResized(i);
+ }
+ } else if (widget) {
+ widget->translatePropertyEvent(event);
+ } else {
+ return -1; // don't know this window
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+bool QApplication::x11EventFilter(XEvent *)
+{
+ return false;
+}
+
+
+
+/*****************************************************************************
+ Modal widgets; Since Xlib has little support for this we roll our own
+ modal widget mechanism.
+ A modal widget without a parent becomes application-modal.
+ A modal widget with a parent becomes modal to its parent and grandparents..
+
+ QApplicationPrivate::enterModal()
+ Enters modal state
+ Arguments:
+ QWidget *widget A modal widget
+
+ QApplicationPrivate::leaveModal()
+ Leaves modal state for a widget
+ Arguments:
+ QWidget *widget A modal widget
+ *****************************************************************************/
+
+bool QApplicationPrivate::modalState()
+{
+ return app_do_modal;
+}
+
+void QApplicationPrivate::enterModal_sys(QWidget *widget)
+{
+ if (!qt_modal_stack)
+ qt_modal_stack = new QWidgetList;
+
+ QWidget *leave = qt_last_mouse_receiver;
+ if (!leave)
+ leave = QWidget::find((WId)curWin);
+ QApplicationPrivate::dispatchEnterLeave(0, leave);
+ qt_modal_stack->insert(0, widget);
+ app_do_modal = true;
+ curWin = 0;
+ qt_last_mouse_receiver = 0;
+}
+
+void QApplicationPrivate::leaveModal_sys(QWidget *widget)
+{
+ if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
+ if (qt_modal_stack->isEmpty()) {
+ delete qt_modal_stack;
+ qt_modal_stack = 0;
+ QPoint p(QCursor::pos());
+ QWidget* w = QApplication::widgetAt(p.x(), p.y());
+ QWidget *leave = qt_last_mouse_receiver;
+ if (!leave)
+ leave = QWidget::find((WId)curWin);
+ if (QWidget *grabber = QWidget::mouseGrabber()) {
+ w = grabber;
+ if (leave == w)
+ leave = 0;
+ }
+ QApplicationPrivate::dispatchEnterLeave(w, leave); // send synthetic enter event
+ curWin = w ? w->effectiveWinId() : 0;
+ qt_last_mouse_receiver = w;
+ }
+ }
+ app_do_modal = qt_modal_stack != 0;
+}
+
+bool qt_try_modal(QWidget *widget, XEvent *event)
+{
+ if (qt_xdnd_dragging) {
+ // allow mouse events while DnD is active
+ switch (event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ return true;
+ default:
+ break;
+ }
+ }
+
+ // allow mouse release events to be sent to widgets that have been pressed
+ if (event->type == ButtonRelease) {
+ QWidget *alienWidget = widget->childAt(widget->mapFromGlobal(QPoint(event->xbutton.x_root,
+ event->xbutton.y_root)));
+ if (widget == qt_button_down || (alienWidget && alienWidget == qt_button_down))
+ return true;
+ }
+
+ if (QApplicationPrivate::tryModalHelper(widget))
+ return true;
+
+ // disallow mouse/key events
+ switch (event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ case XKeyPress:
+ case XKeyRelease:
+ case EnterNotify:
+ case LeaveNotify:
+ case ClientMessage:
+ return false;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+
+/*****************************************************************************
+ Popup widget mechanism
+
+ openPopup()
+ Adds a widget to the list of popup widgets
+ Arguments:
+ QWidget *widget The popup widget to be added
+
+ closePopup()
+ Removes a widget from the list of popup widgets
+ Arguments:
+ QWidget *widget The popup widget to be removed
+ *****************************************************************************/
+
+
+static int openPopupCount = 0;
+void QApplicationPrivate::openPopup(QWidget *popup)
+{
+ Q_Q(QApplication);
+ openPopupCount++;
+ if (!QApplicationPrivate::popupWidgets) { // create list
+ QApplicationPrivate::popupWidgets = new QWidgetList;
+ }
+ QApplicationPrivate::popupWidgets->append(popup); // add to end of list
+ Display *dpy = X11->display;
+ if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()){ // grab mouse/keyboard
+ Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
+ int r = XGrabKeyboard(dpy, popup->effectiveWinId(), false,
+ GrabModeAsync, GrabModeAsync, X11->time);
+ if ((popupGrabOk = (r == GrabSuccess))) {
+ r = XGrabPointer(dpy, popup->effectiveWinId(), true,
+ (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
+ | EnterWindowMask | LeaveWindowMask | PointerMotionMask),
+ GrabModeAsync, GrabModeAsync, XNone, XNone, X11->time);
+ if (!(popupGrabOk = (r == GrabSuccess))) {
+ // transfer grab back to the keyboard grabber if any
+ if (QWidgetPrivate::keyboardGrabber != 0)
+ QWidgetPrivate::keyboardGrabber->grabKeyboard();
+ else
+ XUngrabKeyboard(dpy, X11->time);
+ }
+ }
+ }
+
+ // popups are not focus-handled by the window system (the first
+ // popup grabbed the keyboard), so we have to do that manually: A
+ // new popup gets the focus
+ if (popup->focusWidget()) {
+ popup->focusWidget()->setFocus(Qt::PopupFocusReason);
+ } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
+ if (QWidget *fw = QApplication::focusWidget()) {
+ QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
+ q->sendEvent(fw, &e);
+ }
+ }
+}
+
+void QApplicationPrivate::closePopup(QWidget *popup)
+{
+ Q_Q(QApplication);
+ if (!QApplicationPrivate::popupWidgets)
+ return;
+ QApplicationPrivate::popupWidgets->removeAll(popup);
+ if (popup == qt_popup_down) {
+ qt_button_down = 0;
+ qt_popup_down = 0;
+ }
+ if (QApplicationPrivate::popupWidgets->count() == 0) { // this was the last popup
+ delete QApplicationPrivate::popupWidgets;
+ QApplicationPrivate::popupWidgets = 0;
+ if (!qt_nograb() && popupGrabOk) { // grabbing not disabled
+ Display *dpy = X11->display;
+ if (popup->geometry().contains(QPoint(mouseGlobalXPos, mouseGlobalYPos))
+ || popup->testAttribute(Qt::WA_NoMouseReplay)) {
+ // mouse release event or inside
+ replayPopupMouseEvent = false;
+ } else { // mouse press event
+ mouseButtonPressTime -= 10000; // avoid double click
+ replayPopupMouseEvent = true;
+ }
+ // transfer grab back to mouse grabber if any, otherwise release the grab
+ if (QWidgetPrivate::mouseGrabber != 0)
+ QWidgetPrivate::mouseGrabber->grabMouse();
+ else
+ XUngrabPointer(dpy, X11->time);
+
+ // transfer grab back to keyboard grabber if any, otherwise release the grab
+ if (QWidgetPrivate::keyboardGrabber != 0)
+ QWidgetPrivate::keyboardGrabber->grabKeyboard();
+ else
+ XUngrabKeyboard(dpy, X11->time);
+
+ XFlush(dpy);
+ }
+ if (QApplicationPrivate::active_window) {
+ if (QWidget *fw = QApplicationPrivate::active_window->focusWidget()) {
+ if (fw != QApplication::focusWidget()) {
+ fw->setFocus(Qt::PopupFocusReason);
+ } else {
+ QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
+ q->sendEvent(fw, &e);
+ }
+ }
+ }
+ } else {
+ // popups are not focus-handled by the window system (the
+ // first popup grabbed the keyboard), so we have to do that
+ // manually: A popup was closed, so the previous popup gets
+ // the focus.
+ QWidget* aw = QApplicationPrivate::popupWidgets->last();
+ if (QWidget *fw = aw->focusWidget())
+ fw->setFocus(Qt::PopupFocusReason);
+
+ // regrab the keyboard and mouse in case 'popup' lost the grab
+ if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()){ // grab mouse/keyboard
+ Display *dpy = X11->display;
+ Q_ASSERT(aw->testAttribute(Qt::WA_WState_Created));
+ int r = XGrabKeyboard(dpy, aw->effectiveWinId(), false,
+ GrabModeAsync, GrabModeAsync, X11->time);
+ if ((popupGrabOk = (r == GrabSuccess))) {
+ r = XGrabPointer(dpy, aw->effectiveWinId(), true,
+ (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
+ | EnterWindowMask | LeaveWindowMask | PointerMotionMask),
+ GrabModeAsync, GrabModeAsync, XNone, XNone, X11->time);
+ if (!(popupGrabOk = (r == GrabSuccess))) {
+ // transfer grab back to keyboard grabber
+ if (QWidgetPrivate::keyboardGrabber != 0)
+ QWidgetPrivate::keyboardGrabber->grabKeyboard();
+ else
+ XUngrabKeyboard(dpy, X11->time);
+ }
+ }
+ }
+ }
+}
+
+/*****************************************************************************
+ Event translation; translates X11 events to Qt events
+ *****************************************************************************/
+
+//
+// Mouse event translation
+//
+// Xlib doesn't give mouse double click events, so we generate them by
+// comparing window, time and position between two mouse press events.
+//
+
+static Qt::MouseButtons translateMouseButtons(int s)
+{
+ Qt::MouseButtons ret = 0;
+ if (s & Button1Mask)
+ ret |= Qt::LeftButton;
+ if (s & Button2Mask)
+ ret |= Qt::MidButton;
+ if (s & Button3Mask)
+ ret |= Qt::RightButton;
+ return ret;
+}
+
+Qt::KeyboardModifiers QX11Data::translateModifiers(int s)
+{
+ Qt::KeyboardModifiers ret = 0;
+ if (s & ShiftMask)
+ ret |= Qt::ShiftModifier;
+ if (s & ControlMask)
+ ret |= Qt::ControlModifier;
+ if (s & qt_alt_mask)
+ ret |= Qt::AltModifier;
+ if (s & qt_meta_mask)
+ ret |= Qt::MetaModifier;
+ if (s & qt_mode_switch_mask)
+ ret |= Qt::GroupSwitchModifier;
+ return ret;
+}
+
+bool QETWidget::translateMouseEvent(const XEvent *event)
+{
+ if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
+ Q_ASSERT(internalWinId());
+
+ Q_D(QWidget);
+ QEvent::Type type; // event parameters
+ QPoint pos;
+ QPoint globalPos;
+ Qt::MouseButton button = Qt::NoButton;
+ Qt::MouseButtons buttons;
+ Qt::KeyboardModifiers modifiers;
+ XEvent nextEvent;
+
+ if (qt_sm_blockUserInput) // block user interaction during session management
+ return true;
+
+ if (event->type == MotionNotify) { // mouse move
+ if (event->xmotion.root != RootWindow(X11->display, x11Info().screen()) &&
+ ! qt_xdnd_dragging)
+ return false;
+
+ XMotionEvent lastMotion = event->xmotion;
+ while(XPending(X11->display)) { // compress mouse moves
+ XNextEvent(X11->display, &nextEvent);
+ if (nextEvent.type == ConfigureNotify
+ || nextEvent.type == PropertyNotify
+ || nextEvent.type == Expose
+ || nextEvent.type == GraphicsExpose
+ || nextEvent.type == NoExpose
+ || nextEvent.type == KeymapNotify
+ || ((nextEvent.type == EnterNotify || nextEvent.type == LeaveNotify)
+ && qt_button_down == this)
+ || (nextEvent.type == ClientMessage
+ && (nextEvent.xclient.message_type == ATOM(_QT_SCROLL_DONE) ||
+ (nextEvent.xclient.message_type == ATOM(WM_PROTOCOLS) &&
+ (Atom)nextEvent.xclient.data.l[0] == ATOM(_NET_WM_SYNC_REQUEST))))) {
+ qApp->x11ProcessEvent(&nextEvent);
+ continue;
+ } else if (nextEvent.type != MotionNotify ||
+ nextEvent.xmotion.window != event->xmotion.window ||
+ nextEvent.xmotion.state != event->xmotion.state) {
+ XPutBackEvent(X11->display, &nextEvent);
+ break;
+ }
+ if (!qt_x11EventFilter(&nextEvent)
+ && !x11Event(&nextEvent)) // send event through filter
+ lastMotion = nextEvent.xmotion;
+ else
+ break;
+ }
+ type = QEvent::MouseMove;
+ pos.rx() = lastMotion.x;
+ pos.ry() = lastMotion.y;
+ pos = d->mapFromWS(pos);
+ globalPos.rx() = lastMotion.x_root;
+ globalPos.ry() = lastMotion.y_root;
+ buttons = translateMouseButtons(lastMotion.state);
+ modifiers = X11->translateModifiers(lastMotion.state);
+ if (qt_button_down && !buttons)
+ qt_button_down = 0;
+ } else if (event->type == EnterNotify || event->type == LeaveNotify) {
+ XEvent *xevent = (XEvent *)event;
+ //unsigned int xstate = event->xcrossing.state;
+ type = QEvent::MouseMove;
+ pos.rx() = xevent->xcrossing.x;
+ pos.ry() = xevent->xcrossing.y;
+ pos = d->mapFromWS(pos);
+ globalPos.rx() = xevent->xcrossing.x_root;
+ globalPos.ry() = xevent->xcrossing.y_root;
+ buttons = translateMouseButtons(xevent->xcrossing.state);
+ modifiers = X11->translateModifiers(xevent->xcrossing.state);
+ if (qt_button_down && !buttons)
+ qt_button_down = 0;
+ if (qt_button_down)
+ return true;
+ } else { // button press or release
+ pos.rx() = event->xbutton.x;
+ pos.ry() = event->xbutton.y;
+ pos = d->mapFromWS(pos);
+ globalPos.rx() = event->xbutton.x_root;
+ globalPos.ry() = event->xbutton.y_root;
+ buttons = translateMouseButtons(event->xbutton.state);
+ modifiers = X11->translateModifiers(event->xbutton.state);
+ switch (event->xbutton.button) {
+ case Button1: button = Qt::LeftButton; break;
+ case Button2: button = Qt::MidButton; break;
+ case Button3: button = Qt::RightButton; break;
+ case Button4:
+ case Button5:
+ case 6:
+ case 7:
+ // the fancy mouse wheel.
+
+ // We are only interested in ButtonPress.
+ if (event->type == ButtonPress){
+ // compress wheel events (the X Server will simply
+ // send a button press for each single notch,
+ // regardless whether the application can catch up
+ // or not)
+ int delta = 1;
+ XEvent xevent;
+ while (XCheckTypedWindowEvent(X11->display, effectiveWinId(), ButtonPress, &xevent)){
+ if (xevent.xbutton.button != event->xbutton.button){
+ XPutBackEvent(X11->display, &xevent);
+ break;
+ }
+ delta++;
+ }
+
+ // the delta is defined as multiples of
+ // WHEEL_DELTA, which is set to 120. Future wheels
+ // may offer a finer-resolution. A positive delta
+ // indicates forward rotation, a negative one
+ // backward rotation respectively.
+ int btn = event->xbutton.button;
+ delta *= 120 * ((btn == Button4 || btn == 6) ? 1 : -1);
+ bool hor = (((btn == Button4 || btn == Button5) && (modifiers & Qt::AltModifier)) ||
+ (btn == 6 || btn == 7));
+ translateWheelEvent(globalPos.x(), globalPos.y(), delta, buttons,
+ modifiers, (hor) ? Qt::Horizontal: Qt::Vertical);
+ }
+ return true;
+ case 8: button = Qt::XButton1; break;
+ case 9: button = Qt::XButton2; break;
+ }
+ if (event->type == ButtonPress) { // mouse button pressed
+ buttons |= button;
+#if defined(Q_OS_IRIX) && !defined(QT_NO_TABLET)
+ QTabletDeviceDataList *tablets = qt_tablet_devices();
+ for (int i = 0; i < tablets->size(); ++i) {
+ QTabletDeviceData &tab = tablets->operator[](i);
+ XEvent myEv;
+ if (XCheckTypedEvent(X11->display, tab.xinput_button_press, &myEv)) {
+ if (translateXinputEvent(&myEv, &tab)) {
+ //Spontaneous event sent. Check if we need to continue.
+ if (qt_tabletChokeMouse) {
+ qt_tabletChokeMouse = false;
+ return false;
+ }
+ }
+ }
+ }
+#endif
+ if (!qt_button_down) {
+ qt_button_down = childAt(pos); //magic for masked widgets
+ if (!qt_button_down)
+ qt_button_down = this;
+ }
+ if (mouseActWindow == event->xbutton.window &&
+ mouseButtonPressed == button &&
+ (long)event->xbutton.time -(long)mouseButtonPressTime
+ < QApplication::doubleClickInterval() &&
+ qAbs(event->xbutton.x - mouseXPos) < QT_GUI_DOUBLE_CLICK_RADIUS &&
+ qAbs(event->xbutton.y - mouseYPos) < QT_GUI_DOUBLE_CLICK_RADIUS) {
+ type = QEvent::MouseButtonDblClick;
+ mouseButtonPressTime -= 2000; // no double-click next time
+ } else {
+ type = QEvent::MouseButtonPress;
+ mouseButtonPressTime = event->xbutton.time;
+ }
+ mouseButtonPressed = button; // save event params for
+ mouseXPos = event->xbutton.x; // future double click tests
+ mouseYPos = event->xbutton.y;
+ mouseGlobalXPos = globalPos.x();
+ mouseGlobalYPos = globalPos.y();
+ } else { // mouse button released
+ buttons &= ~button;
+#if defined(Q_OS_IRIX) && !defined(QT_NO_TABLET)
+ QTabletDeviceDataList *tablets = qt_tablet_devices();
+ for (int i = 0; i < tablets->size(); ++i) {
+ QTabletDeviceData &tab = tablets->operator[](i);
+ XEvent myEv;
+ if (XCheckTypedEvent(X11->display, tab.xinput_button_press, &myEv)) {
+ if (translateXinputEvent(&myEv, &tab)) {
+ //Spontaneous event sent. Check if we need to continue.
+ if (qt_tabletChokeMouse) {
+ qt_tabletChokeMouse = false;
+ return false;
+ }
+ }
+ }
+ }
+#endif
+ type = QEvent::MouseButtonRelease;
+ }
+ }
+ mouseActWindow = effectiveWinId(); // save some event params
+ mouseButtonState = buttons;
+ if (type == 0) // don't send event
+ return false;
+
+ if (qApp->d_func()->inPopupMode()) { // in popup mode
+ QWidget *activePopupWidget = qApp->activePopupWidget();
+ QWidget *popup = qApp->activePopupWidget();
+ if (popup != this) {
+ if (event->type == LeaveNotify)
+ return false;
+ if ((windowType() == Qt::Popup) && rect().contains(pos) && 0)
+ popup = this;
+ else // send to last popup
+ pos = popup->mapFromGlobal(globalPos);
+ }
+ bool releaseAfter = false;
+ QWidget *popupChild = popup->childAt(pos);
+
+ if (popup != qt_popup_down){
+ qt_button_down = 0;
+ qt_popup_down = 0;
+ }
+
+ switch (type) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ qt_button_down = popupChild;
+ qt_popup_down = popup;
+ break;
+ case QEvent::MouseButtonRelease:
+ releaseAfter = true;
+ break;
+ default:
+ break; // nothing for mouse move
+ }
+
+ int oldOpenPopupCount = openPopupCount;
+
+ if (popup->isEnabled()) {
+ // deliver event
+ replayPopupMouseEvent = false;
+ QWidget *receiver = popup;
+ QPoint widgetPos = pos;
+ if (qt_button_down)
+ receiver = qt_button_down;
+ else if (popupChild)
+ receiver = popupChild;
+ if (receiver != popup)
+ widgetPos = receiver->mapFromGlobal(globalPos);
+ QWidget *alien = childAt(mapFromGlobal(globalPos));
+ QMouseEvent e(type, widgetPos, globalPos, button, buttons, modifiers);
+ QApplicationPrivate::sendMouseEvent(receiver, &e, alien, this, &qt_button_down, qt_last_mouse_receiver);
+ } else {
+ // close disabled popups when a mouse button is pressed or released
+ switch (type) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseButtonRelease:
+ popup->close();
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (qApp->activePopupWidget() != activePopupWidget
+ && replayPopupMouseEvent) {
+ // the active popup was closed, replay the mouse event
+ if (!(windowType() == Qt::Popup)) {
+#if 1
+ qt_button_down = 0;
+#else
+ if (buttons == button)
+ qt_button_down = this;
+ QMouseEvent e(type, mapFromGlobal(globalPos), globalPos, button,
+ buttons, modifiers);
+ QApplication::sendSpontaneousEvent(this, &e);
+
+ if (type == QEvent::MouseButtonPress
+ && button == Qt::RightButton
+ && (openPopupCount == oldOpenPopupCount)) {
+ QContextMenuEvent e(QContextMenuEvent::Mouse, mapFromGlobal(globalPos),
+ globalPos, modifiers);
+ QApplication::sendSpontaneousEvent(this, &e);
+ }
+#endif
+ }
+ replayPopupMouseEvent = false;
+ } else if (type == QEvent::MouseButtonPress
+ && button == Qt::RightButton
+ && (openPopupCount == oldOpenPopupCount)) {
+ QWidget *popupEvent = popup;
+ if (qt_button_down)
+ popupEvent = qt_button_down;
+ else if(popupChild)
+ popupEvent = popupChild;
+ QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos, modifiers);
+ QApplication::sendSpontaneousEvent(popupEvent, &e);
+ }
+
+ if (releaseAfter) {
+ qt_button_down = 0;
+ qt_popup_down = 0;
+ }
+ } else {
+ QWidget *alienWidget = childAt(pos);
+ QWidget *widget = QApplicationPrivate::pickMouseReceiver(this, globalPos, pos, type, buttons,
+ qt_button_down, alienWidget);
+ if (!widget) {
+ if (type == QEvent::MouseButtonRelease)
+ QApplicationPrivate::mouse_buttons &= ~button;
+ return false; // don't send event
+ }
+
+ int oldOpenPopupCount = openPopupCount;
+ QMouseEvent e(type, pos, globalPos, button, buttons, modifiers);
+ QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down,
+ qt_last_mouse_receiver);
+ if (type == QEvent::MouseButtonPress
+ && button == Qt::RightButton
+ && (openPopupCount == oldOpenPopupCount)) {
+ QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos, modifiers);
+ QApplication::sendSpontaneousEvent(widget, &e);
+ }
+ }
+ return true;
+}
+
+
+//
+// Wheel event translation
+//
+bool QETWidget::translateWheelEvent(int global_x, int global_y, int delta,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers,
+ Qt::Orientation orient)
+{
+ const QPoint globalPos = QPoint(global_x, global_y);
+ QPoint pos = mapFromGlobal(globalPos);
+ QWidget *widget = childAt(pos);
+ if (!widget)
+ widget = this;
+ else if (!widget->internalWinId())
+ pos = widget->mapFromGlobal(globalPos);
+
+#ifdef ALIEN_DEBUG
+ qDebug() << "QETWidget::translateWheelEvent: receiver:" << widget << "pos:" << pos;
+#endif
+
+ // send the event to the widget or its ancestors
+ {
+ QWidget* popup = qApp->activePopupWidget();
+ if (popup && window() != popup)
+ popup->close();
+#ifndef QT_NO_WHEELEVENT
+ QWheelEvent e(pos, globalPos, delta, buttons, modifiers, orient);
+ if (QApplication::sendSpontaneousEvent(widget, &e))
+#endif
+ return true;
+ }
+
+ // send the event to the widget that has the focus or its ancestors, if different
+ if (widget != qApp->focusWidget() && (widget = qApp->focusWidget())) {
+ if (widget && !widget->internalWinId())
+ pos = widget->mapFromGlobal(globalPos);
+ QWidget* popup = qApp->activePopupWidget();
+ if (popup && widget != popup)
+ popup->hide();
+#ifndef QT_NO_WHEELEVENT
+ QWheelEvent e(pos, globalPos, delta, buttons, modifiers, orient);
+ if (QApplication::sendSpontaneousEvent(widget, &e))
+#endif
+ return true;
+ }
+ return false;
+}
+
+
+//
+// XInput Translation Event
+//
+#if !defined (QT_NO_TABLET)
+
+#if !defined (Q_OS_IRIX)
+void fetchWacomToolId(int &deviceType, qint64 &serialId)
+{
+ if (ptrWacomConfigInit == 0) // we actually have the lib
+ return;
+ WACOMCONFIG *config = ptrWacomConfigInit(X11->display, 0);
+ if (config == 0)
+ return;
+ WACOMDEVICE *device = ptrWacomConfigOpenDevice (config, wacomDeviceName()->constData());
+ if (device == 0)
+ return;
+ unsigned keys[1];
+ int serialInt;
+ ptrWacomConfigGetRawParam (device, XWACOM_PARAM_TOOLSERIAL, &serialInt, 1, keys);
+ serialId = serialInt;
+ int toolId;
+ ptrWacomConfigGetRawParam (device, XWACOM_PARAM_TOOLID, &toolId, 1, keys);
+ switch(toolId) {
+ case 0x007: /* Mouse 4D and 2D */
+ case 0x017: /* Intuos3 2D Mouse */
+ case 0x094:
+ case 0x09c:
+ deviceType = QTabletEvent::FourDMouse;
+ break;
+ case 0x096: /* Lens cursor */
+ case 0x097: /* Intuos3 Lens cursor */
+ deviceType = QTabletEvent::Puck;
+ break;
+ case 0x0fa:
+ case 0x81b: /* Intuos3 Classic Pen Eraser */
+ case 0x82a: /* Eraser */
+ case 0x82b: /* Intuos3 Grip Pen Eraser */
+ case 0x85a:
+ case 0x91a:
+ case 0x91b: /* Intuos3 Airbrush Eraser */
+ case 0xd1a:
+ deviceType = QTabletEvent::XFreeEraser;
+ break;
+ case 0x112:
+ case 0x912:
+ case 0x913: /* Intuos3 Airbrush */
+ case 0xd12:
+ deviceType = QTabletEvent::Airbrush;
+ break;
+ case 0x012:
+ case 0x022:
+ case 0x032:
+ case 0x801: /* Intuos3 Inking pen */
+ case 0x812: /* Inking pen */
+ case 0x813: /* Intuos3 Classic Pen */
+ case 0x822: /* Pen */
+ case 0x823: /* Intuos3 Grip Pen */
+ case 0x832: /* Stroke pen */
+ case 0x842:
+ case 0x852:
+ case 0x885: /* Intuos3 Marker Pen */
+ default: /* Unknown tool */
+ deviceType = QTabletEvent::Stylus;
+ }
+
+ /* Close device and return */
+ ptrWacomConfigCloseDevice (device);
+ ptrWacomConfigTerm(config);
+}
+#endif
+
+struct qt_tablet_motion_data
+{
+ bool filterByWidget;
+ const QWidget *widget;
+ const QWidget *etWidget;
+ int tabletMotionType;
+ bool error; // found a reason to stop searching
+};
+
+static Bool qt_mouseMotion_scanner(Display *, XEvent *event, XPointer arg)
+{
+ qt_tablet_motion_data *data = (qt_tablet_motion_data *) arg;
+ if (data->error)
+ return false;
+
+ if (event->type == MotionNotify)
+ return true;
+
+ data->error = event->type != data->tabletMotionType; // we stop compression when another event gets in between.
+ return false;
+}
+
+static Bool qt_tabletMotion_scanner(Display *, XEvent *event, XPointer arg)
+{
+ qt_tablet_motion_data *data = (qt_tablet_motion_data *) arg;
+ if (data->error)
+ return false;
+ if (event->type == data->tabletMotionType) {
+ const XDeviceMotionEvent *const motion = reinterpret_cast<const XDeviceMotionEvent*>(event);
+ if (data->filterByWidget) {
+ const QPoint curr(motion->x, motion->y);
+ const QWidget *w = data->etWidget;
+ const QWidget *const child = w->childAt(curr);
+ if (child) {
+ w = child;
+ }
+ if (w == data->widget)
+ return true;
+ } else {
+ return true;
+ }
+ }
+
+ data->error = event->type != MotionNotify; // we stop compression when another event gets in between.
+ return false;
+}
+
+bool QETWidget::translateXinputEvent(const XEvent *ev, QTabletDeviceData *tablet)
+{
+#if defined (Q_OS_IRIX)
+ // Wacom has put defines in their wacom.h file so it would be quite wise
+ // to use them, need to think of a decent way of not using
+ // it when it doesn't exist...
+ XDeviceState *s;
+ XInputClass *iClass;
+ XValuatorState *vs;
+ int j;
+#endif
+
+ Q_ASSERT(tablet != 0);
+
+ QWidget *w = this;
+ QPoint global,
+ curr;
+ QPointF hiRes;
+ qreal pressure = 0;
+ int xTilt = 0,
+ yTilt = 0,
+ z = 0;
+ qreal tangentialPressure = 0;
+ qreal rotation = 0;
+ int deviceType = QTabletEvent::NoDevice;
+ int pointerType = QTabletEvent::UnknownPointer;
+ const XDeviceMotionEvent *motion = 0;
+ XDeviceButtonEvent *button = 0;
+ const XProximityNotifyEvent *proximity = 0;
+ QEvent::Type t;
+ Qt::KeyboardModifiers modifiers = 0;
+#if !defined (Q_OS_IRIX)
+ XID device_id;
+#endif
+
+ if (ev->type == tablet->xinput_motion) {
+ motion = reinterpret_cast<const XDeviceMotionEvent*>(ev);
+ t = QEvent::TabletMove;
+ global = QPoint(motion->x_root, motion->y_root);
+ curr = QPoint(motion->x, motion->y);
+#if !defined (Q_OS_IRIX)
+ device_id = motion->deviceid;
+#endif
+ } else if (ev->type == tablet->xinput_button_press || ev->type == tablet->xinput_button_release) {
+ if (ev->type == tablet->xinput_button_press) {
+ t = QEvent::TabletPress;
+ } else {
+ t = QEvent::TabletRelease;
+ }
+ button = (XDeviceButtonEvent*)ev;
+
+ global = QPoint(button->x_root, button->y_root);
+ curr = QPoint(button->x, button->y);
+#if !defined (Q_OS_IRIX)
+ device_id = button->deviceid;
+#endif
+ } else { // Proximity
+ if (ev->type == tablet->xinput_proximity_in)
+ t = QEvent::TabletEnterProximity;
+ else
+ t = QEvent::TabletLeaveProximity;
+ proximity = (const XProximityNotifyEvent*)ev;
+#if !defined (Q_OS_IRIX)
+ device_id = proximity->deviceid;
+#endif
+ }
+
+ qint64 uid = 0;
+#if defined (Q_OS_IRIX)
+ QRect screenArea = qApp->desktop()->screenGeometry(this);
+ s = XQueryDeviceState(X11->display, static_cast<XDevice *>(tablet->device));
+ if (!s)
+ return false;
+ iClass = s->data;
+ for (j = 0; j < s->num_classes; j++) {
+ if (iClass->c_class == ValuatorClass) {
+ vs = reinterpret_cast<XValuatorState *>(iClass);
+ // figure out what device we have, based on bitmasking...
+ if (vs->valuators[WAC_TRANSDUCER_I]
+ & WAC_TRANSDUCER_PROX_MSK) {
+ switch (vs->valuators[WAC_TRANSDUCER_I]
+ & WAC_TRANSDUCER_MSK) {
+ case WAC_PUCK_ID:
+ pointerType = QTabletEvent::Puck;
+ break;
+ case WAC_STYLUS_ID:
+ pointerType = QTabletEvent::Pen;
+ break;
+ case WAC_ERASER_ID:
+ pointerType = QTabletEvent::Eraser;
+ break;
+ }
+ // Get a Unique Id for the device, Wacom gives us this ability
+ uid = vs->valuators[WAC_TRANSDUCER_I] & WAC_TRANSDUCER_ID_MSK;
+ uid = (uid << 24) | vs->valuators[WAC_SERIAL_NUM_I];
+ switch (WAC_TRANSDUCER_I & 0x0F0600) {
+ case 0x080200:
+ deviceType = QTabletEvent::Stylus;
+ break;
+ case 0x090200:
+ deviceType = QTabletEvent::Airbrush;
+ break;
+ case 0x000400:
+ deviceType = QTabletEvent::FourDMouse;
+ break;
+ case 0x000600:
+ deviceType = QTabletEvent::Puck;
+ break;
+ case 0x080400:
+ deviceType = QTabletEvent::RotationStylus;
+ break;
+ }
+ } else {
+ pointerType = QTabletEvent::UnknownPointer;
+ deviceType = QTabletEvent::NoDevice;
+ uid = 0;
+ }
+
+ if (!proximity) {
+ // apparently Wacom needs a cast for the +/- values to make sense
+ xTilt = short(vs->valuators[WAC_XTILT_I]);
+ yTilt = short(vs->valuators[WAC_YTILT_I]);
+ pressure = vs->valuators[WAC_PRESSURE_I];
+ if (deviceType == QTabletEvent::FourDMouse
+ || deviceType == QTabletEvent::RotationStylus) {
+ rotation = vs->valuators[WAC_ROTATION_I] / 64.0;
+ if (deviceType == QTabletEvent::FourDMouse)
+ z = vs->valuators[WAC_ZCOORD_I];
+ } else if (deviceType == QTabletEvent::Airbrush) {
+ tangentialPressure = vs->valuators[WAC_TAN_PRESSURE_I]
+ / qreal(tablet->maxTanPressure - tablet->minTanPressure);
+ }
+
+ hiRes = tablet->scaleCoord(vs->valuators[WAC_XCOORD_I], vs->valuators[WAC_YCOORD_I],
+ screenArea.x(), screenArea.width(),
+ screenArea.y(), screenArea.height());
+ }
+ break;
+ }
+ iClass = reinterpret_cast<XInputClass*>(reinterpret_cast<char*>(iClass) + iClass->length);
+ }
+ XFreeDeviceState(s);
+#else
+ QTabletDeviceDataList *tablet_list = qt_tablet_devices();
+ for (int i = 0; i < tablet_list->size(); ++i) {
+ const QTabletDeviceData &t = tablet_list->at(i);
+ if (device_id == static_cast<XDevice *>(t.device)->device_id) {
+ deviceType = t.deviceType;
+ if (t.deviceType == QTabletEvent::XFreeEraser) {
+ deviceType = QTabletEvent::Stylus;
+ pointerType = QTabletEvent::Eraser;
+ } else if (t.deviceType == QTabletEvent::Stylus) {
+ pointerType = QTabletEvent::Pen;
+ }
+ break;
+ }
+ }
+
+ fetchWacomToolId(deviceType, uid);
+
+ QRect screenArea = qApp->desktop()->rect();
+ if (motion) {
+ xTilt = (short) motion->axis_data[3];
+ yTilt = (short) motion->axis_data[4];
+ rotation = ((short) motion->axis_data[5]) / 64.0;
+ pressure = (short) motion->axis_data[2];
+ modifiers = X11->translateModifiers(motion->state);
+ hiRes = tablet->scaleCoord(motion->axis_data[0], motion->axis_data[1],
+ screenArea.x(), screenArea.width(),
+ screenArea.y(), screenArea.height());
+ } else if (button) {
+ xTilt = (short) button->axis_data[3];
+ yTilt = (short) button->axis_data[4];
+ rotation = ((short) button->axis_data[5]) / 64.0;
+ pressure = (short) button->axis_data[2];
+ modifiers = X11->translateModifiers(button->state);
+ hiRes = tablet->scaleCoord(button->axis_data[0], button->axis_data[1],
+ screenArea.x(), screenArea.width(),
+ screenArea.y(), screenArea.height());
+ } else if (proximity) {
+ pressure = 0;
+ modifiers = 0;
+ }
+ if (deviceType == QTabletEvent::Airbrush) {
+ tangentialPressure = rotation;
+ rotation = 0.;
+ }
+#endif
+
+ if (tablet->widgetToGetPress) {
+ w = tablet->widgetToGetPress;
+ } else {
+ QWidget *child = w->childAt(curr);
+ if (child)
+ w = child;
+ }
+ curr = w->mapFromGlobal(global);
+
+ if (t == QEvent::TabletPress) {
+ tablet->widgetToGetPress = w;
+ } else if (t == QEvent::TabletRelease && tablet->widgetToGetPress) {
+ w = tablet->widgetToGetPress;
+ curr = w->mapFromGlobal(global);
+ tablet->widgetToGetPress = 0;
+ }
+
+ QTabletEvent e(t, curr, global, hiRes,
+ deviceType, pointerType,
+ qreal(pressure / qreal(tablet->maxPressure - tablet->minPressure)),
+ xTilt, yTilt, tangentialPressure, rotation, z, modifiers, uid);
+ if (proximity) {
+ QApplication::sendSpontaneousEvent(qApp, &e);
+ } else {
+ QApplication::sendSpontaneousEvent(w, &e);
+ const bool accepted = e.isAccepted();
+ if (!accepted && ev->type == tablet->xinput_motion) {
+ // If the widget does not accept tablet events, we drop the next ones from the event queue
+ // for this widget so it is not overloaded with the numerous tablet events.
+ qt_tablet_motion_data tabletMotionData;
+ tabletMotionData.tabletMotionType = tablet->xinput_motion;
+ tabletMotionData.widget = w;
+ tabletMotionData.etWidget = this;
+ // if nothing is pressed, the events are filtered by position
+ tabletMotionData.filterByWidget = (tablet->widgetToGetPress == 0);
+
+ bool reinsertMouseEvent = false;
+ XEvent mouseMotionEvent;
+ while (true) {
+ // Find first mouse event since we expect them in pairs inside Qt
+ tabletMotionData.error =false;
+ if (XCheckIfEvent(X11->display, &mouseMotionEvent, &qt_mouseMotion_scanner, (XPointer) &tabletMotionData)) {
+ reinsertMouseEvent = true;
+ } else {
+ break;
+ }
+
+ // Now discard any duplicate tablet events.
+ tabletMotionData.error = false;
+ XEvent dummy;
+ while (XCheckIfEvent(X11->display, &dummy, &qt_tabletMotion_scanner, (XPointer) &tabletMotionData)) {
+ // just discard the event
+ }
+ }
+
+ if (reinsertMouseEvent) {
+ XPutBackEvent(X11->display, &mouseMotionEvent);
+ }
+ }
+ }
+ return true;
+}
+#endif
+
+bool QETWidget::translatePropertyEvent(const XEvent *event)
+{
+ Q_D(QWidget);
+ if (!isWindow()) return true;
+
+ Atom ret;
+ int format, e;
+ unsigned char *data = 0;
+ unsigned long nitems, after;
+
+ if (event->xproperty.atom == ATOM(_KDE_NET_WM_FRAME_STRUT)) {
+ this->data->fstrut_dirty = 1;
+
+ if (event->xproperty.state == PropertyNewValue) {
+ e = XGetWindowProperty(X11->display, event->xproperty.window, ATOM(_KDE_NET_WM_FRAME_STRUT),
+ 0, 4, // struts are 4 longs
+ False, XA_CARDINAL, &ret, &format, &nitems, &after, &data);
+
+ if (e == Success && ret == XA_CARDINAL &&
+ format == 32 && nitems == 4) {
+ long *strut = (long *) data;
+ d->topData()->frameStrut.setCoords(strut[0], strut[2], strut[1], strut[3]);
+ this->data->fstrut_dirty = 0;
+ }
+ }
+ } else if (event->xproperty.atom == ATOM(_NET_WM_STATE)) {
+ bool max = false;
+ bool full = false;
+ Qt::WindowStates oldState = Qt::WindowStates(this->data->window_state);
+
+ if (event->xproperty.state == PropertyNewValue) {
+ // using length of 1024 should be safe for all current and
+ // possible NET states...
+ e = XGetWindowProperty(X11->display, event->xproperty.window, ATOM(_NET_WM_STATE), 0, 1024,
+ False, XA_ATOM, &ret, &format, &nitems, &after, &data);
+
+ if (e == Success && ret == XA_ATOM && format == 32 && nitems > 0) {
+ Atom *states = (Atom *) data;
+
+ unsigned long i;
+ uint maximized = 0;
+ for (i = 0; i < nitems; i++) {
+ if (states[i] == ATOM(_NET_WM_STATE_MAXIMIZED_VERT))
+ maximized |= 1;
+ else if (states[i] == ATOM(_NET_WM_STATE_MAXIMIZED_HORZ))
+ maximized |= 2;
+ else if (states[i] == ATOM(_NET_WM_STATE_FULLSCREEN))
+ full = true;
+ }
+ if (maximized == 3) {
+ // only set maximized if both horizontal and vertical properties are set
+ max = true;
+ }
+ }
+ }
+
+ bool send_event = false;
+
+ if (X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT))
+ && X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ))) {
+ if (max && !isMaximized()) {
+ this->data->window_state = this->data->window_state | Qt::WindowMaximized;
+ send_event = true;
+ } else if (!max && isMaximized()) {
+ this->data->window_state &= ~Qt::WindowMaximized;
+ send_event = true;
+ }
+ }
+
+ if (X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN))) {
+ if (full && !isFullScreen()) {
+ this->data->window_state = this->data->window_state | Qt::WindowFullScreen;
+ send_event = true;
+ } else if (!full && isFullScreen()) {
+ this->data->window_state &= ~Qt::WindowFullScreen;
+ send_event = true;
+ }
+ }
+
+ if (send_event) {
+ QWindowStateChangeEvent e(oldState);
+ QApplication::sendSpontaneousEvent(this, &e);
+ }
+ } else if (event->xproperty.atom == ATOM(WM_STATE)) {
+ // the widget frame strut should also be invalidated
+ this->data->fstrut_dirty = 1;
+
+ if (event->xproperty.state == PropertyDelete) {
+ // the window manager has removed the WM State property,
+ // so it is now in the withdrawn state (ICCCM 4.1.3.1) and
+ // we are free to reuse this window
+ d->topData()->parentWinId = 0;
+ d->topData()->validWMState = 0;
+ // map the window if we were waiting for a transition to
+ // withdrawn
+ if (X11->deferred_map.removeAll(this)) {
+ doDeferredMap();
+ } else if (isVisible()
+ && !testAttribute(Qt::WA_Mapped)
+ && !testAttribute(Qt::WA_OutsideWSRange)) {
+ // so that show() will work again. As stated in the
+ // ICCCM section 4.1.4: "Only the client can effect a
+ // transition into or out of the Withdrawn state.",
+ // but apparently this particular window manager
+ // doesn't seem to care
+ setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+ setAttribute(Qt::WA_WState_Visible, false);
+ }
+ } else {
+ // the window manager has changed the WM State property...
+ // we are wanting to see if we are withdrawn so that we
+ // can reuse this window...
+ e = XGetWindowProperty(X11->display, internalWinId(), ATOM(WM_STATE), 0, 2, False,
+ ATOM(WM_STATE), &ret, &format, &nitems, &after, &data);
+
+ if (e == Success && ret == ATOM(WM_STATE) && format == 32 && nitems > 0) {
+ long *state = (long *) data;
+ switch (state[0]) {
+ case WithdrawnState:
+ // if we are in the withdrawn state, we are free
+ // to reuse this window provided we remove the
+ // WM_STATE property (ICCCM 4.1.3.1)
+ XDeleteProperty(X11->display, internalWinId(), ATOM(WM_STATE));
+
+ // set the parent id to zero, so that show() will
+ // work again
+ d->topData()->parentWinId = 0;
+ d->topData()->validWMState = 0;
+ // map the window if we were waiting for a
+ // transition to withdrawn
+ if (X11->deferred_map.removeAll(this)) {
+ doDeferredMap();
+ } else if (isVisible()
+ && !testAttribute(Qt::WA_Mapped)
+ && !testAttribute(Qt::WA_OutsideWSRange)) {
+ // so that show() will work again. As stated
+ // in the ICCCM section 4.1.4: "Only the
+ // client can effect a transition into or out
+ // of the Withdrawn state.", but apparently
+ // this particular window manager doesn't seem
+ // to care
+ setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+ setAttribute(Qt::WA_WState_Visible, false);
+ }
+ break;
+
+ case IconicState:
+ d->topData()->validWMState = 1;
+ if (!isMinimized()) {
+ // window was minimized
+ this->data->window_state = this->data->window_state | Qt::WindowMinimized;
+ QWindowStateChangeEvent e(Qt::WindowStates(this->data->window_state & ~Qt::WindowMinimized));
+ QApplication::sendSpontaneousEvent(this, &e);
+ }
+ break;
+
+ default:
+ d->topData()->validWMState = 1;
+ if (isMinimized()) {
+ // window was un-minimized
+ this->data->window_state &= ~Qt::WindowMinimized;
+ QWindowStateChangeEvent e(Qt::WindowStates(this->data->window_state | Qt::WindowMinimized));
+ QApplication::sendSpontaneousEvent(this, &e);
+ }
+ break;
+ }
+ }
+ }
+ } else if (event->xproperty.atom == ATOM(_NET_WM_WINDOW_OPACITY)) {
+ // the window opacity was changed
+ if (event->xproperty.state == PropertyNewValue) {
+ e = XGetWindowProperty(event->xclient.display,
+ event->xclient.window,
+ ATOM(_NET_WM_WINDOW_OPACITY),
+ 0, 1, False, XA_CARDINAL,
+ &ret, &format, &nitems, &after, &data);
+
+ if (e == Success && ret == XA_CARDINAL && format == 32 && nitems == 1
+ && after == 0 && data) {
+ ulong value = *(ulong*)(data);
+ d->topData()->opacity = uint(value >> 24);
+ }
+ } else
+ d->topData()->opacity = 255;
+ }
+
+ if (data)
+ XFree(data);
+
+ return true;
+}
+
+
+//
+// Paint event translation
+//
+// When receiving many expose events, we compress them (union of all expose
+// rectangles) into one event which is sent to the widget.
+
+struct PaintEventInfo {
+ Window window;
+};
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static Bool isPaintOrScrollDoneEvent(Display *, XEvent *ev, XPointer a)
+{
+ PaintEventInfo *info = (PaintEventInfo *)a;
+ if (ev->type == Expose || ev->type == GraphicsExpose
+ || (ev->type == ClientMessage && ev->xclient.message_type == ATOM(_QT_SCROLL_DONE)))
+ {
+ if (ev->xexpose.window == info->window)
+ return True;
+ }
+ return False;
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+
+
+static
+bool translateBySips(QWidget* that, QRect& paintRect)
+{
+ int dx=0, dy=0;
+ int sips=0;
+ for (int i = 0; i < X11->sip_list.size(); ++i) {
+ const QX11Data::ScrollInProgress &sip = X11->sip_list.at(i);
+ if (sip.scrolled_widget == that) {
+ if (sips) {
+ dx += sip.dx;
+ dy += sip.dy;
+ }
+ sips++;
+ }
+ }
+ if (sips > 1) {
+ paintRect.translate(dx, dy);
+ return true;
+ }
+ return false;
+}
+
+void QETWidget::translatePaintEvent(const XEvent *event)
+{
+ if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
+ Q_ASSERT(internalWinId());
+
+ Q_D(QWidget);
+ QRect paintRect(event->xexpose.x, event->xexpose.y,
+ event->xexpose.width, event->xexpose.height);
+ XEvent xevent;
+ PaintEventInfo info;
+ info.window = internalWinId();
+ translateBySips(this, paintRect);
+ paintRect = d->mapFromWS(paintRect);
+
+ QRegion paintRegion = paintRect;
+
+ // WARNING: this is O(number_of_events * number_of_matching_events)
+ while (XCheckIfEvent(X11->display,&xevent,isPaintOrScrollDoneEvent,
+ (XPointer)&info) &&
+ !qt_x11EventFilter(&xevent) &&
+ !x11Event(&xevent)) // send event through filter
+ {
+ if (xevent.type == Expose || xevent.type == GraphicsExpose) {
+ QRect exposure(xevent.xexpose.x,
+ xevent.xexpose.y,
+ xevent.xexpose.width,
+ xevent.xexpose.height);
+ translateBySips(this, exposure);
+ exposure = d->mapFromWS(exposure);
+ paintRegion |= exposure;
+ } else {
+ translateScrollDoneEvent(&xevent);
+ }
+ }
+
+ if (!paintRegion.isEmpty() && !testAttribute(Qt::WA_WState_ConfigPending))
+ d->syncBackingStore(paintRegion);
+}
+
+//
+// Scroll-done event translation.
+//
+
+bool QETWidget::translateScrollDoneEvent(const XEvent *event)
+{
+ long id = event->xclient.data.l[0];
+
+ // Remove any scroll-in-progress record for the given id.
+ for (int i = 0; i < X11->sip_list.size(); ++i) {
+ const QX11Data::ScrollInProgress &sip = X11->sip_list.at(i);
+ if (sip.id == id) {
+ X11->sip_list.removeAt(i);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// ConfigureNotify (window move and resize) event translation
+
+bool QETWidget::translateConfigEvent(const XEvent *event)
+{
+ Q_ASSERT((!isWindow() && !testAttribute(Qt::WA_NativeWindow)) ? internalWinId() : true);
+
+ Q_D(QWidget);
+ bool wasResize = testAttribute(Qt::WA_WState_ConfigPending); // set in QWidget::setGeometry_sys()
+ setAttribute(Qt::WA_WState_ConfigPending, false);
+
+ if (testAttribute(Qt::WA_OutsideWSRange)) {
+ // discard events for windows that have a geometry X can't handle
+ XEvent xevent;
+ while (XCheckTypedWindowEvent(X11->display,internalWinId(), ConfigureNotify,&xevent) &&
+ !qt_x11EventFilter(&xevent) &&
+ !x11Event(&xevent)) // send event through filter
+ ;
+ return true;
+ }
+
+ const QSize oldSize = size();
+
+ if (isWindow()) {
+ QPoint newCPos(geometry().topLeft());
+ QSize newSize(event->xconfigure.width, event->xconfigure.height);
+
+ bool trust = isVisible()
+ && (d->topData()->parentWinId == XNone ||
+ d->topData()->parentWinId == QX11Info::appRootWindow());
+ bool isCPos = false;
+
+ if (event->xconfigure.send_event || trust) {
+ // if a ConfigureNotify comes from a real sendevent request, we can
+ // trust its values.
+ newCPos.rx() = event->xconfigure.x + event->xconfigure.border_width;
+ newCPos.ry() = event->xconfigure.y + event->xconfigure.border_width;
+ isCPos = true;
+ }
+ if (isVisible())
+ QApplication::syncX();
+
+ if (d->extra->compress_events) {
+ // ConfigureNotify compression for faster opaque resizing
+ XEvent otherEvent;
+ while (XCheckTypedWindowEvent(X11->display, internalWinId(), ConfigureNotify,
+ &otherEvent)) {
+ if (qt_x11EventFilter(&otherEvent))
+ continue;
+
+ if (x11Event(&otherEvent))
+ continue;
+
+ if (otherEvent.xconfigure.event != otherEvent.xconfigure.window)
+ continue;
+
+ newSize.setWidth(otherEvent.xconfigure.width);
+ newSize.setHeight(otherEvent.xconfigure.height);
+
+ if (otherEvent.xconfigure.send_event || trust) {
+ newCPos.rx() = otherEvent.xconfigure.x +
+ otherEvent.xconfigure.border_width;
+ newCPos.ry() = otherEvent.xconfigure.y +
+ otherEvent.xconfigure.border_width;
+ isCPos = true;
+ }
+ }
+#ifndef QT_NO_XSYNC
+ qt_sync_request_event_data sync_event;
+ sync_event.window = internalWinId();
+ for (XEvent ev;;) {
+ if (!XCheckIfEvent(X11->display, &ev, &qt_sync_request_scanner, (XPointer)&sync_event))
+ break;
+ }
+#endif // QT_NO_XSYNC
+ }
+
+ if (!isCPos) {
+ // we didn't get an updated position of the toplevel.
+ // either we haven't moved or there is a bug in the window manager.
+ // anyway, let's query the position to be certain.
+ int x, y;
+ Window child;
+ XTranslateCoordinates(X11->display, internalWinId(),
+ QApplication::desktop()->screen(d->xinfo.screen())->internalWinId(),
+ 0, 0, &x, &y, &child);
+ newCPos.rx() = x;
+ newCPos.ry() = y;
+ }
+
+ QRect cr (geometry());
+ if (newCPos != cr.topLeft()) { // compare with cpos (exluding frame)
+ QPoint oldPos = geometry().topLeft();
+ cr.moveTopLeft(newCPos);
+ data->crect = cr;
+ if (isVisible()) {
+ QMoveEvent e(newCPos, oldPos); // pos (including frame), not cpos
+ QApplication::sendSpontaneousEvent(this, &e);
+ } else {
+ setAttribute(Qt::WA_PendingMoveEvent, true);
+ }
+ }
+ if (newSize != cr.size()) { // size changed
+ cr.setSize(newSize);
+ data->crect = cr;
+
+ uint old_state = data->window_state;
+ if (!X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT))
+ && !X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ)))
+ data->window_state &= ~Qt::WindowMaximized;
+ if (!X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN)))
+ data->window_state &= ~Qt::WindowFullScreen;
+
+ if (old_state != data->window_state) {
+ QWindowStateChangeEvent e((Qt::WindowStates) old_state);
+ QApplication::sendEvent(this, &e);
+ }
+
+ if (!isVisible())
+ setAttribute(Qt::WA_PendingResizeEvent, true);
+ wasResize = true;
+ }
+
+ } else {
+ XEvent xevent;
+ while (XCheckTypedWindowEvent(X11->display,internalWinId(), ConfigureNotify,&xevent) &&
+ !qt_x11EventFilter(&xevent) &&
+ !x11Event(&xevent)) // send event through filter
+ ;
+ }
+
+ if (wasResize) {
+ if (isVisible() && data->crect.size() != oldSize) {
+ Q_ASSERT(d->extra->topextra);
+ QWidgetBackingStore *bs = d->extra->topextra->backingStore.data();
+ const bool hasStaticContents = bs && bs->hasStaticContents();
+ // If we have a backing store with static contents, we have to disable the top-level
+ // resize optimization in order to get invalidated regions for resized widgets.
+ // The optimization discards all invalidateBuffer() calls since we're going to
+ // repaint everything anyways, but that's not the case with static contents.
+ if (!hasStaticContents)
+ d->extra->topextra->inTopLevelResize = true;
+ QResizeEvent e(data->crect.size(), oldSize);
+ QApplication::sendSpontaneousEvent(this, &e);
+ }
+
+ const bool waitingForMapNotify = d->extra->topextra && d->extra->topextra->waitingForMapNotify;
+ if (!waitingForMapNotify) {
+ if (d->paintOnScreen()) {
+ QRegion updateRegion(rect());
+ if (testAttribute(Qt::WA_StaticContents))
+ updateRegion -= QRect(0, 0, oldSize.width(), oldSize.height());
+ d->syncBackingStore(updateRegion);
+ } else {
+ d->syncBackingStore();
+ }
+ }
+
+ if (d->extra && d->extra->topextra)
+ d->extra->topextra->inTopLevelResize = false;
+ }
+#ifndef QT_NO_XSYNC
+ if (QTLWExtra *tlwExtra = d->maybeTopData()) {
+ if (tlwExtra->newCounterValueLo != 0 || tlwExtra->newCounterValueHi != 0) {
+ XSyncValue value;
+ XSyncIntsToValue(&value,
+ tlwExtra->newCounterValueLo,
+ tlwExtra->newCounterValueHi);
+
+ XSyncSetCounter(X11->display, tlwExtra->syncUpdateCounter, value);
+ tlwExtra->newCounterValueHi = 0;
+ tlwExtra->newCounterValueLo = 0;
+ }
+ }
+#endif
+ return true;
+}
+
+//
+// Close window event translation.
+//
+bool QETWidget::translateCloseEvent(const XEvent *)
+{
+ Q_D(QWidget);
+ return d->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
+}
+
+
+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 n)
+{
+ QApplicationPrivate::wheel_scroll_lines = n;
+}
+
+int QApplication::wheelScrollLines()
+{
+ return QApplicationPrivate::wheel_scroll_lines;
+}
+#endif
+
+void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
+{
+ switch (effect) {
+ case Qt::UI_AnimateMenu:
+ if (enable) QApplicationPrivate::fade_menu = false;
+ 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:
+ if (enable) QApplicationPrivate::fade_tooltip = false;
+ 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;
+ }
+}
+
+/*****************************************************************************
+ Session management support
+ *****************************************************************************/
+
+#ifndef QT_NO_SESSIONMANAGER
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <X11/SM/SMlib.h>
+QT_END_INCLUDE_NAMESPACE
+
+class QSessionManagerPrivate : public QObjectPrivate
+{
+public:
+ QSessionManagerPrivate(QSessionManager* mgr, QString& id, QString& key)
+ : QObjectPrivate(), sm(mgr), sessionId(id), sessionKey(key),
+ restartHint(QSessionManager::RestartIfRunning), eventLoop(0) {}
+ QSessionManager* sm;
+ QStringList restartCommand;
+ QStringList discardCommand;
+ QString& sessionId;
+ QString& sessionKey;
+ QSessionManager::RestartHint restartHint;
+ QEventLoop *eventLoop;
+};
+
+class QSmSocketReceiver : public QObject
+{
+ Q_OBJECT
+public:
+ QSmSocketReceiver(int socket)
+ {
+ QSocketNotifier* sn = new QSocketNotifier(socket, QSocketNotifier::Read, this);
+ connect(sn, SIGNAL(activated(int)), this, SLOT(socketActivated(int)));
+ }
+
+public slots:
+ void socketActivated(int);
+};
+
+
+static SmcConn smcConnection = 0;
+static bool sm_interactionActive;
+static bool sm_smActive;
+static int sm_interactStyle;
+static int sm_saveType;
+static bool sm_cancel;
+// static bool sm_waitingForPhase2; ### never used?!?
+static bool sm_waitingForInteraction;
+static bool sm_isshutdown;
+// static bool sm_shouldbefast; ### never used?!?
+static bool sm_phase2;
+static bool sm_in_phase2;
+
+static QSmSocketReceiver* sm_receiver = 0;
+
+static void resetSmState();
+static void sm_setProperty(const char* name, const char* type,
+ int num_vals, SmPropValue* vals);
+static void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
+ int saveType, Bool shutdown , int interactStyle, Bool fast);
+static void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData) ;
+static void sm_dieCallback(SmcConn smcConn, SmPointer clientData) ;
+static void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData);
+static void sm_saveCompleteCallback(SmcConn smcConn, SmPointer clientData);
+static void sm_interactCallback(SmcConn smcConn, SmPointer clientData);
+static void sm_performSaveYourself(QSessionManagerPrivate*);
+
+static void resetSmState()
+{
+// sm_waitingForPhase2 = false; ### never used?!?
+ sm_waitingForInteraction = false;
+ sm_interactionActive = false;
+ sm_interactStyle = SmInteractStyleNone;
+ sm_smActive = false;
+ qt_sm_blockUserInput = false;
+ sm_isshutdown = false;
+// sm_shouldbefast = false; ### never used?!?
+ sm_phase2 = false;
+ sm_in_phase2 = false;
+}
+
+
+// theoretically it's possible to set several properties at once. For
+// simplicity, however, we do just one property at a time
+static void sm_setProperty(const char* name, const char* type,
+ int num_vals, SmPropValue* vals)
+{
+ if (num_vals) {
+ SmProp prop;
+ prop.name = (char*)name;
+ prop.type = (char*)type;
+ prop.num_vals = num_vals;
+ prop.vals = vals;
+
+ SmProp* props[1];
+ props[0] = &prop;
+ SmcSetProperties(smcConnection, 1, props);
+ }
+ else {
+ char* names[1];
+ names[0] = (char*) name;
+ SmcDeleteProperties(smcConnection, 1, names);
+ }
+}
+
+static void sm_setProperty(const QString& name, const QString& value)
+{
+ QByteArray v = value.toUtf8();
+ SmPropValue prop;
+ prop.length = v.length();
+ prop.value = (SmPointer) v.constData();
+ sm_setProperty(name.toLatin1().data(), SmARRAY8, 1, &prop);
+}
+
+static void sm_setProperty(const QString& name, const QStringList& value)
+{
+ SmPropValue *prop = new SmPropValue[value.count()];
+ int count = 0;
+ QList<QByteArray> vl;
+ for (QStringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
+ prop[count].length = (*it).length();
+ vl.append((*it).toUtf8());
+ prop[count].value = (char*)vl.last().data();
+ ++count;
+ }
+ sm_setProperty(name.toLatin1().data(), SmLISTofARRAY8, count, prop);
+ delete [] prop;
+}
+
+
+// workaround for broken libsm, see below
+struct QT_smcConn {
+ unsigned int save_yourself_in_progress : 1;
+ unsigned int shutdown_in_progress : 1;
+};
+
+static void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
+ int saveType, Bool shutdown , int interactStyle, Bool /*fast*/)
+{
+ if (smcConn != smcConnection)
+ return;
+ sm_cancel = false;
+ sm_smActive = true;
+ sm_isshutdown = shutdown;
+ sm_saveType = saveType;
+ sm_interactStyle = interactStyle;
+// sm_shouldbefast = fast; ### never used?!?
+
+ // ugly workaround for broken libSM. libSM should do that _before_
+ // actually invoking the callback in sm_process.c
+ ((QT_smcConn*)smcConn)->save_yourself_in_progress = true;
+ if (sm_isshutdown)
+ ((QT_smcConn*)smcConn)->shutdown_in_progress = true;
+
+ sm_performSaveYourself((QSessionManagerPrivate*) clientData);
+ if (!sm_isshutdown) // we cannot expect a confirmation message in that case
+ resetSmState();
+}
+
+static void sm_performSaveYourself(QSessionManagerPrivate* smd)
+{
+ if (sm_isshutdown)
+ qt_sm_blockUserInput = true;
+
+ QSessionManager* sm = smd->sm;
+
+ // generate a new session key
+ timeval tv;
+ gettimeofday(&tv, 0);
+ smd->sessionKey = QString::number(qulonglong(tv.tv_sec)) + QLatin1Char('_') + QString::number(qulonglong(tv.tv_usec));
+
+ QStringList arguments = qApp->arguments();
+ QString argument0 = arguments.isEmpty() ? qApp->applicationFilePath() : arguments.at(0);
+
+ // tell the session manager about our program in best POSIX style
+ sm_setProperty(QString::fromLatin1(SmProgram), argument0);
+ // tell the session manager about our user as well.
+ struct passwd *entryPtr = 0;
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
+ QVarLengthArray<char, 1024> buf(qMax<long>(sysconf(_SC_GETPW_R_SIZE_MAX), 1024L));
+ struct passwd entry;
+ while (getpwuid_r(geteuid(), &entry, buf.data(), buf.size(), &entryPtr) == ERANGE) {
+ if (buf.size() >= 32768) {
+ // too big already, fail
+ static char badusername[] = "";
+ entryPtr = &entry;
+ entry.pw_name = badusername;
+ break;
+ }
+
+ // retry with a bigger buffer
+ buf.resize(buf.size() * 2);
+ }
+#else
+ entryPtr = getpwuid(geteuid());
+#endif
+ if (entryPtr)
+ sm_setProperty(QString::fromLatin1(SmUserID), QString::fromLatin1(entryPtr->pw_name));
+
+ // generate a restart and discard command that makes sense
+ QStringList restart;
+ restart << argument0 << QLatin1String("-session")
+ << smd->sessionId + QLatin1Char('_') + smd->sessionKey;
+ if (qstricmp(appName, QX11Info::appClass()) != 0)
+ restart << QLatin1String("-name") << qAppName();
+ sm->setRestartCommand(restart);
+ QStringList discard;
+ sm->setDiscardCommand(discard);
+
+ switch (sm_saveType) {
+ case SmSaveBoth:
+ qApp->commitData(*sm);
+ if (sm_isshutdown && sm_cancel)
+ break; // we cancelled the shutdown, no need to save state
+ // fall through
+ case SmSaveLocal:
+ qApp->saveState(*sm);
+ break;
+ case SmSaveGlobal:
+ qApp->commitData(*sm);
+ break;
+ default:
+ break;
+ }
+
+ if (sm_phase2 && !sm_in_phase2) {
+ SmcRequestSaveYourselfPhase2(smcConnection, sm_saveYourselfPhase2Callback, (SmPointer*) smd);
+ qt_sm_blockUserInput = false;
+ }
+ else {
+ // close eventual interaction monitors and cancel the
+ // shutdown, if required. Note that we can only cancel when
+ // performing a shutdown, it does not work for checkpoints
+ if (sm_interactionActive) {
+ SmcInteractDone(smcConnection, sm_isshutdown && sm_cancel);
+ sm_interactionActive = false;
+ }
+ else if (sm_cancel && sm_isshutdown) {
+ if (sm->allowsErrorInteraction()) {
+ SmcInteractDone(smcConnection, True);
+ sm_interactionActive = false;
+ }
+ }
+
+ // set restart and discard command in session manager
+ sm_setProperty(QString::fromLatin1(SmRestartCommand), sm->restartCommand());
+ sm_setProperty(QString::fromLatin1(SmDiscardCommand), sm->discardCommand());
+
+ // set the restart hint
+ SmPropValue prop;
+ prop.length = sizeof(int);
+ int value = sm->restartHint();
+ prop.value = (SmPointer) &value;
+ sm_setProperty(SmRestartStyleHint, SmCARD8, 1, &prop);
+
+ // we are done
+ SmcSaveYourselfDone(smcConnection, !sm_cancel);
+ }
+}
+
+static void sm_dieCallback(SmcConn smcConn, SmPointer /* clientData */)
+{
+ if (smcConn != smcConnection)
+ return;
+ resetSmState();
+ QEvent quitEvent(QEvent::Quit);
+ QApplication::sendEvent(qApp, &quitEvent);
+}
+
+static void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData)
+{
+ if (smcConn != smcConnection)
+ return;
+ if (sm_waitingForInteraction)
+ ((QSessionManagerPrivate *) clientData)->eventLoop->exit();
+ resetSmState();
+}
+
+static void sm_saveCompleteCallback(SmcConn smcConn, SmPointer /*clientData */)
+{
+ if (smcConn != smcConnection)
+ return;
+ resetSmState();
+}
+
+static void sm_interactCallback(SmcConn smcConn, SmPointer clientData)
+{
+ if (smcConn != smcConnection)
+ return;
+ if (sm_waitingForInteraction)
+ ((QSessionManagerPrivate *) clientData)->eventLoop->exit();
+}
+
+static void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData)
+{
+ if (smcConn != smcConnection)
+ return;
+ sm_in_phase2 = true;
+ sm_performSaveYourself((QSessionManagerPrivate*) clientData);
+}
+
+
+void QSmSocketReceiver::socketActivated(int)
+{
+ IceProcessMessages(SmcGetIceConnection(smcConnection), 0, 0);
+}
+
+
+#undef Bool
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "qapplication_x11.moc"
+QT_END_INCLUDE_NAMESPACE
+
+QSessionManager::QSessionManager(QApplication * app, QString &id, QString& key)
+ : QObject(*new QSessionManagerPrivate(this, id, key), app)
+{
+ Q_D(QSessionManager);
+ d->restartHint = RestartIfRunning;
+
+ resetSmState();
+ char cerror[256];
+ char* myId = 0;
+ QByteArray b_id = id.toLatin1();
+ char* prevId = b_id.data();
+
+ SmcCallbacks cb;
+ cb.save_yourself.callback = sm_saveYourselfCallback;
+ cb.save_yourself.client_data = (SmPointer) d;
+ cb.die.callback = sm_dieCallback;
+ cb.die.client_data = (SmPointer) d;
+ cb.save_complete.callback = sm_saveCompleteCallback;
+ cb.save_complete.client_data = (SmPointer) d;
+ cb.shutdown_cancelled.callback = sm_shutdownCancelledCallback;
+ cb.shutdown_cancelled.client_data = (SmPointer) d;
+
+ // avoid showing a warning message below
+ if (qgetenv("SESSION_MANAGER").isEmpty())
+ return;
+
+ smcConnection = SmcOpenConnection(0, 0, 1, 0,
+ SmcSaveYourselfProcMask |
+ SmcDieProcMask |
+ SmcSaveCompleteProcMask |
+ SmcShutdownCancelledProcMask,
+ &cb,
+ prevId,
+ &myId,
+ 256, cerror);
+
+ id = QString::fromLatin1(myId);
+ ::free(myId); // it was allocated by C
+
+ QString error = QString::fromLocal8Bit(cerror);
+ if (!smcConnection) {
+ qWarning("Qt: Session management error: %s", qPrintable(error));
+ }
+ else {
+ sm_receiver = new QSmSocketReceiver(IceConnectionNumber(SmcGetIceConnection(smcConnection)));
+ }
+}
+
+QSessionManager::~QSessionManager()
+{
+ if (smcConnection)
+ SmcCloseConnection(smcConnection, 0, 0);
+ smcConnection = 0;
+ delete sm_receiver;
+}
+
+QString QSessionManager::sessionId() const
+{
+ Q_D(const QSessionManager);
+ return d->sessionId;
+}
+
+QString QSessionManager::sessionKey() const
+{
+ Q_D(const QSessionManager);
+ return d->sessionKey;
+}
+
+
+void* QSessionManager::handle() const
+{
+ return (void*) smcConnection;
+}
+
+
+bool QSessionManager::allowsInteraction()
+{
+ Q_D(QSessionManager);
+ if (sm_interactionActive)
+ return true;
+
+ if (sm_waitingForInteraction)
+ return false;
+
+ if (sm_interactStyle == SmInteractStyleAny) {
+ sm_waitingForInteraction = SmcInteractRequest(smcConnection, SmDialogNormal,
+ sm_interactCallback, (SmPointer*) d);
+ }
+ if (sm_waitingForInteraction) {
+ QEventLoop eventLoop;
+ d->eventLoop = &eventLoop;
+ (void) eventLoop.exec();
+ d->eventLoop = 0;
+
+ sm_waitingForInteraction = false;
+ if (sm_smActive) { // not cancelled
+ sm_interactionActive = true;
+ qt_sm_blockUserInput = false;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QSessionManager::allowsErrorInteraction()
+{
+ Q_D(QSessionManager);
+ if (sm_interactionActive)
+ return true;
+
+ if (sm_waitingForInteraction)
+ return false;
+
+ if (sm_interactStyle == SmInteractStyleAny || sm_interactStyle == SmInteractStyleErrors) {
+ sm_waitingForInteraction = SmcInteractRequest(smcConnection, SmDialogError,
+ sm_interactCallback, (SmPointer*) d);
+ }
+ if (sm_waitingForInteraction) {
+ QEventLoop eventLoop;
+ d->eventLoop = &eventLoop;
+ (void) eventLoop.exec();
+ d->eventLoop = 0;
+
+ sm_waitingForInteraction = false;
+ if (sm_smActive) { // not cancelled
+ sm_interactionActive = true;
+ qt_sm_blockUserInput = false;
+ return true;
+ }
+ }
+ return false;
+}
+
+void QSessionManager::release()
+{
+ if (sm_interactionActive) {
+ SmcInteractDone(smcConnection, False);
+ sm_interactionActive = false;
+ if (sm_smActive && sm_isshutdown)
+ qt_sm_blockUserInput = true;
+ }
+}
+
+void QSessionManager::cancel()
+{
+ sm_cancel = true;
+}
+
+void QSessionManager::setRestartHint(QSessionManager::RestartHint hint)
+{
+ Q_D(QSessionManager);
+ d->restartHint = hint;
+}
+
+QSessionManager::RestartHint QSessionManager::restartHint() const
+{
+ Q_D(const QSessionManager);
+ return d->restartHint;
+}
+
+void QSessionManager::setRestartCommand(const QStringList& command)
+{
+ Q_D(QSessionManager);
+ d->restartCommand = command;
+}
+
+QStringList QSessionManager::restartCommand() const
+{
+ Q_D(const QSessionManager);
+ return d->restartCommand;
+}
+
+void QSessionManager::setDiscardCommand(const QStringList& command)
+{
+ Q_D(QSessionManager);
+ d->discardCommand = command;
+}
+
+QStringList QSessionManager::discardCommand() const
+{
+ Q_D(const QSessionManager);
+ return d->discardCommand;
+}
+
+void QSessionManager::setManagerProperty(const QString& name, const QString& value)
+{
+ sm_setProperty(name, value);
+}
+
+void QSessionManager::setManagerProperty(const QString& name, const QStringList& value)
+{
+ sm_setProperty(name, value);
+}
+
+bool QSessionManager::isPhase2() const
+{
+ return sm_in_phase2;
+}
+
+void QSessionManager::requestPhase2()
+{
+ sm_phase2 = true;
+}
+
+#endif // QT_NO_SESSIONMANAGER
+
+#if defined(QT_RX71_MULTITOUCH)
+
+static inline int testBit(const char *array, int bit)
+{
+ return (array[bit/8] & (1<<(bit%8)));
+}
+
+static int openRX71Device(const QByteArray &deviceName)
+{
+ int fd = open(deviceName, O_RDONLY | O_NONBLOCK);
+ if (fd == -1) {
+ fd = -errno;
+ return fd;
+ }
+
+ // fetch the event type mask and check that the device reports absolute coordinates
+ char eventTypeMask[(EV_MAX + sizeof(char) - 1) * sizeof(char) + 1];
+ memset(eventTypeMask, 0, sizeof(eventTypeMask));
+ if (ioctl(fd, EVIOCGBIT(0, sizeof(eventTypeMask)), eventTypeMask) < 0) {
+ close(fd);
+ return -1;
+ }
+ if (!testBit(eventTypeMask, EV_ABS)) {
+ close(fd);
+ return -1;
+ }
+
+ // make sure that we can get the absolute X and Y positions from the device
+ char absMask[(ABS_MAX + sizeof(char) - 1) * sizeof(char) + 1];
+ memset(absMask, 0, sizeof(absMask));
+ if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absMask)), absMask) < 0) {
+ close(fd);
+ return -1;
+ }
+ if (!testBit(absMask, ABS_X) || !testBit(absMask, ABS_Y)) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+void QApplicationPrivate::initializeMultitouch_sys()
+{
+ Q_Q(QApplication);
+
+ QByteArray deviceName = QByteArray("/dev/input/event");
+ int currentDeviceNumber = 0;
+ for (;;) {
+ int fd = openRX71Device(QByteArray(deviceName + QByteArray::number(currentDeviceNumber++)));
+ if (fd == -ENOENT) {
+ // no more devices
+ break;
+ }
+ if (fd < 0) {
+ // not a touch device
+ continue;
+ }
+
+ struct input_absinfo abs_x, abs_y, abs_z;
+ ioctl(fd, EVIOCGABS(ABS_X), &abs_x);
+ ioctl(fd, EVIOCGABS(ABS_Y), &abs_y);
+ ioctl(fd, EVIOCGABS(ABS_Z), &abs_z);
+
+ int deviceNumber = allRX71TouchPoints.count();
+
+ QSocketNotifier *socketNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, q);
+ QObject::connect(socketNotifier, SIGNAL(activated(int)), q, SLOT(_q_readRX71MultiTouchEvents()));
+
+ RX71TouchPointState touchPointState = {
+ socketNotifier,
+ QTouchEvent::TouchPoint(deviceNumber),
+
+ abs_x.minimum, abs_x.maximum, q->desktop()->screenGeometry().width(),
+ abs_y.minimum, abs_y.maximum, q->desktop()->screenGeometry().height(),
+ abs_z.minimum, abs_z.maximum
+ };
+ allRX71TouchPoints.append(touchPointState);
+ }
+
+ hasRX71MultiTouch = allRX71TouchPoints.count() > 1;
+ if (!hasRX71MultiTouch) {
+ for (int i = 0; i < allRX71TouchPoints.count(); ++i) {
+ QSocketNotifier *socketNotifier = allRX71TouchPoints.at(i).socketNotifier;
+ close(socketNotifier->socket());
+ delete socketNotifier;
+ }
+ allRX71TouchPoints.clear();
+ }
+}
+
+void QApplicationPrivate::cleanupMultitouch_sys()
+{
+ hasRX71MultiTouch = false;
+ for (int i = 0; i < allRX71TouchPoints.count(); ++i) {
+ QSocketNotifier *socketNotifier = allRX71TouchPoints.at(i).socketNotifier;
+ close(socketNotifier->socket());
+ delete socketNotifier;
+ }
+ allRX71TouchPoints.clear();
+}
+
+bool QApplicationPrivate::readRX71MultiTouchEvents(int deviceNumber)
+{
+ RX71TouchPointState &touchPointState = allRX71TouchPoints[deviceNumber];
+ QSocketNotifier *socketNotifier = touchPointState.socketNotifier;
+ int fd = socketNotifier->socket();
+
+ QTouchEvent::TouchPoint &touchPoint = touchPointState.touchPoint;
+
+ bool down = touchPoint.state() != Qt::TouchPointReleased;
+ if (down)
+ touchPoint.setState(Qt::TouchPointStationary);
+
+ bool changed = false;
+ for (;;) {
+ struct input_event inputEvent;
+ int bytesRead = read(fd, &inputEvent, sizeof(inputEvent));
+ if (bytesRead <= 0)
+ break;
+ if (bytesRead != sizeof(inputEvent)) {
+ qWarning("Qt: INTERNAL ERROR: short read in readRX71MultiTouchEvents()");
+ return false;
+ }
+
+ switch (inputEvent.type) {
+ case EV_SYN:
+ changed = true;
+ switch (touchPoint.state()) {
+ case Qt::TouchPointPressed:
+ case Qt::TouchPointReleased:
+ // make sure we don't compress pressed and releases with any other events
+ return changed;
+ default:
+ break;
+ }
+ continue;
+ case EV_KEY:
+ case EV_ABS:
+ break;
+ default:
+ qWarning("Qt: WARNING: unknown event type %d on multitouch device", inputEvent.type);
+ continue;
+ }
+
+ QPointF screenPos = touchPoint.screenPos();
+ switch (inputEvent.code) {
+ case BTN_TOUCH:
+ if (!down && inputEvent.value != 0)
+ touchPoint.setState(Qt::TouchPointPressed);
+ else if (down && inputEvent.value == 0)
+ touchPoint.setState(Qt::TouchPointReleased);
+ break;
+ case ABS_TOOL_WIDTH:
+ case ABS_VOLUME:
+ case ABS_PRESSURE:
+ // ignore for now
+ break;
+ case ABS_X:
+ {
+ qreal newValue = ((qreal(inputEvent.value - touchPointState.minX)
+ / qreal(touchPointState.maxX - touchPointState.minX))
+ * touchPointState.scaleX);
+ screenPos.rx() = newValue;
+ touchPoint.setScreenPos(screenPos);
+ break;
+ }
+ case ABS_Y:
+ {
+ qreal newValue = ((qreal(inputEvent.value - touchPointState.minY)
+ / qreal(touchPointState.maxY - touchPointState.minY))
+ * touchPointState.scaleY);
+ screenPos.ry() = newValue;
+ touchPoint.setScreenPos(screenPos);
+ break;
+ }
+ case ABS_Z:
+ {
+ // map Z (signal strength) to pressure for now
+ qreal newValue = (qreal(inputEvent.value - touchPointState.minZ)
+ / qreal(touchPointState.maxZ - touchPointState.minZ));
+ touchPoint.setPressure(newValue);
+ break;
+ }
+ default:
+ qWarning("Qt: WARNING: unknown event code %d on multitouch device", inputEvent.code);
+ continue;
+ }
+ }
+
+ if (down && touchPoint.state() != Qt::TouchPointReleased)
+ touchPoint.setState(changed ? Qt::TouchPointMoved : Qt::TouchPointStationary);
+
+ return changed;
+}
+
+void QApplicationPrivate::_q_readRX71MultiTouchEvents()
+{
+ // read touch events from all devices
+ bool changed = false;
+ for (int i = 0; i < allRX71TouchPoints.count(); ++i)
+ changed = readRX71MultiTouchEvents(i) || changed;
+ if (!changed)
+ return;
+
+ QList<QTouchEvent::TouchPoint> touchPoints;
+ for (int i = 0; i < allRX71TouchPoints.count(); ++i)
+ touchPoints.append(allRX71TouchPoints.at(i).touchPoint);
+
+ translateRawTouchEvent(0, QTouchEvent::TouchScreen, touchPoints);
+}
+
+#else // !QT_RX71_MULTITOUCH
+
+void QApplicationPrivate::initializeMultitouch_sys()
+{ }
+void QApplicationPrivate::cleanupMultitouch_sys()
+{ }
+
+#endif // QT_RX71_MULTITOUCH
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qclipboard_x11.cpp b/src/widgets/platforms/x11/qclipboard_x11.cpp
new file mode 100644
index 0000000000..d566c86e04
--- /dev/null
+++ b/src/widgets/platforms/x11/qclipboard_x11.cpp
@@ -0,0 +1,1539 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QCLIPBOARD_DEBUG
+// #define QCLIPBOARD_DEBUG_VERBOSE
+
+#ifdef QCLIPBOARD_DEBUG
+# define DEBUG qDebug
+#else
+# define DEBUG if (false) qDebug
+#endif
+
+#ifdef QCLIPBOARD_DEBUG_VERBOSE
+# define VDEBUG qDebug
+#else
+# define VDEBUG if (false) qDebug
+#endif
+
+#include "qplatformdefs.h"
+
+#include "qclipboard.h"
+#include "qclipboard_p.h"
+
+#ifndef QT_NO_CLIPBOARD
+
+#include "qabstracteventdispatcher.h"
+#include "qapplication.h"
+#include "qdesktopwidget.h"
+#include "qbitmap.h"
+#include "qiodevice.h"
+#include "qbuffer.h"
+#include "qtextcodec.h"
+#include "qlist.h"
+#include "qmap.h"
+#include "qapplication_p.h"
+#include "qevent.h"
+#include "qt_x11_p.h"
+#include "qx11info_x11.h"
+#include "qimagewriter.h"
+#include "qelapsedtimer.h"
+#include "qvariant.h"
+#include "qdnd_p.h"
+#include <private/qwidget_p.h>
+
+#ifndef QT_NO_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif // QT_NO_XFIXES
+
+QT_BEGIN_NAMESPACE
+
+/*****************************************************************************
+ Internal QClipboard functions for X11.
+ *****************************************************************************/
+
+static int clipboard_timeout = 5000; // 5s timeout on clipboard operations
+
+static QWidget * owner = 0;
+static QWidget *requestor = 0;
+static bool timer_event_clear = false;
+static int timer_id = 0;
+
+static int pending_timer_id = 0;
+static bool pending_clipboard_changed = false;
+static bool pending_selection_changed = false;
+
+
+// event capture mechanism for qt_xclb_wait_for_event
+static bool waiting_for_data = false;
+static bool has_captured_event = false;
+static Window capture_event_win = XNone;
+static int capture_event_type = -1;
+static XEvent captured_event;
+
+class QClipboardWatcher; // forward decl
+static QClipboardWatcher *selection_watcher = 0;
+static QClipboardWatcher *clipboard_watcher = 0;
+
+static void cleanup()
+{
+ delete owner;
+ delete requestor;
+ owner = 0;
+ requestor = 0;
+}
+
+static
+void setupOwner()
+{
+ if (owner)
+ return;
+ owner = new QWidget(0);
+ owner->setObjectName(QLatin1String("internal clipboard owner"));
+ owner->createWinId();
+ requestor = new QWidget(0);
+ requestor->createWinId();
+ requestor->setObjectName(QLatin1String("internal clipboard requestor"));
+ // We don't need this internal widgets to appear in QApplication::topLevelWidgets()
+ if (QWidgetPrivate::allWidgets) {
+ QWidgetPrivate::allWidgets->remove(owner);
+ QWidgetPrivate::allWidgets->remove(requestor);
+ }
+ qAddPostRoutine(cleanup);
+}
+
+
+class QClipboardWatcher : public QInternalMimeData {
+public:
+ QClipboardWatcher(QClipboard::Mode mode);
+ ~QClipboardWatcher();
+ bool empty() const;
+ virtual bool hasFormat_sys(const QString &mimetype) const;
+ virtual QStringList formats_sys() const;
+
+ QVariant retrieveData_sys(const QString &mimetype, QVariant::Type type) const;
+ QByteArray getDataInFormat(Atom fmtatom) const;
+
+ Atom atom;
+ mutable QStringList formatList;
+ mutable QByteArray format_atoms;
+};
+
+class QClipboardData
+{
+private:
+ QMimeData *&mimeDataRef() const
+ {
+ if(mode == QClipboard::Selection)
+ return selectionData;
+ return clipboardData;
+ }
+
+public:
+ QClipboardData(QClipboard::Mode mode);
+ ~QClipboardData();
+
+ void setSource(QMimeData* s)
+ {
+ if ((mode == QClipboard::Selection && selectionData == s)
+ || clipboardData == s) {
+ return;
+ }
+
+ if (selectionData != clipboardData) {
+ delete mimeDataRef();
+ }
+
+ mimeDataRef() = s;
+ }
+
+ QMimeData *source() const
+ {
+ return mimeDataRef();
+ }
+
+ void clear()
+ {
+ timestamp = CurrentTime;
+ if (selectionData == clipboardData) {
+ mimeDataRef() = 0;
+ } else {
+ QMimeData *&src = mimeDataRef();
+ delete src;
+ src = 0;
+ }
+ }
+
+ static QMimeData *selectionData;
+ static QMimeData *clipboardData;
+ Time timestamp;
+ QClipboard::Mode mode;
+};
+
+QMimeData *QClipboardData::selectionData = 0;
+QMimeData *QClipboardData::clipboardData = 0;
+
+QClipboardData::QClipboardData(QClipboard::Mode clipboardMode)
+{
+ timestamp = CurrentTime;
+ mode = clipboardMode;
+}
+
+QClipboardData::~QClipboardData()
+{ clear(); }
+
+
+static QClipboardData *internalCbData = 0;
+static QClipboardData *internalSelData = 0;
+
+static void cleanupClipboardData()
+{
+ delete internalCbData;
+ internalCbData = 0;
+}
+
+static QClipboardData *clipboardData()
+{
+ if (internalCbData == 0) {
+ internalCbData = new QClipboardData(QClipboard::Clipboard);
+ qAddPostRoutine(cleanupClipboardData);
+ }
+ return internalCbData;
+}
+
+static void cleanupSelectionData()
+{
+ delete internalSelData;
+ internalSelData = 0;
+}
+
+static QClipboardData *selectionData()
+{
+ if (internalSelData == 0) {
+ internalSelData = new QClipboardData(QClipboard::Selection);
+ qAddPostRoutine(cleanupSelectionData);
+ }
+ return internalSelData;
+}
+
+class QClipboardINCRTransaction
+{
+public:
+ QClipboardINCRTransaction(Window w, Atom p, Atom t, int f, QByteArray d, unsigned int i);
+ ~QClipboardINCRTransaction(void);
+
+ int x11Event(XEvent *event);
+
+ Window window;
+ Atom property, target;
+ int format;
+ QByteArray data;
+ unsigned int increment;
+ unsigned int offset;
+};
+
+typedef QMap<Window,QClipboardINCRTransaction*> TransactionMap;
+static TransactionMap *transactions = 0;
+static QApplication::EventFilter prev_event_filter = 0;
+static int incr_timer_id = 0;
+
+static bool qt_x11_incr_event_filter(void *message, long *result)
+{
+ XEvent *event = reinterpret_cast<XEvent *>(message);
+ TransactionMap::Iterator it = transactions->find(event->xany.window);
+ if (it != transactions->end()) {
+ if ((*it)->x11Event(event) != 0)
+ return true;
+ }
+ if (prev_event_filter)
+ return prev_event_filter(event, result);
+ return false;
+}
+
+/*
+ called when no INCR activity has happened for 'clipboard_timeout'
+ milliseconds... we assume that all unfinished transactions have
+ timed out and remove everything from the transaction map
+*/
+static void qt_xclb_incr_timeout(void)
+{
+ qWarning("QClipboard: Timed out while sending data");
+
+ while (transactions)
+ delete *transactions->begin();
+}
+
+QClipboardINCRTransaction::QClipboardINCRTransaction(Window w, Atom p, Atom t, int f,
+ QByteArray d, unsigned int i)
+ : window(w), property(p), target(t), format(f), data(d), increment(i), offset(0u)
+{
+ DEBUG("QClipboard: sending %d bytes (INCR transaction %p)", d.size(), this);
+
+ XSelectInput(X11->display, window, PropertyChangeMask);
+
+ if (! transactions) {
+ VDEBUG("QClipboard: created INCR transaction map");
+ transactions = new TransactionMap;
+ prev_event_filter = qApp->setEventFilter(qt_x11_incr_event_filter);
+ incr_timer_id = QApplication::clipboard()->startTimer(clipboard_timeout);
+ }
+ transactions->insert(window, this);
+}
+
+QClipboardINCRTransaction::~QClipboardINCRTransaction(void)
+{
+ VDEBUG("QClipboard: destroyed INCR transacton %p", this);
+
+ XSelectInput(X11->display, window, NoEventMask);
+
+ transactions->remove(window);
+ if (transactions->isEmpty()) {
+ VDEBUG("QClipboard: no more INCR transactions");
+ delete transactions;
+ transactions = 0;
+
+ (void)qApp->setEventFilter(prev_event_filter);
+
+ if (incr_timer_id != 0) {
+ QApplication::clipboard()->killTimer(incr_timer_id);
+ incr_timer_id = 0;
+ }
+ }
+}
+
+int QClipboardINCRTransaction::x11Event(XEvent *event)
+{
+ if (event->type != PropertyNotify
+ || (event->xproperty.state != PropertyDelete
+ || event->xproperty.atom != property))
+ return 0;
+
+ // restart the INCR timer
+ if (incr_timer_id) QApplication::clipboard()->killTimer(incr_timer_id);
+ incr_timer_id = QApplication::clipboard()->startTimer(clipboard_timeout);
+
+ unsigned int bytes_left = data.size() - offset;
+ if (bytes_left > 0) {
+ unsigned int xfer = qMin(increment, bytes_left);
+ VDEBUG("QClipboard: sending %d bytes, %d remaining (INCR transaction %p)",
+ xfer, bytes_left - xfer, this);
+
+ XChangeProperty(X11->display, window, property, target, format,
+ PropModeReplace, (uchar *) data.data() + offset, xfer);
+ offset += xfer;
+ } else {
+ // INCR transaction finished...
+ XChangeProperty(X11->display, window, property, target, format,
+ PropModeReplace, (uchar *) data.data(), 0);
+ delete this;
+ }
+
+ return 1;
+}
+
+
+/*****************************************************************************
+ QClipboard member functions for X11.
+ *****************************************************************************/
+
+struct qt_init_timestamp_data
+{
+ Time timestamp;
+};
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static Bool qt_init_timestamp_scanner(Display*, XEvent *event, XPointer arg)
+{
+ qt_init_timestamp_data *data =
+ reinterpret_cast<qt_init_timestamp_data*>(arg);
+ switch(event->type)
+ {
+ case ButtonPress:
+ case ButtonRelease:
+ data->timestamp = event->xbutton.time;
+ break;
+ case MotionNotify:
+ data->timestamp = event->xmotion.time;
+ break;
+ case XKeyPress:
+ case XKeyRelease:
+ data->timestamp = event->xkey.time;
+ break;
+ case PropertyNotify:
+ data->timestamp = event->xproperty.time;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ data->timestamp = event->xcrossing.time;
+ break;
+ case SelectionClear:
+ data->timestamp = event->xselectionclear.time;
+ break;
+ default:
+ break;
+ }
+#ifndef QT_NO_XFIXES
+ if (X11->use_xfixes && event->type == (X11->xfixes_eventbase + XFixesSelectionNotify)) {
+ XFixesSelectionNotifyEvent *req =
+ reinterpret_cast<XFixesSelectionNotifyEvent *>(event);
+ data->timestamp = req->selection_timestamp;
+ }
+#endif
+ return false;
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+QClipboard::QClipboard(QObject *parent)
+ : QObject(*new QClipboardPrivate, parent)
+{
+ // create desktop widget since we need it to get PropertyNotify or
+ // XFixesSelectionNotify events when someone changes the
+ // clipboard.
+ (void)QApplication::desktop();
+
+#ifndef QT_NO_XFIXES
+ if (X11->use_xfixes && X11->ptrXFixesSelectSelectionInput) {
+ const unsigned long eventMask =
+ XFixesSetSelectionOwnerNotifyMask | XFixesSelectionWindowDestroyNotifyMask | XFixesSelectionClientCloseNotifyMask;
+ for (int i = 0; i < X11->screenCount; ++i) {
+ X11->ptrXFixesSelectSelectionInput(X11->display, QX11Info::appRootWindow(i),
+ XA_PRIMARY, eventMask);
+ X11->ptrXFixesSelectSelectionInput(X11->display, QX11Info::appRootWindow(i),
+ ATOM(CLIPBOARD), eventMask);
+ }
+ }
+#endif // QT_NO_XFIXES
+
+ if (X11->time == CurrentTime) {
+ // send a dummy event to myself to get the timestamp from X11.
+ qt_init_timestamp_data data;
+ data.timestamp = CurrentTime;
+ XEvent ev;
+ XCheckIfEvent(X11->display, &ev, &qt_init_timestamp_scanner, (XPointer)&data);
+ if (data.timestamp == CurrentTime) {
+ setupOwner();
+ // We need this value just for completeness, we don't use it.
+ long dummy = 0;
+ Window ownerId = owner->internalWinId();
+ XChangeProperty(X11->display, ownerId,
+ ATOM(CLIP_TEMPORARY), XA_INTEGER, 32,
+ PropModeReplace, (uchar*)&dummy, 1);
+ XWindowEvent(X11->display, ownerId, PropertyChangeMask, &ev);
+ data.timestamp = ev.xproperty.time;
+ XDeleteProperty(X11->display, ownerId, ATOM(CLIP_TEMPORARY));
+ }
+ X11->time = data.timestamp;
+ }
+}
+
+void QClipboard::clear(Mode mode)
+{
+ setMimeData(0, mode);
+}
+
+
+bool QClipboard::supportsMode(Mode mode) const
+{
+ return (mode == Clipboard || mode == Selection);
+}
+
+bool QClipboard::ownsMode(Mode mode) const
+{
+ if (mode == Clipboard)
+ return clipboardData()->timestamp != CurrentTime;
+ else if(mode == Selection)
+ return selectionData()->timestamp != CurrentTime;
+ else
+ return false;
+}
+
+
+// event filter function... captures interesting events while
+// qt_xclb_wait_for_event is running the event loop
+static bool qt_x11_clipboard_event_filter(void *message, long *)
+{
+ XEvent *event = reinterpret_cast<XEvent *>(message);
+ if (event->xany.type == capture_event_type &&
+ event->xany.window == capture_event_win) {
+ VDEBUG("QClipboard: event_filter(): caught event type %d", event->type);
+ has_captured_event = true;
+ captured_event = *event;
+ return true;
+ }
+ return false;
+}
+
+static Bool checkForClipboardEvents(Display *, XEvent *e, XPointer)
+{
+ return ((e->type == SelectionRequest && (e->xselectionrequest.selection == XA_PRIMARY
+ || e->xselectionrequest.selection == ATOM(CLIPBOARD)))
+ || (e->type == SelectionClear && (e->xselectionclear.selection == XA_PRIMARY
+ || e->xselectionclear.selection == ATOM(CLIPBOARD))));
+}
+
+bool QX11Data::clipboardWaitForEvent(Window win, int type, XEvent *event, int timeout)
+{
+ QElapsedTimer started;
+ started.start();
+ QElapsedTimer now = started;
+
+ if (QAbstractEventDispatcher::instance()->inherits("QtMotif")
+ || QApplication::clipboard()->property("useEventLoopWhenWaiting").toBool()) {
+ if (waiting_for_data) {
+ Q_ASSERT(!"QClipboard: internal error, qt_xclb_wait_for_event recursed");
+ return false;
+ }
+ waiting_for_data = true;
+
+
+ has_captured_event = false;
+ capture_event_win = win;
+ capture_event_type = type;
+
+ QApplication::EventFilter old_event_filter =
+ qApp->setEventFilter(qt_x11_clipboard_event_filter);
+
+ do {
+ if (XCheckTypedWindowEvent(display, win, type, event)) {
+ waiting_for_data = false;
+ qApp->setEventFilter(old_event_filter);
+ return true;
+ }
+
+ XSync(X11->display, false);
+ usleep(50000);
+
+ now.start();
+
+ QEventLoop::ProcessEventsFlags flags(QEventLoop::ExcludeUserInputEvents
+ | QEventLoop::ExcludeSocketNotifiers
+ | QEventLoop::WaitForMoreEvents
+ | QEventLoop::X11ExcludeTimers);
+ QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance();
+ eventDispatcher->processEvents(flags);
+
+ if (has_captured_event) {
+ waiting_for_data = false;
+ *event = captured_event;
+ qApp->setEventFilter(old_event_filter);
+ return true;
+ }
+ } while (started.msecsTo(now) < timeout);
+
+ waiting_for_data = false;
+ qApp->setEventFilter(old_event_filter);
+ } else {
+ do {
+ if (XCheckTypedWindowEvent(X11->display,win,type,event))
+ return true;
+
+ // process other clipboard events, since someone is probably requesting data from us
+ XEvent e;
+ if (XCheckIfEvent(X11->display, &e, checkForClipboardEvents, 0))
+ qApp->x11ProcessEvent(&e);
+
+ now.start();
+
+ XFlush(X11->display);
+
+ // sleep 50 ms, so we don't use up CPU cycles all the time.
+ struct timeval usleep_tv;
+ usleep_tv.tv_sec = 0;
+ usleep_tv.tv_usec = 50000;
+ select(0, 0, 0, 0, &usleep_tv);
+ } while (started.msecsTo(now) < timeout);
+ }
+ return false;
+}
+
+
+static inline int maxSelectionIncr(Display *dpy)
+{ return XMaxRequestSize(dpy) > 65536 ? 65536*4 : XMaxRequestSize(dpy)*4 - 100; }
+
+bool QX11Data::clipboardReadProperty(Window win, Atom property, bool deleteProperty,
+ QByteArray *buffer, int *size, Atom *type, int *format)
+{
+ int maxsize = maxSelectionIncr(display);
+ ulong bytes_left; // bytes_after
+ ulong length; // nitems
+ uchar *data;
+ Atom dummy_type;
+ int dummy_format;
+ int r;
+
+ if (!type) // allow null args
+ type = &dummy_type;
+ if (!format)
+ format = &dummy_format;
+
+ // Don't read anything, just get the size of the property data
+ r = XGetWindowProperty(display, win, property, 0, 0, False,
+ AnyPropertyType, type, format,
+ &length, &bytes_left, &data);
+ if (r != Success || (type && *type == XNone)) {
+ buffer->resize(0);
+ return false;
+ }
+ XFree((char*)data);
+
+ int offset = 0, buffer_offset = 0, format_inc = 1, proplen = bytes_left;
+
+ VDEBUG("QClipboard: read_property(): initial property length: %d", proplen);
+
+ switch (*format) {
+ case 8:
+ default:
+ format_inc = sizeof(char) / 1;
+ break;
+
+ case 16:
+ format_inc = sizeof(short) / 2;
+ proplen *= sizeof(short) / 2;
+ break;
+
+ case 32:
+ format_inc = sizeof(long) / 4;
+ proplen *= sizeof(long) / 4;
+ break;
+ }
+
+ int newSize = proplen;
+ buffer->resize(newSize);
+
+ bool ok = (buffer->size() == newSize);
+ VDEBUG("QClipboard: read_property(): buffer resized to %d", buffer->size());
+
+ if (ok && newSize) {
+ // could allocate buffer
+
+ while (bytes_left) {
+ // more to read...
+
+ r = XGetWindowProperty(display, win, property, offset, maxsize/4,
+ False, AnyPropertyType, type, format,
+ &length, &bytes_left, &data);
+ if (r != Success || (type && *type == XNone))
+ break;
+
+ offset += length / (32 / *format);
+ length *= format_inc * (*format) / 8;
+
+ // Here we check if we get a buffer overflow and tries to
+ // recover -- this shouldn't normally happen, but it doesn't
+ // hurt to be defensive
+ if ((int)(buffer_offset + length) > buffer->size()) {
+ length = buffer->size() - buffer_offset;
+
+ // escape loop
+ bytes_left = 0;
+ }
+
+ memcpy(buffer->data() + buffer_offset, data, length);
+ buffer_offset += length;
+
+ XFree((char*)data);
+ }
+
+ if (*format == 8 && *type == ATOM(COMPOUND_TEXT)) {
+ // convert COMPOUND_TEXT to a multibyte string
+ XTextProperty textprop;
+ textprop.encoding = *type;
+ textprop.format = *format;
+ textprop.nitems = buffer_offset;
+ textprop.value = (unsigned char *) buffer->data();
+
+ char **list_ret = 0;
+ int count;
+ if (XmbTextPropertyToTextList(display, &textprop, &list_ret,
+ &count) == Success && count && list_ret) {
+ offset = buffer_offset = strlen(list_ret[0]);
+ buffer->resize(offset);
+ memcpy(buffer->data(), list_ret[0], offset);
+ }
+ if (list_ret) XFreeStringList(list_ret);
+ }
+ }
+
+ // correct size, not 0-term.
+ if (size)
+ *size = buffer_offset;
+
+ VDEBUG("QClipboard: read_property(): buffer size %d, buffer offset %d, offset %d",
+ buffer->size(), buffer_offset, offset);
+
+ if (deleteProperty)
+ XDeleteProperty(display, win, property);
+
+ XFlush(display);
+
+ return ok;
+}
+
+QByteArray QX11Data::clipboardReadIncrementalProperty(Window win, Atom property, int nbytes, bool nullterm)
+{
+ XEvent event;
+
+ QByteArray buf;
+ QByteArray tmp_buf;
+ bool alloc_error = false;
+ int length;
+ int offset = 0;
+
+ if (nbytes > 0) {
+ // Reserve buffer + zero-terminator (for text data)
+ // We want to complete the INCR transfer even if we cannot
+ // allocate more memory
+ buf.resize(nbytes+1);
+ alloc_error = buf.size() != nbytes+1;
+ }
+
+ for (;;) {
+ XFlush(display);
+ if (!clipboardWaitForEvent(win,PropertyNotify,&event,clipboard_timeout))
+ break;
+ if (event.xproperty.atom != property ||
+ event.xproperty.state != PropertyNewValue)
+ continue;
+ if (X11->clipboardReadProperty(win, property, true, &tmp_buf, &length, 0, 0)) {
+ if (length == 0) { // no more data, we're done
+ if (nullterm) {
+ buf.resize(offset+1);
+ buf[offset] = '\0';
+ } else {
+ buf.resize(offset);
+ }
+ return buf;
+ } else if (!alloc_error) {
+ if (offset+length > (int)buf.size()) {
+ buf.resize(offset+length+65535);
+ if (buf.size() != offset+length+65535) {
+ alloc_error = true;
+ length = buf.size() - offset;
+ }
+ }
+ memcpy(buf.data()+offset, tmp_buf.constData(), length);
+ tmp_buf.resize(0);
+ offset += length;
+ }
+ } else {
+ break;
+ }
+ }
+
+ // timed out ... create a new requestor window, otherwise the requestor
+ // could consider next request to be still part of this timed out request
+ delete requestor;
+ requestor = new QWidget(0);
+ requestor->setObjectName(QLatin1String("internal clipboard requestor"));
+ // We don't need this internal widget to appear in QApplication::topLevelWidgets()
+ if (QWidgetPrivate::allWidgets)
+ QWidgetPrivate::allWidgets->remove(requestor);
+
+ return QByteArray();
+}
+
+static Atom send_targets_selection(QClipboardData *d, Window window, Atom property)
+{
+ QVector<Atom> types;
+ QStringList formats = QInternalMimeData::formatsHelper(d->source());
+ for (int i = 0; i < formats.size(); ++i) {
+ QList<Atom> atoms = X11->xdndMimeAtomsForFormat(formats.at(i));
+ for (int j = 0; j < atoms.size(); ++j) {
+ if (!types.contains(atoms.at(j)))
+ types.append(atoms.at(j));
+ }
+ }
+ types.append(ATOM(TARGETS));
+ types.append(ATOM(MULTIPLE));
+ types.append(ATOM(TIMESTAMP));
+ types.append(ATOM(SAVE_TARGETS));
+
+ XChangeProperty(X11->display, window, property, XA_ATOM, 32,
+ PropModeReplace, (uchar *) types.data(), types.size());
+ return property;
+}
+
+static Atom send_selection(QClipboardData *d, Atom target, Window window, Atom property)
+{
+ Atom atomFormat = target;
+ int dataFormat = 0;
+ QByteArray data;
+
+ QByteArray fmt = X11->xdndAtomToString(target);
+ if (fmt.isEmpty()) { // Not a MIME type we have
+ DEBUG("QClipboard: send_selection(): converting to type '%s' is not supported", fmt.data());
+ return XNone;
+ }
+ DEBUG("QClipboard: send_selection(): converting to type '%s'", fmt.data());
+
+ if (X11->xdndMimeDataForAtom(target, d->source(), &data, &atomFormat, &dataFormat)) {
+
+ VDEBUG("QClipboard: send_selection():\n"
+ " property type %lx\n"
+ " property name '%s'\n"
+ " format %d\n"
+ " %d bytes\n",
+ target, X11->xdndMimeAtomToString(atomFormat).toLatin1().data(), dataFormat, data.size());
+
+ // don't allow INCR transfers when using MULTIPLE or to
+ // Motif clients (since Motif doesn't support INCR)
+ static Atom motif_clip_temporary = ATOM(CLIP_TEMPORARY);
+ bool allow_incr = property != motif_clip_temporary;
+
+ // X_ChangeProperty protocol request is 24 bytes
+ const int increment = (XMaxRequestSize(X11->display) * 4) - 24;
+ if (data.size() > increment && allow_incr) {
+ long bytes = data.size();
+ XChangeProperty(X11->display, window, property,
+ ATOM(INCR), 32, PropModeReplace, (uchar *) &bytes, 1);
+
+ (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment);
+ return property;
+ }
+
+ // make sure we can perform the XChangeProperty in a single request
+ if (data.size() > increment)
+ return XNone; // ### perhaps use several XChangeProperty calls w/ PropModeAppend?
+ int dataSize = data.size() / (dataFormat / 8);
+ // use a single request to transfer data
+ XChangeProperty(X11->display, window, property, atomFormat,
+ dataFormat, PropModeReplace, (uchar *) data.data(),
+ dataSize);
+ }
+ return property;
+}
+
+/*! \internal
+ Internal cleanup for Windows.
+*/
+void QClipboard::ownerDestroyed()
+{ }
+
+
+/*! \internal
+ Internal optimization for Windows.
+*/
+void QClipboard::connectNotify(const char *)
+{ }
+
+
+bool QClipboard::event(QEvent *e)
+{
+ if (e->type() == QEvent::Timer) {
+ QTimerEvent *te = (QTimerEvent *) e;
+
+ if (waiting_for_data) // should never happen
+ return false;
+
+ if (te->timerId() == timer_id) {
+ killTimer(timer_id);
+ timer_id = 0;
+
+ timer_event_clear = true;
+ if (selection_watcher) // clear selection
+ selectionData()->clear();
+ if (clipboard_watcher) // clear clipboard
+ clipboardData()->clear();
+ timer_event_clear = false;
+
+ return true;
+ } else if (te->timerId() == pending_timer_id) {
+ // I hate klipper
+ killTimer(pending_timer_id);
+ pending_timer_id = 0;
+
+ if (pending_clipboard_changed) {
+ pending_clipboard_changed = false;
+ clipboardData()->clear();
+ emitChanged(QClipboard::Clipboard);
+ }
+ if (pending_selection_changed) {
+ pending_selection_changed = false;
+ selectionData()->clear();
+ emitChanged(QClipboard::Selection);
+ }
+
+ return true;
+ } else if (te->timerId() == incr_timer_id) {
+ killTimer(incr_timer_id);
+ incr_timer_id = 0;
+
+ qt_xclb_incr_timeout();
+
+ return true;
+ } else {
+ return QObject::event(e);
+ }
+ } else if (e->type() != QEvent::Clipboard) {
+ return QObject::event(e);
+ }
+
+ XEvent *xevent = (XEvent *)(((QClipboardEvent *)e)->data());
+ Display *dpy = X11->display;
+
+ if (!xevent) {
+ // That means application exits and we need to give clipboard
+ // content to the clipboard manager.
+ // First we check if there is a clipboard manager.
+ if (XGetSelectionOwner(X11->display, ATOM(CLIPBOARD_MANAGER)) == XNone
+ || !owner)
+ return true;
+
+ Window ownerId = owner->internalWinId();
+ Q_ASSERT(ownerId);
+ // we delete the property so the manager saves all TARGETS.
+ XDeleteProperty(X11->display, ownerId, ATOM(_QT_SELECTION));
+ XConvertSelection(X11->display, ATOM(CLIPBOARD_MANAGER), ATOM(SAVE_TARGETS),
+ ATOM(_QT_SELECTION), ownerId, X11->time);
+ XSync(dpy, false);
+
+ XEvent event;
+ // waiting until the clipboard manager fetches the content.
+ if (!X11->clipboardWaitForEvent(ownerId, SelectionNotify, &event, 10000)) {
+ qWarning("QClipboard: Unable to receive an event from the "
+ "clipboard manager in a reasonable time");
+ }
+
+ return true;
+ }
+
+ switch (xevent->type) {
+
+ case SelectionClear:
+ // new selection owner
+ if (xevent->xselectionclear.selection == XA_PRIMARY) {
+ QClipboardData *d = selectionData();
+
+ // ignore the event if it was generated before we gained selection ownership
+ if (d->timestamp != CurrentTime && xevent->xselectionclear.time <= d->timestamp)
+ break;
+
+ DEBUG("QClipboard: new selection owner 0x%lx at time %lx (ours %lx)",
+ XGetSelectionOwner(dpy, XA_PRIMARY),
+ xevent->xselectionclear.time, d->timestamp);
+
+ if (! waiting_for_data) {
+ d->clear();
+ emitChanged(QClipboard::Selection);
+ } else {
+ pending_selection_changed = true;
+ if (! pending_timer_id)
+ pending_timer_id = QApplication::clipboard()->startTimer(0);
+ }
+ } else if (xevent->xselectionclear.selection == ATOM(CLIPBOARD)) {
+ QClipboardData *d = clipboardData();
+
+ // ignore the event if it was generated before we gained selection ownership
+ if (d->timestamp != CurrentTime && xevent->xselectionclear.time <= d->timestamp)
+ break;
+
+ DEBUG("QClipboard: new clipboard owner 0x%lx at time %lx (%lx)",
+ XGetSelectionOwner(dpy, ATOM(CLIPBOARD)),
+ xevent->xselectionclear.time, d->timestamp);
+
+ if (! waiting_for_data) {
+ d->clear();
+ emitChanged(QClipboard::Clipboard);
+ } else {
+ pending_clipboard_changed = true;
+ if (! pending_timer_id)
+ pending_timer_id = QApplication::clipboard()->startTimer(0);
+ }
+ } else {
+ qWarning("QClipboard: Unknown SelectionClear event received");
+ return false;
+ }
+ break;
+
+ case SelectionNotify:
+ /*
+ Something has delivered data to us, but this was not caught
+ by QClipboardWatcher::getDataInFormat()
+
+ Just skip the event to prevent Bad Things (tm) from
+ happening later on...
+ */
+ break;
+
+ case SelectionRequest:
+ {
+ // someone wants our data
+ XSelectionRequestEvent *req = &xevent->xselectionrequest;
+
+ if (requestor && req->requestor == requestor->internalWinId())
+ break;
+
+ XEvent event;
+ event.xselection.type = SelectionNotify;
+ event.xselection.display = req->display;
+ event.xselection.requestor = req->requestor;
+ event.xselection.selection = req->selection;
+ event.xselection.target = req->target;
+ event.xselection.property = XNone;
+ event.xselection.time = req->time;
+
+ DEBUG("QClipboard: SelectionRequest from %lx\n"
+ " selection 0x%lx (%s) target 0x%lx (%s)",
+ req->requestor,
+ req->selection,
+ X11->xdndAtomToString(req->selection).data(),
+ req->target,
+ X11->xdndAtomToString(req->target).data());
+
+ QClipboardData *d;
+ if (req->selection == XA_PRIMARY) {
+ d = selectionData();
+ } else if (req->selection == ATOM(CLIPBOARD)) {
+ d = clipboardData();
+ } else {
+ qWarning("QClipboard: Unknown selection '%lx'", req->selection);
+ XSendEvent(dpy, req->requestor, False, NoEventMask, &event);
+ break;
+ }
+
+ if (! d->source()) {
+ qWarning("QClipboard: Cannot transfer data, no data available");
+ XSendEvent(dpy, req->requestor, False, NoEventMask, &event);
+ break;
+ }
+
+ DEBUG("QClipboard: SelectionRequest at time %lx (ours %lx)",
+ req->time, d->timestamp);
+
+ if (d->timestamp == CurrentTime // we don't own the selection anymore
+ || (req->time != CurrentTime && req->time < d->timestamp)) {
+ DEBUG("QClipboard: SelectionRequest too old");
+ XSendEvent(dpy, req->requestor, False, NoEventMask, &event);
+ break;
+ }
+
+ Atom xa_targets = ATOM(TARGETS);
+ Atom xa_multiple = ATOM(MULTIPLE);
+ Atom xa_timestamp = ATOM(TIMESTAMP);
+
+ struct AtomPair { Atom target; Atom property; } *multi = 0;
+ Atom multi_type = XNone;
+ int multi_format = 0;
+ int nmulti = 0;
+ int imulti = -1;
+ bool multi_writeback = false;
+
+ if (req->target == xa_multiple) {
+ QByteArray multi_data;
+ if (req->property == XNone
+ || !X11->clipboardReadProperty(req->requestor, req->property, false, &multi_data,
+ 0, &multi_type, &multi_format)
+ || multi_format != 32) {
+ // MULTIPLE property not formatted correctly
+ XSendEvent(dpy, req->requestor, False, NoEventMask, &event);
+ break;
+ }
+ nmulti = multi_data.size()/sizeof(*multi);
+ multi = new AtomPair[nmulti];
+ memcpy(multi,multi_data.data(),multi_data.size());
+ imulti = 0;
+ }
+
+ for (; imulti < nmulti; ++imulti) {
+ Atom target;
+ Atom property;
+
+ if (multi) {
+ target = multi[imulti].target;
+ property = multi[imulti].property;
+ } else {
+ target = req->target;
+ property = req->property;
+ if (property == XNone) // obsolete client
+ property = target;
+ }
+
+ Atom ret = XNone;
+ if (target == XNone || property == XNone) {
+ ;
+ } else if (target == xa_timestamp) {
+ if (d->timestamp != CurrentTime) {
+ XChangeProperty(dpy, req->requestor, property, XA_INTEGER, 32,
+ PropModeReplace, (uchar *) &d->timestamp, 1);
+ ret = property;
+ } else {
+ qWarning("QClipboard: Invalid data timestamp");
+ }
+ } else if (target == xa_targets) {
+ ret = send_targets_selection(d, req->requestor, property);
+ } else {
+ ret = send_selection(d, target, req->requestor, property);
+ }
+
+ if (nmulti > 0) {
+ if (ret == XNone) {
+ multi[imulti].property = XNone;
+ multi_writeback = true;
+ }
+ } else {
+ event.xselection.property = ret;
+ break;
+ }
+ }
+
+ if (nmulti > 0) {
+ if (multi_writeback) {
+ // according to ICCCM 2.6.2 says to put None back
+ // into the original property on the requestor window
+ XChangeProperty(dpy, req->requestor, req->property, multi_type, 32,
+ PropModeReplace, (uchar *) multi, nmulti * 2);
+ }
+
+ delete [] multi;
+ event.xselection.property = req->property;
+ }
+
+ // send selection notify to requestor
+ XSendEvent(dpy, req->requestor, False, NoEventMask, &event);
+
+ DEBUG("QClipboard: SelectionNotify to 0x%lx\n"
+ " property 0x%lx (%s)",
+ req->requestor, event.xselection.property,
+ X11->xdndAtomToString(event.xselection.property).data());
+ }
+ break;
+ }
+
+ return true;
+}
+
+
+
+
+
+
+QClipboardWatcher::QClipboardWatcher(QClipboard::Mode mode)
+ : QInternalMimeData()
+{
+ switch (mode) {
+ case QClipboard::Selection:
+ atom = XA_PRIMARY;
+ break;
+
+ case QClipboard::Clipboard:
+ atom = ATOM(CLIPBOARD);
+ break;
+
+ default:
+ qWarning("QClipboardWatcher: Internal error: Unsupported clipboard mode");
+ break;
+ }
+
+ setupOwner();
+}
+
+QClipboardWatcher::~QClipboardWatcher()
+{
+ if(selection_watcher == this)
+ selection_watcher = 0;
+ if(clipboard_watcher == this)
+ clipboard_watcher = 0;
+}
+
+bool QClipboardWatcher::empty() const
+{
+ Display *dpy = X11->display;
+ Window win = XGetSelectionOwner(dpy, atom);
+
+ if(win == requestor->internalWinId()) {
+ qWarning("QClipboardWatcher::empty: Internal error: Application owns the selection");
+ return true;
+ }
+
+ return win == XNone;
+}
+
+QStringList QClipboardWatcher::formats_sys() const
+{
+ if (empty())
+ return QStringList();
+
+ if (!formatList.count()) {
+ // get the list of targets from the current clipboard owner - we do this
+ // once so that multiple calls to this function don't require multiple
+ // server round trips...
+
+ format_atoms = getDataInFormat(ATOM(TARGETS));
+
+ if (format_atoms.size() > 0) {
+ Atom *targets = (Atom *) format_atoms.data();
+ int size = format_atoms.size() / sizeof(Atom);
+
+ for (int i = 0; i < size; ++i) {
+ if (targets[i] == 0)
+ continue;
+
+ QStringList formatsForAtom = X11->xdndMimeFormatsForAtom(targets[i]);
+ for (int j = 0; j < formatsForAtom.size(); ++j) {
+ if (!formatList.contains(formatsForAtom.at(j)))
+ formatList.append(formatsForAtom.at(j));
+ }
+ VDEBUG(" format: %s", X11->xdndAtomToString(targets[i]).data());
+ VDEBUG(" data:\n%s\n", getDataInFormat(targets[i]).data());
+ }
+ DEBUG("QClipboardWatcher::format: %d formats available", formatList.count());
+ }
+ }
+
+ return formatList;
+}
+
+bool QClipboardWatcher::hasFormat_sys(const QString &format) const
+{
+ QStringList list = formats();
+ return list.contains(format);
+}
+
+QVariant QClipboardWatcher::retrieveData_sys(const QString &fmt, QVariant::Type requestedType) const
+{
+ if (fmt.isEmpty() || empty())
+ return QByteArray();
+
+ (void)formats(); // trigger update of format list
+ DEBUG("QClipboardWatcher::data: fetching format '%s'", fmt.toLatin1().data());
+
+ QList<Atom> atoms;
+ Atom *targets = (Atom *) format_atoms.data();
+ int size = format_atoms.size() / sizeof(Atom);
+ for (int i = 0; i < size; ++i)
+ atoms.append(targets[i]);
+
+ QByteArray encoding;
+ Atom fmtatom = X11->xdndMimeAtomForFormat(fmt, requestedType, atoms, &encoding);
+
+ if (fmtatom == 0)
+ return QVariant();
+
+ return X11->xdndMimeConvertToFormat(fmtatom, getDataInFormat(fmtatom), fmt, requestedType, encoding);
+}
+
+QByteArray QClipboardWatcher::getDataInFormat(Atom fmtatom) const
+{
+ QByteArray buf;
+
+ Display *dpy = X11->display;
+ requestor->createWinId();
+ Window win = requestor->internalWinId();
+ Q_ASSERT(requestor->testAttribute(Qt::WA_WState_Created));
+
+ DEBUG("QClipboardWatcher::getDataInFormat: selection '%s' format '%s'",
+ X11->xdndAtomToString(atom).data(), X11->xdndAtomToString(fmtatom).data());
+
+ XSelectInput(dpy, win, NoEventMask); // don't listen for any events
+
+ XDeleteProperty(dpy, win, ATOM(_QT_SELECTION));
+ XConvertSelection(dpy, atom, fmtatom, ATOM(_QT_SELECTION), win, X11->time);
+ XSync(dpy, false);
+
+ VDEBUG("QClipboardWatcher::getDataInFormat: waiting for SelectionNotify event");
+
+ XEvent xevent;
+ if (!X11->clipboardWaitForEvent(win,SelectionNotify,&xevent,clipboard_timeout) ||
+ xevent.xselection.property == XNone) {
+ DEBUG("QClipboardWatcher::getDataInFormat: format not available");
+ return buf;
+ }
+
+ VDEBUG("QClipboardWatcher::getDataInFormat: fetching data...");
+
+ Atom type;
+ XSelectInput(dpy, win, PropertyChangeMask);
+
+ if (X11->clipboardReadProperty(win, ATOM(_QT_SELECTION), true, &buf, 0, &type, 0)) {
+ if (type == ATOM(INCR)) {
+ int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0;
+ buf = X11->clipboardReadIncrementalProperty(win, ATOM(_QT_SELECTION), nbytes, false);
+ }
+ }
+
+ XSelectInput(dpy, win, NoEventMask);
+
+ DEBUG("QClipboardWatcher::getDataInFormat: %d bytes received", buf.size());
+
+ return buf;
+}
+
+
+const QMimeData* QClipboard::mimeData(Mode mode) const
+{
+ QClipboardData *d = 0;
+ switch (mode) {
+ case Selection:
+ d = selectionData();
+ break;
+ case Clipboard:
+ d = clipboardData();
+ break;
+ default:
+ qWarning("QClipboard::mimeData: unsupported mode '%d'", mode);
+ return 0;
+ }
+
+ if (! d->source() && ! timer_event_clear) {
+ if (mode == Selection) {
+ if (! selection_watcher)
+ selection_watcher = new QClipboardWatcher(mode);
+ d->setSource(selection_watcher);
+ } else {
+ if (! clipboard_watcher)
+ clipboard_watcher = new QClipboardWatcher(mode);
+ d->setSource(clipboard_watcher);
+ }
+
+ if (! timer_id) {
+ // start a zero timer - we will clear cached data when the timer
+ // times out, which will be the next time we hit the event loop...
+ // that way, the data is cached long enough for calls within a single
+ // loop/function, but the data doesn't linger around in case the selection
+ // changes
+ QClipboard *that = ((QClipboard *) this);
+ timer_id = that->startTimer(0);
+ }
+ }
+
+ return d->source();
+}
+
+
+void QClipboard::setMimeData(QMimeData* src, Mode mode)
+{
+ Atom atom, sentinel_atom;
+ QClipboardData *d;
+ switch (mode) {
+ case Selection:
+ atom = XA_PRIMARY;
+ sentinel_atom = ATOM(_QT_SELECTION_SENTINEL);
+ d = selectionData();
+ break;
+
+ case Clipboard:
+ atom = ATOM(CLIPBOARD);
+ sentinel_atom = ATOM(_QT_CLIPBOARD_SENTINEL);
+ d = clipboardData();
+ break;
+
+ default:
+ qWarning("QClipboard::setMimeData: unsupported mode '%d'", mode);
+ return;
+ }
+
+ Display *dpy = X11->display;
+ Window newOwner;
+
+ if (! src) { // no data, clear clipboard contents
+ newOwner = XNone;
+ d->clear();
+ } else {
+ setupOwner();
+
+ newOwner = owner->internalWinId();
+
+ d->setSource(src);
+ d->timestamp = X11->time;
+ }
+
+ Window prevOwner = XGetSelectionOwner(dpy, atom);
+ // use X11->time, since d->timestamp == CurrentTime when clearing
+ XSetSelectionOwner(dpy, atom, newOwner, X11->time);
+
+ if (mode == Selection)
+ emitChanged(QClipboard::Selection);
+ else
+ emitChanged(QClipboard::Clipboard);
+
+ if (XGetSelectionOwner(dpy, atom) != newOwner) {
+ qWarning("QClipboard::setData: Cannot set X11 selection owner for %s",
+ X11->xdndAtomToString(atom).data());
+ d->clear();
+ return;
+ }
+
+ // Signal to other Qt processes that the selection has changed
+ Window owners[2];
+ owners[0] = newOwner;
+ owners[1] = prevOwner;
+ XChangeProperty(dpy, QApplication::desktop()->screen(0)->internalWinId(),
+ sentinel_atom, XA_WINDOW, 32, PropModeReplace,
+ (unsigned char*)&owners, 2);
+}
+
+
+/*
+ Called by the main event loop in qapplication_x11.cpp when either
+ the _QT_SELECTION_SENTINEL property has been changed (i.e. when some
+ Qt process has performed QClipboard::setData()) or when Xfixes told
+ us that an other application changed the selection. If it returns
+ true, the QClipBoard dataChanged() signal should be emitted.
+*/
+
+bool qt_check_selection_sentinel()
+{
+ bool doIt = true;
+ if (owner && !X11->use_xfixes) {
+ /*
+ Since the X selection mechanism cannot give any signal when
+ the selection has changed, we emulate it (for Qt processes) here.
+ The notification should be ignored in case of either
+ a) This is the process that did setData (because setData()
+ then has already emitted dataChanged())
+ b) This is the process that owned the selection when dataChanged()
+ was called (because we have then received a SelectionClear event,
+ and have already emitted dataChanged() as a result of that)
+ */
+
+ unsigned char *retval;
+ Atom actualType;
+ int actualFormat;
+ ulong nitems;
+ ulong bytesLeft;
+
+ if (XGetWindowProperty(X11->display,
+ QApplication::desktop()->screen(0)->internalWinId(),
+ ATOM(_QT_SELECTION_SENTINEL), 0, 2, False, XA_WINDOW,
+ &actualType, &actualFormat, &nitems,
+ &bytesLeft, &retval) == Success) {
+ Window *owners = (Window *)retval;
+ if (actualType == XA_WINDOW && actualFormat == 32 && nitems == 2) {
+ Window win = owner->internalWinId();
+ if (owners[0] == win || owners[1] == win)
+ doIt = false;
+ }
+
+ XFree(owners);
+ }
+ }
+
+ if (doIt) {
+ if (waiting_for_data) {
+ pending_selection_changed = true;
+ if (! pending_timer_id)
+ pending_timer_id = QApplication::clipboard()->startTimer(0);
+ doIt = false;
+ } else {
+ selectionData()->clear();
+ }
+ }
+
+ return doIt;
+}
+
+
+bool qt_check_clipboard_sentinel()
+{
+ bool doIt = true;
+ if (owner && !X11->use_xfixes) {
+ unsigned char *retval;
+ Atom actualType;
+ int actualFormat;
+ unsigned long nitems, bytesLeft;
+
+ if (XGetWindowProperty(X11->display,
+ QApplication::desktop()->screen(0)->internalWinId(),
+ ATOM(_QT_CLIPBOARD_SENTINEL), 0, 2, False, XA_WINDOW,
+ &actualType, &actualFormat, &nitems, &bytesLeft,
+ &retval) == Success) {
+ Window *owners = (Window *)retval;
+ if (actualType == XA_WINDOW && actualFormat == 32 && nitems == 2) {
+ Window win = owner->internalWinId();
+ if (owners[0] == win || owners[1] == win)
+ doIt = false;
+ }
+
+ XFree(owners);
+ }
+ }
+
+ if (doIt) {
+ if (waiting_for_data) {
+ pending_clipboard_changed = true;
+ if (! pending_timer_id)
+ pending_timer_id = QApplication::clipboard()->startTimer(0);
+ doIt = false;
+ } else {
+ clipboardData()->clear();
+ }
+ }
+
+ return doIt;
+}
+
+bool qt_xfixes_selection_changed(Window selectionOwner, Time timestamp)
+{
+ QClipboardData *d = selectionData();
+#ifdef QCLIPBOARD_DEBUG
+ DEBUG("qt_xfixes_selection_changed: owner = %u; selectionOwner = %u; internal timestamp = %u; external timestamp = %u",
+ (unsigned int)(owner ? (int)owner->internalWinId() : 0), (unsigned int)selectionOwner,
+ (unsigned int)(d ? d->timestamp : 0), (unsigned int)timestamp);
+#endif
+ if (!owner || (selectionOwner && selectionOwner != owner->internalWinId()) ||
+ (!selectionOwner && (d->timestamp == CurrentTime || d->timestamp < timestamp)))
+ return qt_check_selection_sentinel();
+ return false;
+}
+
+bool qt_xfixes_clipboard_changed(Window clipboardOwner, Time timestamp)
+{
+ QClipboardData *d = clipboardData();
+#ifdef QCLIPBOARD_DEBUG
+ DEBUG("qt_xfixes_clipboard_changed: owner = %u; clipboardOwner = %u; internal timestamp = %u; external timestamp = %u",
+ (unsigned int)(owner ? (int)owner->internalWinId() : 0), (unsigned int)clipboardOwner,
+ (unsigned int)(d ? d->timestamp : 0), (unsigned int)timestamp);
+#endif
+ if (!owner || (clipboardOwner && clipboardOwner != owner->internalWinId()) ||
+ (!clipboardOwner && (d->timestamp == CurrentTime || d->timestamp < timestamp)))
+ return qt_check_clipboard_sentinel();
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_CLIPBOARD
diff --git a/src/widgets/platforms/x11/qcolormap_x11.cpp b/src/widgets/platforms/x11/qcolormap_x11.cpp
new file mode 100644
index 0000000000..05eefa455b
--- /dev/null
+++ b/src/widgets/platforms/x11/qcolormap_x11.cpp
@@ -0,0 +1,670 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qcolormap.h"
+
+#include "qapplication.h"
+#include "qdebug.h"
+#include "qdesktopwidget.h"
+#include "qvarlengtharray.h"
+
+#include "qx11info_x11.h"
+#include <private/qt_x11_p.h>
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+class QColormapPrivate
+{
+public:
+ QColormapPrivate()
+ : ref(1), mode(QColormap::Direct), depth(0),
+ colormap(0), defaultColormap(true),
+ visual(0), defaultVisual(true),
+ r_max(0), g_max(0), b_max(0),
+ r_shift(0), g_shift(0), b_shift(0)
+ {}
+
+ QAtomicInt ref;
+
+ QColormap::Mode mode;
+ int depth;
+
+ Colormap colormap;
+ bool defaultColormap;
+
+ Visual *visual;
+ bool defaultVisual;
+
+ int r_max;
+ int g_max;
+ int b_max;
+
+ uint r_shift;
+ uint g_shift;
+ uint b_shift;
+
+ QVector<QColor> colors;
+ QVector<int> pixels;
+};
+
+
+static uint right_align(uint v)
+{
+ while (!(v & 0x1))
+ v >>= 1;
+ return v;
+}
+
+static int lowest_bit(uint v)
+{
+ int i;
+ uint b = 1u;
+ for (i = 0; ((v & b) == 0u) && i < 32; ++i)
+ b <<= 1u;
+ return i == 32 ? -1 : i;
+}
+
+static int cube_root(int v)
+{
+ if (v == 1)
+ return 1;
+ // brute force algorithm
+ int i = 1;
+ for (;;) {
+ const int b = i * i * i;
+ if (b <= v) {
+ ++i;
+ } else {
+ --i;
+ break;
+ }
+ }
+ return i;
+}
+
+static Visual *find_visual(Display *display,
+ int screen,
+ int visual_class,
+ int visual_id,
+ int *depth,
+ bool *defaultVisual)
+{
+ XVisualInfo *vi, rvi;
+ int count;
+
+ uint mask = VisualScreenMask;
+ rvi.screen = screen;
+
+ if (visual_class != -1) {
+ rvi.c_class = visual_class;
+ mask |= VisualClassMask;
+ }
+ if (visual_id != -1) {
+ rvi.visualid = visual_id;
+ mask |= VisualIDMask;
+ }
+
+ Visual *visual = DefaultVisual(display, screen);
+ *defaultVisual = true;
+ *depth = DefaultDepth(display, screen);
+
+ vi = XGetVisualInfo(display, mask, &rvi, &count);
+ if (vi) {
+ int best = 0;
+ for (int x = 0; x < count; ++x) {
+ if (vi[x].depth > vi[best].depth)
+ best = x;
+ }
+ if (best >= 0 && best <= count && vi[best].visualid != XVisualIDFromVisual(visual)) {
+ visual = vi[best].visual;
+ *defaultVisual = (visual == DefaultVisual(display, screen));
+ *depth = vi[best].depth;
+ }
+ }
+ if (vi)
+ XFree((char *)vi);
+ return visual;
+}
+
+static void query_colormap(QColormapPrivate *d, int screen)
+{
+ Display *display = QX11Info::display();
+
+ // query existing colormap
+ int q_colors = (((1u << d->depth) > 256u) ? 256u : (1u << d->depth));
+ XColor queried[256];
+ memset(queried, 0, sizeof(queried));
+ for (int x = 0; x < q_colors; ++x)
+ queried[x].pixel = x;
+ XQueryColors(display, d->colormap, queried, q_colors);
+
+ d->colors.resize(q_colors);
+ for (int x = 0; x < q_colors; ++x) {
+ if (queried[x].red == 0
+ && queried[x].green == 0
+ && queried[x].blue == 0
+ && queried[x].pixel != BlackPixel(display, screen)) {
+ // unallocated color cell, skip it
+ continue;
+ }
+
+ d->colors[x] = QColor::fromRgbF(queried[x].red / float(USHRT_MAX),
+ queried[x].green / float(USHRT_MAX),
+ queried[x].blue / float(USHRT_MAX));
+ }
+
+ // for missing colors, find the closest color in the existing colormap
+ Q_ASSERT(d->pixels.size());
+ for (int x = 0; x < d->pixels.size(); ++x) {
+ if (d->pixels.at(x) != -1)
+ continue;
+
+ QRgb rgb;
+ if (d->mode == QColormap::Indexed) {
+ const int r = (x / (d->g_max * d->b_max)) % d->r_max;
+ const int g = (x / d->b_max) % d->g_max;
+ const int b = x % d->b_max;
+ rgb = qRgb((r * 0xff + (d->r_max - 1) / 2) / (d->r_max - 1),
+ (g * 0xff + (d->g_max - 1) / 2) / (d->g_max - 1),
+ (b * 0xff + (d->b_max - 1) / 2) / (d->b_max - 1));
+ } else {
+ rgb = qRgb(x, x, x);
+ }
+
+ // find closest color
+ int mindist = INT_MAX, best = -1;
+ for (int y = 0; y < q_colors; ++y) {
+ int r = qRed(rgb) - (queried[y].red >> 8);
+ int g = qGreen(rgb) - (queried[y].green >> 8);
+ int b = qBlue(rgb) - (queried[y].blue >> 8);
+ int dist = (r * r) + (g * g) + (b * b);
+ if (dist < mindist) {
+ mindist = dist;
+ best = y;
+ }
+ }
+
+ Q_ASSERT(best >= 0 && best < q_colors);
+ if (d->visual->c_class & 1) {
+ XColor xcolor;
+ xcolor.red = queried[best].red;
+ xcolor.green = queried[best].green;
+ xcolor.blue = queried[best].blue;
+ xcolor.pixel = queried[best].pixel;
+
+ if (XAllocColor(display, d->colormap, &xcolor)) {
+ d->pixels[x] = xcolor.pixel;
+ } else {
+ // some weird stuff is going on...
+ d->pixels[x] = (qGray(rgb) < 127
+ ? BlackPixel(display, screen)
+ : WhitePixel(display, screen));
+ }
+ } else {
+ d->pixels[x] = best;
+ }
+ }
+}
+
+static void init_gray(QColormapPrivate *d, int screen)
+{
+ d->pixels.resize(d->r_max);
+
+ for (int g = 0; g < d->g_max; ++g) {
+ const int gray = (g * 0xff + (d->r_max - 1) / 2) / (d->r_max - 1);
+ const QRgb rgb = qRgb(gray, gray, gray);
+
+ d->pixels[g] = -1;
+
+ if (d->visual->c_class & 1) {
+ XColor xcolor;
+ xcolor.red = qRed(rgb) * 0x101;
+ xcolor.green = qGreen(rgb) * 0x101;
+ xcolor.blue = qBlue(rgb) * 0x101;
+ xcolor.pixel = 0ul;
+
+ if (XAllocColor(QX11Info::display(), d->colormap, &xcolor))
+ d->pixels[g] = xcolor.pixel;
+ }
+ }
+
+ query_colormap(d, screen);
+}
+
+static void init_indexed(QColormapPrivate *d, int screen)
+{
+ d->pixels.resize(d->r_max * d->g_max * d->b_max);
+
+ // create color cube
+ for (int x = 0, r = 0; r < d->r_max; ++r) {
+ for (int g = 0; g < d->g_max; ++g) {
+ for (int b = 0; b < d->b_max; ++b, ++x) {
+ const QRgb rgb = qRgb((r * 0xff + (d->r_max - 1) / 2) / (d->r_max - 1),
+ (g * 0xff + (d->g_max - 1) / 2) / (d->g_max - 1),
+ (b * 0xff + (d->b_max - 1) / 2) / (d->b_max - 1));
+
+ d->pixels[x] = -1;
+
+ if (d->visual->c_class & 1) {
+ XColor xcolor;
+ xcolor.red = qRed(rgb) * 0x101;
+ xcolor.green = qGreen(rgb) * 0x101;
+ xcolor.blue = qBlue(rgb) * 0x101;
+ xcolor.pixel = 0ul;
+
+ if (XAllocColor(QX11Info::display(), d->colormap, &xcolor))
+ d->pixels[x] = xcolor.pixel;
+ }
+ }
+ }
+ }
+
+ query_colormap(d, screen);
+}
+
+static void init_direct(QColormapPrivate *d, bool ownColormap)
+{
+ if (d->visual->c_class != DirectColor || !ownColormap)
+ return;
+
+ // preallocate 768 on the stack, so that we don't have to malloc
+ // for the common case (<= 24 bpp)
+ QVarLengthArray<XColor, 768> colorTable(d->r_max + d->g_max + d->b_max);
+ int i = 0;
+
+ for (int r = 0; r < d->r_max; ++r) {
+ colorTable[i].red = r << 8 | r;
+ colorTable[i].pixel = r << d->r_shift;
+ colorTable[i].flags = DoRed;
+ ++i;
+ }
+
+ for (int g = 0; g < d->g_max; ++g) {
+ colorTable[i].green = g << 8 | g;
+ colorTable[i].pixel = g << d->g_shift;
+ colorTable[i].flags = DoGreen;
+ ++i;
+ }
+
+ for (int b = 0; b < d->b_max; ++b) {
+ colorTable[i].blue = (b << 8 | b);
+ colorTable[i].pixel = b << d->b_shift;
+ colorTable[i].flags = DoBlue;
+ ++i;
+ }
+
+ XStoreColors(X11->display, d->colormap, colorTable.data(), colorTable.count());
+}
+
+static QColormap **cmaps = 0;
+
+void QColormap::initialize()
+{
+ Display *display = QX11Info::display();
+ const int screens = ScreenCount(display);
+
+ cmaps = new QColormap*[screens];
+
+ for (int i = 0; i < screens; ++i) {
+ cmaps[i] = new QColormap;
+ QColormapPrivate * const d = cmaps[i]->d;
+
+ bool use_stdcmap = false;
+ int color_count = X11->color_count;
+
+ // defaults
+ d->depth = DefaultDepth(display, i);
+ d->colormap = DefaultColormap(display, i);
+ d->defaultColormap = true;
+ d->visual = DefaultVisual(display, i);
+ d->defaultVisual = true;
+
+ Visual *argbVisual = 0;
+
+ if (X11->visual && i == DefaultScreen(display)) {
+ // only use the outside colormap on the default screen
+ d->visual = find_visual(display, i, X11->visual->c_class,
+ XVisualIDFromVisual(X11->visual),
+ &d->depth, &d->defaultVisual);
+ } else if ((X11->visual_class != -1 && X11->visual_class >= 0 && X11->visual_class < 6)
+ || (X11->visual_id != -1)) {
+ // look for a specific visual or type of visual
+ d->visual = find_visual(display, i, X11->visual_class, X11->visual_id,
+ &d->depth, &d->defaultVisual);
+ } else if (QApplication::colorSpec() == QApplication::ManyColor) {
+ // look for a TrueColor w/ a depth higher than 8bpp
+ d->visual = find_visual(display, i, TrueColor, -1, &d->depth, &d->defaultVisual);
+ if (d->depth <= 8) {
+ d->visual = DefaultVisual(display, i);
+ d->defaultVisual = true;
+ color_count = 216;
+ }
+ } else if (!X11->custom_cmap) {
+ XStandardColormap *stdcmap = 0;
+ int ncmaps = 0;
+
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender) {
+ int nvi;
+ XVisualInfo templ;
+ templ.screen = i;
+ templ.depth = 32;
+ templ.c_class = TrueColor;
+ XVisualInfo *xvi = XGetVisualInfo(X11->display, VisualScreenMask |
+ VisualDepthMask |
+ VisualClassMask, &templ, &nvi);
+ for (int idx = 0; idx < nvi; ++idx) {
+ XRenderPictFormat *format = XRenderFindVisualFormat(X11->display,
+ xvi[idx].visual);
+ if (format->type == PictTypeDirect && format->direct.alphaMask) {
+ argbVisual = xvi[idx].visual;
+ break;
+ }
+ }
+ XFree(xvi);
+ }
+#endif
+ if (XGetRGBColormaps(display, RootWindow(display, i),
+ &stdcmap, &ncmaps, XA_RGB_DEFAULT_MAP)) {
+ if (stdcmap) {
+ for (int c = 0; c < ncmaps; ++c) {
+ if (!stdcmap[c].red_max ||
+ !stdcmap[c].green_max ||
+ !stdcmap[c].blue_max ||
+ !stdcmap[c].red_mult ||
+ !stdcmap[c].green_mult ||
+ !stdcmap[c].blue_mult)
+ continue; // invalid stdcmap
+
+ XVisualInfo proto;
+ proto.visualid = stdcmap[c].visualid;
+ proto.screen = i;
+
+ int nvisuals = 0;
+ XVisualInfo *vi = XGetVisualInfo(display, VisualIDMask | VisualScreenMask,
+ &proto, &nvisuals);
+ if (vi) {
+ if (nvisuals > 0) {
+ use_stdcmap = true;
+
+ d->mode = ((vi[0].visual->c_class < StaticColor)
+ ? Gray
+ : ((vi[0].visual->c_class < TrueColor)
+ ? Indexed
+ : Direct));
+
+ d->depth = vi[0].depth;
+ d->colormap = stdcmap[c].colormap;
+ d->defaultColormap = true;
+ d->visual = vi[0].visual;
+ d->defaultVisual = (d->visual == DefaultVisual(display, i));
+
+ d->r_max = stdcmap[c].red_max + 1;
+ d->g_max = stdcmap[c].green_max + 1;
+ d->b_max = stdcmap[c].blue_max + 1;
+
+ if (d->mode == Direct) {
+ // calculate offsets
+ d->r_shift = lowest_bit(d->visual->red_mask);
+ d->g_shift = lowest_bit(d->visual->green_mask);
+ d->b_shift = lowest_bit(d->visual->blue_mask);
+ } else {
+ d->r_shift = 0;
+ d->g_shift = 0;
+ d->b_shift = 0;
+ }
+ }
+ XFree(vi);
+ }
+ break;
+ }
+ XFree(stdcmap);
+ }
+ }
+ }
+ if (!use_stdcmap) {
+ switch (d->visual->c_class) {
+ case StaticGray:
+ d->mode = Gray;
+
+ d->r_max = d->g_max = d->b_max = d->visual->map_entries;
+ break;
+
+ case XGrayScale:
+ d->mode = Gray;
+
+ // follow precedent set in libXmu...
+ if (color_count != 0)
+ d->r_max = d->g_max = d->b_max = color_count;
+ else if (d->visual->map_entries > 65000)
+ d->r_max = d->g_max = d->b_max = 4096;
+ else if (d->visual->map_entries > 4000)
+ d->r_max = d->g_max = d->b_max = 512;
+ else if (d->visual->map_entries > 250)
+ d->r_max = d->g_max = d->b_max = 12;
+ else
+ d->r_max = d->g_max = d->b_max = 4;
+ break;
+
+ case StaticColor:
+ d->mode = Indexed;
+
+ d->r_max = right_align(d->visual->red_mask) + 1;
+ d->g_max = right_align(d->visual->green_mask) + 1;
+ d->b_max = right_align(d->visual->blue_mask) + 1;
+ break;
+
+ case PseudoColor:
+ d->mode = Indexed;
+
+ // follow precedent set in libXmu...
+ if (color_count != 0)
+ d->r_max = d->g_max = d->b_max = cube_root(color_count);
+ else if (d->visual->map_entries > 65000)
+ d->r_max = d->g_max = d->b_max = 27;
+ else if (d->visual->map_entries > 4000)
+ d->r_max = d->g_max = d->b_max = 12;
+ else if (d->visual->map_entries > 250)
+ d->r_max = d->g_max = d->b_max = cube_root(d->visual->map_entries - 125);
+ else
+ d->r_max = d->g_max = d->b_max = cube_root(d->visual->map_entries);
+ break;
+
+ case TrueColor:
+ case DirectColor:
+ d->mode = Direct;
+
+ d->r_max = right_align(d->visual->red_mask) + 1;
+ d->g_max = right_align(d->visual->green_mask) + 1;
+ d->b_max = right_align(d->visual->blue_mask) + 1;
+
+ d->r_shift = lowest_bit(d->visual->red_mask);
+ d->g_shift = lowest_bit(d->visual->green_mask);
+ d->b_shift = lowest_bit(d->visual->blue_mask);
+ break;
+ }
+ }
+
+ bool ownColormap = false;
+ if (X11->colormap && i == DefaultScreen(display)) {
+ // only use the outside colormap on the default screen
+ d->colormap = X11->colormap;
+ d->defaultColormap = (d->colormap == DefaultColormap(display, i));
+ } else if ((!use_stdcmap
+ && (((d->visual->c_class & 1) && X11->custom_cmap)
+ || d->visual != DefaultVisual(display, i)))
+ || d->visual->c_class == DirectColor) {
+ // allocate custom colormap (we always do this when using DirectColor visuals)
+ d->colormap =
+ XCreateColormap(display, RootWindow(display, i), d->visual,
+ d->visual->c_class == DirectColor ? AllocAll : AllocNone);
+ d->defaultColormap = false;
+ ownColormap = true;
+ }
+
+ switch (d->mode) {
+ case Gray:
+ init_gray(d, i);
+ break;
+ case Indexed:
+ init_indexed(d, i);
+ break;
+ case Direct:
+ init_direct(d, ownColormap);
+ break;
+ }
+
+ QX11InfoData *screen = X11->screens + i;
+ screen->depth = d->depth;
+ screen->visual = d->visual;
+ screen->defaultVisual = d->defaultVisual;
+ screen->colormap = d->colormap;
+ screen->defaultColormap = d->defaultColormap;
+ screen->cells = screen->visual->map_entries;
+
+ if (argbVisual) {
+ X11->argbVisuals[i] = argbVisual;
+ X11->argbColormaps[i] = XCreateColormap(display, RootWindow(display, i), argbVisual, AllocNone);
+ }
+
+ // ###
+ // We assume that 8bpp == pseudocolor, but this is not
+ // always the case (according to the X server), so we need
+ // to make sure that our internal data is setup in a way
+ // that is compatible with our assumptions
+ if (screen->visual->c_class == TrueColor && screen->depth == 8 && screen->cells == 8)
+ screen->cells = 256;
+ }
+}
+
+void QColormap::cleanup()
+{
+ Display *display = QX11Info::display();
+ const int screens = ScreenCount(display);
+
+ for (int i = 0; i < screens; ++i)
+ delete cmaps[i];
+
+ delete [] cmaps;
+ cmaps = 0;
+}
+
+
+QColormap QColormap::instance(int screen)
+{
+ if (screen == -1)
+ screen = QX11Info::appScreen();
+ return *cmaps[screen];
+}
+
+/*! \internal
+ Constructs a new colormap.
+*/
+QColormap::QColormap()
+ : d(new QColormapPrivate)
+{}
+
+QColormap::QColormap(const QColormap &colormap)
+ :d (colormap.d)
+{ d->ref.ref(); }
+
+QColormap::~QColormap()
+{
+ if (!d->ref.deref()) {
+ if (!d->defaultColormap)
+ XFreeColormap(QX11Info::display(), d->colormap);
+ delete d;
+ }
+}
+
+QColormap::Mode QColormap::mode() const
+{ return d->mode; }
+
+int QColormap::depth() const
+{ return d->depth; }
+
+int QColormap::size() const
+{
+ return (d->mode == Gray
+ ? d->r_max
+ : (d->mode == Indexed
+ ? d->r_max * d->g_max * d->b_max
+ : -1));
+}
+
+uint QColormap::pixel(const QColor &color) const
+{
+ const QColor c = color.toRgb();
+ const uint r = (c.ct.argb.red * d->r_max) >> 16;
+ const uint g = (c.ct.argb.green * d->g_max) >> 16;
+ const uint b = (c.ct.argb.blue * d->b_max) >> 16;
+ if (d->mode != Direct) {
+ if (d->mode == Gray)
+ return d->pixels.at((r * 30 + g * 59 + b * 11) / 100);
+ return d->pixels.at(r * d->g_max * d->b_max + g * d->b_max + b);
+ }
+ return (r << d->r_shift) + (g << d->g_shift) + (b << d->b_shift);
+}
+
+const QColor QColormap::colorAt(uint pixel) const
+{
+ if (d->mode != Direct) {
+ Q_ASSERT(pixel <= (uint)d->colors.size());
+ return d->colors.at(pixel);
+ }
+
+ const int r = (((pixel & d->visual->red_mask) >> d->r_shift) << 8) / d->r_max;
+ const int g = (((pixel & d->visual->green_mask) >> d->g_shift) << 8) / d->g_max;
+ const int b = (((pixel & d->visual->blue_mask) >> d->b_shift) << 8) / d->b_max;
+ return QColor(r, g, b);
+}
+
+const QVector<QColor> QColormap::colormap() const
+{ return d->colors; }
+
+QColormap &QColormap::operator=(const QColormap &colormap)
+{
+ qAtomicAssign(d, colormap.d);
+ return *this;
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qcursor_x11.cpp b/src/widgets/platforms/x11/qcursor_x11.cpp
new file mode 100644
index 0000000000..d0ed98e1fe
--- /dev/null
+++ b/src/widgets/platforms/x11/qcursor_x11.cpp
@@ -0,0 +1,637 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 <qdebug.h>
+#include <qdatastream.h>
+#include <private/qcursor_p.h>
+#include <private/qt_x11_p.h>
+#include <private/qapplication_p.h>
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <X11/cursorfont.h>
+
+#include <qlibrary.h>
+
+#ifndef QT_NO_XCURSOR
+# include <X11/Xcursor/Xcursor.h>
+#endif // QT_NO_XCURSOR
+
+#ifndef QT_NO_XFIXES
+# include <X11/extensions/Xfixes.h>
+#endif // QT_NO_XFIXES
+
+#include "qx11info_x11.h"
+#include <private/qpixmap_x11_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// Define QT_USE_APPROXIMATE_CURSORS when compiling if you REALLY want to
+// use the ugly X11 cursors.
+
+/*****************************************************************************
+ Internal QCursorData class
+ *****************************************************************************/
+
+QCursorData::QCursorData(Qt::CursorShape s)
+ : cshape(s), bm(0), bmm(0), hx(0), hy(0), hcurs(0), pm(0), pmm(0)
+{
+ ref = 1;
+}
+
+QCursorData::~QCursorData()
+{
+ Display *dpy = X11 ? X11->display : (Display*)0;
+
+ // Add in checking for the display too as on HP-UX
+ // we seem to get a core dump as the cursor data is
+ // deleted again from main() on exit...
+ if (hcurs && dpy)
+ XFreeCursor(dpy, hcurs);
+ if (pm && dpy)
+ XFreePixmap(dpy, pm);
+ if (pmm && dpy)
+ XFreePixmap(dpy, pmm);
+ delete bm;
+ delete bmm;
+}
+
+#ifndef QT_NO_CURSOR
+QCursor::QCursor(Qt::HANDLE cursor)
+{
+ if (!QCursorData::initialized)
+ QCursorData::initialize();
+ d = new QCursorData(Qt::CustomCursor);
+ d->hcurs = cursor;
+}
+
+#endif
+
+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->ref = 1;
+
+ extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap); // qpixmap_x11.cpp
+ d->bm = new QBitmap(qt_toX11Pixmap(bitmap));
+ d->bmm = new QBitmap(qt_toX11Pixmap(mask));
+
+ d->hcurs = 0;
+ d->cshape = Qt::BitmapCursor;
+ d->hx = hotX >= 0 ? hotX : bitmap.width() / 2;
+ d->hy = hotY >= 0 ? hotY : bitmap.height() / 2;
+ d->fg.red = 0x0000;
+ d->fg.green = 0x0000;
+ d->fg.blue = 0x0000;
+ d->bg.red = 0xffff;
+ d->bg.green = 0xffff;
+ d->bg.blue = 0xffff;
+ return d;
+}
+
+
+
+#ifndef QT_NO_CURSOR
+Qt::HANDLE QCursor::handle() const
+{
+ if (!QCursorData::initialized)
+ QCursorData::initialize();
+ if (!d->hcurs)
+ d->update();
+ return d->hcurs;
+}
+#endif
+
+QPoint QCursor::pos()
+{
+ Window root;
+ Window child;
+ int root_x, root_y, win_x, win_y;
+ uint buttons;
+ Display* dpy = X11->display;
+ for (int i = 0; i < ScreenCount(dpy); ++i) {
+ if (XQueryPointer(dpy, QX11Info::appRootWindow(i), &root, &child, &root_x, &root_y,
+ &win_x, &win_y, &buttons))
+
+ return QPoint(root_x, root_y);
+ }
+ return QPoint();
+}
+
+/*! \internal
+*/
+#ifndef QT_NO_CURSOR
+int QCursor::x11Screen()
+{
+ Window root;
+ Window child;
+ int root_x, root_y, win_x, win_y;
+ uint buttons;
+ Display* dpy = X11->display;
+ for (int i = 0; i < ScreenCount(dpy); ++i) {
+ if (XQueryPointer(dpy, QX11Info::appRootWindow(i), &root, &child, &root_x, &root_y,
+ &win_x, &win_y, &buttons))
+ return i;
+ }
+ return -1;
+}
+#endif
+
+void QCursor::setPos(int x, int y)
+{
+ QPoint current, target(x, y);
+
+ // this is copied from pos(), since we need the screen number for the correct
+ // root window in the XWarpPointer call
+ Window root;
+ Window child;
+ int root_x, root_y, win_x, win_y;
+ uint buttons;
+ Display* dpy = X11->display;
+ int screen;
+ for (screen = 0; screen < ScreenCount(dpy); ++screen) {
+ if (XQueryPointer(dpy, QX11Info::appRootWindow(screen), &root, &child, &root_x, &root_y,
+ &win_x, &win_y, &buttons)) {
+ current = QPoint(root_x, root_y);
+ break;
+ }
+ }
+
+ if (screen >= ScreenCount(dpy))
+ return;
+
+ // 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 (current == target)
+ return;
+
+ XWarpPointer(X11->display, XNone, QX11Info::appRootWindow(screen), 0, 0, 0, 0, x, y);
+}
+
+
+/*!
+ \internal
+
+ Creates the cursor.
+*/
+
+void QCursorData::update()
+{
+ if (!QCursorData::initialized)
+ QCursorData::initialize();
+ if (hcurs)
+ return;
+
+ Display *dpy = X11->display;
+ Window rootwin = QX11Info::appRootWindow();
+
+ if (cshape == Qt::BitmapCursor) {
+ extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap); // qpixmap_x11.cpp
+#ifndef QT_NO_XRENDER
+ if (!pixmap.isNull() && X11->use_xrender) {
+ pixmap = qt_toX11Pixmap(pixmap);
+ hcurs = XRenderCreateCursor (X11->display, pixmap.x11PictureHandle(), hx, hy);
+ } else
+#endif
+ {
+ hcurs = XCreatePixmapCursor(dpy, bm->handle(), bmm->handle(), &fg, &bg, hx, hy);
+ }
+ return;
+ }
+
+ static const char *cursorNames[] = {
+ "left_ptr",
+ "up_arrow",
+ "cross",
+ "wait",
+ "ibeam",
+ "size_ver",
+ "size_hor",
+ "size_bdiag",
+ "size_fdiag",
+ "size_all",
+ "blank",
+ "split_v",
+ "split_h",
+ "pointing_hand",
+ "forbidden",
+ "whats_this",
+ "left_ptr_watch",
+ "openhand",
+ "closedhand",
+ "copy",
+ "move",
+ "link"
+ };
+
+#ifndef QT_NO_XCURSOR
+ if (X11->ptrXcursorLibraryLoadCursor) {
+ // special case for non-standard dnd-* cursors
+ switch (cshape) {
+ case Qt::DragCopyCursor:
+ hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-copy");
+ break;
+ case Qt::DragMoveCursor:
+ hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-move");
+ break;
+ case Qt::DragLinkCursor:
+ hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-link");
+ break;
+ default:
+ break;
+ }
+ if (!hcurs)
+ hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]);
+ }
+ if (hcurs)
+ return;
+#endif // QT_NO_XCURSOR
+
+ static const uchar cur_blank_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ // Non-standard X11 cursors are created from bitmaps
+
+#ifndef QT_USE_APPROXIMATE_CURSORS
+ static const uchar cur_ver_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xf0, 0x0f,
+ 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00 };
+ static const uchar mcur_ver_bits[] = {
+ 0x00, 0x00, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f,
+ 0xfc, 0x7f, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xfc, 0x7f, 0xf8, 0x3f,
+ 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03 };
+ static const uchar cur_hor_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x30, 0x18,
+ 0x38, 0x38, 0xfc, 0x7f, 0xfc, 0x7f, 0x38, 0x38, 0x30, 0x18, 0x20, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar mcur_hor_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x60, 0x0c, 0x70, 0x1c, 0x78, 0x3c,
+ 0xfc, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0x7f, 0x78, 0x3c,
+ 0x70, 0x1c, 0x60, 0x0c, 0x40, 0x04, 0x00, 0x00 };
+ static const uchar cur_bdiag_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x3e,
+ 0x00, 0x37, 0x88, 0x23, 0xd8, 0x01, 0xf8, 0x00, 0x78, 0x00, 0xf8, 0x00,
+ 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar mcur_bdiag_bits[] = {
+ 0x00, 0x00, 0xc0, 0x7f, 0x80, 0x7f, 0x00, 0x7f, 0x00, 0x7e, 0x04, 0x7f,
+ 0x8c, 0x7f, 0xdc, 0x77, 0xfc, 0x63, 0xfc, 0x41, 0xfc, 0x00, 0xfc, 0x01,
+ 0xfc, 0x03, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar cur_fdiag_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0xf8, 0x00, 0x78, 0x00,
+ 0xf8, 0x00, 0xd8, 0x01, 0x88, 0x23, 0x00, 0x37, 0x00, 0x3e, 0x00, 0x3c,
+ 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar mcur_fdiag_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x01, 0xfc, 0x00,
+ 0xfc, 0x41, 0xfc, 0x63, 0xdc, 0x77, 0x8c, 0x7f, 0x04, 0x7f, 0x00, 0x7e,
+ 0x00, 0x7f, 0x80, 0x7f, 0xc0, 0x7f, 0x00, 0x00 };
+ static const uchar *cursor_bits16[] = {
+ cur_ver_bits, mcur_ver_bits, cur_hor_bits, mcur_hor_bits,
+ cur_bdiag_bits, mcur_bdiag_bits, cur_fdiag_bits, mcur_fdiag_bits,
+ 0, 0, cur_blank_bits, cur_blank_bits };
+
+ static const uchar vsplit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar vsplitm_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00,
+ 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
+ 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
+ 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00,
+ 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar hsplit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03,
+ 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar hsplitm_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00,
+ 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07,
+ 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00,
+ 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar whatsthis_bits[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0xf0, 0x07, 0x00,
+ 0x09, 0x18, 0x0e, 0x00, 0x11, 0x1c, 0x0e, 0x00, 0x21, 0x1c, 0x0e, 0x00,
+ 0x41, 0x1c, 0x0e, 0x00, 0x81, 0x1c, 0x0e, 0x00, 0x01, 0x01, 0x07, 0x00,
+ 0x01, 0x82, 0x03, 0x00, 0xc1, 0xc7, 0x01, 0x00, 0x49, 0xc0, 0x01, 0x00,
+ 0x95, 0xc0, 0x01, 0x00, 0x93, 0xc0, 0x01, 0x00, 0x21, 0x01, 0x00, 0x00,
+ 0x20, 0xc1, 0x01, 0x00, 0x40, 0xc2, 0x01, 0x00, 0x40, 0x02, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+ static const uchar whatsthism_bits[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x07, 0x00, 0x07, 0xf8, 0x0f, 0x00,
+ 0x0f, 0xfc, 0x1f, 0x00, 0x1f, 0x3e, 0x1f, 0x00, 0x3f, 0x3e, 0x1f, 0x00,
+ 0x7f, 0x3e, 0x1f, 0x00, 0xff, 0x3e, 0x1f, 0x00, 0xff, 0x9d, 0x0f, 0x00,
+ 0xff, 0xc3, 0x07, 0x00, 0xff, 0xe7, 0x03, 0x00, 0x7f, 0xe0, 0x03, 0x00,
+ 0xf7, 0xe0, 0x03, 0x00, 0xf3, 0xe0, 0x03, 0x00, 0xe1, 0xe1, 0x03, 0x00,
+ 0xe0, 0xe1, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+ static const uchar busy_bits[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
+ 0x41, 0xe0, 0xff, 0x00, 0x81, 0x20, 0x80, 0x00, 0x01, 0xe1, 0xff, 0x00,
+ 0x01, 0x42, 0x40, 0x00, 0xc1, 0x47, 0x40, 0x00, 0x49, 0x40, 0x55, 0x00,
+ 0x95, 0x80, 0x2a, 0x00, 0x93, 0x00, 0x15, 0x00, 0x21, 0x01, 0x0a, 0x00,
+ 0x20, 0x01, 0x11, 0x00, 0x40, 0x82, 0x20, 0x00, 0x40, 0x42, 0x44, 0x00,
+ 0x80, 0x41, 0x4a, 0x00, 0x00, 0x40, 0x55, 0x00, 0x00, 0xe0, 0xff, 0x00,
+ 0x00, 0x20, 0x80, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static const uchar busym_bits[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
+ 0x7f, 0xe0, 0xff, 0x00, 0xff, 0xe0, 0xff, 0x00, 0xff, 0xe1, 0xff, 0x00,
+ 0xff, 0xc3, 0x7f, 0x00, 0xff, 0xc7, 0x7f, 0x00, 0x7f, 0xc0, 0x7f, 0x00,
+ 0xf7, 0x80, 0x3f, 0x00, 0xf3, 0x00, 0x1f, 0x00, 0xe1, 0x01, 0x0e, 0x00,
+ 0xe0, 0x01, 0x1f, 0x00, 0xc0, 0x83, 0x3f, 0x00, 0xc0, 0xc3, 0x7f, 0x00,
+ 0x80, 0xc1, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00,
+ 0x00, 0xe0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ static const uchar * const cursor_bits32[] = {
+ vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits,
+ 0, 0, 0, 0, whatsthis_bits, whatsthism_bits, busy_bits, busym_bits
+ };
+
+ static const uchar forbidden_bits[] = {
+ 0x00,0x00,0x00,0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xf0,0x00,0x38,0xc0,0x01,
+ 0x7c,0x80,0x03,0xec,0x00,0x03,0xce,0x01,0x07,0x86,0x03,0x06,0x06,0x07,0x06,
+ 0x06,0x0e,0x06,0x06,0x1c,0x06,0x0e,0x38,0x07,0x0c,0x70,0x03,0x1c,0xe0,0x03,
+ 0x38,0xc0,0x01,0xf0,0xe0,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00,0x00,0x00,0x00 };
+
+ static const uchar forbiddenm_bits[] = {
+ 0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xff,0x00,0xf8,0xff,0x01,0xfc,0xf0,0x03,
+ 0xfe,0xc0,0x07,0xfe,0x81,0x07,0xff,0x83,0x0f,0xcf,0x07,0x0f,0x8f,0x0f,0x0f,
+ 0x0f,0x1f,0x0f,0x0f,0x3e,0x0f,0x1f,0xfc,0x0f,0x1e,0xf8,0x07,0x3e,0xf0,0x07,
+ 0xfc,0xe0,0x03,0xf8,0xff,0x01,0xf0,0xff,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00};
+
+ static const uchar openhand_bits[] = {
+ 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92,
+ 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20,
+ 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00};
+ static const uchar openhandm_bits[] = {
+ 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff,
+ 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f,
+ 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00};
+ static const uchar closedhand_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50,
+ 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,
+ 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00};
+ static const uchar closedhandm_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f,
+ 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,
+ 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};
+
+ static const uchar * const cursor_bits20[] = {
+ forbidden_bits, forbiddenm_bits
+ };
+
+ if ((cshape >= Qt::SizeVerCursor && cshape < Qt::SizeAllCursor)
+ || cshape == Qt::BlankCursor) {
+ XColor bg, fg;
+ bg.red = 255 << 8;
+ bg.green = 255 << 8;
+ bg.blue = 255 << 8;
+ fg.red = 0;
+ fg.green = 0;
+ fg.blue = 0;
+ int i = (cshape - Qt::SizeVerCursor) * 2;
+ pm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char*>(cursor_bits16[i]), 16, 16);
+ pmm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char*>(cursor_bits16[i + 1]), 16, 16);
+ hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8);
+ } else if ((cshape >= Qt::SplitVCursor && cshape <= Qt::SplitHCursor)
+ || cshape == Qt::WhatsThisCursor || cshape == Qt::BusyCursor) {
+ XColor bg, fg;
+ bg.red = 255 << 8;
+ bg.green = 255 << 8;
+ bg.blue = 255 << 8;
+ fg.red = 0;
+ fg.green = 0;
+ fg.blue = 0;
+ int i = (cshape - Qt::SplitVCursor) * 2;
+ pm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(cursor_bits32[i]), 32, 32);
+ pmm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(cursor_bits32[i + 1]), 32, 32);
+ int hs = (cshape == Qt::PointingHandCursor || cshape == Qt::WhatsThisCursor
+ || cshape == Qt::BusyCursor) ? 0 : 16;
+ hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, hs, hs);
+ } else if (cshape == Qt::ForbiddenCursor) {
+ XColor bg, fg;
+ bg.red = 255 << 8;
+ bg.green = 255 << 8;
+ bg.blue = 255 << 8;
+ fg.red = 0;
+ fg.green = 0;
+ fg.blue = 0;
+ int i = (cshape - Qt::ForbiddenCursor) * 2;
+ pm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(cursor_bits20[i]), 20, 20);
+ pmm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(cursor_bits20[i + 1]), 20, 20);
+ hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 10, 10);
+ } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) {
+ XColor bg, fg;
+ bg.red = 255 << 8;
+ bg.green = 255 << 8;
+ bg.blue = 255 << 8;
+ fg.red = 0;
+ fg.green = 0;
+ fg.blue = 0;
+ bool open = cshape == Qt::OpenHandCursor;
+ pm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(open ? openhand_bits : closedhand_bits), 16, 16);
+ pmm = XCreateBitmapFromData(dpy, rootwin, reinterpret_cast<const char *>(open ? openhandm_bits : closedhandm_bits), 16, 16);
+ hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8);
+ } else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor
+ || cshape == Qt::DragLinkCursor) {
+ XColor bg, fg;
+ bg.red = 255 << 8;
+ bg.green = 255 << 8;
+ bg.blue = 255 << 8;
+ fg.red = 0;
+ fg.green = 0;
+ fg.blue = 0;
+ QImage image = QApplicationPrivate::instance()->getPixmapCursor(cshape).toImage();
+ pm = QX11PixmapData::createBitmapFromImage(image);
+ pmm = QX11PixmapData::createBitmapFromImage(image.createAlphaMask().convertToFormat(QImage::Format_MonoLSB));
+ hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8);
+ }
+
+ if (hcurs)
+ {
+#ifndef QT_NO_XFIXES
+ if (X11->use_xfixes && X11->ptrXFixesSetCursorName)
+ X11->ptrXFixesSetCursorName(dpy, hcurs, cursorNames[cshape]);
+#endif /* ! QT_NO_XFIXES */
+ return;
+ }
+
+#endif /* ! QT_USE_APPROXIMATE_CURSORS */
+
+ uint sh;
+ switch (cshape) { // map Q cursor to X cursor
+ case Qt::ArrowCursor:
+ sh = XC_left_ptr;
+ break;
+ case Qt::UpArrowCursor:
+ sh = XC_center_ptr;
+ break;
+ case Qt::CrossCursor:
+ sh = XC_crosshair;
+ break;
+ case Qt::WaitCursor:
+ sh = XC_watch;
+ break;
+ case Qt::IBeamCursor:
+ sh = XC_xterm;
+ break;
+ case Qt::SizeAllCursor:
+ sh = XC_fleur;
+ break;
+ case Qt::PointingHandCursor:
+ sh = XC_hand2;
+ break;
+#ifdef QT_USE_APPROXIMATE_CURSORS
+ case Qt::SizeBDiagCursor:
+ sh = XC_top_right_corner;
+ break;
+ case Qt::SizeFDiagCursor:
+ sh = XC_bottom_right_corner;
+ break;
+ case Qt::BlankCursor:
+ XColor bg, fg;
+ bg.red = 255 << 8;
+ bg.green = 255 << 8;
+ bg.blue = 255 << 8;
+ fg.red = 0;
+ fg.green = 0;
+ fg.blue = 0;
+ pm = XCreateBitmapFromData(dpy, rootwin, cur_blank_bits, 16, 16);
+ pmm = XCreateBitmapFromData(dpy, rootwin, cur_blank_bits, 16, 16);
+ hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8);
+ return;
+ break;
+ case Qt::SizeVerCursor:
+ case Qt::SplitVCursor:
+ sh = XC_sb_v_double_arrow;
+ break;
+ case Qt::SizeHorCursor:
+ case Qt::SplitHCursor:
+ sh = XC_sb_h_double_arrow;
+ break;
+ case Qt::WhatsThisCursor:
+ sh = XC_question_arrow;
+ break;
+ case Qt::ForbiddenCursor:
+ sh = XC_circle;
+ break;
+ case Qt::BusyCursor:
+ sh = XC_watch;
+ break;
+ case Qt::DragCopyCursor:
+ sh = XC_tcross;
+ break;
+ case Qt::DragLinkCursor:
+ sh = XC_center_ptr;
+ break;
+ case Qt::DragMoveCursor:
+ sh = XC_top_left_arrow;
+ break;
+#endif /* QT_USE_APPROXIMATE_CURSORS */
+ default:
+ qWarning("QCursor::update: Invalid cursor shape %d", cshape);
+ return;
+ }
+ hcurs = XCreateFontCursor(dpy, sh);
+
+#ifndef QT_NO_XFIXES
+ if (X11->use_xfixes && X11->ptrXFixesSetCursorName)
+ X11->ptrXFixesSetCursorName(dpy, hcurs, cursorNames[cshape]);
+#endif /* ! QT_NO_XFIXES */
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qdesktopwidget_x11.cpp b/src/widgets/platforms/x11/qdesktopwidget_x11.cpp
new file mode 100644
index 0000000000..b0f12903a1
--- /dev/null
+++ b/src/widgets/platforms/x11/qdesktopwidget_x11.cpp
@@ -0,0 +1,406 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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"
+#include "qdesktopwidget.h"
+#include "qlibrary.h"
+#include "qt_x11_p.h"
+#include "qvariant.h"
+#include "qwidget_p.h"
+#include "qx11info_x11.h"
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+// defined in qwidget_x11.cpp
+extern int qt_x11_create_desktop_on_screen;
+
+
+// function to update the workarea of the screen
+static bool qt_desktopwidget_workarea_dirty = true;
+void qt_desktopwidget_update_workarea()
+{
+ qt_desktopwidget_workarea_dirty = true;
+}
+
+
+class QSingleDesktopWidget : public QWidget
+{
+public:
+ QSingleDesktopWidget();
+ ~QSingleDesktopWidget();
+};
+
+QSingleDesktopWidget::QSingleDesktopWidget()
+ : QWidget(0, Qt::Desktop)
+{
+}
+
+QSingleDesktopWidget::~QSingleDesktopWidget()
+{
+ const QObjectList &childList = children();
+ for (int i = childList.size(); i > 0 ;) {
+ --i;
+ childList.at(i)->setParent(0);
+ }
+}
+
+
+class QDesktopWidgetPrivate : public QWidgetPrivate
+{
+public:
+ QDesktopWidgetPrivate();
+ ~QDesktopWidgetPrivate();
+
+ void init();
+
+ bool use_xinerama;
+ int defaultScreen;
+ int screenCount;
+
+ QWidget **screens;
+ QRect *rects;
+ QRect *workareas;
+};
+
+QDesktopWidgetPrivate::QDesktopWidgetPrivate()
+ : use_xinerama(false), defaultScreen(0), screenCount(1),
+ screens(0), rects(0), workareas(0)
+{
+}
+
+QDesktopWidgetPrivate::~QDesktopWidgetPrivate()
+{
+ if (screens) {
+ for (int i = 0; i < screenCount; ++i) {
+ if (i == defaultScreen) continue;
+ delete screens[i];
+ screens[i] = 0;
+ }
+
+ free (screens);
+ }
+
+ if (rects) delete [] rects;
+ if (workareas) delete [] workareas;
+}
+
+void QDesktopWidgetPrivate::init()
+{
+ // get the screen count
+ int newScreenCount = ScreenCount(X11->display);
+#ifndef QT_NO_XINERAMA
+
+ XineramaScreenInfo *xinerama_screeninfo = 0;
+
+ // we ignore the Xinerama extension when using the display is
+ // using traditional multi-screen (with multiple root windows)
+ if (newScreenCount == 1
+ && X11->ptrXineramaQueryExtension
+ && X11->ptrXineramaIsActive
+ && X11->ptrXineramaQueryScreens) {
+ int unused;
+ use_xinerama = (X11->ptrXineramaQueryExtension(X11->display, &unused, &unused)
+ && X11->ptrXineramaIsActive(X11->display));
+ }
+
+ if (use_xinerama) {
+ xinerama_screeninfo =
+ X11->ptrXineramaQueryScreens(X11->display, &newScreenCount);
+ }
+
+ if (xinerama_screeninfo) {
+ defaultScreen = 0;
+ } else
+#endif // QT_NO_XINERAMA
+ {
+ defaultScreen = DefaultScreen(X11->display);
+ newScreenCount = ScreenCount(X11->display);
+ use_xinerama = false;
+ }
+
+ delete [] rects;
+ rects = new QRect[newScreenCount];
+ delete [] workareas;
+ workareas = new QRect[newScreenCount];
+
+ // get the geometry of each screen
+ int i, j, x, y, w, h;
+ for (i = 0, j = 0; i < newScreenCount; i++, j++) {
+
+#ifndef QT_NO_XINERAMA
+ if (use_xinerama) {
+ x = xinerama_screeninfo[i].x_org;
+ y = xinerama_screeninfo[i].y_org;
+ w = xinerama_screeninfo[i].width;
+ h = xinerama_screeninfo[i].height;
+ } else
+#endif // QT_NO_XINERAMA
+ {
+ x = 0;
+ y = 0;
+ w = WidthOfScreen(ScreenOfDisplay(X11->display, i));
+ h = HeightOfScreen(ScreenOfDisplay(X11->display, i));
+ }
+
+ rects[j].setRect(x, y, w, h);
+
+ if (use_xinerama && j > 0 && rects[j-1].intersects(rects[j])) {
+ // merge a "cloned" screen with the previous, hiding all crtcs
+ // that are currently showing a sub-rect of the previous screen
+ if ((rects[j].width()*rects[j].height()) >
+ (rects[j-1].width()*rects[j-1].height()))
+ rects[j-1] = rects[j];
+ j--;
+ }
+
+ workareas[i] = QRect();
+ }
+
+ if (screens) {
+ // leaks QWidget* pointers on purpose, can't delete them as pointer escapes
+ screens = q_check_ptr((QWidget**) realloc(screens, j * sizeof(QWidget*)));
+ if (j > screenCount)
+ memset(&screens[screenCount], 0, (j-screenCount) * sizeof(QWidget*));
+ }
+
+ screenCount = j;
+
+#ifndef QT_NO_XINERAMA
+ if (use_xinerama && screenCount == 1)
+ use_xinerama = false;
+
+ if (xinerama_screeninfo)
+ XFree(xinerama_screeninfo);
+#endif // QT_NO_XINERAMA
+
+}
+
+// the QDesktopWidget itself will be created on the default screen
+// as qt_x11_create_desktop_on_screen defaults to -1
+QDesktopWidget::QDesktopWidget()
+ : QWidget(*new QDesktopWidgetPrivate, 0, Qt::Desktop)
+{
+ Q_D(QDesktopWidget);
+ d->init();
+}
+
+QDesktopWidget::~QDesktopWidget()
+{
+}
+
+bool QDesktopWidget::isVirtualDesktop() const
+{
+ Q_D(const QDesktopWidget);
+ return d->use_xinerama;
+}
+
+int QDesktopWidget::primaryScreen() const
+{
+ Q_D(const QDesktopWidget);
+ return d->defaultScreen;
+}
+
+int QDesktopWidget::numScreens() const
+{
+ Q_D(const QDesktopWidget);
+ return d->screenCount;
+}
+
+QWidget *QDesktopWidget::screen(int screen)
+{
+ Q_D(QDesktopWidget);
+ if (d->use_xinerama)
+ return this;
+
+ if (screen < 0 || screen >= d->screenCount)
+ screen = d->defaultScreen;
+
+ if (! d->screens) {
+ d->screens = (QWidget**) calloc( d->screenCount, sizeof(QWidget*));
+ d->screens[d->defaultScreen] = this;
+ }
+
+ if (! d->screens[screen] || // not created yet
+ ! (d->screens[screen]->windowType() == Qt::Desktop)) { // reparented away
+ qt_x11_create_desktop_on_screen = screen;
+ d->screens[screen] = new QSingleDesktopWidget;
+ qt_x11_create_desktop_on_screen = -1;
+ }
+
+ return d->screens[screen];
+}
+
+const QRect QDesktopWidget::availableGeometry(int screen) const
+{
+ Q_D(const QDesktopWidget);
+ if (qt_desktopwidget_workarea_dirty) {
+ // the workareas are dirty, invalidate them
+ for (int i = 0; i < d->screenCount; ++i)
+ d->workareas[i] = QRect();
+ qt_desktopwidget_workarea_dirty = false;
+ }
+
+ if (screen < 0 || screen >= d->screenCount)
+ screen = d->defaultScreen;
+
+ if (d->workareas[screen].isValid())
+ return d->workareas[screen];
+
+ if (X11->isSupportedByWM(ATOM(_NET_WORKAREA))) {
+ int x11Screen = isVirtualDesktop() ? DefaultScreen(X11->display) : screen;
+
+ Atom ret;
+ int format, e;
+ unsigned char *data = 0;
+ unsigned long nitems, after;
+
+ e = XGetWindowProperty(X11->display,
+ QX11Info::appRootWindow(x11Screen),
+ ATOM(_NET_WORKAREA), 0, 4, False, XA_CARDINAL,
+ &ret, &format, &nitems, &after, &data);
+
+ QRect workArea;
+ if (e == Success && ret == XA_CARDINAL &&
+ format == 32 && nitems == 4) {
+ long *workarea = (long *) data;
+ workArea = QRect(workarea[0], workarea[1], workarea[2], workarea[3]);
+ } else {
+ workArea = screenGeometry(screen);
+ }
+
+ if (isVirtualDesktop()) {
+ // intersect the workarea (which spawns all Xinerama screens) with the rect for the
+ // requested screen
+ workArea &= screenGeometry(screen);
+ }
+
+ d->workareas[screen] = workArea;
+
+ if (data)
+ XFree(data);
+ } else {
+ d->workareas[screen] = screenGeometry(screen);
+ }
+
+ return d->workareas[screen];
+}
+
+const QRect QDesktopWidget::screenGeometry(int screen) const
+{
+ Q_D(const QDesktopWidget);
+ if (screen < 0 || screen >= d->screenCount)
+ screen = d->defaultScreen;
+
+ return d->rects[screen];
+}
+
+int QDesktopWidget::screenNumber(const QWidget *widget) const
+{
+ Q_D(const QDesktopWidget);
+ if (!widget)
+ return d->defaultScreen;
+
+#ifndef QT_NO_XINERAMA
+ if (d->use_xinerama) {
+ // this is how we do it for xinerama
+ QRect frame = widget->frameGeometry();
+ if (!widget->isWindow())
+ frame.moveTopLeft(widget->mapToGlobal(QPoint(0, 0)));
+
+ int maxSize = -1;
+ int maxScreen = -1;
+
+ for (int i = 0; i < d->screenCount; ++i) {
+ QRect sect = d->rects[i].intersected(frame);
+ int size = sect.width() * sect.height();
+ if (size > maxSize && sect.width() > 0 && sect.height() > 0) {
+ maxSize = size;
+ maxScreen = i;
+ }
+ }
+ return maxScreen;
+ }
+#endif // QT_NO_XINERAMA
+
+ return widget->x11Info().screen();
+}
+
+int QDesktopWidget::screenNumber(const QPoint &point) const
+{
+ Q_D(const QDesktopWidget);
+ int closestScreen = -1;
+ int shortestDistance = INT_MAX;
+ for (int i = 0; i < d->screenCount; ++i) {
+ int thisDistance = d->pointToRect(point, d->rects[i]);
+ if (thisDistance < shortestDistance) {
+ shortestDistance = thisDistance;
+ closestScreen = i;
+ }
+ }
+ return closestScreen;
+}
+
+void QDesktopWidget::resizeEvent(QResizeEvent *event)
+{
+ Q_D(QDesktopWidget);
+ int oldScreenCount = d->screenCount;
+ QVector<QRect> oldRects(oldScreenCount);
+ for (int i = 0; i < oldScreenCount; ++i) {
+ oldRects[i] = d->rects[i];
+ }
+
+ d->init();
+
+ for (int i = 0; i < qMin(oldScreenCount, d->screenCount); ++i) {
+ if (oldRects.at(i) != d->rects[i])
+ emit resized(i);
+ }
+
+ if (oldScreenCount != d->screenCount) {
+ emit screenCountChanged(d->screenCount);
+ }
+
+ qt_desktopwidget_workarea_dirty = true;
+ QWidget::resizeEvent(event);
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qdnd_x11.cpp b/src/widgets/platforms/x11/qdnd_x11.cpp
new file mode 100644
index 0000000000..9ff1543e51
--- /dev/null
+++ b/src/widgets/platforms/x11/qdnd_x11.cpp
@@ -0,0 +1,2072 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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"
+
+#ifndef QT_NO_DRAGANDDROP
+
+#include "qwidget.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qbitmap.h"
+#include "qdesktopwidget.h"
+#include "qevent.h"
+#include "qiodevice.h"
+#include "qpointer.h"
+#include "qcursor.h"
+#include "qelapsedtimer.h"
+#include "qvariant.h"
+#include "qvector.h"
+#include "qurl.h"
+#include "qdebug.h"
+#include "qimagewriter.h"
+#include "qbuffer.h"
+#include "qtextcodec.h"
+
+#include "qdnd_p.h"
+#include "qapplication_p.h"
+#include "qt_x11_p.h"
+#include "qx11info_x11.h"
+
+#include "qwidget_p.h"
+#include "qcursor_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// #define DND_DEBUG
+#ifdef DND_DEBUG
+#define DEBUG qDebug
+#else
+#define DEBUG if(0) qDebug
+#endif
+
+#ifdef DND_DEBUG
+#define DNDDEBUG qDebug()
+#else
+#define DNDDEBUG if(0) qDebug()
+#endif
+
+static int findXdndDropTransactionByWindow(Window window)
+{
+ int at = -1;
+ for (int i = 0; i < X11->dndDropTransactions.count(); ++i) {
+ const QXdndDropTransaction &t = X11->dndDropTransactions.at(i);
+ if (t.target == window || t.proxy_target == window) {
+ at = i;
+ break;
+ }
+ }
+ return at;
+}
+
+static int findXdndDropTransactionByTime(Time timestamp)
+{
+ int at = -1;
+ for (int i = 0; i < X11->dndDropTransactions.count(); ++i) {
+ const QXdndDropTransaction &t = X11->dndDropTransactions.at(i);
+ if (t.timestamp == timestamp) {
+ at = i;
+ break;
+ }
+ }
+ return at;
+}
+
+// timer used to discard old XdndDrop transactions
+static int transaction_expiry_timer = -1;
+enum { XdndDropTransactionTimeout = 5000 }; // 5 seconds
+
+static void restartXdndDropExpiryTimer()
+{
+ if (transaction_expiry_timer != -1)
+ QDragManager::self()->killTimer(transaction_expiry_timer);
+ transaction_expiry_timer = QDragManager::self()->startTimer(XdndDropTransactionTimeout);
+}
+
+
+// find an ancestor with XdndAware on it
+static Window findXdndAwareParent(Window window)
+{
+ Window target = 0;
+ forever {
+ // check if window has XdndAware
+ Atom type = 0;
+ int f;
+ unsigned long n, a;
+ unsigned char *data = 0;
+ if (XGetWindowProperty(X11->display, window, ATOM(XdndAware), 0, 0, False,
+ AnyPropertyType, &type, &f,&n,&a,&data) == Success) {
+ if (data)
+ XFree(data);
+ if (type) {
+ target = window;
+ break;
+ }
+ }
+
+ // try window's parent
+ Window root;
+ Window parent;
+ Window *children;
+ uint unused;
+ if (!XQueryTree(X11->display, window, &root, &parent, &children, &unused))
+ break;
+ if (children)
+ XFree(children);
+ if (window == root)
+ break;
+ window = parent;
+ }
+ return target;
+}
+
+
+
+
+// and all this stuff is copied -into- qapp_x11.cpp
+
+static void handle_xdnd_position(QWidget *, const XEvent *, bool);
+static void handle_xdnd_status(QWidget * w, const XEvent * xe, bool /*passive*/);
+
+const int xdnd_version = 5;
+
+static Qt::DropAction xdndaction_to_qtaction(Atom atom)
+{
+ if (atom == ATOM(XdndActionCopy) || atom == 0)
+ return Qt::CopyAction;
+ if (atom == ATOM(XdndActionLink))
+ return Qt::LinkAction;
+ if (atom == ATOM(XdndActionMove))
+ return Qt::MoveAction;
+ return Qt::CopyAction;
+}
+
+static int qtaction_to_xdndaction(Qt::DropAction a)
+{
+ switch (a) {
+ case Qt::CopyAction:
+ return ATOM(XdndActionCopy);
+ case Qt::LinkAction:
+ return ATOM(XdndActionLink);
+ case Qt::MoveAction:
+ case Qt::TargetMoveAction:
+ return ATOM(XdndActionMove);
+ case Qt::IgnoreAction:
+ return XNone;
+ default:
+ return ATOM(XdndActionCopy);
+ }
+}
+
+// clean up the stuff used.
+static void qt_xdnd_cleanup();
+
+static void qt_xdnd_send_leave();
+
+// real variables:
+// xid of current drag source
+static Atom qt_xdnd_dragsource_xid = 0;
+
+// the types in this drop. 100 is no good, but at least it's big.
+const int qt_xdnd_max_type = 100;
+static Atom qt_xdnd_types[qt_xdnd_max_type + 1];
+
+// timer used when target wants "continuous" move messages (eg. scroll)
+static int heartbeat = -1;
+// rectangle in which the answer will be the same
+static QRect qt_xdnd_source_sameanswer;
+// top-level window we sent position to last.
+static Window qt_xdnd_current_target;
+// window to send events to (always valid if qt_xdnd_current_target)
+static Window qt_xdnd_current_proxy_target;
+static Time qt_xdnd_source_current_time;
+
+// widget we forwarded position to last, and local position
+static QPointer<QWidget> qt_xdnd_current_widget;
+static QPoint qt_xdnd_current_position;
+// timestamp from the XdndPosition and XdndDrop
+static Time qt_xdnd_target_current_time;
+// screen number containing the pointer... -1 means default
+static int qt_xdnd_current_screen = -1;
+// state of dragging... true if dragging, false if not
+bool qt_xdnd_dragging = false;
+
+static bool waiting_for_status = false;
+
+// used to preset each new QDragMoveEvent
+static Qt::DropAction last_target_accepted_action = Qt::IgnoreAction;
+
+// Shift/Ctrl handling, and final drop status
+static Qt::DropAction global_accepted_action = Qt::CopyAction;
+static Qt::DropActions possible_actions = Qt::IgnoreAction;
+
+// for embedding only
+static QWidget* current_embedding_widget = 0;
+static XEvent last_enter_event;
+
+// cursors
+static QCursor *noDropCursor = 0;
+static QCursor *moveCursor = 0;
+static QCursor *copyCursor = 0;
+static QCursor *linkCursor = 0;
+
+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"
+};
+
+class QShapedPixmapWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QShapedPixmapWidget(QWidget* w) :
+ QWidget(w,
+ Qt::Tool | Qt::FramelessWindowHint
+ | Qt::X11BypassWindowManagerHint
+ | Qt::BypassGraphicsProxyWidget)
+ {
+ setAttribute(Qt::WA_X11NetWmWindowTypeDND);
+ }
+
+ void setPixmap(const QPixmap &pm)
+ {
+ QBitmap mask = pm.mask();
+ if (!mask.isNull()) {
+ setMask(mask);
+ } else {
+ clearMask();
+ }
+ resize(pm.width(),pm.height());
+ pixmap = pm;
+ update();
+ }
+ QPoint pm_hot;
+
+protected:
+ QPixmap pixmap;
+ void paintEvent(QPaintEvent*)
+ {
+ QPainter p(this);
+ p.drawPixmap(0, 0, pixmap);
+ }
+};
+
+#include "qdnd_x11.moc"
+
+struct XdndData {
+ QShapedPixmapWidget *deco;
+ QWidget* desktop_proxy;
+};
+
+static XdndData xdnd_data = { 0, 0 };
+
+class QExtraWidget : public QWidget
+{
+ Q_DECLARE_PRIVATE(QWidget)
+public:
+ inline QWExtra* extraData();
+ inline QTLWExtra* topData();
+};
+
+inline QWExtra* QExtraWidget::extraData() { return d_func()->extraData(); }
+inline QTLWExtra* QExtraWidget::topData() { return d_func()->topData(); }
+
+
+static WId xdndProxy(WId w)
+{
+ Atom type = XNone;
+ int f;
+ unsigned long n, a;
+ unsigned char *retval = 0;
+ XGetWindowProperty(X11->display, w, ATOM(XdndProxy), 0, 1, False,
+ XA_WINDOW, &type, &f,&n,&a,&retval);
+ WId *proxy_id_ptr = (WId *)retval;
+ WId proxy_id = 0;
+ if (type == XA_WINDOW && proxy_id_ptr) {
+ proxy_id = *proxy_id_ptr;
+ XFree(proxy_id_ptr);
+ proxy_id_ptr = 0;
+ // Already exists. Real?
+ X11->ignoreBadwindow();
+ XGetWindowProperty(X11->display, proxy_id, ATOM(XdndProxy), 0, 1, False,
+ XA_WINDOW, &type, &f,&n,&a,&retval);
+ proxy_id_ptr = (WId *)retval;
+ if (X11->badwindow() || type != XA_WINDOW || !proxy_id_ptr || *proxy_id_ptr != proxy_id)
+ // Bogus - we will overwrite.
+ proxy_id = 0;
+ }
+ if (proxy_id_ptr)
+ XFree(proxy_id_ptr);
+ return proxy_id;
+}
+
+static bool xdndEnable(QWidget* w, bool on)
+{
+ DNDDEBUG << "xdndEnable" << w << on;
+ if (on) {
+ QWidget * xdnd_widget = 0;
+ if ((w->windowType() == Qt::Desktop)) {
+ if (xdnd_data.desktop_proxy) // *WE* already have one.
+ return false;
+
+ // As per Xdnd4, use XdndProxy
+ XGrabServer(X11->display);
+ Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
+ WId proxy_id = xdndProxy(w->effectiveWinId());
+
+ if (!proxy_id) {
+ xdnd_widget = xdnd_data.desktop_proxy = new QWidget;
+ proxy_id = xdnd_data.desktop_proxy->effectiveWinId();
+ XChangeProperty (X11->display, w->effectiveWinId(), ATOM(XdndProxy),
+ XA_WINDOW, 32, PropModeReplace, (unsigned char *)&proxy_id, 1);
+ XChangeProperty (X11->display, proxy_id, ATOM(XdndProxy),
+ XA_WINDOW, 32, PropModeReplace, (unsigned char *)&proxy_id, 1);
+ }
+
+ XUngrabServer(X11->display);
+ } else {
+ xdnd_widget = w->window();
+ }
+ if (xdnd_widget) {
+ DNDDEBUG << "setting XdndAware for" << xdnd_widget << xdnd_widget->effectiveWinId();
+ Atom atm = (Atom)xdnd_version;
+ Q_ASSERT(xdnd_widget->testAttribute(Qt::WA_WState_Created));
+ XChangeProperty(X11->display, xdnd_widget->effectiveWinId(), ATOM(XdndAware),
+ XA_ATOM, 32, PropModeReplace, (unsigned char *)&atm, 1);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ if ((w->windowType() == Qt::Desktop)) {
+ XDeleteProperty(X11->display, w->internalWinId(), ATOM(XdndProxy));
+ delete xdnd_data.desktop_proxy;
+ xdnd_data.desktop_proxy = 0;
+ } else {
+ DNDDEBUG << "not deleting XDndAware";
+ }
+ return true;
+ }
+}
+
+QByteArray QX11Data::xdndAtomToString(Atom a)
+{
+ if (!a) return 0;
+
+ if (a == XA_STRING || a == ATOM(UTF8_STRING)) {
+ return "text/plain"; // some Xdnd clients are dumb
+ }
+ char *atom = XGetAtomName(display, a);
+ QByteArray result = atom;
+ XFree(atom);
+ return result;
+}
+
+Atom QX11Data::xdndStringToAtom(const char *mimeType)
+{
+ if (!mimeType || !*mimeType)
+ return 0;
+ return XInternAtom(display, mimeType, False);
+}
+
+//$$$
+QString QX11Data::xdndMimeAtomToString(Atom a)
+{
+ QString atomName;
+ if (a) {
+ char *atom = XGetAtomName(display, a);
+ atomName = QString::fromLatin1(atom);
+ XFree(atom);
+ }
+ return atomName;
+}
+
+//$$$
+Atom QX11Data::xdndMimeStringToAtom(const QString &mimeType)
+{
+ if (mimeType.isEmpty())
+ return 0;
+ return XInternAtom(display, mimeType.toLatin1().constData(), False);
+}
+
+//$$$ replace ccxdndAtomToString()
+QStringList QX11Data::xdndMimeFormatsForAtom(Atom a)
+{
+ QStringList formats;
+ if (a) {
+ QString atomName = xdndMimeAtomToString(a);
+ formats.append(atomName);
+
+ // special cases for string type
+ if (a == ATOM(UTF8_STRING) || a == XA_STRING
+ || a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT))
+ formats.append(QLatin1String("text/plain"));
+
+ // special cases for uris
+ if (atomName == QLatin1String("text/x-moz-url"))
+ formats.append(QLatin1String("text/uri-list"));
+
+ // special case for images
+ if (a == XA_PIXMAP)
+ formats.append(QLatin1String("image/ppm"));
+ }
+ return formats;
+}
+
+//$$$
+bool QX11Data::xdndMimeDataForAtom(Atom a, QMimeData *mimeData, QByteArray *data, Atom *atomFormat, int *dataFormat)
+{
+ bool ret = false;
+ *atomFormat = a;
+ *dataFormat = 8;
+ QString atomName = xdndMimeAtomToString(a);
+ if (QInternalMimeData::hasFormatHelper(atomName, mimeData)) {
+ *data = QInternalMimeData::renderDataHelper(atomName, mimeData);
+ if (atomName == QLatin1String("application/x-color"))
+ *dataFormat = 16;
+ ret = true;
+ } else {
+ if ((a == ATOM(UTF8_STRING) || a == XA_STRING
+ || a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT))
+ && QInternalMimeData::hasFormatHelper(QLatin1String("text/plain"), mimeData)) {
+ if (a == ATOM(UTF8_STRING)){
+ *data = QInternalMimeData::renderDataHelper(QLatin1String("text/plain"), mimeData);
+ ret = true;
+ } else if (a == XA_STRING) {
+ *data = QString::fromUtf8(QInternalMimeData::renderDataHelper(
+ QLatin1String("text/plain"), mimeData)).toLocal8Bit();
+ ret = true;
+ } else if (a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT)) {
+ // the ICCCM states that TEXT and COMPOUND_TEXT are in the
+ // encoding of choice, so we choose the encoding of the locale
+ QByteArray strData = QString::fromUtf8(QInternalMimeData::renderDataHelper(
+ QLatin1String("text/plain"), mimeData)).toLocal8Bit();
+ char *list[] = { strData.data(), NULL };
+
+ XICCEncodingStyle style = (a == ATOM(COMPOUND_TEXT))
+ ? XCompoundTextStyle : XStdICCTextStyle;
+ XTextProperty textprop;
+ if (list[0] != NULL
+ && XmbTextListToTextProperty(X11->display, list, 1, style,
+ &textprop) == Success) {
+ *atomFormat = textprop.encoding;
+ *dataFormat = textprop.format;
+ *data = QByteArray((const char *) textprop.value, textprop.nitems * textprop.format / 8);
+ ret = true;
+
+ DEBUG(" textprop type %lx\n"
+ " textprop name '%s'\n"
+ " format %d\n"
+ " %ld items\n"
+ " %d bytes\n",
+ textprop.encoding,
+ X11->xdndMimeAtomToString(textprop.encoding).toLatin1().data(),
+ textprop.format, textprop.nitems, data->size());
+
+ XFree(textprop.value);
+ }
+ }
+ } else if (atomName == QLatin1String("text/x-moz-url") &&
+ QInternalMimeData::hasFormatHelper(QLatin1String("text/uri-list"), mimeData)) {
+ QByteArray uri = QInternalMimeData::renderDataHelper(
+ QLatin1String("text/uri-list"), mimeData).split('\n').first();
+ QString mozUri = QString::fromLatin1(uri, uri.size());
+ mozUri += QLatin1Char('\n');
+ *data = QByteArray(reinterpret_cast<const char *>(mozUri.utf16()), mozUri.length() * 2);
+ ret = true;
+ } else if ((a == XA_PIXMAP || a == XA_BITMAP) && mimeData->hasImage()) {
+ QPixmap pm = qvariant_cast<QPixmap>(mimeData->imageData());
+ if (a == XA_BITMAP && pm.depth() != 1) {
+ QImage img = pm.toImage();
+ img = img.convertToFormat(QImage::Format_MonoLSB);
+ pm = QPixmap::fromImage(img);
+ }
+ QDragManager *dm = QDragManager::self();
+ if (dm) {
+ Pixmap handle = pm.handle();
+ *data = QByteArray((const char *) &handle, sizeof(Pixmap));
+ dm->xdndMimeTransferedPixmap[dm->xdndMimeTransferedPixmapIndex] = pm;
+ dm->xdndMimeTransferedPixmapIndex =
+ (dm->xdndMimeTransferedPixmapIndex + 1) % 2;
+ ret = true;
+ }
+ } else {
+ DEBUG("QClipboard: xdndMimeDataForAtom(): converting to type '%s' is not supported", qPrintable(atomName));
+ }
+ }
+ return ret && data != 0;
+}
+
+//$$$
+QList<Atom> QX11Data::xdndMimeAtomsForFormat(const QString &format)
+{
+ QList<Atom> atoms;
+ atoms.append(xdndMimeStringToAtom(format));
+
+ // special cases for strings
+ if (format == QLatin1String("text/plain")) {
+ atoms.append(ATOM(UTF8_STRING));
+ atoms.append(XA_STRING);
+ atoms.append(ATOM(TEXT));
+ atoms.append(ATOM(COMPOUND_TEXT));
+ }
+
+ // special cases for uris
+ if (format == QLatin1String("text/uri-list")) {
+ atoms.append(xdndMimeStringToAtom(QLatin1String("text/x-moz-url")));
+ }
+
+ //special cases for images
+ if (format == QLatin1String("image/ppm"))
+ atoms.append(XA_PIXMAP);
+ if (format == QLatin1String("image/pbm"))
+ atoms.append(XA_BITMAP);
+
+ return atoms;
+}
+
+//$$$
+QVariant QX11Data::xdndMimeConvertToFormat(Atom a, const QByteArray &data, const QString &format, QVariant::Type requestedType, const QByteArray &encoding)
+{
+ QString atomName = xdndMimeAtomToString(a);
+ if (atomName == format)
+ return data;
+
+ if (!encoding.isEmpty()
+ && atomName == format + QLatin1String(";charset=") + QString::fromLatin1(encoding)) {
+
+ if (requestedType == QVariant::String) {
+ QTextCodec *codec = QTextCodec::codecForName(encoding);
+ if (codec)
+ return codec->toUnicode(data);
+ }
+
+ return data;
+ }
+
+ // special cases for string types
+ if (format == QLatin1String("text/plain")) {
+ if (a == ATOM(UTF8_STRING))
+ return QString::fromUtf8(data);
+ if (a == XA_STRING)
+ return QString::fromLatin1(data);
+ if (a == ATOM(TEXT) || a == ATOM(COMPOUND_TEXT))
+ // #### might be wrong for COMPUND_TEXT
+ return QString::fromLocal8Bit(data, data.size());
+ }
+
+ // special case for uri types
+ if (format == QLatin1String("text/uri-list")) {
+ if (atomName == QLatin1String("text/x-moz-url")) {
+ // we expect this as utf16 <url><space><title>
+ // the first part is a url that should only contain ascci char
+ // so it should be safe to check that the second char is 0
+ // to verify that it is utf16
+ if (data.size() > 1 && data.at(1) == 0)
+ return QString::fromRawData((const QChar *)data.constData(),
+ data.size() / 2).split(QLatin1Char('\n')).first().toLatin1();
+ }
+ }
+
+ // special cas for images
+ if (format == QLatin1String("image/ppm")) {
+ if (a == XA_PIXMAP && data.size() == sizeof(Pixmap)) {
+ Pixmap xpm = *((Pixmap*)data.data());
+ if (!xpm)
+ return QByteArray();
+ QPixmap qpm = QPixmap::fromX11Pixmap(xpm);
+ QImageWriter imageWriter;
+ imageWriter.setFormat("PPMRAW");
+ QImage imageToWrite = qpm.toImage();
+ QBuffer buf;
+ buf.open(QIODevice::WriteOnly);
+ imageWriter.setDevice(&buf);
+ imageWriter.write(imageToWrite);
+ return buf.buffer();
+ }
+ }
+ return QVariant();
+}
+
+//$$$ middle of xdndObtainData
+Atom QX11Data::xdndMimeAtomForFormat(const QString &format, QVariant::Type requestedType, const QList<Atom> &atoms, QByteArray *encoding)
+{
+ encoding->clear();
+
+ // find matches for string types
+ if (format == QLatin1String("text/plain")) {
+ if (atoms.contains(ATOM(UTF8_STRING)))
+ return ATOM(UTF8_STRING);
+ if (atoms.contains(ATOM(COMPOUND_TEXT)))
+ return ATOM(COMPOUND_TEXT);
+ if (atoms.contains(ATOM(TEXT)))
+ return ATOM(TEXT);
+ if (atoms.contains(XA_STRING))
+ return XA_STRING;
+ }
+
+ // find matches for uri types
+ if (format == QLatin1String("text/uri-list")) {
+ Atom a = xdndMimeStringToAtom(format);
+ if (a && atoms.contains(a))
+ return a;
+ a = xdndMimeStringToAtom(QLatin1String("text/x-moz-url"));
+ if (a && atoms.contains(a))
+ return a;
+ }
+
+ // find match for image
+ if (format == QLatin1String("image/ppm")) {
+ if (atoms.contains(XA_PIXMAP))
+ return XA_PIXMAP;
+ }
+
+ // for string/text requests try to use a format with a well-defined charset
+ // first to avoid encoding problems
+ if (requestedType == QVariant::String
+ && format.startsWith(QLatin1String("text/"))
+ && !format.contains(QLatin1String("charset="))) {
+
+ QString formatWithCharset = format;
+ formatWithCharset.append(QLatin1String(";charset=utf-8"));
+
+ Atom a = xdndMimeStringToAtom(formatWithCharset);
+ if (a && atoms.contains(a)) {
+ *encoding = "utf-8";
+ return a;
+ }
+ }
+
+ Atom a = xdndMimeStringToAtom(format);
+ if (a && atoms.contains(a))
+ return a;
+
+ return 0;
+}
+
+void QX11Data::xdndSetup() {
+ QCursorData::initialize();
+ qAddPostRoutine(qt_xdnd_cleanup);
+}
+
+
+void qt_xdnd_cleanup()
+{
+ delete noDropCursor;
+ noDropCursor = 0;
+ delete copyCursor;
+ copyCursor = 0;
+ delete moveCursor;
+ moveCursor = 0;
+ delete linkCursor;
+ linkCursor = 0;
+ delete defaultPm;
+ defaultPm = 0;
+ delete xdnd_data.desktop_proxy;
+ xdnd_data.desktop_proxy = 0;
+ delete xdnd_data.deco;
+ xdnd_data.deco = 0;
+}
+
+
+static QWidget *find_child(QWidget *tlw, QPoint & p)
+{
+ QWidget *widget = tlw;
+
+ p = widget->mapFromGlobal(p);
+ bool done = false;
+ while (!done) {
+ done = true;
+ if (((QExtraWidget*)widget)->extraData() &&
+ ((QExtraWidget*)widget)->extraData()->xDndProxy != 0)
+ break; // stop searching for widgets under the mouse cursor if found widget is a proxy.
+ QObjectList children = widget->children();
+ if (!children.isEmpty()) {
+ for(int i = children.size(); i > 0;) {
+ --i;
+ QWidget *w = qobject_cast<QWidget *>(children.at(i));
+ if (!w)
+ continue;
+ if (w->testAttribute(Qt::WA_TransparentForMouseEvents))
+ continue;
+ if (w->isVisible() &&
+ w->geometry().contains(p) &&
+ !w->isWindow()) {
+ widget = w;
+ done = false;
+ p = widget->mapFromParent(p);
+ break;
+ }
+ }
+ }
+ }
+ return widget;
+}
+
+
+static bool checkEmbedded(QWidget* w, const XEvent* xe)
+{
+ if (!w)
+ return false;
+
+ if (current_embedding_widget != 0 && current_embedding_widget != w) {
+ qt_xdnd_current_target = ((QExtraWidget*)current_embedding_widget)->extraData()->xDndProxy;
+ qt_xdnd_current_proxy_target = qt_xdnd_current_target;
+ qt_xdnd_send_leave();
+ qt_xdnd_current_target = 0;
+ qt_xdnd_current_proxy_target = 0;
+ current_embedding_widget = 0;
+ }
+
+ QWExtra* extra = ((QExtraWidget*)w)->extraData();
+ if (extra && extra->xDndProxy != 0) {
+
+ if (current_embedding_widget != w) {
+
+ last_enter_event.xany.window = extra->xDndProxy;
+ XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, &last_enter_event);
+ current_embedding_widget = w;
+ }
+
+ ((XEvent*)xe)->xany.window = extra->xDndProxy;
+ XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, (XEvent*)xe);
+ if (qt_xdnd_current_widget != w) {
+ qt_xdnd_current_widget = w;
+ }
+ return true;
+ }
+ current_embedding_widget = 0;
+ return false;
+}
+
+void QX11Data::xdndHandleEnter(QWidget *, const XEvent * xe, bool /*passive*/)
+{
+ motifdnd_active = false;
+
+ last_enter_event.xclient = xe->xclient;
+
+ const long *l = xe->xclient.data.l;
+ int version = (int)(((unsigned long)(l[1])) >> 24);
+
+ if (version > xdnd_version)
+ return;
+
+ qt_xdnd_dragsource_xid = l[0];
+
+ int j = 0;
+ if (l[1] & 1) {
+ // get the types from XdndTypeList
+ Atom type = XNone;
+ int f;
+ unsigned long n, a;
+ unsigned char *retval = 0;
+ XGetWindowProperty(X11->display, qt_xdnd_dragsource_xid, ATOM(XdndTypelist), 0,
+ qt_xdnd_max_type, False, XA_ATOM, &type, &f,&n,&a,&retval);
+ if (retval) {
+ Atom *data = (Atom *)retval;
+ for (; j<qt_xdnd_max_type && j < (int)n; j++) {
+ qt_xdnd_types[j] = data[j];
+ }
+ XFree((uchar*)data);
+ }
+ } else {
+ // get the types from the message
+ int i;
+ for(i=2; i < 5; i++) {
+ qt_xdnd_types[j++] = l[i];
+ }
+ }
+ qt_xdnd_types[j] = 0;
+}
+
+static void handle_xdnd_position(QWidget *w, const XEvent * xe, bool passive)
+{
+ const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
+
+ QPoint p((l[2] & 0xffff0000) >> 16, l[2] & 0x0000ffff);
+ QWidget * c = find_child(w, p); // changes p to to c-local coordinates
+
+ if (!passive && checkEmbedded(c, xe))
+ return;
+
+ if (!c || (!c->acceptDrops() && (c->windowType() == Qt::Desktop)))
+ return;
+
+ if (l[0] != qt_xdnd_dragsource_xid) {
+ DEBUG("xdnd drag position from unexpected source (%08lx not %08lx)", l[0], qt_xdnd_dragsource_xid);
+ return;
+ }
+
+ // timestamp from the source
+ if (l[3] != 0) {
+ // Some X server/client combination swallow the first 32 bit and
+ // interpret a set bit 31 as negative sign.
+ qt_xdnd_target_current_time = X11->userTime =
+ ((sizeof(Time) == 8 && xe->xclient.data.l[3] < 0)
+ ? uint(l[3])
+ : l[3]);
+ }
+
+ QDragManager *manager = QDragManager::self();
+ QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData;
+
+ XClientMessageEvent response;
+ response.type = ClientMessage;
+ response.window = qt_xdnd_dragsource_xid;
+ response.format = 32;
+ response.message_type = ATOM(XdndStatus);
+ response.data.l[0] = w->effectiveWinId();
+ response.data.l[1] = 0; // flags
+ response.data.l[2] = 0; // x, y
+ response.data.l[3] = 0; // w, h
+ response.data.l[4] = 0; // action
+
+ if (!passive) { // otherwise just reject
+ while (c && !c->acceptDrops() && !c->isWindow()) {
+ p = c->mapToParent(p);
+ c = c->parentWidget();
+ }
+ QWidget *target_widget = c && c->acceptDrops() ? c : 0;
+
+ QRect answerRect(c->mapToGlobal(p), QSize(1,1));
+
+ if (manager->object) {
+ possible_actions = manager->dragPrivate()->possible_actions;
+ } else {
+ possible_actions = Qt::DropActions(xdndaction_to_qtaction(l[4]));
+// possible_actions |= Qt::CopyAction;
+ }
+ QDragMoveEvent me(p, possible_actions, dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers());
+
+ Qt::DropAction accepted_action = Qt::IgnoreAction;
+
+
+ if (target_widget != qt_xdnd_current_widget) {
+ if (qt_xdnd_current_widget) {
+ QDragLeaveEvent e;
+ QApplication::sendEvent(qt_xdnd_current_widget, &e);
+ }
+ if (qt_xdnd_current_widget != target_widget) {
+ qt_xdnd_current_widget = target_widget;
+ }
+ if (target_widget) {
+ qt_xdnd_current_position = p;
+
+ last_target_accepted_action = Qt::IgnoreAction;
+ QDragEnterEvent de(p, possible_actions, dropData, QApplication::mouseButtons(), QApplication::keyboardModifiers());
+ QApplication::sendEvent(target_widget, &de);
+ if (de.isAccepted() && de.dropAction() != Qt::IgnoreAction)
+ last_target_accepted_action = de.dropAction();
+ }
+ }
+
+ DEBUG() << "qt_handle_xdnd_position action=" << X11->xdndAtomToString(l[4]);
+ if (!target_widget) {
+ answerRect = QRect(p, QSize(1, 1));
+ } else {
+ qt_xdnd_current_widget = c;
+ qt_xdnd_current_position = p;
+
+ if (last_target_accepted_action != Qt::IgnoreAction) {
+ me.setDropAction(last_target_accepted_action);
+ me.accept();
+ }
+ QApplication::sendEvent(c, &me);
+ if (me.isAccepted()) {
+ response.data.l[1] = 1; // yes
+ accepted_action = me.dropAction();
+ last_target_accepted_action = accepted_action;
+ } else {
+ response.data.l[0] = 0;
+ last_target_accepted_action = Qt::IgnoreAction;
+ }
+ answerRect = me.answerRect().intersected(c->rect());
+ }
+ answerRect = QRect(c->mapToGlobal(answerRect.topLeft()), answerRect.size());
+
+ if (answerRect.left() < 0)
+ answerRect.setLeft(0);
+ if (answerRect.right() > 4096)
+ answerRect.setRight(4096);
+ if (answerRect.top() < 0)
+ answerRect.setTop(0);
+ if (answerRect.bottom() > 4096)
+ answerRect.setBottom(4096);
+ if (answerRect.width() < 0)
+ answerRect.setWidth(0);
+ if (answerRect.height() < 0)
+ answerRect.setHeight(0);
+
+ response.data.l[2] = (answerRect.x() << 16) + answerRect.y();
+ response.data.l[3] = (answerRect.width() << 16) + answerRect.height();
+ response.data.l[4] = qtaction_to_xdndaction(accepted_action);
+ }
+
+ // reset
+ qt_xdnd_target_current_time = CurrentTime;
+
+ QWidget * source = QWidget::find(qt_xdnd_dragsource_xid);
+ if (source && (source->windowType() == Qt::Desktop) && !source->acceptDrops())
+ source = 0;
+
+ DEBUG() << "sending XdndStatus";
+ if (source)
+ handle_xdnd_status(source, (const XEvent *)&response, passive);
+ else
+ XSendEvent(X11->display, qt_xdnd_dragsource_xid, False, NoEventMask, (XEvent*)&response);
+}
+
+static Bool xdnd_position_scanner(Display *, XEvent *event, XPointer)
+{
+ if (event->type != ClientMessage)
+ return false;
+ XClientMessageEvent *ev = &event->xclient;
+
+ if (ev->message_type == ATOM(XdndPosition))
+ return true;
+
+ return false;
+}
+
+void QX11Data::xdndHandlePosition(QWidget * w, const XEvent * xe, bool passive)
+{
+ DEBUG("xdndHandlePosition");
+ while (XCheckIfEvent(X11->display, (XEvent *)xe, xdnd_position_scanner, 0))
+ ;
+
+ handle_xdnd_position(w, xe, passive);
+}
+
+
+static void handle_xdnd_status(QWidget *, const XEvent * xe, bool)
+{
+ const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
+ // ignore late status messages
+ if (l[0] && l[0] != qt_xdnd_current_proxy_target)
+ return;
+ Qt::DropAction newAction = (l[1] & 0x1) ? xdndaction_to_qtaction(l[4]) : Qt::IgnoreAction;
+
+ if ((int)(l[1] & 2) == 0) {
+ QPoint p((l[2] & 0xffff0000) >> 16, l[2] & 0x0000ffff);
+ QSize s((l[3] & 0xffff0000) >> 16, l[3] & 0x0000ffff);
+ qt_xdnd_source_sameanswer = QRect(p, s);
+ } else {
+ qt_xdnd_source_sameanswer = QRect();
+ }
+ QDragManager *manager = QDragManager::self();
+ manager->willDrop = (l[1] & 0x1);
+ if (global_accepted_action != newAction)
+ manager->emitActionChanged(newAction);
+ global_accepted_action = newAction;
+ manager->updateCursor();
+ waiting_for_status = false;
+}
+
+static Bool xdnd_status_scanner(Display *, XEvent *event, XPointer)
+{
+ if (event->type != ClientMessage)
+ return false;
+ XClientMessageEvent *ev = &event->xclient;
+
+ if (ev->message_type == ATOM(XdndStatus))
+ return true;
+
+ return false;
+}
+
+void QX11Data::xdndHandleStatus(QWidget * w, const XEvent * xe, bool passive)
+{
+ DEBUG("xdndHandleStatus");
+ while (XCheckIfEvent(X11->display, (XEvent *)xe, xdnd_status_scanner, 0))
+ ;
+
+ handle_xdnd_status(w, xe, passive);
+ DEBUG("xdndHandleStatus end");
+}
+
+void QX11Data::xdndHandleLeave(QWidget *w, const XEvent * xe, bool /*passive*/)
+{
+ DEBUG("xdnd leave");
+ if (!qt_xdnd_current_widget ||
+ w->window() != qt_xdnd_current_widget->window()) {
+ return; // sanity
+ }
+
+ if (checkEmbedded(current_embedding_widget, xe)) {
+ current_embedding_widget = 0;
+ qt_xdnd_current_widget = 0;
+ return;
+ }
+
+ const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
+
+ QDragLeaveEvent e;
+ QApplication::sendEvent(qt_xdnd_current_widget, &e);
+
+ if (l[0] != qt_xdnd_dragsource_xid) {
+ // This often happens - leave other-process window quickly
+ DEBUG("xdnd drag leave from unexpected source (%08lx not %08lx", l[0], qt_xdnd_dragsource_xid);
+ qt_xdnd_current_widget = 0;
+ return;
+ }
+
+ qt_xdnd_dragsource_xid = 0;
+ qt_xdnd_types[0] = 0;
+ qt_xdnd_current_widget = 0;
+}
+
+
+void qt_xdnd_send_leave()
+{
+ if (!qt_xdnd_current_target)
+ return;
+
+ QDragManager *manager = QDragManager::self();
+
+ XClientMessageEvent leave;
+ leave.type = ClientMessage;
+ leave.window = qt_xdnd_current_target;
+ leave.format = 32;
+ leave.message_type = ATOM(XdndLeave);
+ leave.data.l[0] = manager->dragPrivate()->source->effectiveWinId();
+ leave.data.l[1] = 0; // flags
+ leave.data.l[2] = 0; // x, y
+ leave.data.l[3] = 0; // w, h
+ leave.data.l[4] = 0; // just null
+
+ QWidget * w = QWidget::find(qt_xdnd_current_proxy_target);
+
+ if (w && (w->windowType() == Qt::Desktop) && !w->acceptDrops())
+ w = 0;
+
+ if (w)
+ X11->xdndHandleLeave(w, (const XEvent *)&leave, false);
+ else
+ XSendEvent(X11->display, qt_xdnd_current_proxy_target, False,
+ NoEventMask, (XEvent*)&leave);
+
+ // reset the drag manager state
+ manager->willDrop = false;
+ if (global_accepted_action != Qt::IgnoreAction)
+ manager->emitActionChanged(Qt::IgnoreAction);
+ global_accepted_action = Qt::IgnoreAction;
+ manager->updateCursor();
+ qt_xdnd_current_target = 0;
+ qt_xdnd_current_proxy_target = 0;
+ qt_xdnd_source_current_time = 0;
+ waiting_for_status = false;
+}
+
+// TODO: remove and use QApplication::currentKeyboardModifiers() in Qt 4.8.
+static Qt::KeyboardModifiers currentKeyboardModifiers()
+{
+ Window root;
+ Window child;
+ int root_x, root_y, win_x, win_y;
+ uint keybstate;
+ for (int i = 0; i < ScreenCount(X11->display); ++i) {
+ if (XQueryPointer(X11->display, QX11Info::appRootWindow(i), &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &keybstate))
+ return X11->translateModifiers(keybstate & 0x00ff);
+ }
+ return 0;
+}
+
+void QX11Data::xdndHandleDrop(QWidget *, const XEvent * xe, bool passive)
+{
+ DEBUG("xdndHandleDrop");
+ if (!qt_xdnd_current_widget) {
+ qt_xdnd_dragsource_xid = 0;
+ return; // sanity
+ }
+
+ if (!passive && checkEmbedded(qt_xdnd_current_widget, xe)){
+ current_embedding_widget = 0;
+ qt_xdnd_dragsource_xid = 0;
+ qt_xdnd_current_widget = 0;
+ return;
+ }
+ const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
+
+ QDragManager *manager = QDragManager::self();
+ DEBUG("xdnd drop");
+
+ if (l[0] != qt_xdnd_dragsource_xid) {
+ DEBUG("xdnd drop from unexpected source (%08lx not %08lx", l[0], qt_xdnd_dragsource_xid);
+ return;
+ }
+
+ // update the "user time" from the timestamp in the event.
+ if (l[2] != 0) {
+ // Some X server/client combination swallow the first 32 bit and
+ // interpret a set bit 31 as negative sign.
+ qt_xdnd_target_current_time = X11->userTime =
+ ((sizeof(Time) == 8 && xe->xclient.data.l[2] < 0)
+ ? uint(l[2])
+ : l[2]);
+ }
+
+ if (!passive) {
+ // this could be a same-application drop, just proxied due to
+ // some XEMBEDding, so try to find the real QMimeData used
+ // based on the timestamp for this drop.
+ QMimeData *dropData = 0;
+ int at = findXdndDropTransactionByTime(qt_xdnd_target_current_time);
+ if (at != -1)
+ dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data;
+ // if we can't find it, then use the data in the drag manager
+ if (!dropData)
+ dropData = (manager->object) ? manager->dragPrivate()->data : manager->dropData;
+
+ // Drop coming from another app? Update keyboard modifiers.
+ if (!qt_xdnd_dragging) {
+ QApplicationPrivate::modifier_buttons = currentKeyboardModifiers();
+ }
+
+ QDropEvent de(qt_xdnd_current_position, possible_actions, dropData,
+ QApplication::mouseButtons(), QApplication::keyboardModifiers());
+ QApplication::sendEvent(qt_xdnd_current_widget, &de);
+ if (!de.isAccepted()) {
+ // Ignore a failed drag
+ global_accepted_action = Qt::IgnoreAction;
+ } else {
+ global_accepted_action = de.dropAction();
+ }
+ XClientMessageEvent finished;
+ finished.type = ClientMessage;
+ finished.window = qt_xdnd_dragsource_xid;
+ finished.format = 32;
+ finished.message_type = ATOM(XdndFinished);
+ DNDDEBUG << "xdndHandleDrop"
+ << "qt_xdnd_current_widget" << qt_xdnd_current_widget
+ << (qt_xdnd_current_widget ? qt_xdnd_current_widget->effectiveWinId() : 0)
+ << "t_xdnd_current_widget->window()"
+ << (qt_xdnd_current_widget ? qt_xdnd_current_widget->window() : 0)
+ << (qt_xdnd_current_widget ? qt_xdnd_current_widget->window()->internalWinId() : 0);
+ finished.data.l[0] = qt_xdnd_current_widget?qt_xdnd_current_widget->window()->internalWinId():0;
+ finished.data.l[1] = de.isAccepted() ? 1 : 0; // flags
+ finished.data.l[2] = qtaction_to_xdndaction(global_accepted_action);
+ XSendEvent(X11->display, qt_xdnd_dragsource_xid, False,
+ NoEventMask, (XEvent*)&finished);
+ } else {
+ QDragLeaveEvent e;
+ QApplication::sendEvent(qt_xdnd_current_widget, &e);
+ }
+ qt_xdnd_dragsource_xid = 0;
+ qt_xdnd_current_widget = 0;
+ waiting_for_status = false;
+
+ // reset
+ qt_xdnd_target_current_time = CurrentTime;
+}
+
+
+void QX11Data::xdndHandleFinished(QWidget *, const XEvent * xe, bool passive)
+{
+ DEBUG("xdndHandleFinished");
+ const unsigned long *l = (const unsigned long *)xe->xclient.data.l;
+
+ DNDDEBUG << "xdndHandleFinished, l[0]" << l[0]
+ << "qt_xdnd_current_target" << qt_xdnd_current_target
+ << "qt_xdnd_current_proxy_targe" << qt_xdnd_current_proxy_target;
+
+ if (l[0]) {
+ int at = findXdndDropTransactionByWindow(l[0]);
+ if (at != -1) {
+ restartXdndDropExpiryTimer();
+
+ QXdndDropTransaction t = X11->dndDropTransactions.takeAt(at);
+ QDragManager *manager = QDragManager::self();
+
+ Window target = qt_xdnd_current_target;
+ Window proxy_target = qt_xdnd_current_proxy_target;
+ QWidget *embedding_widget = current_embedding_widget;
+ QDrag *currentObject = manager->object;
+
+ qt_xdnd_current_target = t.target;
+ qt_xdnd_current_proxy_target = t.proxy_target;
+ current_embedding_widget = t.embedding_widget;
+ manager->object = t.object;
+
+ if (!passive)
+ (void) checkEmbedded(qt_xdnd_current_widget, xe);
+
+ current_embedding_widget = 0;
+ qt_xdnd_current_target = 0;
+ qt_xdnd_current_proxy_target = 0;
+
+ if (t.object)
+ t.object->deleteLater();
+
+ qt_xdnd_current_target = target;
+ qt_xdnd_current_proxy_target = proxy_target;
+ current_embedding_widget = embedding_widget;
+ manager->object = currentObject;
+ }
+ }
+ waiting_for_status = false;
+}
+
+
+void QDragManager::timerEvent(QTimerEvent* e)
+{
+ if (e->timerId() == heartbeat && qt_xdnd_source_sameanswer.isNull()) {
+ move(QCursor::pos());
+ } else if (e->timerId() == transaction_expiry_timer) {
+ for (int i = 0; i < X11->dndDropTransactions.count(); ++i) {
+ const QXdndDropTransaction &t = X11->dndDropTransactions.at(i);
+ if (t.targetWidget) {
+ // dnd within the same process, don't delete these
+ continue;
+ }
+ t.object->deleteLater();
+ X11->dndDropTransactions.removeAt(i--);
+ }
+
+ killTimer(transaction_expiry_timer);
+ transaction_expiry_timer = -1;
+ }
+}
+
+bool QDragManager::eventFilter(QObject * o, QEvent * e)
+{
+ if (beingCancelled) {
+ if (e->type() == QEvent::KeyRelease && ((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;
+ }
+
+ Q_ASSERT(object != 0);
+
+ if (!o->isWidgetType())
+ return false;
+
+ if (e->type() == QEvent::MouseMove) {
+ QMouseEvent* me = (QMouseEvent *)e;
+ move(me->globalPos());
+ return true;
+ } else if (e->type() == QEvent::MouseButtonRelease) {
+ DEBUG("pre drop");
+ qApp->removeEventFilter(this);
+ if (willDrop)
+ drop();
+ else
+ cancel();
+ DEBUG("drop, resetting object");
+ beingCancelled = false;
+ eventLoop->exit();
+ return true;
+ }
+
+ if (e->type() == QEvent::ShortcutOverride) {
+ // prevent accelerators from firing while dragging
+ e->accept();
+ return true;
+ }
+
+ if (e->type() == QEvent::KeyPress || e->type() == 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 {
+ qt_xdnd_source_sameanswer = QRect(); // force move
+ move(QCursor::pos());
+ }
+ return true; // Eat all key events
+ }
+
+ // ### We bind modality to widgets, so we have to do this
+ // ### "manually".
+ // DnD is modal - eat all other interactive events
+ switch (e->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ case QEvent::Wheel:
+ case QEvent::ShortcutOverride:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void QDragManager::updateCursor()
+{
+ if (!noDropCursor) {
+#ifndef QT_NO_CURSOR
+ noDropCursor = new QCursor(Qt::ForbiddenCursor);
+ moveCursor = new QCursor(Qt::DragMoveCursor);
+ copyCursor = new QCursor(Qt::DragCopyCursor);
+ linkCursor = new QCursor(Qt::DragLinkCursor);
+#endif
+ }
+
+ QCursor *c;
+ if (willDrop) {
+ if (global_accepted_action == Qt::CopyAction) {
+ c = copyCursor;
+ } else if (global_accepted_action == Qt::LinkAction) {
+ c = linkCursor;
+ } else {
+ c = moveCursor;
+ }
+ if (xdnd_data.deco) {
+ xdnd_data.deco->show();
+ xdnd_data.deco->raise();
+ }
+ } else {
+ c = noDropCursor;
+ //if (qt_xdnd_deco)
+ // qt_xdnd_deco->hide();
+ }
+#ifndef QT_NO_CURSOR
+ if (c)
+ qApp->changeOverrideCursor(*c);
+#endif
+}
+
+
+void QDragManager::cancel(bool deleteSource)
+{
+ DEBUG("QDragManager::cancel");
+ Q_ASSERT(heartbeat != -1);
+ killTimer(heartbeat);
+ heartbeat = -1;
+ beingCancelled = true;
+ qt_xdnd_dragging = false;
+
+ if (qt_xdnd_current_target)
+ qt_xdnd_send_leave();
+
+#ifndef QT_NO_CURSOR
+ if (restoreCursor) {
+ QApplication::restoreOverrideCursor();
+ restoreCursor = false;
+ }
+#endif
+
+ if (deleteSource && object)
+ object->deleteLater();
+ object = 0;
+ qDeleteInEventHandler(xdnd_data.deco);
+ xdnd_data.deco = 0;
+
+ global_accepted_action = Qt::IgnoreAction;
+}
+
+static
+Window findRealWindow(const QPoint & pos, Window w, int md)
+{
+ if (xdnd_data.deco && w == xdnd_data.deco->effectiveWinId())
+ return 0;
+
+ if (md) {
+ X11->ignoreBadwindow();
+ XWindowAttributes attr;
+ XGetWindowAttributes(X11->display, w, &attr);
+ if (X11->badwindow())
+ return 0;
+
+ if (attr.map_state == IsViewable
+ && QRect(attr.x,attr.y,attr.width,attr.height).contains(pos)) {
+ {
+ Atom type = XNone;
+ int f;
+ unsigned long n, a;
+ unsigned char *data;
+
+ XGetWindowProperty(X11->display, w, ATOM(XdndAware), 0, 0, False,
+ AnyPropertyType, &type, &f,&n,&a,&data);
+ if (data) XFree(data);
+ if (type)
+ return w;
+ }
+
+ Window r, p;
+ Window* c;
+ uint nc;
+ if (XQueryTree(X11->display, w, &r, &p, &c, &nc)) {
+ r=0;
+ for (uint i=nc; !r && i--;) {
+ r = findRealWindow(pos-QPoint(attr.x,attr.y),
+ c[i], md-1);
+ }
+ XFree(c);
+ if (r)
+ return r;
+
+ // We didn't find a client window! Just use the
+ // innermost window.
+ }
+
+ // No children!
+ return w;
+ }
+ }
+ return 0;
+}
+
+void QDragManager::move(const QPoint & globalPos)
+{
+#ifdef QT_NO_CURSOR
+ Q_UNUSED(globalPos);
+ return;
+#else
+ DEBUG() << "QDragManager::move enter";
+ if (!object) {
+ // perhaps the target crashed?
+ return;
+ }
+
+ int screen = QCursor::x11Screen();
+ if ((qt_xdnd_current_screen == -1 && screen != X11->defaultScreen) || (screen != qt_xdnd_current_screen)) {
+ // recreate the pixmap on the new screen...
+ delete xdnd_data.deco;
+ QWidget* parent = object->source()->window()->x11Info().screen() == screen
+ ? object->source()->window() : QApplication::desktop()->screen(screen);
+ xdnd_data.deco = new QShapedPixmapWidget(parent);
+ if (!QWidget::mouseGrabber()) {
+ updatePixmap();
+ xdnd_data.deco->grabMouse();
+ }
+ }
+ xdnd_data.deco->move(QCursor::pos() - xdnd_data.deco->pm_hot);
+
+ if (qt_xdnd_source_sameanswer.contains(globalPos) && qt_xdnd_source_sameanswer.isValid())
+ return;
+
+ qt_xdnd_current_screen = screen;
+ Window rootwin = QX11Info::appRootWindow(qt_xdnd_current_screen);
+ Window target = 0;
+ int lx = 0, ly = 0;
+ if (!XTranslateCoordinates(X11->display, rootwin, rootwin, globalPos.x(), globalPos.y(), &lx, &ly, &target))
+ // some weird error...
+ return;
+
+ if (target == rootwin) {
+ // Ok.
+ } else if (target) {
+ //me
+ Window src = rootwin;
+ while (target != 0) {
+ DNDDEBUG << "checking target for XdndAware" << QWidget::find(target) << target;
+ int lx2, ly2;
+ Window t;
+ // translate coordinates
+ if (!XTranslateCoordinates(X11->display, src, target, lx, ly, &lx2, &ly2, &t)) {
+ target = 0;
+ break;
+ }
+ lx = lx2;
+ ly = ly2;
+ src = target;
+
+ // check if it has XdndAware
+ Atom type = 0;
+ int f;
+ unsigned long n, a;
+ unsigned char *data = 0;
+ XGetWindowProperty(X11->display, target, ATOM(XdndAware), 0, 0, False,
+ AnyPropertyType, &type, &f,&n,&a,&data);
+ if (data)
+ XFree(data);
+ if (type) {
+ DNDDEBUG << "Found XdndAware on " << QWidget::find(target) << target;
+ break;
+ }
+
+ // find child at the coordinates
+ if (!XTranslateCoordinates(X11->display, src, src, lx, ly, &lx2, &ly2, &target)) {
+ target = 0;
+ break;
+ }
+ }
+ if (xdnd_data.deco && (!target || target == xdnd_data.deco->effectiveWinId())) {
+ DNDDEBUG << "need to find real window";
+ target = findRealWindow(globalPos, rootwin, 6);
+ DNDDEBUG << "real window found" << QWidget::find(target) << target;
+ }
+ }
+
+ QWidget* w;
+ if (target) {
+ w = QWidget::find((WId)target);
+ if (w && (w->windowType() == Qt::Desktop) && !w->acceptDrops())
+ w = 0;
+ } else {
+ w = 0;
+ target = rootwin;
+ }
+
+ DNDDEBUG << "and the final target is " << QWidget::find(target) << target;
+ DNDDEBUG << "the widget w is" << w;
+
+ WId proxy_target = xdndProxy(target);
+ if (!proxy_target)
+ proxy_target = target;
+ int target_version = 1;
+
+ if (proxy_target) {
+ Atom type = XNone;
+ int r, f;
+ unsigned long n, a;
+ unsigned char *retval;
+ X11->ignoreBadwindow();
+ r = XGetWindowProperty(X11->display, proxy_target, ATOM(XdndAware), 0,
+ 1, False, AnyPropertyType, &type, &f,&n,&a,&retval);
+ int *tv = (int *)retval;
+ if (r != Success || X11->badwindow()) {
+ target = 0;
+ } else {
+ target_version = qMin(xdnd_version,tv ? *tv : 1);
+ if (tv)
+ XFree(tv);
+// if (!(!X11->badwindow() && type))
+// target = 0;
+ }
+ }
+
+ if (target != qt_xdnd_current_target) {
+ if (qt_xdnd_current_target)
+ qt_xdnd_send_leave();
+
+ qt_xdnd_current_target = target;
+ qt_xdnd_current_proxy_target = proxy_target;
+ if (target) {
+ QVector<Atom> types;
+ int flags = target_version << 24;
+ QStringList fmts = QInternalMimeData::formatsHelper(dragPrivate()->data);
+ for (int i = 0; i < fmts.size(); ++i) {
+ QList<Atom> atoms = X11->xdndMimeAtomsForFormat(fmts.at(i));
+ for (int j = 0; j < atoms.size(); ++j) {
+ if (!types.contains(atoms.at(j)))
+ types.append(atoms.at(j));
+ }
+ }
+ if (types.size() > 3) {
+ XChangeProperty(X11->display,
+ dragPrivate()->source->effectiveWinId(), ATOM(XdndTypelist),
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *)types.data(),
+ types.size());
+ flags |= 0x0001;
+ }
+ XClientMessageEvent enter;
+ enter.type = ClientMessage;
+ enter.window = target;
+ enter.format = 32;
+ enter.message_type = ATOM(XdndEnter);
+ enter.data.l[0] = dragPrivate()->source->effectiveWinId();
+ enter.data.l[1] = flags;
+ enter.data.l[2] = types.size()>0 ? types.at(0) : 0;
+ enter.data.l[3] = types.size()>1 ? types.at(1) : 0;
+ enter.data.l[4] = types.size()>2 ? types.at(2) : 0;
+ // provisionally set the rectangle to 5x5 pixels...
+ qt_xdnd_source_sameanswer = QRect(globalPos.x() - 2,
+ globalPos.y() -2 , 5, 5);
+
+ DEBUG("sending Xdnd enter");
+ if (w)
+ X11->xdndHandleEnter(w, (const XEvent *)&enter, false);
+ else if (target)
+ XSendEvent(X11->display, proxy_target, False, NoEventMask, (XEvent*)&enter);
+ waiting_for_status = false;
+ }
+ }
+ if (waiting_for_status)
+ return;
+
+ if (target) {
+ waiting_for_status = true;
+
+ XClientMessageEvent move;
+ move.type = ClientMessage;
+ move.window = target;
+ move.format = 32;
+ move.message_type = ATOM(XdndPosition);
+ move.window = target;
+ move.data.l[0] = dragPrivate()->source->effectiveWinId();
+ move.data.l[1] = 0; // flags
+ move.data.l[2] = (globalPos.x() << 16) + globalPos.y();
+ move.data.l[3] = X11->time;
+ move.data.l[4] = qtaction_to_xdndaction(defaultAction(dragPrivate()->possible_actions, QApplication::keyboardModifiers()));
+ DEBUG("sending Xdnd position");
+
+ qt_xdnd_source_current_time = X11->time;
+
+ if (w)
+ handle_xdnd_position(w, (const XEvent *)&move, false);
+ else
+ XSendEvent(X11->display, proxy_target, False, NoEventMask,
+ (XEvent*)&move);
+ } else {
+ if (willDrop) {
+ willDrop = false;
+ updateCursor();
+ }
+ }
+ DEBUG() << "QDragManager::move leave";
+#endif
+}
+
+
+void QDragManager::drop()
+{
+ Q_ASSERT(heartbeat != -1);
+ killTimer(heartbeat);
+ heartbeat = -1;
+ qt_xdnd_dragging = false;
+
+ if (!qt_xdnd_current_target)
+ return;
+
+ qDeleteInEventHandler(xdnd_data.deco);
+ xdnd_data.deco = 0;
+
+ XClientMessageEvent drop;
+ drop.type = ClientMessage;
+ drop.window = qt_xdnd_current_target;
+ drop.format = 32;
+ drop.message_type = ATOM(XdndDrop);
+ drop.data.l[0] = dragPrivate()->source->effectiveWinId();
+ drop.data.l[1] = 0; // flags
+ drop.data.l[2] = X11->time;
+
+ drop.data.l[3] = 0;
+ drop.data.l[4] = 0;
+
+ QWidget * w = QWidget::find(qt_xdnd_current_proxy_target);
+
+ if (w && (w->windowType() == Qt::Desktop) && !w->acceptDrops())
+ w = 0;
+
+ QXdndDropTransaction t = {
+ X11->time,
+ qt_xdnd_current_target,
+ qt_xdnd_current_proxy_target,
+ w,
+ current_embedding_widget,
+ object
+ };
+ X11->dndDropTransactions.append(t);
+ restartXdndDropExpiryTimer();
+
+ if (w)
+ X11->xdndHandleDrop(w, (const XEvent *)&drop, false);
+ else
+ XSendEvent(X11->display, qt_xdnd_current_proxy_target, False,
+ NoEventMask, (XEvent*)&drop);
+
+ qt_xdnd_current_target = 0;
+ qt_xdnd_current_proxy_target = 0;
+ qt_xdnd_source_current_time = 0;
+ current_embedding_widget = 0;
+ object = 0;
+
+#ifndef QT_NO_CURSOR
+ if (restoreCursor) {
+ QApplication::restoreOverrideCursor();
+ restoreCursor = false;
+ }
+#endif
+}
+
+
+
+bool QX11Data::xdndHandleBadwindow()
+{
+ if (qt_xdnd_current_target) {
+ QDragManager *manager = QDragManager::self();
+ if (manager->object) {
+ qt_xdnd_current_target = 0;
+ qt_xdnd_current_proxy_target = 0;
+ manager->object->deleteLater();
+ manager->object = 0;
+ delete xdnd_data.deco;
+ xdnd_data.deco = 0;
+ return true;
+ }
+ }
+ if (qt_xdnd_dragsource_xid) {
+ qt_xdnd_dragsource_xid = 0;
+ if (qt_xdnd_current_widget) {
+ QApplication::postEvent(qt_xdnd_current_widget, new QDragLeaveEvent);
+ qt_xdnd_current_widget = 0;
+ }
+ return true;
+ }
+ return false;
+}
+
+void QX11Data::xdndHandleSelectionRequest(const XSelectionRequestEvent * req)
+{
+ if (!req)
+ return;
+ XEvent evt;
+ evt.xselection.type = SelectionNotify;
+ evt.xselection.display = req->display;
+ evt.xselection.requestor = req->requestor;
+ evt.xselection.selection = req->selection;
+ evt.xselection.target = XNone;
+ evt.xselection.property = XNone;
+ evt.xselection.time = req->time;
+
+ QDragManager *manager = QDragManager::self();
+ QDrag *currentObject = manager->object;
+
+ // which transaction do we use? (note: -2 means use current manager->object)
+ int at = -1;
+
+ // figure out which data the requestor is really interested in
+ if (manager->object && req->time == qt_xdnd_source_current_time) {
+ // requestor wants the current drag data
+ at = -2;
+ } else {
+ // if someone has requested data in response to XdndDrop, find the corresponding transaction. the
+ // spec says to call XConvertSelection() using the timestamp from the XdndDrop
+ at = findXdndDropTransactionByTime(req->time);
+ if (at == -1) {
+ // no dice, perhaps the client was nice enough to use the same window id in XConvertSelection()
+ // that we sent the XdndDrop event to.
+ at = findXdndDropTransactionByWindow(req->requestor);
+ }
+ if (at == -1 && req->time == CurrentTime) {
+ // previous Qt versions always requested the data on a child of the target window
+ // using CurrentTime... but it could be asking for either drop data or the current drag's data
+ Window target = findXdndAwareParent(req->requestor);
+ if (target) {
+ if (qt_xdnd_current_target && qt_xdnd_current_target == target)
+ at = -2;
+ else
+ at = findXdndDropTransactionByWindow(target);
+ }
+ }
+ }
+ if (at >= 0) {
+ restartXdndDropExpiryTimer();
+
+ // use the drag object from an XdndDrop tansaction
+ manager->object = X11->dndDropTransactions.at(at).object;
+ } else if (at != -2) {
+ // no transaction found, we'll have to reject the request
+ manager->object = 0;
+ }
+ if (manager->object) {
+ Atom atomFormat = req->target;
+ int dataFormat = 0;
+ QByteArray data;
+ if (X11->xdndMimeDataForAtom(req->target, manager->dragPrivate()->data,
+ &data, &atomFormat, &dataFormat)) {
+ int dataSize = data.size() / (dataFormat / 8);
+ XChangeProperty (X11->display, req->requestor, req->property,
+ atomFormat, dataFormat, PropModeReplace,
+ (unsigned char *)data.data(), dataSize);
+ evt.xselection.property = req->property;
+ evt.xselection.target = atomFormat;
+ }
+ }
+
+ // reset manager->object in case we modified it above
+ manager->object = currentObject;
+
+ // ### this can die if req->requestor crashes at the wrong
+ // ### moment
+ XSendEvent(X11->display, req->requestor, False, 0, &evt);
+}
+
+static QVariant xdndObtainData(const char *format, QVariant::Type requestedType)
+{
+ QByteArray result;
+
+ QWidget* w;
+ QDragManager *manager = QDragManager::self();
+ if (qt_xdnd_dragsource_xid && manager->object &&
+ (w=QWidget::find(qt_xdnd_dragsource_xid))
+ && (!(w->windowType() == Qt::Desktop) || w->acceptDrops()))
+ {
+ QDragPrivate * o = QDragManager::self()->dragPrivate();
+ if (o->data->hasFormat(QLatin1String(format)))
+ result = o->data->data(QLatin1String(format));
+ return result;
+ }
+
+ QList<Atom> atoms;
+ int i = 0;
+ while ((qt_xdnd_types[i])) {
+ atoms.append(qt_xdnd_types[i]);
+ ++i;
+ }
+ QByteArray encoding;
+ Atom a = X11->xdndMimeAtomForFormat(QLatin1String(format), requestedType, atoms, &encoding);
+ if (!a)
+ return result;
+
+ if (XGetSelectionOwner(X11->display, ATOM(XdndSelection)) == XNone)
+ return result; // should never happen?
+
+ QWidget* tw = qt_xdnd_current_widget;
+ if (!qt_xdnd_current_widget || (qt_xdnd_current_widget->windowType() == Qt::Desktop))
+ tw = new QWidget;
+
+ XConvertSelection(X11->display, ATOM(XdndSelection), a, ATOM(XdndSelection), tw->effectiveWinId(),
+ qt_xdnd_target_current_time);
+ XFlush(X11->display);
+
+ XEvent xevent;
+ bool got=X11->clipboardWaitForEvent(tw->effectiveWinId(), SelectionNotify, &xevent, 5000);
+ if (got) {
+ Atom type;
+
+ if (X11->clipboardReadProperty(tw->effectiveWinId(), ATOM(XdndSelection), true, &result, 0, &type, 0)) {
+ if (type == ATOM(INCR)) {
+ int nbytes = result.size() >= 4 ? *((int*)result.data()) : 0;
+ result = X11->clipboardReadIncrementalProperty(tw->effectiveWinId(), ATOM(XdndSelection), nbytes, false);
+ } else if (type != a && type != XNone) {
+ DEBUG("Qt clipboard: unknown atom %ld", type);
+ }
+ }
+ }
+ if (!qt_xdnd_current_widget || (qt_xdnd_current_widget->windowType() == Qt::Desktop))
+ delete tw;
+
+ return X11->xdndMimeConvertToFormat(a, result, QLatin1String(format), requestedType, encoding);
+}
+
+
+/*
+ Enable drag and drop for widget w by installing the proper
+ properties on w's toplevel widget.
+*/
+bool QX11Data::dndEnable(QWidget* w, bool on)
+{
+ w = w->window();
+
+ if (bool(((QExtraWidget*)w)->topData()->dnd) == on)
+ return true; // been there, done that
+ ((QExtraWidget*)w)->topData()->dnd = on ? 1 : 0;
+
+ motifdndEnable(w, on);
+ return xdndEnable(w, on);
+}
+
+Qt::DropAction QDragManager::drag(QDrag * o)
+{
+ if (object == o || !o || !o->d_func()->source)
+ return Qt::IgnoreAction;
+
+ if (object) {
+ cancel();
+ qApp->removeEventFilter(this);
+ beingCancelled = false;
+ }
+
+ if (object) {
+ // the last drag and drop operation hasn't finished, so we are going to wait
+ // for one second to see if it does... if the finish message comes after this,
+ // then we could still have problems, but this is highly unlikely
+ QApplication::flush();
+
+ QElapsedTimer timer;
+ timer.start();
+ do {
+ XEvent event;
+ if (XCheckTypedEvent(X11->display, ClientMessage, &event))
+ qApp->x11ProcessEvent(&event);
+
+ // sleep 50 ms, so we don't use up CPU cycles all the time.
+ struct timeval usleep_tv;
+ usleep_tv.tv_sec = 0;
+ usleep_tv.tv_usec = 50000;
+ select(0, 0, 0, 0, &usleep_tv);
+ } while (object && timer.hasExpired(1000));
+ }
+
+ object = o;
+ object->d_func()->target = 0;
+ xdnd_data.deco = new QShapedPixmapWidget(object->source()->window());
+
+ willDrop = false;
+
+ updatePixmap();
+
+ qApp->installEventFilter(this);
+ XSetSelectionOwner(X11->display, ATOM(XdndSelection), dragPrivate()->source->window()->internalWinId(), X11->time);
+ global_accepted_action = Qt::CopyAction;
+ qt_xdnd_source_sameanswer = QRect();
+#ifndef QT_NO_CURSOR
+ // set the override cursor (must be done here, since it is updated
+ // in the call to move() below)
+ qApp->setOverrideCursor(Qt::ArrowCursor);
+ restoreCursor = true;
+#endif
+ move(QCursor::pos());
+ heartbeat = startTimer(200);
+
+ qt_xdnd_dragging = true;
+
+ if (!QWidget::mouseGrabber())
+ xdnd_data.deco->grabMouse();
+
+ eventLoop = new QEventLoop;
+ (void) eventLoop->exec();
+ delete eventLoop;
+ eventLoop = 0;
+
+#ifndef QT_NO_CURSOR
+ if (restoreCursor) {
+ qApp->restoreOverrideCursor();
+ restoreCursor = false;
+ }
+#endif
+
+ // delete cursors as they may be different next drag.
+ delete noDropCursor;
+ noDropCursor = 0;
+ delete copyCursor;
+ copyCursor = 0;
+ delete moveCursor;
+ moveCursor = 0;
+ delete linkCursor;
+ linkCursor = 0;
+
+ delete xdnd_data.deco;
+ xdnd_data.deco = 0;
+ if (heartbeat != -1)
+ killTimer(heartbeat);
+ heartbeat = -1;
+ qt_xdnd_current_screen = -1;
+ qt_xdnd_dragging = false;
+
+ return global_accepted_action;
+ // object persists until we get an xdnd_finish message
+}
+
+void QDragManager::updatePixmap()
+{
+ if (xdnd_data.deco) {
+ QPixmap pm;
+ QPoint pm_hot(default_pm_hotx,default_pm_hoty);
+ if (object) {
+ pm = dragPrivate()->pixmap;
+ if (!pm.isNull())
+ pm_hot = dragPrivate()->hotspot;
+ }
+ if (pm.isNull()) {
+ if (!defaultPm)
+ defaultPm = new QPixmap(default_pm);
+ pm = *defaultPm;
+ }
+ xdnd_data.deco->pm_hot = pm_hot;
+ xdnd_data.deco->setPixmap(pm);
+ xdnd_data.deco->move(QCursor::pos()-pm_hot);
+ xdnd_data.deco->show();
+ }
+}
+
+QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const
+{
+ QByteArray mime = mimetype.toLatin1();
+ QVariant data = X11->motifdnd_active
+ ? X11->motifdndObtainData(mime)
+ : xdndObtainData(mime, requestedType);
+ return data;
+}
+
+bool QDropData::hasFormat_sys(const QString &format) const
+{
+ return formats().contains(format);
+}
+
+QStringList QDropData::formats_sys() const
+{
+ QStringList formats;
+ if (X11->motifdnd_active) {
+ int i = 0;
+ QByteArray fmt;
+ while (!(fmt = X11->motifdndFormat(i)).isEmpty()) {
+ formats.append(QLatin1String(fmt));
+ ++i;
+ }
+ } else {
+ int i = 0;
+ while ((qt_xdnd_types[i])) {
+ QStringList formatsForAtom = X11->xdndMimeFormatsForAtom(qt_xdnd_types[i]);
+ for (int j = 0; j < formatsForAtom.size(); ++j) {
+ if (!formats.contains(formatsForAtom.at(j)))
+ formats.append(formatsForAtom.at(j));
+ }
+ ++i;
+ }
+ }
+ return formats;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DRAGANDDROP
diff --git a/src/widgets/platforms/x11/qeventdispatcher_x11.cpp b/src/widgets/platforms/x11/qeventdispatcher_x11.cpp
new file mode 100644
index 0000000000..110786a378
--- /dev/null
+++ b/src/widgets/platforms/x11/qeventdispatcher_x11.cpp
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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_x11_p.h"
+
+#include "qapplication.h"
+#include "qx11info_x11.h"
+
+#include "qt_x11_p.h"
+#include <private/qeventdispatcher_unix_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEventDispatcherX11Private : public QEventDispatcherUNIXPrivate
+{
+ Q_DECLARE_PUBLIC(QEventDispatcherX11)
+public:
+ inline QEventDispatcherX11Private()
+ : xfd(-1)
+ { }
+ int xfd;
+ QList<XEvent> queuedUserInputEvents;
+};
+
+QEventDispatcherX11::QEventDispatcherX11(QObject *parent)
+ : QEventDispatcherUNIX(*new QEventDispatcherX11Private, parent)
+{ }
+
+QEventDispatcherX11::~QEventDispatcherX11()
+{ }
+
+bool QEventDispatcherX11::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ Q_D(QEventDispatcherX11);
+
+ d->interrupt = false;
+ QApplication::sendPostedEvents();
+
+ ulong marker = XNextRequest(X11->display);
+ int nevents = 0;
+ do {
+ while (!d->interrupt) {
+ XEvent event;
+ if (!(flags & QEventLoop::ExcludeUserInputEvents)
+ && !d->queuedUserInputEvents.isEmpty()) {
+ // process a pending user input event
+ event = d->queuedUserInputEvents.takeFirst();
+ } else if (XEventsQueued(X11->display, QueuedAlready)) {
+ // process events from the X server
+ XNextEvent(X11->display, &event);
+
+ if (flags & QEventLoop::ExcludeUserInputEvents) {
+ // queue user input events
+ switch (event.type) {
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ case XKeyPress:
+ case XKeyRelease:
+ case EnterNotify:
+ case LeaveNotify:
+ d->queuedUserInputEvents.append(event);
+ continue;
+
+ case ClientMessage:
+ // only keep the wm_take_focus and
+ // _qt_scrolldone protocols, queue all other
+ // client messages
+ if (event.xclient.format == 32) {
+ if (event.xclient.message_type == ATOM(WM_PROTOCOLS) &&
+ (Atom) event.xclient.data.l[0] == ATOM(WM_TAKE_FOCUS)) {
+ break;
+ } else if (event.xclient.message_type == ATOM(_QT_SCROLL_DONE)) {
+ break;
+ }
+ }
+ d->queuedUserInputEvents.append(event);
+ continue;
+
+ default:
+ break;
+ }
+ }
+ } else {
+ // no event to process
+ break;
+ }
+
+ // send through event filter
+ if (filterEvent(&event))
+ continue;
+
+ nevents++;
+ if (qApp->x11ProcessEvent(&event) == 1)
+ return true;
+
+ if (event.xany.serial >= marker) {
+ if (XEventsQueued(X11->display, QueuedAfterFlush))
+ flags &= ~QEventLoop::WaitForMoreEvents;
+ goto out;
+ }
+ }
+ } while (!d->interrupt && XEventsQueued(X11->display, QueuedAfterFlush));
+
+ out:
+ if (!d->interrupt) {
+ const uint exclude_all =
+ QEventLoop::ExcludeSocketNotifiers | QEventLoop::X11ExcludeTimers | QEventLoop::WaitForMoreEvents;
+ if (nevents > 0 && ((uint)flags & exclude_all) == exclude_all) {
+ QApplication::sendPostedEvents();
+ return nevents > 0;
+ }
+ // return true if we handled events, false otherwise
+ return QEventDispatcherUNIX::processEvents(flags) || (nevents > 0);
+ }
+ return nevents > 0;
+}
+
+bool QEventDispatcherX11::hasPendingEvents()
+{
+ extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
+ return (qGlobalPostedEventsCount() || XPending(X11->display));
+}
+
+void QEventDispatcherX11::flush()
+{
+ XFlush(X11->display);
+}
+
+void QEventDispatcherX11::startingUp()
+{
+ Q_D(QEventDispatcherX11);
+ d->xfd = XConnectionNumber(X11->display);
+}
+
+void QEventDispatcherX11::closingDown()
+{
+ Q_D(QEventDispatcherX11);
+ d->xfd = -1;
+}
+
+int QEventDispatcherX11::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ timeval *timeout)
+{
+ Q_D(QEventDispatcherX11);
+ if (d->xfd > 0) {
+ nfds = qMax(nfds - 1, d->xfd) + 1;
+ FD_SET(d->xfd, readfds);
+ }
+ return QEventDispatcherUNIX::select(nfds, readfds, writefds, exceptfds, timeout);
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qeventdispatcher_x11_p.h b/src/widgets/platforms/x11/qeventdispatcher_x11_p.h
new file mode 100644
index 0000000000..cfdd2a5fa6
--- /dev/null
+++ b/src/widgets/platforms/x11/qeventdispatcher_x11_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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_X11_P_H
+#define QEVENTDISPATCHER_X11_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 QEventDispatcherX11Private;
+
+class QEventDispatcherX11 : public QEventDispatcherUNIX
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QEventDispatcherX11)
+
+public:
+ explicit QEventDispatcherX11(QObject *parent = 0);
+ ~QEventDispatcherX11();
+
+ 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_X11_P_H
diff --git a/src/widgets/platforms/x11/qfont_x11.cpp b/src/widgets/platforms/x11/qfont_x11.cpp
new file mode 100644
index 0000000000..c72a5fade5
--- /dev/null
+++ b/src/widgets/platforms/x11/qfont_x11.cpp
@@ -0,0 +1,368 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qfontengine_x11_p.h"
+#include "qtextengine_p.h"
+
+#include <private/qt_x11_p.h>
+#include "qx11info_x11.h"
+
+#include <time.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define QFONTLOADER_DEBUG
+#define QFONTLOADER_DEBUG_VERBOSE
+
+QT_BEGIN_NAMESPACE
+
+double qt_pixelSize(double pointSize, int dpi)
+{
+ if (pointSize < 0)
+ return -1.;
+ if (dpi == 75) // the stupid 75 dpi setting on X11
+ dpi = 72;
+ return (pointSize * dpi) /72.;
+}
+
+double qt_pointSize(double pixelSize, int dpi)
+{
+ if (pixelSize < 0)
+ return -1.;
+ if (dpi == 75) // the stupid 75 dpi setting on X11
+ dpi = 72;
+ return pixelSize * 72. / ((double) dpi);
+}
+
+/*
+ Removes wildcards from an XLFD.
+
+ Returns \a xlfd with all wildcards removed if a match for \a xlfd is
+ found, otherwise it returns \a xlfd.
+*/
+static QByteArray qt_fixXLFD(const QByteArray &xlfd)
+{
+ QByteArray ret = xlfd;
+ int count = 0;
+ char **fontNames =
+ XListFonts(QX11Info::display(), xlfd, 32768, &count);
+ if (count > 0)
+ ret = fontNames[0];
+ XFreeFontNames(fontNames);
+ return ret ;
+}
+
+typedef QHash<int, QString> FallBackHash;
+Q_GLOBAL_STATIC(FallBackHash, fallBackHash)
+
+// Returns the user-configured fallback family for the specified script.
+QString qt_fallback_font_family(int script)
+{
+ FallBackHash *hash = fallBackHash();
+ return hash->value(script);
+}
+
+// Sets the fallback family for the specified script.
+Q_GUI_EXPORT void qt_x11_set_fallback_font_family(int script, const QString &family)
+{
+ FallBackHash *hash = fallBackHash();
+ if (!family.isEmpty())
+ hash->insert(script, family);
+ else
+ hash->remove(script);
+}
+
+int QFontPrivate::defaultEncodingID = -1;
+
+void QFont::initialize()
+{
+ extern int qt_encoding_id_for_mib(int mib); // from qfontdatabase_x11.cpp
+ QTextCodec *codec = QTextCodec::codecForLocale();
+ // determine the default encoding id using the locale, otherwise
+ // fallback to latin1 (mib == 4)
+ int mib = codec ? codec->mibEnum() : 4;
+
+ // for asian locales, use the mib for the font codec instead of the locale codec
+ switch (mib) {
+ case 38: // eucKR
+ mib = 36;
+ break;
+
+ case 2025: // GB2312
+ mib = 57;
+ break;
+
+ case 113: // GBK
+ mib = -113;
+ break;
+
+ case 114: // GB18030
+ mib = -114;
+ break;
+
+ case 2026: // Big5
+ mib = -2026;
+ break;
+
+ case 2101: // Big5-HKSCS
+ mib = -2101;
+ break;
+
+ case 16: // JIS7
+ mib = 15;
+ break;
+
+ case 17: // SJIS
+ case 18: // eucJP
+ mib = 63;
+ break;
+ }
+
+ // get the default encoding id for the locale encoding...
+ QFontPrivate::defaultEncodingID = qt_encoding_id_for_mib(mib);
+}
+
+void QFont::cleanup()
+{
+ QFontCache::cleanup();
+}
+
+/*!
+ \internal
+ X11 Only: Returns the screen with which this font is associated.
+*/
+int QFont::x11Screen() const
+{
+ return d->screen;
+}
+
+/*! \internal
+ X11 Only: Associate the font with the specified \a screen.
+*/
+void QFont::x11SetScreen(int screen)
+{
+ if (screen < 0) // assume default
+ screen = QX11Info::appScreen();
+
+ if (screen == d->screen)
+ return; // nothing to do
+
+ detach();
+ d->screen = screen;
+}
+
+Qt::HANDLE QFont::handle() 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 static_cast<QFontEngineXLFD *>(engine)->fontStruct()->fid;
+ return 0;
+}
+
+
+FT_Face QFont::freetypeFace() const
+{
+#ifndef QT_NO_FREETYPE
+ QFontEngine *engine = 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) {
+ const QFontEngineFT *ft = static_cast<const QFontEngineFT *>(engine);
+ return ft->non_locked_face();
+ } else
+#endif
+ if (engine->type() == QFontEngine::XLFD) {
+ const QFontEngineXLFD *xlfd = static_cast<const QFontEngineXLFD *>(engine);
+ return xlfd->non_locked_face();
+ }
+#endif
+ 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();
+
+ // from qfontdatabase_x11.cpp
+ extern bool qt_fillFontDef(const QByteArray &xlfd, QFontDef *fd, int dpi, QtFontDesc *desc);
+
+ if (!qt_fillFontDef(qt_fixXLFD(name.toLatin1()), &d->request, d->dpi, 0)) {
+ qWarning("QFont::setRawName: Invalid XLFD: \"%s\"", name.toLatin1().constData());
+
+ setFamily(name);
+ setRawMode(true);
+ } else {
+ resolve_mask = QFont::AllPropertiesResolved;
+ }
+}
+
+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::Monospace:
+ return QString::fromLatin1("Courier New");
+
+ case QFont::Cursive:
+ return QString::fromLatin1("Comic Sans MS");
+
+ case QFont::Fantasy:
+ return QString::fromLatin1("Impact");
+
+ 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)
+{
+ int count;
+ char **fontNames = XListFonts(QX11Info::display(), (char*)fontName.toLatin1().constData(), 32768, &count);
+ if (fontNames) XFreeFontNames(fontNames);
+
+ return count != 0;
+}
+
+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/widgets/platforms/x11/qfontdatabase_x11.cpp b/src/widgets/platforms/x11/qfontdatabase_x11.cpp
new file mode 100644
index 0000000000..0c0c4c8343
--- /dev/null
+++ b/src/widgets/platforms/x11/qfontdatabase_x11.cpp
@@ -0,0 +1,2146 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 <qpaintdevice.h>
+#include <qelapsedtimer.h>
+
+#include <private/qt_x11_p.h>
+#include "qx11info_x11.h"
+#include <qdebug.h>
+#include <qfile.h>
+#include <qtemporaryfile.h>
+#include <qabstractfileengine.h>
+#include <qmath.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <private/qfontengine_x11_p.h>
+
+#ifndef QT_NO_FONTCONFIG
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#if FC_VERSION >= 20402
+#include <fontconfig/fcfreetype.h>
+#endif
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// from qfont_x11.cpp
+extern double qt_pointSize(double pixelSize, int dpi);
+extern double qt_pixelSize(double pointSize, int dpi);
+
+// from qapplication.cpp
+extern bool qt_is_gui_used;
+
+static inline void capitalize (char *s)
+{
+ bool space = true;
+ while(*s) {
+ if (space)
+ *s = toupper(*s);
+ space = (*s == ' ');
+ ++s;
+ }
+}
+
+
+/*
+ To regenerate the writingSystems_for_xlfd_encoding table, run
+ 'util/unicode/x11/makeencodings' and paste the generated
+ 'encodings.c' here.
+*/
+// ----- begin of generated code -----
+
+#define make_tag( c1, c2, c3, c4 ) \
+ ((((unsigned int)c1)<<24) | (((unsigned int)c2)<<16) | \
+ (((unsigned int)c3)<<8) | ((unsigned int)c4))
+
+struct XlfdEncoding {
+ const char *name;
+ int id;
+ int mib;
+ unsigned int hash1;
+ unsigned int hash2;
+};
+
+static const XlfdEncoding xlfd_encoding[] = {
+ { "iso8859-1", 0, 4, make_tag('i','s','o','8'), make_tag('5','9','-','1') },
+ { "iso8859-2", 1, 5, make_tag('i','s','o','8'), make_tag('5','9','-','2') },
+ { "iso8859-3", 2, 6, make_tag('i','s','o','8'), make_tag('5','9','-','3') },
+ { "iso8859-4", 3, 7, make_tag('i','s','o','8'), make_tag('5','9','-','4') },
+ { "iso8859-9", 4, 12, make_tag('i','s','o','8'), make_tag('5','9','-','9') },
+ { "iso8859-10", 5, 13, make_tag('i','s','o','8'), make_tag('9','-','1','0') },
+ { "iso8859-13", 6, 109, make_tag('i','s','o','8'), make_tag('9','-','1','3') },
+ { "iso8859-14", 7, 110, make_tag('i','s','o','8'), make_tag('9','-','1','4') },
+ { "iso8859-15", 8, 111, make_tag('i','s','o','8'), make_tag('9','-','1','5') },
+ { "hp-roman8", 9, 2004, make_tag('h','p','-','r'), make_tag('m','a','n','8') },
+ { "iso8859-5", 10, 8, make_tag('i','s','o','8'), make_tag('5','9','-','5') },
+ { "*-cp1251", 11, 2251, 0, make_tag('1','2','5','1') },
+ { "koi8-ru", 12, 2084, make_tag('k','o','i','8'), make_tag('8','-','r','u') },
+ { "koi8-u", 13, 2088, make_tag('k','o','i','8'), make_tag('i','8','-','u') },
+ { "koi8-r", 14, 2084, make_tag('k','o','i','8'), make_tag('i','8','-','r') },
+ { "iso8859-7", 15, 10, make_tag('i','s','o','8'), make_tag('5','9','-','7') },
+ { "iso8859-8", 16, 85, make_tag('i','s','o','8'), make_tag('5','9','-','8') },
+ { "gb18030-0", 17, -114, make_tag('g','b','1','8'), make_tag('3','0','-','0') },
+ { "gb18030.2000-0", 18, -113, make_tag('g','b','1','8'), make_tag('0','0','-','0') },
+ { "gbk-0", 19, -113, make_tag('g','b','k','-'), make_tag('b','k','-','0') },
+ { "gb2312.*-0", 20, 57, make_tag('g','b','2','3'), 0 },
+ { "jisx0201*-0", 21, 15, make_tag('j','i','s','x'), 0 },
+ { "jisx0208*-0", 22, 63, make_tag('j','i','s','x'), 0 },
+ { "ksc5601*-*", 23, 36, make_tag('k','s','c','5'), 0 },
+ { "big5hkscs-0", 24, -2101, make_tag('b','i','g','5'), make_tag('c','s','-','0') },
+ { "hkscs-1", 25, -2101, make_tag('h','k','s','c'), make_tag('c','s','-','1') },
+ { "big5*-*", 26, -2026, make_tag('b','i','g','5'), 0 },
+ { "tscii-*", 27, 2028, make_tag('t','s','c','i'), 0 },
+ { "tis620*-*", 28, 2259, make_tag('t','i','s','6'), 0 },
+ { "iso8859-11", 29, 2259, make_tag('i','s','o','8'), make_tag('9','-','1','1') },
+ { "mulelao-1", 30, -4242, make_tag('m','u','l','e'), make_tag('a','o','-','1') },
+ { "ethiopic-unicode", 31, 0, make_tag('e','t','h','i'), make_tag('c','o','d','e') },
+ { "iso10646-1", 32, 0, make_tag('i','s','o','1'), make_tag('4','6','-','1') },
+ { "unicode-*", 33, 0, make_tag('u','n','i','c'), 0 },
+ { "*-symbol", 34, 0, 0, make_tag('m','b','o','l') },
+ { "*-fontspecific", 35, 0, 0, make_tag('i','f','i','c') },
+ { "fontspecific-*", 36, 0, make_tag('f','o','n','t'), 0 },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const char writingSystems_for_xlfd_encoding[sizeof(xlfd_encoding)][QFontDatabase::WritingSystemsCount] = {
+ // iso8859-1
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-2
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-3
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-4
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-9
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-10
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-13
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-14
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-15
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // hp-roman8
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-5
+ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // *-cp1251
+ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // koi8-ru
+ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // koi8-u
+ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // koi8-r
+ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-7
+ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-8
+ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // gb18030-0
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0 },
+ // gb18030.2000-0
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0 },
+ // gbk-0
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0 },
+ // gb2312.*-0
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0 },
+ // jisx0201*-0
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0 },
+ // jisx0208*-0
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0 },
+ // ksc5601*-*
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0 },
+ // big5hkscs-0
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0 },
+ // hkscs-1
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0 },
+ // big5*-*
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0 },
+ // tscii-*
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // tis620*-*
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso8859-11
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // mulelao-1
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // ethiopic-unicode
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ // iso10646-1
+ { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 0, 1, 0, 1, 1, 0, 0, 0,
+ 0, 0 },
+ // unicode-*
+ { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 0, 1, 0, 1, 1, 0, 0, 0,
+ 0, 0 },
+ // *-symbol
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0 },
+ // *-fontspecific
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0 },
+ // fontspecific-*
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0 }
+
+};
+
+// ----- end of generated code -----
+
+
+const int numEncodings = sizeof(xlfd_encoding) / sizeof(XlfdEncoding) - 1;
+
+int qt_xlfd_encoding_id(const char *encoding)
+{
+ // qDebug("looking for encoding id for '%s'", encoding);
+ int len = strlen(encoding);
+ if (len < 4)
+ return -1;
+ unsigned int hash1 = make_tag(encoding[0], encoding[1], encoding[2], encoding[3]);
+ const char *ch = encoding + len - 4;
+ unsigned int hash2 = make_tag(ch[0], ch[1], ch[2], ch[3]);
+
+ const XlfdEncoding *enc = xlfd_encoding;
+ for (; enc->name; ++enc) {
+ if ((enc->hash1 && enc->hash1 != hash1) ||
+ (enc->hash2 && enc->hash2 != hash2))
+ continue;
+ // hashes match, do a compare if strings match
+ // the enc->name can contain '*'s we have to interpret correctly
+ const char *n = enc->name;
+ const char *e = encoding;
+ while (1) {
+ // qDebug("bol: *e='%c', *n='%c'", *e, *n);
+ if (*e == '\0') {
+ if (*n)
+ break;
+ // qDebug("found encoding id %d", enc->id);
+ return enc->id;
+ }
+ if (*e == *n) {
+ ++e;
+ ++n;
+ continue;
+ }
+ if (*n != '*')
+ break;
+ ++n;
+ // qDebug("skip: *e='%c', *n='%c'", *e, *n);
+ while (*e && *e != *n)
+ ++e;
+ }
+ }
+ // qDebug("couldn't find encoding %s", encoding);
+ return -1;
+}
+
+int qt_mib_for_xlfd_encoding(const char *encoding)
+{
+ int id = qt_xlfd_encoding_id(encoding);
+ if (id != -1) return xlfd_encoding[id].mib;
+ return 0;
+}
+
+int qt_encoding_id_for_mib(int mib)
+{
+ const XlfdEncoding *enc = xlfd_encoding;
+ for (; enc->name; ++enc) {
+ if (enc->mib == mib)
+ return enc->id;
+ }
+ return -1;
+}
+
+static const char * xlfd_for_id(int id)
+{
+ // special case: -1 returns the "*-*" encoding, allowing us to do full
+ // database population in a single X server round trip.
+ if (id < 0 || id > numEncodings)
+ return "*-*";
+ return xlfd_encoding[id].name;
+}
+
+enum XLFDFieldNames {
+ Foundry,
+ Family,
+ Weight,
+ Slant,
+ Width,
+ AddStyle,
+ PixelSize,
+ PointSize,
+ ResolutionX,
+ ResolutionY,
+ Spacing,
+ AverageWidth,
+ CharsetRegistry,
+ CharsetEncoding,
+ NFontFields
+};
+
+// Splits an X font name into fields separated by '-'
+static bool parseXFontName(char *fontName, char **tokens)
+{
+ if (! fontName || fontName[0] == '0' || fontName[0] != '-') {
+ tokens[0] = 0;
+ return false;
+ }
+
+ int i;
+ ++fontName;
+ for (i = 0; i < NFontFields && fontName && fontName[0]; ++i) {
+ tokens[i] = fontName;
+ for (;; ++fontName) {
+ if (*fontName == '-')
+ break;
+ if (! *fontName) {
+ fontName = 0;
+ break;
+ }
+ }
+
+ if (fontName) *fontName++ = '\0';
+ }
+
+ if (i < NFontFields) {
+ for (int j = i ; j < NFontFields; ++j)
+ tokens[j] = 0;
+ return false;
+ }
+
+ return true;
+}
+
+static inline bool isZero(char *x)
+{
+ return (x[0] == '0' && x[1] == 0);
+}
+
+static inline bool isScalable(char **tokens)
+{
+ return (isZero(tokens[PixelSize]) &&
+ isZero(tokens[PointSize]) &&
+ isZero(tokens[AverageWidth]));
+}
+
+static inline bool isSmoothlyScalable(char **tokens)
+{
+ return (isZero(tokens[ResolutionX]) &&
+ isZero(tokens[ResolutionY]));
+}
+
+static inline bool isFixedPitch(char **tokens)
+{
+ return (tokens[Spacing][0] == 'm' ||
+ tokens[Spacing][0] == 'c' ||
+ tokens[Spacing][0] == 'M' ||
+ tokens[Spacing][0] == 'C');
+}
+
+/*
+ Fills in a font definition (QFontDef) from an XLFD (X Logical Font
+ Description).
+
+ Returns true if the given xlfd is valid.
+*/
+bool qt_fillFontDef(const QByteArray &xlfd, QFontDef *fd, int dpi, QtFontDesc *desc)
+{
+ char *tokens[NFontFields];
+ QByteArray buffer = xlfd;
+ if (! parseXFontName(buffer.data(), tokens))
+ return false;
+
+ capitalize(tokens[Family]);
+ capitalize(tokens[Foundry]);
+
+ fd->styleStrategy |= QFont::NoAntialias;
+ fd->family = QString::fromLatin1(tokens[Family]);
+ QString foundry = QString::fromLatin1(tokens[Foundry]);
+ if (! foundry.isEmpty() && foundry != QLatin1String("*") && (!desc || desc->family->count > 1))
+ fd->family +=
+ QLatin1String(" [") + foundry + QLatin1Char(']');
+
+ if (qstrlen(tokens[AddStyle]) > 0)
+ fd->addStyle = QString::fromLatin1(tokens[AddStyle]);
+ else
+ fd->addStyle.clear();
+
+ fd->pointSize = atoi(tokens[PointSize])/10.;
+ fd->styleHint = QFont::AnyStyle; // ### any until we match families
+
+ char slant = tolower((uchar) tokens[Slant][0]);
+ fd->style = (slant == 'o' ? QFont::StyleOblique : (slant == 'i' ? QFont::StyleItalic : QFont::StyleNormal));
+ char fixed = tolower((uchar) tokens[Spacing][0]);
+ fd->fixedPitch = (fixed == 'm' || fixed == 'c');
+ fd->weight = getFontWeight(QLatin1String(tokens[Weight]));
+
+ int r = atoi(tokens[ResolutionY]);
+ fd->pixelSize = atoi(tokens[PixelSize]);
+ // not "0" or "*", or required DPI
+ if (r && fd->pixelSize && r != dpi) {
+ // calculate actual pointsize for display DPI
+ fd->pointSize = qt_pointSize(fd->pixelSize, dpi);
+ } else if (fd->pixelSize == 0 && fd->pointSize) {
+ // calculate pixel size from pointsize/dpi
+ fd->pixelSize = qRound(qt_pixelSize(fd->pointSize, dpi));
+ }
+
+ return true;
+}
+
+/*
+ Fills in a font definition (QFontDef) from the font properties in an
+ XFontStruct.
+
+ Returns true if the QFontDef could be filled with properties from
+ the XFontStruct.
+*/
+static bool qt_fillFontDef(XFontStruct *fs, QFontDef *fd, int dpi, QtFontDesc *desc)
+{
+ unsigned long value;
+ if (!fs || !XGetFontProperty(fs, XA_FONT, &value))
+ return false;
+
+ char *n = XGetAtomName(QX11Info::display(), value);
+ QByteArray xlfd(n);
+ if (n)
+ XFree(n);
+ return qt_fillFontDef(xlfd.toLower(), fd, dpi, desc);
+}
+
+
+static QtFontStyle::Key getStyle(char ** tokens)
+{
+ QtFontStyle::Key key;
+
+ char slant0 = tolower((uchar) tokens[Slant][0]);
+
+ if (slant0 == 'r') {
+ if (tokens[Slant][1]) {
+ char slant1 = tolower((uchar) tokens[Slant][1]);
+
+ if (slant1 == 'o')
+ key.style = QFont::StyleOblique;
+ else if (slant1 == 'i')
+ key.style = QFont::StyleItalic;
+ }
+ } else if (slant0 == 'o')
+ key.style = QFont::StyleOblique;
+ else if (slant0 == 'i')
+ key.style = QFont::StyleItalic;
+
+ key.weight = getFontWeight(QLatin1String(tokens[Weight]));
+
+ if (qstrcmp(tokens[Width], "normal") == 0) {
+ key.stretch = 100;
+ } else if (qstrcmp(tokens[Width], "semi condensed") == 0 ||
+ qstrcmp(tokens[Width], "semicondensed") == 0) {
+ key.stretch = 90;
+ } else if (qstrcmp(tokens[Width], "condensed") == 0) {
+ key.stretch = 80;
+ } else if (qstrcmp(tokens[Width], "narrow") == 0) {
+ key.stretch = 60;
+ }
+
+ return key;
+}
+
+
+static bool xlfdsFullyLoaded = false;
+static unsigned char encodingLoaded[numEncodings];
+
+static void loadXlfds(const char *reqFamily, int encoding_id)
+{
+ QFontDatabasePrivate *db = privateDb();
+ QtFontFamily *fontFamily = reqFamily ? db->family(QLatin1String(reqFamily)) : 0;
+
+ // make sure we don't load twice
+ if ((encoding_id == -1 && xlfdsFullyLoaded)
+ || (encoding_id != -1 && encodingLoaded[encoding_id]))
+ return;
+ if (fontFamily && fontFamily->xlfdLoaded)
+ return;
+
+ int fontCount;
+ // force the X server to give us XLFDs
+ QByteArray xlfd_pattern("-*-");
+ xlfd_pattern += (reqFamily && reqFamily[0] != '\0') ? reqFamily : "*";
+ xlfd_pattern += "-*-*-*-*-*-*-*-*-*-*-";
+ xlfd_pattern += xlfd_for_id(encoding_id);
+
+ char **fontList = XListFonts(QX11Info::display(),
+ xlfd_pattern,
+ 0xffff, &fontCount);
+ // qDebug("requesting xlfd='%s', got %d fonts", xlfd_pattern.data(), fontCount);
+
+
+ char *tokens[NFontFields];
+
+ for(int i = 0 ; i < fontCount ; i++) {
+ if (! parseXFontName(fontList[i], tokens))
+ continue;
+
+ // get the encoding_id for this xlfd. we need to do this
+ // here, since we can pass -1 to this function to do full
+ // database population
+ *(tokens[CharsetEncoding] - 1) = '-';
+ int encoding_id = qt_xlfd_encoding_id(tokens[CharsetRegistry]);
+ if (encoding_id == -1)
+ continue;
+
+ char *familyName = tokens[Family];
+ capitalize(familyName);
+ char *foundryName = tokens[Foundry];
+ capitalize(foundryName);
+ QtFontStyle::Key styleKey = getStyle(tokens);
+
+ bool smooth_scalable = false;
+ bool bitmap_scalable = false;
+ if (isScalable(tokens)) {
+ if (isSmoothlyScalable(tokens))
+ smooth_scalable = true;
+ else
+ bitmap_scalable = true;
+ }
+ uint pixelSize = atoi(tokens[PixelSize]);
+ uint xpointSize = atoi(tokens[PointSize]);
+ uint xres = atoi(tokens[ResolutionX]);
+ uint yres = atoi(tokens[ResolutionY]);
+ uint avgwidth = atoi(tokens[AverageWidth]);
+ bool fixedPitch = isFixedPitch(tokens);
+
+ if (avgwidth == 0 && pixelSize != 0) {
+ /*
+ Ignore bitmap scalable fonts that are automatically
+ generated by some X servers. We know they are bitmap
+ scalable because even though they have a specified pixel
+ size, the average width is zero.
+ */
+ continue;
+ }
+
+ QtFontFamily *family = fontFamily ? fontFamily : db->family(QLatin1String(familyName), true);
+ family->fontFileIndex = -1;
+ family->symbol_checked = true;
+ QtFontFoundry *foundry = family->foundry(QLatin1String(foundryName), true);
+ QtFontStyle *style = foundry->style(styleKey, true);
+
+ delete [] style->weightName;
+ style->weightName = qstrdup(tokens[Weight]);
+ delete [] style->setwidthName;
+ style->setwidthName = qstrdup(tokens[Width]);
+
+ if (smooth_scalable) {
+ style->smoothScalable = true;
+ style->bitmapScalable = false;
+ pixelSize = SMOOTH_SCALABLE;
+ }
+ if (!style->smoothScalable && bitmap_scalable)
+ style->bitmapScalable = true;
+ if (!fixedPitch)
+ family->fixedPitch = false;
+
+ QtFontSize *size = style->pixelSize(pixelSize, true);
+ QtFontEncoding *enc =
+ size->encodingID(encoding_id, xpointSize, xres, yres, avgwidth, true);
+ enc->pitch = *tokens[Spacing];
+ if (!enc->pitch) enc->pitch = '*';
+
+ for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
+ if (writingSystems_for_xlfd_encoding[encoding_id][i])
+ family->writingSystems[i] = QtFontFamily::Supported;
+ }
+ }
+ if (!reqFamily) {
+ // mark encoding as loaded
+ if (encoding_id == -1)
+ xlfdsFullyLoaded = true;
+ else
+ encodingLoaded[encoding_id] = true;
+ }
+
+ XFreeFontNames(fontList);
+}
+
+
+#ifndef QT_NO_FONTCONFIG
+
+#ifndef FC_WIDTH
+#define FC_WIDTH "width"
+#endif
+
+static int getFCWeight(int fc_weight)
+{
+ int qtweight = QFont::Black;
+ if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2)
+ qtweight = QFont::Light;
+ else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2)
+ qtweight = QFont::Normal;
+ else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2)
+ qtweight = QFont::DemiBold;
+ else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2)
+ qtweight = QFont::Bold;
+
+ return qtweight;
+}
+
+QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &request)
+{
+ QFontDef fontDef;
+ fontDef.styleStrategy = request.styleStrategy;
+
+ fontDef.hintingPreference = request.hintingPreference;
+ FcChar8 *value = 0;
+ if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) == FcResultMatch) {
+ fontDef.family = QString::fromUtf8(reinterpret_cast<const char *>(value));
+ }
+
+ double dpi;
+ if (FcPatternGetDouble(pattern, FC_DPI, 0, &dpi) != FcResultMatch) {
+ if (X11->display)
+ dpi = QX11Info::appDpiY();
+ else
+ dpi = qt_defaultDpiY();
+ }
+
+ double size;
+ if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
+ fontDef.pixelSize = size;
+ else
+ fontDef.pixelSize = 12;
+
+ fontDef.pointSize = qt_pointSize(fontDef.pixelSize, qRound(dpi));
+
+ /* ###
+ fontDef.styleHint
+ */
+
+ int weight;
+ if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight) != FcResultMatch)
+ weight = FC_WEIGHT_MEDIUM;
+ fontDef.weight = getFCWeight(weight);
+
+ int slant;
+ if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant) != FcResultMatch)
+ slant = FC_SLANT_ROMAN;
+ fontDef.style = (slant == FC_SLANT_ITALIC)
+ ? QFont::StyleItalic
+ : ((slant == FC_SLANT_OBLIQUE)
+ ? QFont::StyleOblique
+ : QFont::StyleNormal);
+
+
+ FcBool scalable;
+ if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch)
+ scalable = false;
+ if (scalable) {
+ fontDef.stretch = request.stretch;
+ fontDef.style = request.style;
+ } else {
+ int width;
+ if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width) == FcResultMatch)
+ fontDef.stretch = width;
+ else
+ fontDef.stretch = 100;
+ }
+
+ int spacing;
+ if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing) == FcResultMatch) {
+ fontDef.fixedPitch = (spacing >= FC_MONO);
+ fontDef.ignorePitch = false;
+ } else {
+ fontDef.ignorePitch = true;
+ }
+
+ return fontDef;
+}
+
+static const char *specialLanguages[] = {
+ "en", // Common
+ "el", // Greek
+ "ru", // Cyrillic
+ "hy", // Armenian
+ "he", // Hebrew
+ "ar", // Arabic
+ "syr", // Syriac
+ "div", // Thaana
+ "hi", // Devanagari
+ "bn", // Bengali
+ "pa", // Gurmukhi
+ "gu", // Gujarati
+ "or", // Oriya
+ "ta", // Tamil
+ "te", // Telugu
+ "kn", // Kannada
+ "ml", // Malayalam
+ "si", // Sinhala
+ "th", // Thai
+ "lo", // Lao
+ "bo", // Tibetan
+ "my", // Myanmar
+ "ka", // Georgian
+ "ko", // Hangul
+ "", // Ogham
+ "", // Runic
+ "km", // Khmer
+ "" // N'Ko
+};
+enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) };
+
+static const ushort specialChars[] = {
+ 0, // English
+ 0, // Greek
+ 0, // Cyrillic
+ 0, // Armenian
+ 0, // Hebrew
+ 0, // Arabic
+ 0, // Syriac
+ 0, // Thaana
+ 0, // Devanagari
+ 0, // Bengali
+ 0, // Gurmukhi
+ 0, // Gujarati
+ 0, // Oriya
+ 0, // Tamil
+ 0xc15, // Telugu
+ 0xc95, // Kannada
+ 0xd15, // Malayalam
+ 0xd9a, // Sinhala
+ 0, // Thai
+ 0, // Lao
+ 0, // Tibetan
+ 0x1000, // Myanmar
+ 0, // Georgian
+ 0, // Hangul
+ 0x1681, // Ogham
+ 0x16a0, // Runic
+ 0, // Khmer
+ 0x7ca // N'Ko
+};
+enum { SpecialCharCount = sizeof(specialChars) / sizeof(ushort) };
+
+// this could become a list of all languages used for each writing
+// system, instead of using the single most common language.
+static const char *languageForWritingSystem[] = {
+ 0, // Any
+ "en", // Latin
+ "el", // Greek
+ "ru", // Cyrillic
+ "hy", // Armenian
+ "he", // Hebrew
+ "ar", // Arabic
+ "syr", // Syriac
+ "div", // Thaana
+ "hi", // Devanagari
+ "bn", // Bengali
+ "pa", // Gurmukhi
+ "gu", // Gujarati
+ "or", // Oriya
+ "ta", // Tamil
+ "te", // Telugu
+ "kn", // Kannada
+ "ml", // Malayalam
+ "si", // Sinhala
+ "th", // Thai
+ "lo", // Lao
+ "bo", // Tibetan
+ "my", // Myanmar
+ "ka", // Georgian
+ "km", // Khmer
+ "zh-cn", // SimplifiedChinese
+ "zh-tw", // TraditionalChinese
+ "ja", // Japanese
+ "ko", // Korean
+ "vi", // Vietnamese
+ 0, // Symbol
+ 0, // Ogham
+ 0, // Runic
+ 0 // N'Ko
+};
+enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) };
+
+// Unfortunately FontConfig doesn't know about some languages. We have to test these through the
+// charset. The lists below contain the systems where we need to do this.
+static const ushort sampleCharForWritingSystem[] = {
+ 0, // Any
+ 0, // Latin
+ 0, // Greek
+ 0, // Cyrillic
+ 0, // Armenian
+ 0, // Hebrew
+ 0, // Arabic
+ 0, // Syriac
+ 0, // Thaana
+ 0, // Devanagari
+ 0, // Bengali
+ 0, // Gurmukhi
+ 0, // Gujarati
+ 0, // Oriya
+ 0, // Tamil
+ 0xc15, // Telugu
+ 0xc95, // Kannada
+ 0xd15, // Malayalam
+ 0xd9a, // Sinhala
+ 0, // Thai
+ 0, // Lao
+ 0, // Tibetan
+ 0x1000, // Myanmar
+ 0, // Georgian
+ 0, // Khmer
+ 0, // SimplifiedChinese
+ 0, // TraditionalChinese
+ 0, // Japanese
+ 0, // Korean
+ 0, // Vietnamese
+ 0, // Symbol
+ 0x1681, // Ogham
+ 0x16a0, // Runic
+ 0x7ca // N'Ko
+};
+enum { SampleCharCount = sizeof(sampleCharForWritingSystem) / sizeof(ushort) };
+
+// Newer FontConfig let's us sort out fonts that contain certain glyphs, but no
+// open type tables for is directly. Do this so we don't pick some strange
+// pseudo unicode font
+static const char *openType[] = {
+ 0, // Any
+ 0, // Latin
+ 0, // Greek
+ 0, // Cyrillic
+ 0, // Armenian
+ 0, // Hebrew
+ 0, // Arabic
+ "syrc", // Syriac
+ "thaa", // Thaana
+ "deva", // Devanagari
+ "beng", // Bengali
+ "guru", // Gurmukhi
+ "gurj", // Gujarati
+ "orya", // Oriya
+ "taml", // Tamil
+ "telu", // Telugu
+ "knda", // Kannada
+ "mlym", // Malayalam
+ "sinh", // Sinhala
+ 0, // Thai
+ 0, // Lao
+ "tibt", // Tibetan
+ "mymr", // Myanmar
+ 0, // Georgian
+ "khmr", // Khmer
+ 0, // SimplifiedChinese
+ 0, // TraditionalChinese
+ 0, // Japanese
+ 0, // Korean
+ 0, // Vietnamese
+ 0, // Symbol
+ 0, // Ogham
+ 0, // Runic
+ "nko " // N'Ko
+};
+enum { OpenTypeCount = sizeof(openType) / sizeof(const char *) };
+
+
+static void loadFontConfig()
+{
+ Q_ASSERT_X(X11, "QFontDatabase",
+ "A QApplication object needs to be constructed before FontConfig is used.");
+ if (!X11->has_fontconfig)
+ return;
+
+ Q_ASSERT_X(int(QUnicodeTables::ScriptCount) == SpecialLanguageCount,
+ "QFontDatabase", "New scripts have been added.");
+ Q_ASSERT_X(int(QUnicodeTables::ScriptCount) == SpecialCharCount,
+ "QFontDatabase", "New scripts have been added.");
+ Q_ASSERT_X(int(QFontDatabase::WritingSystemsCount) == LanguageCount,
+ "QFontDatabase", "New writing systems have been added.");
+ Q_ASSERT_X(int(QFontDatabase::WritingSystemsCount) == SampleCharCount,
+ "QFontDatabase", "New writing systems have been added.");
+ Q_ASSERT_X(int(QFontDatabase::WritingSystemsCount) == OpenTypeCount,
+ "QFontDatabase", "New writing systems have been added.");
+
+ QFontDatabasePrivate *db = privateDb();
+ FcFontSet *fonts;
+
+ FcPattern *pattern = FcPatternCreate();
+ FcDefaultSubstitute(pattern);
+ FcChar8 *lang = 0;
+ if (FcPatternGetString(pattern, FC_LANG, 0, &lang) == FcResultMatch)
+ db->systemLang = QString::fromUtf8((const char *) lang);
+ FcPatternDestroy(pattern);
+
+ QString familyName;
+ FcChar8 *value = 0;
+ int weight_value;
+ int slant_value;
+ int spacing_value;
+ FcChar8 *file_value;
+ int index_value;
+ FcChar8 *foundry_value;
+ FcBool scalable;
+
+ {
+ FcObjectSet *os = FcObjectSetCreate();
+ FcPattern *pattern = FcPatternCreate();
+ const char *properties [] = {
+ FC_FAMILY, FC_WEIGHT, FC_SLANT,
+ FC_SPACING, FC_FILE, FC_INDEX,
+ FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT,
+ FC_WIDTH,
+#if FC_VERSION >= 20297
+ FC_CAPABILITY,
+#endif
+ (const char *)0
+ };
+ const char **p = properties;
+ while (*p) {
+ FcObjectSetAdd(os, *p);
+ ++p;
+ }
+ fonts = FcFontList(0, pattern, os);
+ FcObjectSetDestroy(os);
+ FcPatternDestroy(pattern);
+ }
+
+ for (int i = 0; i < fonts->nfont; i++) {
+ if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
+ continue;
+ // capitalize(value);
+ familyName = QString::fromUtf8((const char *)value);
+ slant_value = FC_SLANT_ROMAN;
+ weight_value = FC_WEIGHT_MEDIUM;
+ spacing_value = FC_PROPORTIONAL;
+ file_value = 0;
+ index_value = 0;
+ scalable = FcTrue;
+
+ if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch)
+ slant_value = FC_SLANT_ROMAN;
+ if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch)
+ weight_value = FC_WEIGHT_MEDIUM;
+ if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch)
+ spacing_value = FC_PROPORTIONAL;
+ if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch)
+ file_value = 0;
+ if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &index_value) != FcResultMatch)
+ index_value = 0;
+ if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch)
+ scalable = FcTrue;
+ if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
+ foundry_value = 0;
+ QtFontFamily *family = db->family(familyName, true);
+
+ FcLangSet *langset = 0;
+ FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset);
+ if (res == FcResultMatch) {
+ for (int i = 1; i < LanguageCount; ++i) {
+ const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i];
+ if (!lang) {
+ family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
+ } else {
+ FcLangResult langRes = FcLangSetHasLang(langset, lang);
+ if (langRes != FcLangDifferentLang)
+ family->writingSystems[i] = QtFontFamily::Supported;
+ else
+ family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
+ }
+ }
+ family->writingSystems[QFontDatabase::Other] = QtFontFamily::UnsupportedFT;
+ family->ftWritingSystemCheck = true;
+ } else {
+ // we set Other to supported for symbol fonts. It makes no
+ // sense to merge these with other ones, as they are
+ // special in a way.
+ for (int i = 1; i < LanguageCount; ++i)
+ family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
+ family->writingSystems[QFontDatabase::Other] = QtFontFamily::Supported;
+ }
+
+ FcCharSet *cs = 0;
+ res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs);
+ if (res == FcResultMatch) {
+ // some languages are not supported by FontConfig, we rather check the
+ // charset to detect these
+ for (int i = 1; i < SampleCharCount; ++i) {
+ if (!sampleCharForWritingSystem[i])
+ continue;
+ if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i]))
+ family->writingSystems[i] = QtFontFamily::Supported;
+ }
+ }
+
+#if FC_VERSION >= 20297
+ for (int j = 1; j < LanguageCount; ++j) {
+ if (family->writingSystems[j] == QtFontFamily::Supported && requiresOpenType(j) && openType[j]) {
+ FcChar8 *cap;
+ res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap);
+ if (res != FcResultMatch || !strstr((const char *)cap, openType[j]))
+ family->writingSystems[j] = QtFontFamily::UnsupportedFT;
+ }
+ }
+#endif
+
+ QByteArray file((const char *)file_value);
+ family->fontFilename = file;
+ family->fontFileIndex = index_value;
+
+ QtFontStyle::Key styleKey;
+ styleKey.style = (slant_value == FC_SLANT_ITALIC)
+ ? QFont::StyleItalic
+ : ((slant_value == FC_SLANT_OBLIQUE)
+ ? QFont::StyleOblique
+ : QFont::StyleNormal);
+ styleKey.weight = getFCWeight(weight_value);
+ if (!scalable) {
+ int width = 100;
+ FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width);
+ styleKey.stretch = width;
+ }
+
+ QtFontFoundry *foundry
+ = family->foundry(foundry_value ? QString::fromUtf8((const char *)foundry_value) : QString(), true);
+ QtFontStyle *style = foundry->style(styleKey, true);
+
+ if (spacing_value < FC_MONO)
+ family->fixedPitch = false;
+
+ QtFontSize *size;
+ if (scalable) {
+ style->smoothScalable = true;
+ size = style->pixelSize(SMOOTH_SCALABLE, true);
+ } else {
+ double pixel_size = 0;
+ FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size);
+ size = style->pixelSize((int)pixel_size, true);
+ }
+ QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
+ enc->pitch = (spacing_value >= FC_CHARCELL ? 'c' :
+ (spacing_value >= FC_MONO ? 'm' : 'p'));
+ }
+
+ FcFontSetDestroy (fonts);
+
+ struct FcDefaultFont {
+ const char *qtname;
+ const char *rawname;
+ bool fixed;
+ };
+ const FcDefaultFont defaults[] = {
+ { "Serif", "serif", false },
+ { "Sans Serif", "sans-serif", false },
+ { "Monospace", "monospace", true },
+ { 0, 0, false }
+ };
+ const FcDefaultFont *f = defaults;
+ while (f->qtname) {
+ QtFontFamily *family = db->family(QLatin1String(f->qtname), true);
+ family->fixedPitch = f->fixed;
+ family->synthetic = true;
+ QtFontFoundry *foundry = family->foundry(QString(), true);
+
+ // aliases only make sense for 'common', not for any of the specials
+ for (int i = 1; i < LanguageCount; ++i) {
+ if (requiresOpenType(i))
+ family->writingSystems[i] = QtFontFamily::UnsupportedFT;
+ else
+ family->writingSystems[i] = QtFontFamily::Supported;
+ }
+ family->writingSystems[QFontDatabase::Other] = QtFontFamily::UnsupportedFT;
+
+ QtFontStyle::Key styleKey;
+ for (int i = 0; i < 4; ++i) {
+ styleKey.style = (i%2) ? QFont::StyleNormal : QFont::StyleItalic;
+ styleKey.weight = (i > 1) ? QFont::Bold : QFont::Normal;
+ QtFontStyle *style = foundry->style(styleKey, true);
+ style->smoothScalable = true;
+ QtFontSize *size = style->pixelSize(SMOOTH_SCALABLE, true);
+ QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
+ enc->pitch = (f->fixed ? 'm' : 'p');
+ }
+ ++f;
+ }
+}
+#endif // QT_NO_FONTCONFIG
+
+static void initializeDb();
+
+static void load(const QString &family = QString(), int script = -1, bool forceXLFD = false)
+{
+ if (X11->has_fontconfig && !forceXLFD) {
+ initializeDb();
+ return;
+ }
+
+#ifdef QFONTDATABASE_DEBUG
+ QElapsedTimer t;
+ t.start();
+#endif
+
+ if (family.isNull() && script == -1) {
+ loadXlfds(0, -1);
+ } else {
+ if (family.isNull()) {
+ // load all families in all writing systems that match \a script
+ for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
+ if (scriptForWritingSystem[ws] != script)
+ continue;
+ for (int i = 0; i < numEncodings; ++i) {
+ if (writingSystems_for_xlfd_encoding[i][ws])
+ loadXlfds(0, i);
+ }
+ }
+ } else {
+ QtFontFamily *f = privateDb()->family(family);
+ // could reduce this further with some more magic:
+ // would need to remember the encodings loaded for the family.
+ if (!f || !f->xlfdLoaded)
+ loadXlfds(family.toLatin1(), -1);
+ }
+ }
+
+#ifdef QFONTDATABASE_DEBUG
+ FD_DEBUG("QFontDatabase: load(%s, %d) took %d ms",
+ family.toLatin1().constData(), script, t.elapsed());
+#endif
+}
+
+static void checkSymbolFont(QtFontFamily *family)
+{
+ if (!family || family->symbol_checked || family->fontFilename.isEmpty())
+ return;
+// qDebug() << "checking " << family->rawName;
+ family->symbol_checked = true;
+
+ QFontEngine::FaceId id;
+ id.filename = family->fontFilename;
+ id.index = family->fontFileIndex;
+ QFreetypeFace *f = QFreetypeFace::getFace(id);
+ if (!f) {
+ qWarning("checkSymbolFonts: Couldn't open face %s (%s/%d)",
+ qPrintable(family->name), family->fontFilename.data(), family->fontFileIndex);
+ return;
+ }
+ for (int i = 0; i < f->face->num_charmaps; ++i) {
+ FT_CharMap cm = f->face->charmaps[i];
+ if (cm->encoding == FT_ENCODING_ADOBE_CUSTOM
+ || cm->encoding == FT_ENCODING_MS_SYMBOL) {
+ for (int x = QFontDatabase::Latin; x < QFontDatabase::Other; ++x)
+ family->writingSystems[x] = QtFontFamily::Unsupported;
+ family->writingSystems[QFontDatabase::Other] = QtFontFamily::Supported;
+ break;
+ }
+ }
+ f->release(id);
+}
+
+static void checkSymbolFonts(const QString &family = QString())
+{
+#ifndef QT_NO_FONTCONFIG
+ QFontDatabasePrivate *d = privateDb();
+
+ if (family.isEmpty()) {
+ for (int i = 0; i < d->count; ++i)
+ checkSymbolFont(d->families[i]);
+ } else {
+ checkSymbolFont(d->family(family));
+ }
+#endif
+}
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
+
+static void initializeDb()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if (!db || db->count)
+ return;
+
+ QElapsedTimer t;
+ t.start();
+
+#ifndef QT_NO_FONTCONFIG
+ 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]);
+ }
+ }
+
+ loadFontConfig();
+ FD_DEBUG("QFontDatabase: loaded FontConfig: %d ms", int(t.elapsed()));
+#endif
+
+ t.start();
+
+#ifndef QT_NO_FONTCONFIG
+ for (int i = 0; i < db->count; i++) {
+ for (int j = 0; j < db->families[i]->count; ++j) { // each foundry
+ QtFontFoundry *foundry = db->families[i]->foundries[j];
+ for (int k = 0; k < foundry->count; ++k) {
+ QtFontStyle *style = foundry->styles[k];
+ if (style->key.style != QFont::StyleNormal) continue;
+
+ QtFontSize *size = style->pixelSize(SMOOTH_SCALABLE);
+ if (! size) continue; // should not happen
+ QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
+ if (! enc) continue; // should not happen either
+
+ QtFontStyle::Key key = style->key;
+
+ // does this style have an italic equivalent?
+ key.style = QFont::StyleItalic;
+ QtFontStyle *equiv = foundry->style(key);
+ if (equiv) continue;
+
+ // does this style have an oblique equivalent?
+ key.style = QFont::StyleOblique;
+ equiv = foundry->style(key);
+ if (equiv) continue;
+
+ // let's fake one...
+ equiv = foundry->style(key, true);
+ equiv->smoothScalable = true;
+
+ QtFontSize *equiv_size = equiv->pixelSize(SMOOTH_SCALABLE, true);
+ QtFontEncoding *equiv_enc = equiv_size->encodingID(-1, 0, 0, 0, 0, true);
+
+ // keep the same pitch
+ equiv_enc->pitch = enc->pitch;
+ }
+ }
+ }
+#endif
+
+
+#ifdef QFONTDATABASE_DEBUG
+#ifndef QT_NO_FONTCONFIG
+ if (!X11->has_fontconfig)
+#endif
+ // load everything at startup in debug mode.
+ loadXlfds(0, -1);
+
+ // print the database
+ for (int f = 0; f < db->count; f++) {
+ QtFontFamily *family = db->families[f];
+ FD_DEBUG("'%s' %s fixed=%s", family->name.latin1(), (family->fixedPitch ? "fixed" : ""),
+ (family->fixedPitch ? "yes" : "no"));
+ for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
+ QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i);
+ FD_DEBUG("\t%s: %s", QFontDatabase::writingSystemName(ws).toLatin1().constData(),
+ ((family->writingSystems[i] & QtFontFamily::Supported) ? "Supported" :
+ (family->writingSystems[i] & QtFontFamily::Unsupported) == QtFontFamily::Unsupported ?
+ "Unsupported" : "Unknown"));
+ }
+
+ for (int fd = 0; fd < family->count; fd++) {
+ QtFontFoundry *foundry = family->foundries[fd];
+ FD_DEBUG("\t\t'%s'", foundry->name.latin1());
+ for (int s = 0; s < foundry->count; s++) {
+ QtFontStyle *style = foundry->styles[s];
+ FD_DEBUG("\t\t\tstyle: style=%d weight=%d (%s)\n"
+ "\t\t\tstretch=%d (%s)",
+ style->key.style, style->key.weight,
+ style->weightName, style->key.stretch,
+ style->setwidthName ? style->setwidthName : "nil");
+ if (style->smoothScalable)
+ FD_DEBUG("\t\t\t\tsmooth scalable");
+ else if (style->bitmapScalable)
+ FD_DEBUG("\t\t\t\tbitmap scalable");
+ if (style->pixelSizes) {
+ qDebug("\t\t\t\t%d pixel sizes", style->count);
+ for (int z = 0; z < style->count; ++z) {
+ QtFontSize *size = style->pixelSizes + z;
+ for (int e = 0; e < size->count; ++e) {
+ FD_DEBUG("\t\t\t\t size %5d pitch %c encoding %s",
+ size->pixelSize,
+ size->encodings[e].pitch,
+ xlfd_for_id(size->encodings[e].encoding));
+ }
+ }
+ }
+ }
+ }
+ }
+#endif // QFONTDATABASE_DEBUG
+}
+
+
+// --------------------------------------------------------------------------------------
+// font loader
+// --------------------------------------------------------------------------------------
+
+static const char *styleHint(const QFontDef &request)
+{
+ const char *stylehint = 0;
+ switch (request.styleHint) {
+ case QFont::SansSerif:
+ stylehint = "sans-serif";
+ break;
+ case QFont::Serif:
+ stylehint = "serif";
+ break;
+ case QFont::TypeWriter:
+ stylehint = "monospace";
+ break;
+ default:
+ if (request.fixedPitch)
+ stylehint = "monospace";
+ break;
+ }
+ return stylehint;
+}
+
+#ifndef QT_NO_FONTCONFIG
+
+void qt_addPatternProps(FcPattern *pattern, int screen, int script, const QFontDef &request)
+{
+ int weight_value = FC_WEIGHT_BLACK;
+ if (request.weight == 0)
+ weight_value = FC_WEIGHT_MEDIUM;
+ else if (request.weight < (QFont::Light + QFont::Normal) / 2)
+ weight_value = FC_WEIGHT_LIGHT;
+ else if (request.weight < (QFont::Normal + QFont::DemiBold) / 2)
+ weight_value = FC_WEIGHT_MEDIUM;
+ else if (request.weight < (QFont::DemiBold + QFont::Bold) / 2)
+ weight_value = FC_WEIGHT_DEMIBOLD;
+ else if (request.weight < (QFont::Bold + QFont::Black) / 2)
+ weight_value = FC_WEIGHT_BOLD;
+ FcPatternDel(pattern, FC_WEIGHT);
+ FcPatternAddInteger(pattern, FC_WEIGHT, weight_value);
+
+ int slant_value = FC_SLANT_ROMAN;
+ if (request.style == QFont::StyleItalic)
+ slant_value = FC_SLANT_ITALIC;
+ else if (request.style == QFont::StyleOblique)
+ slant_value = FC_SLANT_OBLIQUE;
+ FcPatternDel(pattern, FC_SLANT);
+ FcPatternAddInteger(pattern, FC_SLANT, slant_value);
+
+ double size_value = qMax(qreal(1.), request.pixelSize);
+ FcPatternDel(pattern, FC_PIXEL_SIZE);
+ FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size_value);
+
+ int stretch = request.stretch;
+ if (!stretch)
+ stretch = 100;
+ FcPatternDel(pattern, FC_WIDTH);
+ FcPatternAddInteger(pattern, FC_WIDTH, stretch);
+
+ if (X11->display && QX11Info::appDepth(screen) <= 8) {
+ FcPatternDel(pattern, FC_ANTIALIAS);
+ // can't do antialiasing on 8bpp
+ FcPatternAddBool(pattern, FC_ANTIALIAS, false);
+ } else if (request.styleStrategy & (QFont::PreferAntialias|QFont::NoAntialias)) {
+ FcPatternDel(pattern, FC_ANTIALIAS);
+ FcPatternAddBool(pattern, FC_ANTIALIAS,
+ !(request.styleStrategy & QFont::NoAntialias));
+ }
+
+ if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') {
+ Q_ASSERT(script < QUnicodeTables::ScriptCount);
+ FcLangSet *ls = FcLangSetCreate();
+ FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
+ FcPatternDel(pattern, FC_LANG);
+ FcPatternAddLangSet(pattern, FC_LANG, ls);
+ FcLangSetDestroy(ls);
+ }
+}
+
+static bool preferScalable(const QFontDef &request)
+{
+ return request.styleStrategy & (QFont::PreferOutline|QFont::ForceOutline|QFont::PreferQuality|QFont::PreferAntialias);
+}
+
+
+static FcPattern *getFcPattern(const QFontPrivate *fp, int script, const QFontDef &request)
+{
+ if (!X11->has_fontconfig)
+ return 0;
+
+ FcPattern *pattern = FcPatternCreate();
+ if (!pattern)
+ return 0;
+
+ FcValue value;
+ value.type = FcTypeString;
+
+ QtFontDesc desc;
+ QStringList families_and_foundries = familyList(request);
+ for (int i = 0; i < families_and_foundries.size(); ++i) {
+ QString family, foundry;
+ parseFontName(families_and_foundries.at(i), foundry, family);
+ if (!family.isEmpty()) {
+ QByteArray cs = family.toUtf8();
+ value.u.s = (const FcChar8 *)cs.data();
+ FcPatternAdd(pattern, FC_FAMILY, value, FcTrue);
+ }
+ if (i == 0) {
+ QT_PREPEND_NAMESPACE(match)(script, request, family, foundry, -1, &desc);
+ if (!foundry.isEmpty()) {
+ QByteArray cs = foundry.toUtf8();
+ value.u.s = (const FcChar8 *)cs.data();
+ FcPatternAddWeak(pattern, FC_FOUNDRY, value, FcTrue);
+ }
+ }
+ }
+
+ const char *stylehint = styleHint(request);
+ if (stylehint) {
+ value.u.s = (const FcChar8 *)stylehint;
+ FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
+ }
+
+ if (!request.ignorePitch) {
+ char pitch_value = FC_PROPORTIONAL;
+ if (request.fixedPitch || (desc.family && desc.family->fixedPitch))
+ pitch_value = FC_MONO;
+ FcPatternAddInteger(pattern, FC_SPACING, pitch_value);
+ }
+ FcPatternAddBool(pattern, FC_OUTLINE, !(request.styleStrategy & QFont::PreferBitmap));
+ if (preferScalable(request) || (desc.style && desc.style->smoothScalable))
+ FcPatternAddBool(pattern, FC_SCALABLE, true);
+
+ qt_addPatternProps(pattern, fp->screen, script, request);
+
+ FcDefaultSubstitute(pattern);
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ FcConfigSubstitute(0, pattern, FcMatchFont);
+
+ // these should only get added to the pattern _after_ substitution
+ // append the default fallback font for the specified script
+ extern QString qt_fallback_font_family(int);
+ QString fallback = qt_fallback_font_family(script);
+ if (!fallback.isEmpty()) {
+ QByteArray cs = fallback.toUtf8();
+ value.u.s = (const FcChar8 *)cs.data();
+ FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
+ }
+
+ // add the default family
+ QString defaultFamily = QApplication::font().family();
+ QByteArray cs = defaultFamily.toUtf8();
+ value.u.s = (const FcChar8 *)cs.data();
+ FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
+
+ // add QFont::defaultFamily() to the list, for compatibility with
+ // previous versions
+ defaultFamily = QApplication::font().defaultFamily();
+ cs = defaultFamily.toUtf8();
+ value.u.s = (const FcChar8 *)cs.data();
+ FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
+
+ return pattern;
+}
+
+
+static void FcFontSetRemove(FcFontSet *fs, int at)
+{
+ Q_ASSERT(at < fs->nfont);
+ FcPatternDestroy(fs->fonts[at]);
+ int len = (--fs->nfont - at) * sizeof(FcPattern *);;
+ if (len > 0)
+ memmove(fs->fonts + at, fs->fonts + at + 1, len);
+}
+
+static QFontEngine *tryPatternLoad(FcPattern *p, int screen,
+ const QFontDef &request, int script, FcPattern **matchedPattern = 0)
+{
+#ifdef FONT_MATCH_DEBUG
+ FcChar8 *fam;
+ FcPatternGetString(p, FC_FAMILY, 0, &fam);
+ FM_DEBUG("==== trying %s\n", fam);
+#endif
+ FM_DEBUG("passes charset test\n");
+ FcPattern *pattern = FcPatternDuplicate(p);
+ // add properties back in as the font selected from the
+ // list doesn't contain them.
+ qt_addPatternProps(pattern, screen, script, request);
+
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+ FcResult res;
+ FcPattern *match = FcFontMatch(0, pattern, &res);
+
+ if (matchedPattern)
+ *matchedPattern = 0;
+
+ QFontEngineX11FT *engine = 0;
+ if (!match) // probably no fonts available.
+ goto done;
+
+ if (matchedPattern)
+ *matchedPattern = FcPatternDuplicate(match);
+
+ if (script != QUnicodeTables::Common) {
+ // skip font if it doesn't support the language we want
+ if (specialChars[script]) {
+ // need to check the charset, as the langset doesn't work for these scripts
+ FcCharSet *cs;
+ if (FcPatternGetCharSet(match, FC_CHARSET, 0, &cs) != FcResultMatch)
+ goto done;
+ if (!FcCharSetHasChar(cs, specialChars[script]))
+ goto done;
+ } else if (*specialLanguages[script] != '\0'){
+ FcLangSet *langSet = 0;
+ if (FcPatternGetLangSet(match, FC_LANG, 0, &langSet) != FcResultMatch)
+ goto done;
+ if (FcLangSetHasLang(langSet, (const FcChar8*)specialLanguages[script]) != FcLangEqual)
+ goto done;
+ }
+ }
+
+ // enforce non-antialiasing if requested. the ft font engine looks at this property.
+ if (request.styleStrategy & QFont::NoAntialias) {
+ FcPatternDel(match, FC_ANTIALIAS);
+ FcPatternAddBool(match, FC_ANTIALIAS, false);
+ }
+
+ engine = new QFontEngineX11FT(match, qt_FcPatternToQFontDef(match, request), screen);
+ if (engine->invalid()) {
+ FM_DEBUG(" --> invalid!\n");
+ delete engine;
+ engine = 0;
+ } else if (scriptRequiresOpenType(script)) {
+ HB_Face hbFace = engine->harfbuzzFace();
+ if (!hbFace || !hbFace->supported_scripts[script]) {
+ FM_DEBUG(" OpenType support missing for script\n");
+ delete engine;
+ engine = 0;
+ }
+ }
+done:
+ FcPatternDestroy(pattern);
+ if (!engine && matchedPattern && *matchedPattern) {
+ FcPatternDestroy(*matchedPattern);
+ *matchedPattern = 0;
+ }
+ return engine;
+}
+
+FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request)
+{
+ FcResult result;
+ FcFontSet *fs = FcFontSort(0, pattern, FcTrue, 0, &result);
+#ifdef FONT_MATCH_DEBUG
+ FM_DEBUG("first font in fontset:\n");
+ FcPatternPrint(fs->fonts[0]);
+#endif
+
+ FcBool forceScalable = request.styleStrategy & QFont::ForceOutline;
+
+ // remove fonts if they are not scalable (and should be)
+ if (forceScalable && fs) {
+ for (int i = 0; i < fs->nfont; ++i) {
+ FcPattern *font = fs->fonts[i];
+ FcResult res;
+ FcBool scalable;
+ res = FcPatternGetBool(font, FC_SCALABLE, 0, &scalable);
+ if (res != FcResultMatch || !scalable) {
+ FcFontSetRemove(fs, i);
+#ifdef FONT_MATCH_DEBUG
+ FM_DEBUG("removing pattern:");
+ FcPatternPrint(font);
+#endif
+ --i; // go back one
+ }
+ }
+ }
+
+ FM_DEBUG("final pattern contains %d fonts\n", fs->nfont);
+
+ return fs;
+}
+
+static QFontEngine *loadFc(const QFontPrivate *fp, int script, const QFontDef &request)
+{
+ FM_DEBUG("===================== loadFc: script=%d family='%s'\n", script, request.family.toLatin1().data());
+ FcPattern *pattern = getFcPattern(fp, script, request);
+
+#ifdef FONT_MATCH_DEBUG
+ FM_DEBUG("\n\nfinal FcPattern contains:\n");
+ FcPatternPrint(pattern);
+#endif
+
+ QFontEngine *fe = 0;
+ FcPattern *matchedPattern = 0;
+ fe = tryPatternLoad(pattern, fp->screen, request, script, &matchedPattern);
+ if (!fe) {
+ FcFontSet *fs = qt_fontSetForPattern(pattern, request);
+
+ if (fs) {
+ for (int i = 0; !fe && i < fs->nfont; ++i)
+ fe = tryPatternLoad(fs->fonts[i], fp->screen, request, script, &matchedPattern);
+ FcFontSetDestroy(fs);
+ }
+ FM_DEBUG("engine for script %d is %s\n", script, fe ? fe->fontDef.family.toLatin1().data(): "(null)");
+ }
+ if (fe
+ && script == QUnicodeTables::Common
+ && !(request.styleStrategy & QFont::NoFontMerging) && !fe->symbol) {
+ fe = new QFontEngineMultiFT(fe, matchedPattern, pattern, fp->screen, request);
+ } else {
+ FcPatternDestroy(pattern);
+ if (matchedPattern)
+ FcPatternDestroy(matchedPattern);
+ }
+ return fe;
+}
+
+static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count)
+{
+#if FC_VERSION < 20402
+ Q_UNUSED(data)
+ return FcFreeTypeQuery(file, id, blanks, count);
+#else
+ if (data.isEmpty())
+ return FcFreeTypeQuery(file, id, blanks, count);
+
+ extern FT_Library qt_getFreetype();
+ FT_Library lib = qt_getFreetype();
+
+ FcPattern *pattern = 0;
+
+ FT_Face face;
+ if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, &face)) {
+ *count = face->num_faces;
+
+ pattern = FcFreeTypeQueryFace(face, file, id, blanks);
+
+ FT_Done_Face(face);
+ }
+
+ return pattern;
+#endif
+}
+#endif // QT_NO_FONTCONFIG
+
+static QFontEngine *loadRaw(const QFontPrivate *fp, const QFontDef &request)
+{
+ Q_ASSERT(fp && fp->rawMode);
+
+ QByteArray xlfd = request.family.toLatin1();
+ FM_DEBUG("Loading XLFD (rawmode) '%s'", xlfd.data());
+
+ QFontEngine *fe;
+ XFontStruct *xfs;
+ if (!(xfs = XLoadQueryFont(QX11Info::display(), xlfd.data())))
+ if (!(xfs = XLoadQueryFont(QX11Info::display(), "fixed")))
+ return 0;
+
+ fe = new QFontEngineXLFD(xfs, xlfd, 0);
+ if (! qt_fillFontDef(xfs, &fe->fontDef, fp->dpi, 0) &&
+ ! qt_fillFontDef(xlfd, &fe->fontDef, fp->dpi, 0))
+ fe->fontDef = QFontDef();
+ return fe;
+}
+
+QFontEngine *QFontDatabase::loadXlfd(int screen, int script, const QFontDef &request, int force_encoding_id)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QtFontDesc desc;
+ FM_DEBUG() << "---> loadXlfd: request is" << request.family;
+ QStringList families_and_foundries = familyList(request);
+ const char *stylehint = styleHint(request);
+ if (stylehint)
+ families_and_foundries << QString::fromLatin1(stylehint);
+ families_and_foundries << QString();
+ FM_DEBUG() << "loadXlfd: list is" << families_and_foundries;
+ for (int i = 0; i < families_and_foundries.size(); ++i) {
+ QString family, foundry;
+ QT_PREPEND_NAMESPACE(parseFontName)(families_and_foundries.at(i), foundry, family);
+ FM_DEBUG("loadXlfd: >>>>>>>>>>>>>>trying to match '%s' encoding=%d", family.toLatin1().data(), force_encoding_id);
+ QT_PREPEND_NAMESPACE(match)(script, request, family, foundry, force_encoding_id, &desc, QList<int>(), true);
+ if (desc.family)
+ break;
+ }
+
+ QFontEngine *fe = 0;
+ if (force_encoding_id != -1
+ || (request.styleStrategy & QFont::NoFontMerging)
+ || (desc.family && desc.family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
+ if (desc.family) {
+ int px = desc.size->pixelSize;
+ if (desc.style->smoothScalable && px == SMOOTH_SCALABLE)
+ px = request.pixelSize;
+ else if (desc.style->bitmapScalable && px == 0)
+ px = request.pixelSize;
+
+ QByteArray xlfd("-");
+ xlfd += desc.foundry->name.isEmpty() ? QByteArray("*") : desc.foundry->name.toLatin1();
+ xlfd += '-';
+ xlfd += desc.family->name.isEmpty() ? QByteArray("*") : desc.family->name.toLatin1();
+ xlfd += '-';
+ xlfd += desc.style->weightName ? desc.style->weightName : "*";
+ xlfd += '-';
+ xlfd += (desc.style->key.style == QFont::StyleItalic
+ ? 'i'
+ : (desc.style->key.style == QFont::StyleOblique ? 'o' : 'r'));
+ xlfd += '-';
+ xlfd += desc.style->setwidthName ? desc.style->setwidthName : "*";
+ // ### handle add-style
+ xlfd += "-*-";
+ xlfd += QByteArray::number(px);
+ xlfd += '-';
+ xlfd += QByteArray::number(desc.encoding->xpoint);
+ xlfd += '-';
+ xlfd += QByteArray::number(desc.encoding->xres);
+ xlfd += '-';
+ xlfd += QByteArray::number(desc.encoding->yres);
+ xlfd += '-';
+ xlfd += desc.encoding->pitch;
+ xlfd += '-';
+ xlfd += QByteArray::number(desc.encoding->avgwidth);
+ xlfd += '-';
+ xlfd += xlfd_for_id(desc.encoding->encoding);
+
+ FM_DEBUG(" using XLFD: %s\n", xlfd.data());
+
+ const int mib = xlfd_encoding[desc.encoding->encoding].mib;
+ XFontStruct *xfs;
+ if ((xfs = XLoadQueryFont(QX11Info::display(), xlfd))) {
+ fe = new QFontEngineXLFD(xfs, xlfd, mib);
+ const int dpi = QX11Info::appDpiY();
+ if (!qt_fillFontDef(xfs, &fe->fontDef, dpi, &desc)
+ && !qt_fillFontDef(xlfd, &fe->fontDef, dpi, &desc)) {
+ initFontDef(desc, request, &fe->fontDef);
+ }
+ }
+ }
+ if (!fe) {
+ fe = new QFontEngineBox(request.pixelSize);
+ fe->fontDef = QFontDef();
+ }
+ } else {
+ QList<int> encodings;
+ if (desc.encoding) {
+ if (desc.encoding->encoding >= 0)
+ encodings.append(int(desc.encoding->encoding));
+ }
+
+ if (desc.size) {
+ // append all other encodings for the matched font
+ for (int i = 0; i < desc.size->count; ++i) {
+ QtFontEncoding *e = desc.size->encodings + i;
+ if (e == desc.encoding || e->encoding < 0)
+ continue;
+ encodings.append(int(e->encoding));
+ }
+ }
+ // fill in the missing encodings
+ const XlfdEncoding *enc = xlfd_encoding;
+ for (; enc->name; ++enc) {
+ if (!encodings.contains(enc->id) && enc->id >= 0) {
+ encodings.append(enc->id);
+ }
+ }
+
+#if defined(FONT_MATCH_DEBUG)
+ FM_DEBUG(" using MultiXLFD, encodings:");
+ for (int i = 0; i < encodings.size(); ++i) {
+ const int id = encodings.at(i);
+ FM_DEBUG(" %2d: %s", xlfd_encoding[id].id, xlfd_encoding[id].name);
+ }
+#endif
+
+ fe = new QFontEngineMultiXLFD(request, encodings, screen);
+ }
+ return fe;
+}
+
+#if (defined(QT_ARCH_ARM) || defined(QT_ARCH_ARMV6)) && defined(Q_CC_GNU) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
+#define NEEDS_GCC_BUG_WORKAROUND
+#endif
+
+#ifdef NEEDS_GCC_BUG_WORKAROUND
+static inline void gccBugWorkaround(const QFontDef &req)
+{
+ char buffer[8];
+ snprintf(buffer, 8, "%f", req.pixelSize);
+}
+#endif
+
+/*! \internal
+ Loads a QFontEngine for the specified \a script that matches the
+ QFontDef \e request member variable.
+*/
+void QFontDatabase::load(const QFontPrivate *d, int script)
+{
+ Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
+
+ // normalize the request to get better caching
+ QFontDef req = d->request;
+ if (req.pixelSize <= 0)
+ req.pixelSize = qFloor(qt_pixelSize(req.pointSize, d->dpi) * 100.0 + 0.5) * 0.01;
+ if (req.pixelSize < 1)
+ req.pixelSize = 1;
+
+#ifdef NEEDS_GCC_BUG_WORKAROUND
+ // req.pixelSize ends up with a bogus value unless this workaround is called
+ gccBugWorkaround(req);
+#endif
+
+ if (req.weight == 0)
+ req.weight = QFont::Normal;
+ if (req.stretch == 0)
+ req.stretch = 100;
+
+ QFontCache::Key key(req, d->rawMode ? QUnicodeTables::Common : script, d->screen);
+ if (!d->engineData)
+ getEngineData(d, key);
+
+ // the cached engineData could have already loaded the engine we want
+ if (d->engineData->engines[script])
+ return;
+
+ // set it to the actual pointsize, so QFontInfo will do the right thing
+ if (req.pointSize < 0)
+ req.pointSize = qt_pointSize(req.pixelSize, d->dpi);
+
+
+ QFontEngine *fe = QFontCache::instance()->findEngine(key);
+
+ if (!fe) {
+ QMutexLocker locker(fontDatabaseMutex());
+ if (!privateDb()->count)
+ initializeDb();
+
+ const bool mainThread = (qApp->thread() == QThread::currentThread());
+ if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
+ fe = new QTestFontEngine(req.pixelSize);
+ fe->fontDef = req;
+ } else if (d->rawMode) {
+ if (mainThread)
+ fe = loadRaw(d, req);
+#ifndef QT_NO_FONTCONFIG
+ } else if (X11->has_fontconfig) {
+ fe = loadFc(d, script, req);
+#endif
+ } else if (mainThread && qt_is_gui_used) {
+ fe = loadXlfd(d->screen, script, req);
+ }
+ if (!fe) {
+ fe = new QFontEngineBox(req.pixelSize);
+ fe->fontDef = QFontDef();
+ }
+ }
+ if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
+ for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
+ if (!d->engineData->engines[i]) {
+ d->engineData->engines[i] = fe;
+ fe->ref.ref();
+ }
+ }
+ } else {
+ d->engineData->engines[script] = fe;
+ fe->ref.ref();
+ }
+ QFontCache::instance()->insertEngine(key, fe);
+}
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
+{
+#if defined(QT_NO_FONTCONFIG)
+ return;
+#else
+ if (!X11->has_fontconfig)
+ return;
+
+ FcConfig *config = FcConfigGetCurrent();
+ if (!config)
+ return;
+
+ FcFontSet *set = FcConfigGetFonts(config, FcSetApplication);
+ if (!set) {
+ FcConfigAppFontAddFile(config, (const FcChar8 *)":/non-existent");
+ set = FcConfigGetFonts(config, FcSetApplication); // try again
+ if (!set)
+ return;
+ }
+
+ QString fileNameForQuery = fnt->fileName;
+#if FC_VERSION < 20402
+ QTemporaryFile tmp;
+
+ if (!fnt->data.isEmpty()) {
+ if (!tmp.open())
+ return;
+ tmp.write(fnt->data);
+ tmp.flush();
+ fileNameForQuery = tmp.fileName();
+ }
+#endif
+
+ int id = 0;
+ FcBlanks *blanks = FcConfigGetBlanks(0);
+ int count = 0;
+
+ QStringList families;
+ QFontDatabasePrivate *db = privateDb();
+
+ FcPattern *pattern = 0;
+ do {
+ pattern = queryFont((const FcChar8 *)QFile::encodeName(fileNameForQuery).constData(),
+ fnt->data, id, blanks, &count);
+ if (!pattern)
+ return;
+
+ FcPatternDel(pattern, FC_FILE);
+ FcPatternAddString(pattern, FC_FILE, (const FcChar8 *)fnt->fileName.toUtf8().constData());
+
+ FcChar8 *fam = 0, *familylang = 0;
+ int i, n = 0;
+ for (i = 0; ; i++) {
+ if (FcPatternGetString(pattern, FC_FAMILYLANG, i, &familylang) != FcResultMatch)
+ break;
+ QString familyLang = QString::fromUtf8((const char *) familylang);
+ if (familyLang.compare(db->systemLang, Qt::CaseInsensitive) == 0) {
+ n = i;
+ break;
+ }
+ }
+
+ if (FcPatternGetString(pattern, FC_FAMILY, n, &fam) == FcResultMatch) {
+ QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
+ families << family;
+ }
+
+ if (!FcFontSetAdd(set, pattern))
+ return;
+
+ ++id;
+ } while (pattern && id < count);
+
+ fnt->families = families;
+#endif
+}
+
+bool QFontDatabase::removeApplicationFont(int handle)
+{
+#if defined(QT_NO_FONTCONFIG)
+ return false;
+#else
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ if (handle < 0 || handle >= db->applicationFonts.count())
+ return false;
+
+ FcConfigAppFontClear(0);
+
+ db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
+
+ db->reregisterAppFonts = true;
+ db->invalidate();
+ return true;
+#endif
+}
+
+bool QFontDatabase::removeAllApplicationFonts()
+{
+#if defined(QT_NO_FONTCONFIG)
+ return false;
+#else
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ if (db->applicationFonts.isEmpty())
+ return false;
+
+ FcConfigAppFontClear(0);
+ db->applicationFonts.clear();
+ db->invalidate();
+ return true;
+#endif
+}
+
+bool QFontDatabase::supportsThreadedFontRendering()
+{
+#if defined(QT_NO_FONTCONFIG)
+ return false;
+#else
+ return X11->has_fontconfig;
+#endif
+}
+
+QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
+{
+#if defined(QT_NO_FONTCONFIG)
+ return family;
+#else
+ FcPattern *pattern = FcPatternCreate();
+ if (!pattern)
+ return family;
+
+ FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) family.toUtf8().data());
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+
+ FcChar8 *familyAfterSubstitution;
+ FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution);
+ QString resolved = QString::fromUtf8((const char *) familyAfterSubstitution);
+ FcPatternDestroy(pattern);
+
+ return resolved;
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qfontengine_x11.cpp b/src/widgets/platforms/x11/qfontengine_x11.cpp
new file mode 100644
index 0000000000..4260b85b11
--- /dev/null
+++ b/src/widgets/platforms/x11/qfontengine_x11.cpp
@@ -0,0 +1,1215 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qbitmap.h"
+
+// #define FONTENGINE_DEBUG
+
+#include <qapplication.h>
+#include <qbytearray.h>
+#include <qdebug.h>
+#include <qtextcodec.h>
+#include <qthread.h>
+
+#include "qfontdatabase.h"
+#include "qpaintdevice.h"
+#include "qpainter.h"
+#include "qvarlengtharray.h"
+#include "qwidget.h"
+#include "qsettings.h"
+#include "qfile.h"
+
+#include <private/qpaintengine_x11_p.h>
+#include "qfont.h"
+#include "qfont_p.h"
+#include "qfontengine_p.h"
+#include <qhash.h>
+
+#include <private/qpainter_p.h>
+#include <private/qunicodetables_p.h>
+
+#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
+#include "qx11info_x11.h"
+#include "qfontengine_x11_p.h"
+
+#include <limits.h>
+
+#include <ft2build.h>
+#if defined(FT_LCD_FILTER_H)
+#include FT_LCD_FILTER_H
+#endif
+
+#if defined(FC_LCD_FILTER)
+
+#ifndef FC_LCD_FILTER_NONE
+#define FC_LCD_FILTER_NONE FC_LCD_NONE
+#endif
+
+#ifndef FC_LCD_FILTER_DEFAULT
+#define FC_LCD_FILTER_DEFAULT FC_LCD_DEFAULT
+#endif
+
+#ifndef FC_LCD_FILTER_LIGHT
+#define FC_LCD_FILTER_LIGHT FC_LCD_LIGHT
+#endif
+
+#ifndef FC_LCD_FILTER_LEGACY
+#define FC_LCD_FILTER_LEGACY FC_LCD_LEGACY
+#endif
+
+#endif
+
+QT_BEGIN_NAMESPACE
+
+
+// ------------------------------------------------------------------
+// Multi XLFD engine
+// ------------------------------------------------------------------
+
+QFontEngineMultiXLFD::QFontEngineMultiXLFD(const QFontDef &r, const QList<int> &l, int s)
+ : QFontEngineMulti(l.size()), encodings(l), screen(s), request(r)
+{
+ loadEngine(0);
+ fontDef = engines[0]->fontDef;
+}
+
+QFontEngineMultiXLFD::~QFontEngineMultiXLFD()
+{ }
+
+void QFontEngineMultiXLFD::loadEngine(int at)
+{
+ Q_ASSERT(at < engines.size());
+ Q_ASSERT(engines.at(at) == 0);
+ const int encoding = encodings.at(at);
+ QFontEngine *fontEngine = QFontDatabase::loadXlfd(0, QUnicodeTables::Common, request, encoding);
+ Q_ASSERT(fontEngine != 0);
+ fontEngine->ref.ref();
+ engines[at] = fontEngine;
+}
+
+// ------------------------------------------------------------------
+// Xlfd font engine
+// ------------------------------------------------------------------
+
+#ifndef QT_NO_FREETYPE
+
+static QStringList *qt_fontpath = 0;
+
+static QStringList fontPath()
+{
+ if (qt_fontpath)
+ return *qt_fontpath;
+
+ // append qsettings fontpath
+ QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
+ settings.beginGroup(QLatin1String("Qt"));
+
+ QStringList fontpath;
+
+ int npaths;
+ char** font_path;
+ font_path = XGetFontPath(X11->display, &npaths);
+ bool xfsconfig_read = false;
+ for (int i=0; i<npaths; i++) {
+ // If we're using xfs, append font paths from /etc/X11/fs/config
+ // can't hurt, and chances are we'll get all fonts that way.
+ if (((font_path[i])[0] != '/') && !xfsconfig_read) {
+ // We're using xfs -> read its config
+ bool finished = false;
+ QFile f(QLatin1String("/etc/X11/fs/config"));
+ if (!f.exists())
+ f.setFileName(QLatin1String("/usr/X11R6/lib/X11/fs/config"));
+ if (!f.exists())
+ f.setFileName(QLatin1String("/usr/X11/lib/X11/fs/config"));
+ if (f.exists()) {
+ f.open(QIODevice::ReadOnly);
+ while (f.error()==QFile::NoError && !finished) {
+ QString fs = QString::fromLocal8Bit(f.readLine(1024));
+ fs=fs.trimmed();
+ if (fs.left(9)==QLatin1String("catalogue") && fs.contains(QLatin1Char('='))) {
+ fs = fs.mid(fs.indexOf(QLatin1Char('=')) + 1).trimmed();
+ bool end = false;
+ while (f.error()==QFile::NoError && !end) {
+ if (fs[int(fs.length())-1] == QLatin1Char(','))
+ fs = fs.left(fs.length()-1);
+ else
+ end = true;
+
+ fs = fs.left(fs.indexOf(QLatin1String(":unscaled")));
+ if (fs[0] != QLatin1Char('#'))
+ fontpath += fs;
+ fs = QLatin1String(f.readLine(1024));
+ fs = fs.trimmed();
+ if (fs.isEmpty())
+ end = true;
+ }
+ finished = true;
+ }
+ }
+ f.close();
+ }
+ xfsconfig_read = true;
+ } else {
+ QString fs = QString::fromLocal8Bit(font_path[i]);
+ fontpath += fs.left(fs.indexOf(QLatin1String(":unscaled")));
+ }
+ }
+ XFreeFontPath(font_path);
+
+ // append qsettings fontpath
+ QStringList fp = settings.value(QLatin1String("fontPath")).toStringList();
+ if (!fp.isEmpty())
+ fontpath += fp;
+
+ qt_fontpath = new QStringList(fontpath);
+ return fontpath;
+}
+
+static QFontEngine::FaceId fontFile(const QByteArray &_xname, QFreetypeFace **freetype, int *synth)
+{
+ *freetype = 0;
+ *synth = 0;
+
+ QByteArray xname = _xname.toLower();
+
+ int pos = 0;
+ int minus = 0;
+ while (minus < 5 && (pos = xname.indexOf('-', pos + 1)))
+ ++minus;
+ QByteArray searchname = xname.left(pos);
+ while (minus < 12 && (pos = xname.indexOf('-', pos + 1)))
+ ++minus;
+ QByteArray encoding = xname.mid(pos + 1);
+ //qDebug("xname='%s', searchname='%s', encoding='%s'", xname.data(), searchname.data(), encoding.data());
+ QStringList fontpath = fontPath();
+ QFontEngine::FaceId face_id;
+ face_id.index = 0;
+
+ QByteArray best_mapping;
+
+ for (QStringList::ConstIterator it = fontpath.constBegin(); it != fontpath.constEnd(); ++it) {
+ if (!(*it).startsWith(QLatin1Char('/')))
+ continue; // not a path name, a font server
+ QString fontmapname;
+ int num = 0;
+ // search font.dir and font.scale for the right file
+ while (num < 2) {
+ if (num == 0)
+ fontmapname = (*it) + QLatin1String("/fonts.scale");
+ else
+ fontmapname = (*it) + QLatin1String("/fonts.dir");
+ ++num;
+ //qWarning(fontmapname);
+ QFile fontmap(fontmapname);
+ if (!fontmap.open(QIODevice::ReadOnly))
+ continue;
+ while (!fontmap.atEnd()) {
+ QByteArray mapping = fontmap.readLine();
+ QByteArray lmapping = mapping.toLower();
+
+ //qWarning(xfontname);
+ //qWarning(mapping);
+ if (!lmapping.contains(searchname))
+ continue;
+ int index = mapping.indexOf(' ');
+ QByteArray ffn = mapping.mid(0,index);
+ // remove bitmap formats freetype can't handle
+ if (ffn.contains(".spd") || ffn.contains(".phont"))
+ continue;
+ bool best_match = false;
+ if (!best_mapping.isEmpty()) {
+ if (lmapping.contains("-0-0-0-0-")) { // scalable font
+ best_match = true;
+ goto found;
+ }
+ if (lmapping.contains(encoding) && !best_mapping.toLower().contains(encoding))
+ goto found;
+ continue;
+ }
+
+ found:
+ int colon = ffn.lastIndexOf(':');
+ if (colon != -1) {
+ QByteArray s = ffn.left(colon);
+ ffn = ffn.mid(colon + 1);
+ if (s.contains("ds="))
+ *synth |= QFontEngine::SynthesizedBold;
+ if (s.contains("ai="))
+ *synth |= QFontEngine::SynthesizedItalic;
+ }
+ face_id.filename = (*it).toLocal8Bit() + '/' + ffn;
+ best_mapping = mapping;
+ if (best_match)
+ goto end;
+ }
+ }
+ }
+end:
+// qDebug("fontfile for %s is from '%s'\n got %s synth=%d", xname.data(),
+// best_mapping.data(), face_id.filename.data(), *synth);
+ *freetype = QFreetypeFace::getFace(face_id);
+ if (!*freetype) {
+ face_id.index = 0;
+ face_id.filename = QByteArray();
+ }
+ return face_id;
+}
+
+#endif // QT_NO_FREETYPE
+
+// defined in qfontdatabase_x11.cpp
+extern int qt_mib_for_xlfd_encoding(const char *encoding);
+extern int qt_xlfd_encoding_id(const char *encoding);
+
+static inline XCharStruct *charStruct(XFontStruct *xfs, uint ch)
+{
+ XCharStruct *xcs = 0;
+ unsigned char r = ch>>8;
+ unsigned char c = ch&0xff;
+ if (xfs->per_char &&
+ r >= xfs->min_byte1 &&
+ r <= xfs->max_byte1 &&
+ c >= xfs->min_char_or_byte2 &&
+ c <= xfs->max_char_or_byte2) {
+ xcs = xfs->per_char + ((r - xfs->min_byte1) *
+ (xfs->max_char_or_byte2 -
+ xfs->min_char_or_byte2 + 1)) +
+ (c - xfs->min_char_or_byte2);
+ if (xcs->width == 0 && xcs->ascent == 0 && xcs->descent == 0)
+ xcs = 0;
+ }
+ return xcs;
+}
+
+QFontEngineXLFD::QFontEngineXLFD(XFontStruct *fs, const QByteArray &name, int mib)
+ : _fs(fs), _name(name), _codec(0), _cmap(mib)
+{
+ if (_cmap) _codec = QTextCodec::codecForMib(_cmap);
+
+ cache_cost = (((fs->max_byte1 - fs->min_byte1) *
+ (fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1)) +
+ fs->max_char_or_byte2 - fs->min_char_or_byte2);
+ cache_cost = ((fs->max_bounds.ascent + fs->max_bounds.descent) *
+ (fs->max_bounds.width * cache_cost / 8));
+ lbearing = SHRT_MIN;
+ rbearing = SHRT_MIN;
+ face_id.index = -1;
+ freetype = 0;
+ synth = 0;
+}
+
+QFontEngineXLFD::~QFontEngineXLFD()
+{
+ XFreeFont(QX11Info::display(), _fs);
+ _fs = 0;
+#ifndef QT_NO_FREETYPE
+ if (freetype)
+ freetype->release(face_id);
+#endif
+}
+
+bool QFontEngineXLFD::stringToCMap(const QChar *s, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
+{
+ if (*nglyphs < len) {
+ *nglyphs = len;
+ return false;
+ }
+
+ // filter out surrogates, we can't handle them anyway with XLFD fonts
+ QVarLengthArray<ushort> _s(len);
+ QChar *str = (QChar *)_s.data();
+ for (int i = 0; i < len; ++i) {
+ if (i < len - 1
+ && s[i].unicode() >= 0xd800 && s[i].unicode() < 0xdc00
+ && s[i+1].unicode() >= 0xdc00 && s[i].unicode() < 0xe000) {
+ *str = QChar();
+ ++i;
+ } else {
+ *str = s[i];
+ }
+ ++str;
+ }
+
+ len = str - (QChar *)_s.data();
+ str = (QChar *)_s.data();
+
+ bool mirrored = flags & QTextEngine::RightToLeft;
+ if (_codec) {
+ bool haveNbsp = false;
+ for (int i = 0; i < len; i++)
+ if (str[i].unicode() == 0xa0) {
+ haveNbsp = true;
+ break;
+ }
+
+ QVarLengthArray<unsigned short> ch(len);
+ QChar *chars = (QChar *)ch.data();
+ if (haveNbsp || mirrored) {
+ for (int i = 0; i < len; i++)
+ chars[i] = (str[i].unicode() == 0xa0 ? 0x20 :
+ (mirrored ? QChar::mirroredChar(str[i].unicode()) : str[i].unicode()));
+ } else {
+ for (int i = 0; i < len; i++)
+ chars[i] = str[i].unicode();
+ }
+ QTextCodec::ConverterState state;
+ state.flags = QTextCodec::ConvertInvalidToNull;
+ QByteArray ba = _codec->fromUnicode(chars, len, &state);
+ if (ba.length() == 2*len) {
+ // double byte encoding
+ const uchar *data = (const uchar *)ba.constData();
+ for (int i = 0; i < len; i++) {
+ glyphs->glyphs[i] = ((ushort)data[0] << 8) + data[1];
+ data += 2;
+ }
+ } else {
+ const uchar *data = (const uchar *)ba.constData();
+ for (int i = 0; i < len; i++)
+ glyphs->glyphs[i] = (ushort)data[i];
+ }
+ } else {
+ int i = len;
+ const QChar *c = str + len;
+ if (mirrored) {
+ while (c != str)
+ glyphs->glyphs[--i] = (--c)->unicode() == 0xa0 ? 0x20 : QChar::mirroredChar(c->unicode());
+ } else {
+ while (c != str)
+ glyphs->glyphs[--i] = (--c)->unicode() == 0xa0 ? 0x20 : c->unicode();
+ }
+ }
+ *nglyphs = len;
+ glyphs->numGlyphs = len;
+
+ if (!(flags & QTextEngine::GlyphIndicesOnly))
+ recalcAdvances(glyphs, flags);
+ return true;
+}
+
+void QFontEngineXLFD::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags /*flags*/) const
+{
+ int i = glyphs->numGlyphs;
+ XCharStruct *xcs;
+ // inlined for better performance
+ if (!_fs->per_char) {
+ xcs = &_fs->min_bounds;
+ while (i != 0) {
+ --i;
+ const unsigned char r = glyphs->glyphs[i] >> 8;
+ const unsigned char c = glyphs->glyphs[i] & 0xff;
+ if (r >= _fs->min_byte1 &&
+ r <= _fs->max_byte1 &&
+ c >= _fs->min_char_or_byte2 &&
+ c <= _fs->max_char_or_byte2) {
+ glyphs->advances_x[i] = xcs->width;
+ } else {
+ glyphs->glyphs[i] = 0;
+ }
+ }
+ }
+ else if (!_fs->max_byte1) {
+ XCharStruct *base = _fs->per_char - _fs->min_char_or_byte2;
+ while (i != 0) {
+ unsigned int gl = glyphs->glyphs[--i];
+ xcs = (gl >= _fs->min_char_or_byte2 && gl <= _fs->max_char_or_byte2) ?
+ base + gl : 0;
+ if (!xcs || (!xcs->width && !xcs->ascent && !xcs->descent)) {
+ glyphs->glyphs[i] = 0;
+ } else {
+ glyphs->advances_x[i] = xcs->width;
+ }
+ }
+ }
+ else {
+ while (i != 0) {
+ xcs = charStruct(_fs, glyphs->glyphs[--i]);
+ if (!xcs) {
+ glyphs->glyphs[i] = 0;
+ } else {
+ glyphs->advances_x[i] = xcs->width;
+ }
+ }
+ }
+}
+
+glyph_metrics_t QFontEngineXLFD::boundingBox(const QGlyphLayout &glyphs)
+{
+ int i;
+
+ glyph_metrics_t overall;
+ // initialize with line height, we get the same behaviour on all platforms
+ overall.y = -ascent();
+ overall.height = ascent() + descent() + 1;
+ QFixed ymax;
+ QFixed xmax;
+ for (i = 0; i < glyphs.numGlyphs; i++) {
+ XCharStruct *xcs = charStruct(_fs, glyphs.glyphs[i]);
+ if (xcs) {
+ QFixed x = overall.xoff + glyphs.offsets[i].x + xcs->lbearing;
+ QFixed y = overall.yoff + glyphs.offsets[i].y - xcs->ascent;
+ overall.x = qMin(overall.x, x);
+ overall.y = qMin(overall.y, y);
+ // XCharStruct::rbearing is defined as distance from left edge to rightmost pixel
+ xmax = qMax(xmax, overall.xoff + glyphs.offsets[i].x + xcs->rbearing);
+ ymax = qMax(ymax, y + xcs->ascent + xcs->descent);
+ overall.xoff += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
+ } else {
+ QFixed size = _fs->ascent;
+ overall.x = qMin(overall.x, overall.xoff);
+ overall.y = qMin(overall.y, overall.yoff - size);
+ ymax = qMax(ymax, overall.yoff);
+ overall.xoff += size;
+ xmax = qMax(xmax, overall.xoff);
+ }
+ }
+ overall.height = qMax(overall.height, ymax - overall.y);
+ overall.width = xmax - overall.x;
+
+ return overall;
+}
+
+glyph_metrics_t QFontEngineXLFD::boundingBox(glyph_t glyph)
+{
+ glyph_metrics_t gm;
+ XCharStruct *xcs = charStruct(_fs, glyph);
+ if (xcs) {
+ // XCharStruct::rbearing is defined as distance from left edge to rightmost pixel
+ // XCharStruct::width is defined as the advance
+ gm = glyph_metrics_t(xcs->lbearing, -xcs->ascent, xcs->rbearing- xcs->lbearing, xcs->ascent + xcs->descent,
+ xcs->width, 0);
+ } else {
+ QFixed size = ascent();
+ gm = glyph_metrics_t(0, size, size, size, size, 0);
+ }
+ return gm;
+}
+
+QFixed QFontEngineXLFD::ascent() const
+{
+ return _fs->ascent;
+}
+
+QFixed QFontEngineXLFD::descent() const
+{
+ return (_fs->descent-1);
+}
+
+QFixed QFontEngineXLFD::leading() const
+{
+ QFixed l = QFixed(qMin<int>(_fs->ascent, _fs->max_bounds.ascent)
+ + qMin<int>(_fs->descent, _fs->max_bounds.descent)) * QFixed::fromReal(0.15);
+ return l.ceil();
+}
+
+qreal QFontEngineXLFD::maxCharWidth() const
+{
+ return _fs->max_bounds.width;
+}
+
+
+// Loads the font for the specified script
+static inline int maxIndex(XFontStruct *f) {
+ return (((f->max_byte1 - f->min_byte1) *
+ (f->max_char_or_byte2 - f->min_char_or_byte2 + 1)) +
+ f->max_char_or_byte2 - f->min_char_or_byte2);
+}
+
+qreal QFontEngineXLFD::minLeftBearing() const
+{
+ if (lbearing == SHRT_MIN) {
+ if (_fs->per_char) {
+ XCharStruct *cs = _fs->per_char;
+ int nc = maxIndex(_fs) + 1;
+ int mx = cs->lbearing;
+
+ for (int c = 1; c < nc; c++) {
+ // ignore the bearings for characters whose ink is
+ // completely outside the normal bounding box
+ if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
+ (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
+ continue;
+
+ int nmx = cs[c].lbearing;
+
+ if (nmx < mx)
+ mx = nmx;
+ }
+
+ ((QFontEngineXLFD *)this)->lbearing = mx;
+ } else
+ ((QFontEngineXLFD *)this)->lbearing = _fs->min_bounds.lbearing;
+ }
+ return lbearing;
+}
+
+qreal QFontEngineXLFD::minRightBearing() const
+{
+ if (rbearing == SHRT_MIN) {
+ if (_fs->per_char) {
+ XCharStruct *cs = _fs->per_char;
+ int nc = maxIndex(_fs) + 1;
+ int mx = cs->rbearing;
+
+ for (int c = 1; c < nc; c++) {
+ // ignore the bearings for characters whose ink is
+ // completely outside the normal bounding box
+ if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
+ (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
+ continue;
+
+ int nmx = cs[c].rbearing;
+
+ if (nmx < mx)
+ mx = nmx;
+ }
+
+ ((QFontEngineXLFD *)this)->rbearing = mx;
+ } else
+ ((QFontEngineXLFD *)this)->rbearing = _fs->min_bounds.rbearing;
+ }
+ return rbearing;
+}
+
+const char *QFontEngineXLFD::name() const
+{
+ return _name;
+}
+
+bool QFontEngineXLFD::canRender(const QChar *string, int len)
+{
+ QVarLengthGlyphLayoutArray glyphs(len);
+ int nglyphs = len;
+ if (stringToCMap(string, len, &glyphs, &nglyphs, 0) == false) {
+ glyphs.resize(nglyphs);
+ stringToCMap(string, len, &glyphs, &nglyphs, 0);
+ }
+
+ bool allExist = true;
+ for (int i = 0; i < nglyphs; i++) {
+ if (!glyphs.glyphs[i] || !charStruct(_fs, glyphs.glyphs[i])) {
+ allExist = false;
+ break;
+ }
+ }
+
+ return allExist;
+}
+
+QBitmap QFontEngineXLFD::bitmapForGlyphs(const QGlyphLayout &glyphs, const glyph_metrics_t &metrics, QTextItem::RenderFlags flags)
+{
+ int w = metrics.width.toInt();
+ int h = metrics.height.toInt();
+ if (w <= 0 || h <= 0)
+ return QBitmap();
+
+ QPixmapData *data = new QX11PixmapData(QPixmapData::BitmapType);
+ data->resize(w, h);
+ QPixmap bm(data);
+ QPainter p(&bm);
+ p.fillRect(0, 0, w, h, Qt::color0);
+ p.setPen(Qt::color1);
+
+ QTextItemInt item;
+ item.flags = flags;
+ item.ascent = -metrics.y;
+ item.descent = metrics.height - item.ascent;
+ item.width = metrics.width;
+ item.chars = 0;
+ item.num_chars = 0;
+ item.logClusters = 0;
+ item.glyphs = glyphs;
+ item.fontEngine = this;
+ item.f = 0;
+
+ p.drawTextItem(QPointF(-metrics.x.toReal(), item.ascent.toReal()), item);
+ p.end();
+
+ return QBitmap(bm);
+}
+
+void QFontEngineXLFD::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
+{
+ // cannot use QFontEngine::addBitmapFontToPath(), since we don't
+ // have direct access to the glyph bitmaps, so we have to draw
+ // onto a QBitmap, then convert to QImage, then to path
+ glyph_metrics_t metrics = boundingBox(glyphs);
+
+ QImage image = bitmapForGlyphs(glyphs, metrics, flags).toImage();
+ if (image.isNull())
+ return;
+
+ image = image.convertToFormat(QImage::Format_Mono);
+ const uchar *image_data = image.bits();
+ uint bpl = image.bytesPerLine();
+ // from qfontengine.cpp
+ extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data,
+ int bpl, int w, int h, QPainterPath *path);
+ qt_addBitmapToPath(x, y + metrics.y.toReal(), image_data, bpl, image.width(), image.height(), path);
+}
+
+QFontEngine::FaceId QFontEngineXLFD::faceId() const
+{
+#ifndef QT_NO_FREETYPE
+ if (face_id.index == -1) {
+ face_id = fontFile(_name, &freetype, &synth);
+ if (_codec)
+ face_id.encoding = _codec->mibEnum();
+ if (freetype) {
+ const_cast<QFontEngineXLFD *>(this)->fsType = freetype->fsType();
+ } else {
+ face_id.index = 0;
+ face_id.filename = '-' + QFontEngine::properties().postscriptName;
+ }
+ }
+#endif
+
+ return face_id;
+}
+
+QFontEngine::Properties QFontEngineXLFD::properties() const
+{
+ if (face_id.index == -1)
+ (void)faceId();
+
+#ifndef QT_NO_FREETYPE
+ if (freetype)
+ return freetype->properties();
+#endif
+ return QFontEngine::properties();
+}
+
+void QFontEngineXLFD::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
+{
+ if (face_id.index == -1)
+ (void)faceId();
+#ifndef QT_NO_FREETYPE
+ if (!freetype)
+#endif
+ {
+ QFontEngine::getUnscaledGlyph(glyph, path, metrics);
+ return;
+ }
+
+#ifndef QT_NO_FREETYPE
+ freetype->lock();
+
+ FT_Face face = freetype->face;
+ FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
+ freetype->xsize = face->units_per_EM << 6;
+ freetype->ysize = face->units_per_EM << 6;
+ FT_Set_Transform(face, 0, 0);
+ glyph = glyphIndexToFreetypeGlyphIndex(glyph);
+ FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
+
+ int left = face->glyph->metrics.horiBearingX;
+ int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
+ int top = face->glyph->metrics.horiBearingY;
+ int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
+
+ QFixedPoint p;
+ p.x = 0;
+ p.y = 0;
+ metrics->width = QFixed::fromFixed(right-left);
+ metrics->height = QFixed::fromFixed(top-bottom);
+ metrics->x = QFixed::fromFixed(left);
+ metrics->y = QFixed::fromFixed(-top);
+ metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
+
+ if (!FT_IS_SCALABLE(freetype->face))
+ QFreetypeFace::addBitmapToPath(face->glyph, p, path);
+ else
+ QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
+
+ FT_Set_Transform(face, &freetype->matrix, 0);
+ freetype->unlock();
+#endif // QT_NO_FREETYPE
+}
+
+
+bool QFontEngineXLFD::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+#ifndef QT_NO_FREETYPE
+ if (face_id.index == -1)
+ (void)faceId();
+ if (!freetype)
+ return false;
+ return freetype->getSfntTable(tag, buffer, length);
+#else
+ Q_UNUSED(tag);
+ Q_UNUSED(buffer);
+ Q_UNUSED(length);
+ return false;
+#endif
+}
+
+int QFontEngineXLFD::synthesized() const
+{
+ return synth;
+}
+
+QImage QFontEngineXLFD::alphaMapForGlyph(glyph_t glyph)
+{
+ glyph_metrics_t metrics = boundingBox(glyph);
+
+/*
+ printf("a) w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n",
+ metrics.width.toReal(),
+ metrics.height.toReal(),
+ metrics.xoff.toReal(),
+ metrics.yoff.toReal(),
+ metrics.x.toReal(),
+ metrics.y.toReal());
+*/
+
+ QGlyphLayoutArray<1> glyphs;
+ glyphs.glyphs[0] = glyph;
+
+ QImage image = bitmapForGlyphs(glyphs, metrics).toImage();
+//image.save(QString::fromLatin1("x11cache-%1.png").arg((int)glyph));
+
+ image = image.convertToFormat(QImage::Format_Indexed8);
+ QVector<QRgb> colors(256);
+ for (int i = 0; i < 256; ++i)
+ colors[i] = qRgba(0, 0, 0, i);
+ image.setColorTable(colors);
+
+ int width = image.width();
+ int height = image.height();
+ for (int y = 0; y < height; ++y) {
+ uchar *bits = image.scanLine(y);
+ for (int x = 0; x < width; ++x)
+ bits[x] = ~(bits[x]-1);
+ }
+
+ return image;
+}
+
+#ifndef QT_NO_FREETYPE
+
+FT_Face QFontEngineXLFD::non_locked_face() const
+{
+ return freetype ? freetype->face : 0;
+}
+
+uint QFontEngineXLFD::toUnicode(glyph_t g) const
+{
+ if (_codec) {
+ QTextCodec::ConverterState state;
+ state.flags = QTextCodec::ConvertInvalidToNull;
+ uchar data[2];
+ int l = 1;
+ if (g > 255) {
+ data[0] = (g >> 8);
+ data[1] = (g & 255);
+ l = 2;
+ } else {
+ data[0] = g;
+ }
+ QString s = _codec->toUnicode((char *)data, l, &state);
+ Q_ASSERT(s.length() == 1);
+ g = s.at(0).unicode();
+ }
+ return g;
+}
+
+glyph_t QFontEngineXLFD::glyphIndexToFreetypeGlyphIndex(glyph_t g) const
+{
+ return FT_Get_Char_Index(freetype->face, toUnicode(g));
+}
+#endif
+
+#ifndef QT_NO_FONTCONFIG
+
+// ------------------------------------------------------------------
+// Multi FT engine
+// ------------------------------------------------------------------
+
+static QFontEngine *engineForPattern(FcPattern *pattern, const QFontDef &request,
+ int screen)
+{
+ FcResult res;
+ FcPattern *match = FcFontMatch(0, pattern, &res);
+ QFontEngineX11FT *engine = new QFontEngineX11FT(match, request, screen);
+ if (!engine->invalid())
+ return engine;
+
+ delete engine;
+ QFontEngine *fe = new QFontEngineBox(request.pixelSize);
+ fe->fontDef = request;
+ return fe;
+}
+
+QFontEngineMultiFT::QFontEngineMultiFT(QFontEngine *fe, FcPattern *matchedPattern, FcPattern *p, int s, const QFontDef &req)
+ : QFontEngineMulti(2), request(req), pattern(p), firstEnginePattern(matchedPattern), fontSet(0), screen(s)
+{
+
+ engines[0] = fe;
+ engines.at(0)->ref.ref();
+ fontDef = engines[0]->fontDef;
+ cache_cost = 100;
+ firstFontIndex = 1;
+}
+
+QFontEngineMultiFT::~QFontEngineMultiFT()
+{
+ extern QMutex *qt_fontdatabase_mutex();
+ QMutexLocker locker(qt_fontdatabase_mutex());
+
+ FcPatternDestroy(pattern);
+ if (firstEnginePattern)
+ FcPatternDestroy(firstEnginePattern);
+ if (fontSet)
+ FcFontSetDestroy(fontSet);
+}
+
+
+void QFontEngineMultiFT::loadEngine(int at)
+{
+ extern QMutex *qt_fontdatabase_mutex();
+ QMutexLocker locker(qt_fontdatabase_mutex());
+
+ extern void qt_addPatternProps(FcPattern *pattern, int screen, int script,
+ const QFontDef &request);
+ extern QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &);
+ extern FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request);
+
+ Q_ASSERT(at > 0);
+ if (!fontSet) {
+ fontSet = qt_fontSetForPattern(pattern, request);
+
+ // it may happen that the fontset of fallbacks consists of only one font. In this case we
+ // have to fall back to the box fontengine as we cannot render the glyph.
+ if (fontSet->nfont == 1 && at == 1 && engines.size() == 2) {
+ Q_ASSERT(engines.at(at) == 0);
+ QFontEngine *fe = new QFontEngineBox(request.pixelSize);
+ fe->fontDef = request;
+ engines[at] = fe;
+ return;
+ }
+
+ if (firstEnginePattern) {
+
+ if (!FcPatternEqual(firstEnginePattern, fontSet->fonts[0]))
+ firstFontIndex = 0;
+
+ FcPatternDestroy(firstEnginePattern);
+ firstEnginePattern = 0;
+ }
+
+ engines.resize(fontSet->nfont + 1 - firstFontIndex);
+ }
+ Q_ASSERT(at < engines.size());
+ Q_ASSERT(engines.at(at) == 0);
+
+ FcPattern *pattern = FcPatternDuplicate(fontSet->fonts[at + firstFontIndex - 1]);
+ qt_addPatternProps(pattern, screen, QUnicodeTables::Common, request);
+
+ QFontDef fontDef = qt_FcPatternToQFontDef(pattern, this->request);
+
+ // note: we use -1 for the script to make sure that we keep real
+ // FT engines separate from Multi engines in the font cache
+ QFontCache::Key key(fontDef, -1, screen);
+ QFontEngine *fontEngine = QFontCache::instance()->findEngine(key);
+ if (!fontEngine) {
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+ fontEngine = engineForPattern(pattern, request, screen);
+ QFontCache::instance()->insertEngine(key, fontEngine);
+ }
+ FcPatternDestroy(pattern);
+ fontEngine->ref.ref();
+ engines[at] = fontEngine;
+}
+
+// ------------------------------------------------------------------
+// X11 FT engine
+// ------------------------------------------------------------------
+
+
+
+Q_GUI_EXPORT void qt_x11ft_convert_pattern(FcPattern *pattern, QByteArray *file_name, int *index, bool *antialias)
+{
+ FcChar8 *fileName;
+ FcPatternGetString(pattern, FC_FILE, 0, &fileName);
+ *file_name = (const char *)fileName;
+ if (!FcPatternGetInteger(pattern, FC_INDEX, 0, index))
+ index = 0;
+ FcBool b;
+ if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &b) == FcResultMatch)
+ *antialias = b;
+}
+
+
+QFontEngineX11FT::QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int screen)
+ : QFontEngineFT(fd)
+{
+// FcPatternPrint(pattern);
+
+ bool antialias = X11->fc_antialias;
+ QByteArray file_name;
+ int face_index;
+ qt_x11ft_convert_pattern(pattern, &file_name, &face_index, &antialias);
+ QFontEngine::FaceId face_id;
+ face_id.filename = file_name;
+ face_id.index = face_index;
+
+ canUploadGlyphsToServer = QApplication::testAttribute(Qt::AA_X11InitThreads) || (qApp->thread() == QThread::currentThread());
+
+ subpixelType = Subpixel_None;
+ if (antialias) {
+ int subpixel = X11->display ? X11->screens[screen].subpixel : FC_RGBA_UNKNOWN;
+ if (subpixel == FC_RGBA_UNKNOWN)
+ (void) FcPatternGetInteger(pattern, FC_RGBA, 0, &subpixel);
+ if (!antialias || subpixel == FC_RGBA_UNKNOWN)
+ subpixel = FC_RGBA_NONE;
+
+ switch (subpixel) {
+ case FC_RGBA_NONE: subpixelType = Subpixel_None; break;
+ case FC_RGBA_RGB: subpixelType = Subpixel_RGB; break;
+ case FC_RGBA_BGR: subpixelType = Subpixel_BGR; break;
+ case FC_RGBA_VRGB: subpixelType = Subpixel_VRGB; break;
+ case FC_RGBA_VBGR: subpixelType = Subpixel_VBGR; break;
+ default: break;
+ }
+ }
+
+ if (fd.hintingPreference != QFont::PreferDefaultHinting) {
+ switch (fd.hintingPreference) {
+ case QFont::PreferNoHinting:
+ default_hint_style = HintNone;
+ break;
+ case QFont::PreferVerticalHinting:
+ default_hint_style = HintLight;
+ break;
+ case QFont::PreferFullHinting:
+ default:
+ default_hint_style = HintFull;
+ break;
+ }
+ }
+#ifdef FC_HINT_STYLE
+ else {
+ int hint_style = 0;
+ // Try to use Xft.hintstyle from XDefaults first if running in GNOME, to match
+ // the behavior of cairo
+ if (X11->fc_hint_style > -1 && X11->desktopEnvironment == DE_GNOME)
+ hint_style = X11->fc_hint_style;
+ else if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch
+ && X11->fc_hint_style > -1)
+ hint_style = X11->fc_hint_style;
+
+ switch (hint_style) {
+ case FC_HINT_NONE:
+ default_hint_style = HintNone;
+ break;
+ case FC_HINT_SLIGHT:
+ default_hint_style = HintLight;
+ break;
+ case FC_HINT_MEDIUM:
+ default_hint_style = HintMedium;
+ break;
+ default:
+ default_hint_style = HintFull;
+ break;
+ }
+ }
+#endif
+
+#if defined(FC_AUTOHINT) && defined(FT_LOAD_FORCE_AUTOHINT)
+ {
+ bool autohint = false;
+
+ FcBool b;
+ if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &b) == FcResultMatch)
+ autohint = b;
+
+ if (autohint)
+ default_load_flags |= FT_LOAD_FORCE_AUTOHINT;
+ }
+#endif
+
+#if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
+ {
+ int filter = FC_LCD_FILTER_NONE;
+ if (FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
+ switch (filter) {
+ case FC_LCD_FILTER_NONE:
+ lcdFilterType = FT_LCD_FILTER_NONE;
+ break;
+ case FC_LCD_FILTER_DEFAULT:
+ lcdFilterType = FT_LCD_FILTER_DEFAULT;
+ break;
+ case FC_LCD_FILTER_LIGHT:
+ lcdFilterType = FT_LCD_FILTER_LIGHT;
+ break;
+ case FC_LCD_FILTER_LEGACY:
+ lcdFilterType = FT_LCD_FILTER_LEGACY;
+ break;
+ default:
+ // new unknown lcd filter type?!
+ break;
+ }
+ }
+ }
+#endif
+
+#ifdef FC_EMBEDDED_BITMAP
+ {
+ FcBool b;
+ if (FcPatternGetBool(pattern, FC_EMBEDDED_BITMAP, 0, &b) == FcResultMatch)
+ embeddedbitmap = b;
+ }
+#endif
+
+ GlyphFormat defaultFormat = Format_None;
+
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender) {
+ int format = PictStandardA8;
+ if (!antialias)
+ format = PictStandardA1;
+ else if (subpixelType == Subpixel_RGB
+ || subpixelType == Subpixel_BGR
+ || subpixelType == Subpixel_VRGB
+ || subpixelType == Subpixel_VBGR)
+ format = PictStandardARGB32;
+ xglyph_format = format;
+
+ if (subpixelType != QFontEngineFT::Subpixel_None)
+ defaultFormat = Format_A32;
+ else if (antialias)
+ defaultFormat = Format_A8;
+ else
+ defaultFormat = Format_Mono;
+ }
+#endif
+
+ if (!init(face_id, antialias, defaultFormat)) {
+ FcPatternDestroy(pattern);
+ return;
+ }
+
+ if (!freetype->charset) {
+ FcCharSet *cs;
+ FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
+ freetype->charset = FcCharSetCopy(cs);
+ }
+ FcPatternDestroy(pattern);
+}
+
+QFontEngineX11FT::~QFontEngineX11FT()
+{
+ freeGlyphSets();
+}
+
+unsigned long QFontEngineX11FT::allocateServerGlyphSet()
+{
+#ifndef QT_NO_XRENDER
+ if (!canUploadGlyphsToServer || !X11->use_xrender)
+ return 0;
+ return XRenderCreateGlyphSet(X11->display, XRenderFindStandardFormat(X11->display, xglyph_format));
+#else
+ return 0;
+#endif
+}
+
+void QFontEngineX11FT::freeServerGlyphSet(unsigned long id)
+{
+#ifndef QT_NO_XRENDER
+ if (!id)
+ return;
+ XRenderFreeGlyphSet(X11->display, id);
+#endif
+}
+
+bool QFontEngineX11FT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
+{
+#ifndef QT_NO_XRENDER
+ if (!canUploadGlyphsToServer)
+ return false;
+ if (g->format == Format_Mono) {
+ /*
+ * swap bit order around; FreeType is always MSBFirst
+ */
+ if (BitmapBitOrder(X11->display) != MSBFirst) {
+ unsigned char *line = g->data;
+ int i = glyphDataSize;
+ while (i--) {
+ unsigned char c;
+ c = *line;
+ c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
+ c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
+ c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
+ *line++ = c;
+ }
+ }
+ }
+
+ ::Glyph xglyph = glyphid;
+ XRenderAddGlyphs (X11->display, set->id, &xglyph, info, 1, (const char *)g->data, glyphDataSize);
+ delete [] g->data;
+ g->data = 0;
+ g->format = Format_None;
+ g->uploadedToServer = true;
+ return true;
+#else
+ return false;
+#endif
+}
+
+QFontEngine *QFontEngineX11FT::cloneWithSize(qreal pixelSize) const
+{
+ QFontDef fontDef;
+ fontDef.pixelSize = pixelSize;
+ QFontEngineX11FT *fe = new QFontEngineX11FT(fontDef);
+ if (!fe->initFromFontEngine(this)) {
+ delete fe;
+ return 0;
+ } else {
+ fe->xglyph_format = xglyph_format;
+ return fe;
+ }
+}
+
+#endif // QT_NO_FONTCONFIG
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qfontengine_x11_p.h b/src/widgets/platforms/x11/qfontengine_x11_p.h
new file mode 100644
index 0000000000..d7eb39daaa
--- /dev/null
+++ b/src/widgets/platforms/x11/qfontengine_x11_p.h
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QFONTENGINE_X11_P_H
+#define QFONTENGINE_X11_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/qt_x11_p.h>
+
+#include <private/qfontengine_ft_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFreetypeFace;
+
+// --------------------------------------------------------------------------
+
+class QFontEngineMultiXLFD : public QFontEngineMulti
+{
+public:
+ QFontEngineMultiXLFD(const QFontDef &r, const QList<int> &l, int s);
+ ~QFontEngineMultiXLFD();
+
+ void loadEngine(int at);
+
+private:
+ QList<int> encodings;
+ int screen;
+ QFontDef request;
+};
+
+/**
+ * \internal The font engine for X Logical Font Description (XLFD) fonts, which is for X11 systems without freetype.
+ */
+class QFontEngineXLFD : public QFontEngine
+{
+public:
+ QFontEngineXLFD(XFontStruct *f, const QByteArray &name, int mib);
+ ~QFontEngineXLFD();
+
+ virtual QFontEngine::FaceId faceId() const;
+ QFontEngine::Properties properties() const;
+ virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics);
+ virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
+ virtual int synthesized() const;
+
+ virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
+ QTextEngine::ShaperFlags flags) const;
+ virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const;
+
+ virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs);
+ virtual glyph_metrics_t boundingBox(glyph_t glyph);
+
+ virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags);
+ virtual QFixed ascent() const;
+ virtual QFixed descent() const;
+ virtual QFixed leading() const;
+ virtual qreal maxCharWidth() const;
+ virtual qreal minLeftBearing() const;
+ virtual qreal minRightBearing() const;
+ virtual QImage alphaMapForGlyph(glyph_t);
+
+ virtual inline Type type() const
+ { return QFontEngine::XLFD; }
+
+ virtual bool canRender(const QChar *string, int len);
+ virtual const char *name() const;
+
+ inline XFontStruct *fontStruct() const
+ { return _fs; }
+
+#ifndef QT_NO_FREETYPE
+ FT_Face non_locked_face() const;
+ glyph_t glyphIndexToFreetypeGlyphIndex(glyph_t g) const;
+#endif
+ uint toUnicode(glyph_t g) const;
+
+private:
+ QBitmap bitmapForGlyphs(const QGlyphLayout &glyphs, const glyph_metrics_t &metrics, QTextItem::RenderFlags flags = 0);
+
+ XFontStruct *_fs;
+ QByteArray _name;
+ QTextCodec *_codec;
+ int _cmap;
+ int lbearing, rbearing;
+ mutable QFontEngine::FaceId face_id;
+ mutable QFreetypeFace *freetype;
+ mutable int synth;
+};
+
+#ifndef QT_NO_FONTCONFIG
+
+class Q_GUI_EXPORT QFontEngineMultiFT : public QFontEngineMulti
+{
+public:
+ QFontEngineMultiFT(QFontEngine *fe, FcPattern *firstEnginePattern, FcPattern *p, int s, const QFontDef &request);
+ ~QFontEngineMultiFT();
+
+ void loadEngine(int at);
+
+private:
+ QFontDef request;
+ FcPattern *pattern;
+ FcPattern *firstEnginePattern;
+ FcFontSet *fontSet;
+ int screen;
+ int firstFontIndex; // first font in fontset
+};
+
+class Q_GUI_EXPORT QFontEngineX11FT : public QFontEngineFT
+{
+public:
+ explicit QFontEngineX11FT(const QFontDef &fontDef) : QFontEngineFT(fontDef) {}
+ explicit QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int screen);
+ ~QFontEngineX11FT();
+
+ QFontEngine *cloneWithSize(qreal pixelSize) const;
+
+#ifndef QT_NO_XRENDER
+ int xglyph_format;
+#endif
+
+protected:
+ virtual bool uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const;
+ virtual unsigned long allocateServerGlyphSet();
+ virtual void freeServerGlyphSet(unsigned long id);
+};
+
+#endif // QT_NO_FONTCONFIG
+
+QT_END_NAMESPACE
+
+#endif // QFONTENGINE_X11_P_H
diff --git a/src/widgets/platforms/x11/qkde.cpp b/src/widgets/platforms/x11/qkde.cpp
new file mode 100644
index 0000000000..7d333feb9a
--- /dev/null
+++ b/src/widgets/platforms/x11/qkde.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qkde_p.h"
+#include <QtCore/QLibrary>
+#include <QtCore/QDir>
+#include <QtCore/qdebug.h>
+#include <QtCore/QSettings>
+#include "QtGui/qstylefactory.h"
+#include "qt_x11_p.h"
+
+#if defined(Q_WS_X11)
+
+QT_BEGIN_NAMESPACE
+
+/*! \internal
+Gets the current KDE home path
+like "/home/troll/.kde"
+*/
+QString QKde::kdeHome()
+{
+ static QString kdeHomePath;
+ if (kdeHomePath.isEmpty()) {
+ kdeHomePath = QString::fromLocal8Bit(qgetenv("KDEHOME"));
+ if (kdeHomePath.isEmpty()) {
+ QDir homeDir(QDir::homePath());
+ QString kdeConfDir(QLatin1String("/.kde"));
+ if (4 == X11->desktopVersion && homeDir.exists(QLatin1String(".kde4")))
+ kdeConfDir = QLatin1String("/.kde4");
+ kdeHomePath = QDir::homePath() + kdeConfDir;
+ }
+ }
+ return kdeHomePath;
+}
+
+/*!\internal
+ Reads the color from the config, and store it in the palette with the given color role if found
+ */
+static bool kdeColor(QPalette *pal, QPalette::ColorRole role, const QSettings &kdeSettings, const QString &kde4Key, const QString &kde3Key = QString())
+{
+ QVariant variant = kdeSettings.value(kde4Key);
+ if (!variant.isValid())
+ QVariant variant = kdeSettings.value(kde3Key);
+ if (variant.isValid()) {
+ QStringList values = variant.toStringList();
+ if (values.size() == 3) {
+ int r = values[0].toInt();
+ int g = values[1].toInt();
+ int b = values[2].toInt();
+ pal->setBrush(role, QColor(r, g, b));
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/*!\internal
+ Returns the KDE palette
+*/
+QPalette QKde::kdePalette()
+{
+ const QSettings theKdeSettings(QKde::kdeHome() +
+ QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat);
+ QPalette pal;
+
+ // Setup KDE palette
+ kdeColor(&pal, QPalette::Button, theKdeSettings, QLatin1String("Colors:Button/BackgroundNormal"), QLatin1String("buttonBackground"));
+ kdeColor(&pal, QPalette::Window, theKdeSettings, QLatin1String("Colors:Window/BackgroundNormal"), QLatin1String("background"));
+ kdeColor(&pal, QPalette::Text, theKdeSettings, QLatin1String("Colors:View/ForegroundNormal"), QLatin1String("foreground"));
+ kdeColor(&pal, QPalette::WindowText, theKdeSettings, QLatin1String("Colors:Window/ForegroundNormal"), QLatin1String("windowForeground"));
+ kdeColor(&pal, QPalette::Base, theKdeSettings, QLatin1String("Colors:View/BackgroundNormal"), QLatin1String("windowBackground"));
+ kdeColor(&pal, QPalette::Highlight, theKdeSettings, QLatin1String("Colors:Selection/BackgroundNormal"), QLatin1String("selectBackground"));
+ kdeColor(&pal, QPalette::HighlightedText, theKdeSettings, QLatin1String("Colors:Selection/ForegroundNormal"), QLatin1String("selectForeground"));
+ kdeColor(&pal, QPalette::AlternateBase, theKdeSettings, QLatin1String("Colors:View/BackgroundAlternate"), QLatin1String("alternateBackground"));
+ kdeColor(&pal, QPalette::ButtonText, theKdeSettings, QLatin1String("Colors:Button/ForegroundNormal"), QLatin1String("buttonForeground"));
+ kdeColor(&pal, QPalette::Link, theKdeSettings, QLatin1String("Colors:View/ForegroundLink"), QLatin1String("linkColor"));
+ kdeColor(&pal, QPalette::LinkVisited, theKdeSettings, QLatin1String("Colors:View/ForegroundVisited"), QLatin1String("visitedLinkColor"));
+ //## TODO tooltip color
+
+ return pal;
+}
+
+/*!\internal
+ Returns the name of the QStyle to use.
+ (read from the kde config if needed)
+*/
+QString QKde::kdeStyle()
+{
+ if (X11->desktopVersion >= 4) {
+ QSettings kdeSettings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat);
+ QString style = kdeSettings.value(QLatin1String("widgetStyle"), QLatin1String("Oxygen")).toString();
+
+ QStringList availableStyles = QStyleFactory::keys();
+ if(availableStyles.contains(style, Qt::CaseInsensitive))
+ return style;
+ }
+
+ if (X11->use_xrender)
+ return QLatin1String("plastique");
+ else
+ return QLatin1String("windows");
+}
+
+
+int QKde::kdeToolButtonStyle()
+{
+ QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"),
+ QSettings::IniFormat);
+ settings.beginGroup(QLatin1String("Toolbar style"));
+ QString toolbarStyle = settings.value(QLatin1String("ToolButtonStyle"), QLatin1String("TextBesideIcon")).toString();
+ if (toolbarStyle == QLatin1String("TextBesideIcon"))
+ return Qt::ToolButtonTextBesideIcon;
+ else if (toolbarStyle == QLatin1String("TextOnly"))
+ return Qt::ToolButtonTextOnly;
+ else if (toolbarStyle == QLatin1String("TextUnderIcon"))
+ return Qt::ToolButtonTextUnderIcon;
+
+ return Qt::ToolButtonTextBesideIcon;
+}
+
+int QKde::kdeToolBarIconSize()
+{
+ static int iconSize = -1;
+ if (iconSize == -1) {
+ QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"),
+ QSettings::IniFormat);
+ settings.beginGroup(QLatin1String("ToolbarIcons"));
+ iconSize = settings.value(QLatin1String("Size")).toInt();
+ }
+ return iconSize;
+}
+
+QT_END_NAMESPACE
+
+#endif //Q_WS_X11
+
diff --git a/src/widgets/platforms/x11/qkde_p.h b/src/widgets/platforms/x11/qkde_p.h
new file mode 100644
index 0000000000..4e108f6e9e
--- /dev/null
+++ b/src/widgets/platforms/x11/qkde_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QKDE_H
+#define QKDE_H
+
+#include <QtCore/qglobal.h>
+#include <QtGui/QPalette>
+#include <QtGui/QIcon>
+
+//
+// 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.
+//
+#if defined(Q_WS_X11)
+
+
+QT_BEGIN_NAMESPACE
+
+/*!\internal
+ This namespace contains helper function to help KDE integration
+ They are only used if we detect the use of KDE and the KDE platform plugin is not found (old KDE version)
+ Or if the detected KDE version is KDE3
+*/
+namespace QKde {
+ QString kdeHome();
+ QString kdeStyle();
+ QPalette kdePalette();
+ int kdeToolButtonStyle();
+ int kdeToolBarIconSize();
+}
+
+
+QT_END_NAMESPACE
+
+#endif // Q_WS_X11
+#endif // QKDE_H
diff --git a/src/widgets/platforms/x11/qkeymapper_x11.cpp b/src/widgets/platforms/x11/qkeymapper_x11.cpp
new file mode 100644
index 0000000000..5383bfd456
--- /dev/null
+++ b/src/widgets/platforms/x11/qkeymapper_x11.cpp
@@ -0,0 +1,1869 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qtextcodec.h"
+#include "qwidget.h"
+
+#include "qapplication_p.h"
+#include "qevent_p.h"
+#include "qt_x11_p.h"
+
+#ifndef QT_NO_XKB
+# include <X11/XKBlib.h>
+#endif
+
+#define XK_MISCELLANY
+#define XK_LATIN1
+#define XK_KOREAN
+#define XK_XKB_KEYS
+#include <X11/keysymdef.h>
+
+#include <ctype.h>
+
+#ifdef QT_LINUXBASE
+// LSB's IsKeypadKey define is wrong - see
+// http://bugs.linuxbase.org/show_bug.cgi?id=2521
+#undef IsKeypadKey
+#define IsKeypadKey(keysym) \
+ (((KeySym)(keysym) >= XK_KP_Space) && ((KeySym)(keysym) <= XK_KP_Equal))
+
+#undef IsPrivateKeypadKey
+#define IsPrivateKeypadKey(keysym) \
+ (((KeySym)(keysym) >= 0x11000000) && ((KeySym)(keysym) <= 0x1100FFFF))
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_XKB
+
+// bring in the auto-generated xkbLayoutData
+#include "qkeymapper_x11_p.cpp"
+
+QLocale q_getKeyboardLocale(const QByteArray &layoutName, const QByteArray &variantName)
+{
+ int i = 0;
+ while (xkbLayoutData[i].layout != 0) {
+ if (layoutName == xkbLayoutData[i].layout && variantName == xkbLayoutData[i].variant)
+ return QLocale(xkbLayoutData[i].language, xkbLayoutData[i].country);
+ ++i;
+ }
+ return QLocale::c();
+}
+#endif // QT_NO_XKB
+
+// from qapplication_x11.cpp
+extern uchar qt_alt_mask;
+extern uchar qt_meta_mask;
+extern uchar qt_super_mask;
+extern uchar qt_hyper_mask;
+extern uchar qt_mode_switch_mask;
+uchar qt_num_lock_mask = 0;
+extern bool qt_sendSpontaneousEvent(QObject*, QEvent*);
+
+// ### we should really resolve conflicts with other masks by
+// ### decomposing the Qt::KeyboardModifers in possibleKeys()
+#define SETMASK(sym, mask) \
+ do { \
+ if (qt_alt_mask == 0 \
+ && qt_meta_mask != mask \
+ && qt_super_mask != mask \
+ && qt_hyper_mask != mask \
+ && (sym == XK_Alt_L || sym == XK_Alt_R)) { \
+ qt_alt_mask = mask; \
+ } \
+ if (qt_meta_mask == 0 \
+ && qt_alt_mask != mask \
+ && qt_super_mask != mask \
+ && qt_hyper_mask != mask \
+ && (sym == XK_Meta_L || sym == XK_Meta_R)) { \
+ qt_meta_mask = mask; \
+ } \
+ if (qt_super_mask == 0 \
+ && qt_alt_mask != mask \
+ && qt_meta_mask != mask \
+ && qt_hyper_mask != mask \
+ && (sym == XK_Super_L || sym == XK_Super_R)) { \
+ qt_super_mask = mask; \
+ } \
+ if (qt_hyper_mask == 0 \
+ && qt_alt_mask != mask \
+ && qt_meta_mask != mask \
+ && qt_super_mask != mask \
+ && (sym == XK_Hyper_L || sym == XK_Hyper_R)) { \
+ qt_hyper_mask = mask; \
+ } \
+ if (qt_mode_switch_mask == 0 \
+ && qt_alt_mask != mask \
+ && qt_meta_mask != mask \
+ && qt_super_mask != mask \
+ && qt_hyper_mask != mask \
+ && sym == XK_Mode_switch) { \
+ qt_mode_switch_mask = mask; \
+ } \
+ if (qt_num_lock_mask == 0 \
+ && sym == XK_Num_Lock) { \
+ qt_num_lock_mask = mask; \
+ } \
+ } while(false)
+
+// qt_XTranslateKey() is based on _XTranslateKey() taken from:
+
+/* $Xorg: KeyBind.c,v 1.4 2001/02/09 02:03:34 xorgcvs Exp $ */
+
+/*
+
+Copyright 1985, 1987, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+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
+OPEN GROUP 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 Open Group 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 Open Group.
+
+*/
+static int
+qt_XTranslateKey(register QXCoreDesc *dpy,
+ KeyCode keycode,
+ register unsigned int modifiers,
+ unsigned int *modifiers_return,
+ KeySym *keysym_return)
+{
+ int per;
+ register KeySym *syms;
+ KeySym sym, lsym, usym;
+
+ if (! dpy->keysyms)
+ return 0;
+ *modifiers_return = ((ShiftMask|LockMask)
+ | dpy->mode_switch | dpy->num_lock);
+ if (((int)keycode < dpy->min_keycode) || ((int)keycode > dpy->max_keycode))
+ {
+ *keysym_return = NoSymbol;
+ return 1;
+ }
+ per = dpy->keysyms_per_keycode;
+ syms = &dpy->keysyms[(keycode - dpy->min_keycode) * per];
+ while ((per > 2) && (syms[per - 1] == NoSymbol))
+ per--;
+ if ((per > 2) && (modifiers & dpy->mode_switch)) {
+ syms += 2;
+ per -= 2;
+ }
+ if ((modifiers & dpy->num_lock) &&
+ (per > 1 && (IsKeypadKey(syms[1]) || IsPrivateKeypadKey(syms[1])))) {
+ if ((modifiers & ShiftMask) ||
+ ((modifiers & LockMask) && (dpy->lock_meaning == XK_Shift_Lock)))
+ *keysym_return = syms[0];
+ else
+ *keysym_return = syms[1];
+ } else if (!(modifiers & ShiftMask) &&
+ (!(modifiers & LockMask) || (dpy->lock_meaning == NoSymbol))) {
+ if ((per == 1) || (syms[1] == NoSymbol))
+ XConvertCase(syms[0], keysym_return, &usym);
+ else
+ *keysym_return = syms[0];
+ } else if (!(modifiers & LockMask) ||
+ (dpy->lock_meaning != XK_Caps_Lock)) {
+ if ((per == 1) || ((usym = syms[1]) == NoSymbol))
+ XConvertCase(syms[0], &lsym, &usym);
+ *keysym_return = usym;
+ } else {
+ if ((per == 1) || ((sym = syms[1]) == NoSymbol))
+ sym = syms[0];
+ XConvertCase(sym, &lsym, &usym);
+ if (!(modifiers & ShiftMask) && (sym != syms[0]) &&
+ ((sym != usym) || (lsym == usym)))
+ XConvertCase(syms[0], &lsym, &usym);
+ *keysym_return = usym;
+ }
+ if (*keysym_return == XK_VoidSymbol)
+ *keysym_return = NoSymbol;
+ return 1;
+}
+
+
+
+
+QKeyMapperPrivate::QKeyMapperPrivate()
+ : keyboardInputDirection(Qt::LeftToRight), xkb_currentGroup(0)
+{
+ memset(&coreDesc, 0, sizeof(coreDesc));
+
+#ifndef QT_NO_XKB
+ if (X11->use_xkb) {
+ // get the current group
+ XkbStateRec xkbState;
+ if (XkbGetState(X11->display, XkbUseCoreKbd, &xkbState) == Success)
+ xkb_currentGroup = xkbState.group;
+ }
+#endif
+}
+
+QKeyMapperPrivate::~QKeyMapperPrivate()
+{
+ if (coreDesc.keysyms)
+ XFree(coreDesc.keysyms);
+}
+
+QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *event)
+{
+#ifndef QT_NO_XKB
+ if (X11->use_xkb)
+ return possibleKeysXKB(event);
+#endif
+ return possibleKeysCore(event);
+}
+
+enum { MaxBits = sizeof(uint) * 8 };
+static QString translateKeySym(KeySym keysym, uint xmodifiers,
+ int &code, Qt::KeyboardModifiers &modifiers,
+ QByteArray &chars, int &count);
+
+QList<int> QKeyMapperPrivate::possibleKeysXKB(QKeyEvent *event)
+{
+#ifndef QT_NO_XKB
+ const int xkeycode = event->nativeScanCode();
+ const uint xmodifiers = event->nativeModifiers();
+
+ // first, translate key only using lock modifiers (there are no Qt equivalents for these, so we must
+ // always use them when determining the baseKeySym)
+ KeySym baseKeySym;
+ uint consumedModifiers;
+ if (!XkbLookupKeySym(X11->display, xkeycode, (xmodifiers & (LockMask | qt_num_lock_mask)),
+ &consumedModifiers, &baseKeySym))
+ return QList<int>();
+
+ QList<int> result;
+
+ // translate sym -> code
+ Qt::KeyboardModifiers baseModifiers = 0;
+ int baseCode = -1;
+ QByteArray chars;
+ int count = 0;
+ QString text = translateKeySym(baseKeySym, xmodifiers, baseCode, baseModifiers, chars, count);
+ if (baseCode == -1) {
+ if (text.isEmpty())
+ return QList<int>();
+ baseCode = text.at(0).unicode();
+ }
+
+ if (baseCode && baseCode < 0xfffe)
+ baseCode = QChar(baseCode).toUpper().unicode();
+ result += (baseCode | baseModifiers);
+
+ int pos1Bits[MaxBits];
+ int num1Bits = 0;
+
+ for (int i = 0; i < MaxBits; ++i) {
+ if (consumedModifiers & (1 << i))
+ pos1Bits[num1Bits++] = i;
+ }
+
+ const int numPerms = (1 << num1Bits);
+
+ // translate the key again using each permutation of consumedModifiers
+ for (int i = 1; i < numPerms; ++i) {
+ uint val = 0;
+ for (int j = 0; j < num1Bits; ++j) {
+ if (i & (1 << j))
+ val |= (1 << pos1Bits[j]);
+ }
+
+ if ((xmodifiers & val) != val)
+ continue;
+
+ KeySym sym;
+ uint mods;
+ if (!XkbLookupKeySym(X11->display, xkeycode, val, &mods, &sym))
+ continue;
+
+ // translate sym -> code
+ Qt::KeyboardModifiers modifiers = 0;
+ int code = -1;
+ chars.clear();
+ count = 0;
+ // mask out the modifiers needed to translate keycode
+ text = translateKeySym(sym, xmodifiers & ~val, code, modifiers, chars, count);
+ if (code == -1) {
+ if (text.isEmpty())
+ continue;
+ code = text.at(0).unicode();
+ }
+
+ if (code && code < 0xfffe)
+ code = QChar(code).toUpper().unicode();
+
+ if (code == Qt::Key_Tab && (baseModifiers & Qt::ShiftModifier)) {
+ // map shift+tab to shift+backtab
+ code = Qt::Key_Backtab;
+ text = QString();
+ }
+
+ if (code == baseCode)
+ continue;
+
+ result += (code | modifiers);
+ }
+
+#if 0
+ qDebug() << "possibleKeysXKB()" << hex << result;
+#endif
+ return result;
+#else
+ Q_UNUSED(event);
+ return QList<int>();
+#endif // QT_NO_XKB
+}
+
+QList<int> QKeyMapperPrivate::possibleKeysCore(QKeyEvent *event)
+{
+ const int xkeycode = event->nativeScanCode();
+ const uint xmodifiers = event->nativeModifiers();
+
+ // first, translate key only using lock modifiers (there are no Qt equivalents for these, so we must
+ // always use them when determining the baseKeySym)
+ KeySym baseKeySym;
+ uint consumedModifiers;
+ if (!qt_XTranslateKey(&coreDesc, xkeycode, (xmodifiers & (LockMask | qt_num_lock_mask)),
+ &consumedModifiers, &baseKeySym))
+ return QList<int>();
+
+ QList<int> result;
+
+ // translate sym -> code
+ Qt::KeyboardModifiers baseModifiers = 0;
+ int baseCode = -1;
+ QByteArray chars;
+ int count = 0;
+ QString text = translateKeySym(baseKeySym, xmodifiers, baseCode, baseModifiers, chars, count);
+ if (baseCode == -1) {
+ if (text.isEmpty())
+ return QList<int>();
+ baseCode = text.at(0).unicode();
+ }
+
+ if (baseCode && baseCode < 0xfffe)
+ baseCode = QChar(baseCode).toUpper().unicode();
+ result += (baseCode | baseModifiers);
+
+ int pos1Bits[MaxBits];
+ int num1Bits = 0;
+
+ for (int i = 0; i < MaxBits; ++i) {
+ if (consumedModifiers & (1 << i))
+ pos1Bits[num1Bits++] = i;
+ }
+
+ const int numPerms = (1 << num1Bits);
+
+ // translate the key again using each permutation of consumedModifiers
+ for (int i = 1; i < numPerms; ++i) {
+ uint val = 0;
+ for (int j = 0; j < num1Bits; ++j) {
+ if (i & (1 << j))
+ val |= (1 << pos1Bits[j]);
+ }
+
+ if ((xmodifiers & val) != val)
+ continue;
+
+ KeySym sym;
+ uint mods;
+ if (!qt_XTranslateKey(&coreDesc, xkeycode, val, &mods, &sym))
+ continue;
+
+ // translate sym -> code
+ Qt::KeyboardModifiers modifiers = 0;
+ int code = -1;
+ chars.clear();
+ count = 0;
+ // mask out the modifiers needed to translate keycode
+ text = translateKeySym(sym, xmodifiers & ~val, code, modifiers, chars, count);
+ if (code == -1) {
+ if (text.isEmpty())
+ continue;
+ code = text.at(0).unicode();
+ }
+
+ if (code && code < 0xfffe)
+ code = QChar(code).toUpper().unicode();
+
+ if (code == Qt::Key_Tab && (baseModifiers & Qt::ShiftModifier)) {
+ // map shift+tab to shift+backtab
+ code = Qt::Key_Backtab;
+ text = QString();
+ }
+
+ if (code == baseCode)
+ continue;
+
+ result += (code | modifiers);
+ }
+
+#if 0
+ qDebug() << "possibleKeysCore()" << hex << result;
+#endif
+ return result;
+}
+
+// for parsing the _XKB_RULES_NAMES property
+enum {
+ RulesFileIndex = 0,
+ ModelIndex = 1,
+ LayoutIndex = 2,
+ VariantIndex = 3,
+ OptionsIndex = 4
+};
+
+void QKeyMapperPrivate::clearMappings()
+{
+#ifndef QT_NO_XKB
+ if (X11->use_xkb) {
+ // try to determine the layout name and input direction by reading the _XKB_RULES_NAMES property off
+ // the root window
+ QByteArray layoutName;
+ QByteArray variantName;
+
+ Atom type = XNone;
+ int format = 0;
+ ulong nitems = 0;
+ ulong bytesAfter = 0;
+ uchar *data = 0;
+ if (XGetWindowProperty(X11->display, RootWindow(X11->display, 0), ATOM(_XKB_RULES_NAMES), 0, 1024,
+ false, XA_STRING, &type, &format, &nitems, &bytesAfter, &data) == Success
+ && type == XA_STRING && format == 8 && nitems > 2) {
+ /*
+ index 0 == rules file name
+ index 1 == model name
+ index 2 == layout name
+ index 3 == variant name
+ index 4 == options
+ */
+ char *names[5] = { 0, 0, 0, 0, 0 };
+ char *p = reinterpret_cast<char *>(data), *end = p + nitems;
+ int i = 0;
+ do {
+ names[i++] = p;
+ p += qstrlen(p) + 1;
+ } while (p < end);
+
+ // the layout names and variants are saved in the _XKB_RULES_NAMES property as a comma separated list
+ QList<QByteArray> layoutNames = QByteArray::fromRawData(names[2], qstrlen(names[2])).split(',');
+ if (uint(xkb_currentGroup) < uint(layoutNames.count()))
+ layoutName = layoutNames.at(xkb_currentGroup);
+ QList<QByteArray> variantNames = QByteArray::fromRawData(names[3], qstrlen(names[3])).split(',');
+ if (uint(xkb_currentGroup) < uint(variantNames.count()))
+ variantName = variantNames.at(xkb_currentGroup);
+ }
+
+ // ### ???
+ // if (keyboardLayoutName.isEmpty())
+ // qWarning("Qt: unable to determine keyboard layout, please talk to qt-bugs@trolltech.com"); ?
+
+ keyboardInputLocale = q_getKeyboardLocale(layoutName, variantName);
+ keyboardInputDirection = keyboardInputLocale.textDirection();
+
+#if 0
+ qDebug() << "keyboard input locale ="
+ << keyboardInputLocale.name()
+ << "direction ="
+ << keyboardInputDirection;
+#endif
+ if (data)
+ XFree(data);
+ } else
+#endif // QT_NO_XKB
+ {
+ if (coreDesc.keysyms)
+ XFree(coreDesc.keysyms);
+
+ coreDesc.min_keycode = 8;
+ coreDesc.max_keycode = 255;
+ XDisplayKeycodes(X11->display, &coreDesc.min_keycode, &coreDesc.max_keycode);
+
+ coreDesc.keysyms_per_keycode = 0;
+ coreDesc.keysyms = XGetKeyboardMapping(X11->display,
+ coreDesc.min_keycode,
+ coreDesc.max_keycode - coreDesc.min_keycode + 1,
+ &coreDesc.keysyms_per_keycode);
+
+#if 0
+ qDebug() << "min_keycode =" << coreDesc.min_keycode;
+ qDebug() << "max_keycode =" << coreDesc.max_keycode;
+ qDebug() << "keysyms_per_keycode =" << coreDesc.keysyms_per_keycode;
+ qDebug() << "keysyms =" << coreDesc.keysyms;
+#endif
+
+ // ### cannot get/guess the locale with the core protocol
+ keyboardInputLocale = QLocale::c();
+ // ### could examine group 0 for RTL keys
+ keyboardInputDirection = Qt::LeftToRight;
+ }
+
+ qt_alt_mask = 0;
+ qt_meta_mask = 0;
+ qt_super_mask = 0;
+ qt_hyper_mask = 0;
+ qt_mode_switch_mask = 0;
+
+ // look at the modifier mapping, and get the correct masks for alt, meta, super, hyper, and mode_switch
+#ifndef QT_NO_XKB
+ if (X11->use_xkb) {
+ XkbDescPtr xkbDesc = XkbGetMap(X11->display, XkbAllClientInfoMask, XkbUseCoreKbd);
+ for (int i = xkbDesc->min_key_code; i < xkbDesc->max_key_code; ++i) {
+ const uint mask = xkbDesc->map->modmap ? xkbDesc->map->modmap[i] : 0;
+ if (mask == 0) {
+ // key is not bound to a modifier
+ continue;
+ }
+
+ for (int j = 0; j < XkbKeyGroupsWidth(xkbDesc, i); ++j) {
+ KeySym keySym = XkbKeySym(xkbDesc, i, j);
+ if (keySym == NoSymbol)
+ continue;
+ SETMASK(keySym, mask);
+ }
+ }
+ XkbFreeKeyboard(xkbDesc, XkbAllComponentsMask, true);
+ } else
+#endif // QT_NO_XKB
+ {
+ coreDesc.lock_meaning = NoSymbol;
+
+ XModifierKeymap *map = XGetModifierMapping(X11->display);
+
+ if (map) {
+ int i, maskIndex = 0, mapIndex = 0;
+ for (maskIndex = 0; maskIndex < 8; maskIndex++) {
+ for (i = 0; i < map->max_keypermod; i++) {
+ if (map->modifiermap[mapIndex]) {
+ KeySym sym;
+ int x = 0;
+ do {
+ sym = XKeycodeToKeysym(X11->display, map->modifiermap[mapIndex], x++);
+ } while (sym == NoSymbol && x < coreDesc.keysyms_per_keycode);
+ const uchar mask = 1 << maskIndex;
+ SETMASK(sym, mask);
+ }
+ mapIndex++;
+ }
+ }
+
+ // determine the meaning of the Lock modifier
+ for (i = 0; i < map->max_keypermod; ++i) {
+ for (int x = 0; x < coreDesc.keysyms_per_keycode; ++x) {
+ KeySym sym = XKeycodeToKeysym(X11->display, map->modifiermap[LockMapIndex], x);
+ if (sym == XK_Caps_Lock || sym == XK_ISO_Lock) {
+ coreDesc.lock_meaning = XK_Caps_Lock;
+ break;
+ } else if (sym == XK_Shift_Lock) {
+ coreDesc.lock_meaning = XK_Shift_Lock;
+ }
+ }
+ }
+
+ XFreeModifiermap(map);
+ }
+
+ // for qt_XTranslateKey()
+ coreDesc.num_lock = qt_num_lock_mask;
+ coreDesc.mode_switch = qt_mode_switch_mask;
+
+#if 0
+ qDebug() << "lock_meaning =" << coreDesc.lock_meaning;
+ qDebug() << "num_lock =" << coreDesc.num_lock;
+ qDebug() << "mode_switch =" << coreDesc.mode_switch;
+#endif
+ }
+
+ // set default modifier masks if needed
+ if( qt_alt_mask == 0 )
+ qt_alt_mask = Mod1Mask;
+ if( qt_meta_mask == 0 )
+ qt_meta_mask = Mod4Mask;
+
+ // if we don't have a meta key (or it's hidden behind alt), use super or hyper to generate
+ // Qt::Key_Meta and Qt::MetaModifier, since most newer XFree86/Xorg installations map the Windows
+ // key to Super
+ if (qt_meta_mask == 0 || qt_meta_mask == qt_alt_mask) {
+ // no meta keys... s,meta,super,
+ qt_meta_mask = qt_super_mask;
+ if (qt_meta_mask == 0 || qt_meta_mask == qt_alt_mask) {
+ // no super keys either? guess we'll use hyper then
+ qt_meta_mask = qt_hyper_mask;
+ }
+ }
+
+#if 0
+ qDebug() << "qt_alt_mask =" << hex << qt_alt_mask;
+ qDebug() << "qt_meta_mask =" << hex << qt_meta_mask;
+ qDebug() << "qt_super_mask =" << hex << qt_super_mask;
+ qDebug() << "qt_hyper_mask =" << hex << qt_hyper_mask;
+ qDebug() << "qt_mode_switch_mask =" << hex << qt_mode_switch_mask;
+ qDebug() << "qt_num_lock_mask =" << hex << qt_num_lock_mask;
+#endif
+}
+
+extern bool qt_sm_blockUserInput;
+
+//
+// Keyboard event translation
+//
+
+#ifndef XK_ISO_Left_Tab
+#define XK_ISO_Left_Tab 0xFE20
+#endif
+
+#ifndef XK_dead_hook
+#define XK_dead_hook 0xFE61
+#endif
+
+#ifndef XK_dead_horn
+#define XK_dead_horn 0xFE62
+#endif
+
+#ifndef XK_Codeinput
+#define XK_Codeinput 0xFF37
+#endif
+
+#ifndef XK_Kanji_Bangou
+#define XK_Kanji_Bangou 0xFF37 /* same as codeinput */
+#endif
+
+// Fix old X libraries
+#ifndef XK_KP_Home
+#define XK_KP_Home 0xFF95
+#endif
+#ifndef XK_KP_Left
+#define XK_KP_Left 0xFF96
+#endif
+#ifndef XK_KP_Up
+#define XK_KP_Up 0xFF97
+#endif
+#ifndef XK_KP_Right
+#define XK_KP_Right 0xFF98
+#endif
+#ifndef XK_KP_Down
+#define XK_KP_Down 0xFF99
+#endif
+#ifndef XK_KP_Prior
+#define XK_KP_Prior 0xFF9A
+#endif
+#ifndef XK_KP_Next
+#define XK_KP_Next 0xFF9B
+#endif
+#ifndef XK_KP_End
+#define XK_KP_End 0xFF9C
+#endif
+#ifndef XK_KP_Insert
+#define XK_KP_Insert 0xFF9E
+#endif
+#ifndef XK_KP_Delete
+#define XK_KP_Delete 0xFF9F
+#endif
+
+// the next lines are taken on 10/2009 from X.org (X11/XF86keysym.h), defining some special
+// multimedia keys. They are included here as not every system has them.
+#define XF86XK_MonBrightnessUp 0x1008FF02
+#define XF86XK_MonBrightnessDown 0x1008FF03
+#define XF86XK_KbdLightOnOff 0x1008FF04
+#define XF86XK_KbdBrightnessUp 0x1008FF05
+#define XF86XK_KbdBrightnessDown 0x1008FF06
+#define XF86XK_Standby 0x1008FF10
+#define XF86XK_AudioLowerVolume 0x1008FF11
+#define XF86XK_AudioMute 0x1008FF12
+#define XF86XK_AudioRaiseVolume 0x1008FF13
+#define XF86XK_AudioPlay 0x1008FF14
+#define XF86XK_AudioStop 0x1008FF15
+#define XF86XK_AudioPrev 0x1008FF16
+#define XF86XK_AudioNext 0x1008FF17
+#define XF86XK_HomePage 0x1008FF18
+#define XF86XK_Mail 0x1008FF19
+#define XF86XK_Start 0x1008FF1A
+#define XF86XK_Search 0x1008FF1B
+#define XF86XK_AudioRecord 0x1008FF1C
+#define XF86XK_Calculator 0x1008FF1D
+#define XF86XK_Memo 0x1008FF1E
+#define XF86XK_ToDoList 0x1008FF1F
+#define XF86XK_Calendar 0x1008FF20
+#define XF86XK_PowerDown 0x1008FF21
+#define XF86XK_ContrastAdjust 0x1008FF22
+#define XF86XK_Back 0x1008FF26
+#define XF86XK_Forward 0x1008FF27
+#define XF86XK_Stop 0x1008FF28
+#define XF86XK_Refresh 0x1008FF29
+#define XF86XK_PowerOff 0x1008FF2A
+#define XF86XK_WakeUp 0x1008FF2B
+#define XF86XK_Eject 0x1008FF2C
+#define XF86XK_ScreenSaver 0x1008FF2D
+#define XF86XK_WWW 0x1008FF2E
+#define XF86XK_Sleep 0x1008FF2F
+#define XF86XK_Favorites 0x1008FF30
+#define XF86XK_AudioPause 0x1008FF31
+#define XF86XK_AudioMedia 0x1008FF32
+#define XF86XK_MyComputer 0x1008FF33
+#define XF86XK_LightBulb 0x1008FF35
+#define XF86XK_Shop 0x1008FF36
+#define XF86XK_History 0x1008FF37
+#define XF86XK_OpenURL 0x1008FF38
+#define XF86XK_AddFavorite 0x1008FF39
+#define XF86XK_HotLinks 0x1008FF3A
+#define XF86XK_BrightnessAdjust 0x1008FF3B
+#define XF86XK_Finance 0x1008FF3C
+#define XF86XK_Community 0x1008FF3D
+#define XF86XK_AudioRewind 0x1008FF3E
+#define XF86XK_BackForward 0x1008FF3F
+#define XF86XK_Launch0 0x1008FF40
+#define XF86XK_Launch1 0x1008FF41
+#define XF86XK_Launch2 0x1008FF42
+#define XF86XK_Launch3 0x1008FF43
+#define XF86XK_Launch4 0x1008FF44
+#define XF86XK_Launch5 0x1008FF45
+#define XF86XK_Launch6 0x1008FF46
+#define XF86XK_Launch7 0x1008FF47
+#define XF86XK_Launch8 0x1008FF48
+#define XF86XK_Launch9 0x1008FF49
+#define XF86XK_LaunchA 0x1008FF4A
+#define XF86XK_LaunchB 0x1008FF4B
+#define XF86XK_LaunchC 0x1008FF4C
+#define XF86XK_LaunchD 0x1008FF4D
+#define XF86XK_LaunchE 0x1008FF4E
+#define XF86XK_LaunchF 0x1008FF4F
+#define XF86XK_ApplicationLeft 0x1008FF50
+#define XF86XK_ApplicationRight 0x1008FF51
+#define XF86XK_Book 0x1008FF52
+#define XF86XK_CD 0x1008FF53
+#define XF86XK_Calculater 0x1008FF54
+#define XF86XK_Clear 0x1008FF55
+#define XF86XK_ClearGrab 0x1008FE21
+#define XF86XK_Close 0x1008FF56
+#define XF86XK_Copy 0x1008FF57
+#define XF86XK_Cut 0x1008FF58
+#define XF86XK_Display 0x1008FF59
+#define XF86XK_DOS 0x1008FF5A
+#define XF86XK_Documents 0x1008FF5B
+#define XF86XK_Excel 0x1008FF5C
+#define XF86XK_Explorer 0x1008FF5D
+#define XF86XK_Game 0x1008FF5E
+#define XF86XK_Go 0x1008FF5F
+#define XF86XK_iTouch 0x1008FF60
+#define XF86XK_LogOff 0x1008FF61
+#define XF86XK_Market 0x1008FF62
+#define XF86XK_Meeting 0x1008FF63
+#define XF86XK_MenuKB 0x1008FF65
+#define XF86XK_MenuPB 0x1008FF66
+#define XF86XK_MySites 0x1008FF67
+#define XF86XK_News 0x1008FF69
+#define XF86XK_OfficeHome 0x1008FF6A
+#define XF86XK_Option 0x1008FF6C
+#define XF86XK_Paste 0x1008FF6D
+#define XF86XK_Phone 0x1008FF6E
+#define XF86XK_Reply 0x1008FF72
+#define XF86XK_Reload 0x1008FF73
+#define XF86XK_RotateWindows 0x1008FF74
+#define XF86XK_RotationPB 0x1008FF75
+#define XF86XK_RotationKB 0x1008FF76
+#define XF86XK_Save 0x1008FF77
+#define XF86XK_Send 0x1008FF7B
+#define XF86XK_Spell 0x1008FF7C
+#define XF86XK_SplitScreen 0x1008FF7D
+#define XF86XK_Support 0x1008FF7E
+#define XF86XK_TaskPane 0x1008FF7F
+#define XF86XK_Terminal 0x1008FF80
+#define XF86XK_Tools 0x1008FF81
+#define XF86XK_Travel 0x1008FF82
+#define XF86XK_Video 0x1008FF87
+#define XF86XK_Word 0x1008FF89
+#define XF86XK_Xfer 0x1008FF8A
+#define XF86XK_ZoomIn 0x1008FF8B
+#define XF86XK_ZoomOut 0x1008FF8C
+#define XF86XK_Away 0x1008FF8D
+#define XF86XK_Messenger 0x1008FF8E
+#define XF86XK_WebCam 0x1008FF8F
+#define XF86XK_MailForward 0x1008FF90
+#define XF86XK_Pictures 0x1008FF91
+#define XF86XK_Music 0x1008FF92
+#define XF86XK_Battery 0x1008FF93
+#define XF86XK_Bluetooth 0x1008FF94
+#define XF86XK_WLAN 0x1008FF95
+#define XF86XK_UWB 0x1008FF96
+#define XF86XK_AudioForward 0x1008FF97
+#define XF86XK_AudioRepeat 0x1008FF98
+#define XF86XK_AudioRandomPlay 0x1008FF99
+#define XF86XK_Subtitle 0x1008FF9A
+#define XF86XK_AudioCycleTrack 0x1008FF9B
+#define XF86XK_Time 0x1008FF9F
+#define XF86XK_Select 0x1008FFA0
+#define XF86XK_View 0x1008FFA1
+#define XF86XK_TopMenu 0x1008FFA2
+#define XF86XK_Suspend 0x1008FFA7
+#define XF86XK_Hibernate 0x1008FFA8
+
+
+// end of XF86keysyms.h
+
+// Special keys used by Qtopia, mapped into the X11 private keypad range.
+#define QTOPIAXK_Select 0x11000601
+#define QTOPIAXK_Yes 0x11000602
+#define QTOPIAXK_No 0x11000603
+#define QTOPIAXK_Cancel 0x11000604
+#define QTOPIAXK_Printer 0x11000605
+#define QTOPIAXK_Execute 0x11000606
+#define QTOPIAXK_Sleep 0x11000607
+#define QTOPIAXK_Play 0x11000608
+#define QTOPIAXK_Zoom 0x11000609
+#define QTOPIAXK_Context1 0x1100060A
+#define QTOPIAXK_Context2 0x1100060B
+#define QTOPIAXK_Context3 0x1100060C
+#define QTOPIAXK_Context4 0x1100060D
+#define QTOPIAXK_Call 0x1100060E
+#define QTOPIAXK_Hangup 0x1100060F
+#define QTOPIAXK_Flip 0x11000610
+
+// keyboard mapping table
+static const unsigned int KeyTbl[] = {
+
+ // misc keys
+
+ XK_Escape, Qt::Key_Escape,
+ XK_Tab, Qt::Key_Tab,
+ XK_ISO_Left_Tab, Qt::Key_Backtab,
+ XK_BackSpace, Qt::Key_Backspace,
+ XK_Return, Qt::Key_Return,
+ XK_Insert, Qt::Key_Insert,
+ XK_Delete, Qt::Key_Delete,
+ XK_Clear, Qt::Key_Delete,
+ XK_Pause, Qt::Key_Pause,
+ XK_Print, Qt::Key_Print,
+ 0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq
+ 0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq
+
+ // cursor movement
+
+ XK_Home, Qt::Key_Home,
+ XK_End, Qt::Key_End,
+ XK_Left, Qt::Key_Left,
+ XK_Up, Qt::Key_Up,
+ XK_Right, Qt::Key_Right,
+ XK_Down, Qt::Key_Down,
+ XK_Prior, Qt::Key_PageUp,
+ XK_Next, Qt::Key_PageDown,
+
+ // modifiers
+
+ XK_Shift_L, Qt::Key_Shift,
+ XK_Shift_R, Qt::Key_Shift,
+ XK_Shift_Lock, Qt::Key_Shift,
+ XK_Control_L, Qt::Key_Control,
+ XK_Control_R, Qt::Key_Control,
+ XK_Meta_L, Qt::Key_Meta,
+ XK_Meta_R, Qt::Key_Meta,
+ XK_Alt_L, Qt::Key_Alt,
+ XK_Alt_R, Qt::Key_Alt,
+ XK_Caps_Lock, Qt::Key_CapsLock,
+ XK_Num_Lock, Qt::Key_NumLock,
+ XK_Scroll_Lock, Qt::Key_ScrollLock,
+ XK_Super_L, Qt::Key_Super_L,
+ XK_Super_R, Qt::Key_Super_R,
+ XK_Menu, Qt::Key_Menu,
+ XK_Hyper_L, Qt::Key_Hyper_L,
+ XK_Hyper_R, Qt::Key_Hyper_R,
+ XK_Help, Qt::Key_Help,
+ 0x1000FF74, Qt::Key_Backtab, // hardcoded HP backtab
+ 0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11)
+ 0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12)
+
+ // numeric and function keypad keys
+
+ XK_KP_Space, Qt::Key_Space,
+ XK_KP_Tab, Qt::Key_Tab,
+ XK_KP_Enter, Qt::Key_Enter,
+ //XK_KP_F1, Qt::Key_F1,
+ //XK_KP_F2, Qt::Key_F2,
+ //XK_KP_F3, Qt::Key_F3,
+ //XK_KP_F4, Qt::Key_F4,
+ XK_KP_Home, Qt::Key_Home,
+ XK_KP_Left, Qt::Key_Left,
+ XK_KP_Up, Qt::Key_Up,
+ XK_KP_Right, Qt::Key_Right,
+ XK_KP_Down, Qt::Key_Down,
+ XK_KP_Prior, Qt::Key_PageUp,
+ XK_KP_Next, Qt::Key_PageDown,
+ XK_KP_End, Qt::Key_End,
+ XK_KP_Begin, Qt::Key_Clear,
+ XK_KP_Insert, Qt::Key_Insert,
+ XK_KP_Delete, Qt::Key_Delete,
+ XK_KP_Equal, Qt::Key_Equal,
+ XK_KP_Multiply, Qt::Key_Asterisk,
+ XK_KP_Add, Qt::Key_Plus,
+ XK_KP_Separator, Qt::Key_Comma,
+ XK_KP_Subtract, Qt::Key_Minus,
+ XK_KP_Decimal, Qt::Key_Period,
+ XK_KP_Divide, Qt::Key_Slash,
+
+ // International input method support keys
+
+ // International & multi-key character composition
+ XK_ISO_Level3_Shift, Qt::Key_AltGr,
+ XK_Multi_key, Qt::Key_Multi_key,
+ XK_Codeinput, Qt::Key_Codeinput,
+ XK_SingleCandidate, Qt::Key_SingleCandidate,
+ XK_MultipleCandidate, Qt::Key_MultipleCandidate,
+ XK_PreviousCandidate, Qt::Key_PreviousCandidate,
+
+ // Misc Functions
+ XK_Mode_switch, Qt::Key_Mode_switch,
+ XK_script_switch, Qt::Key_Mode_switch,
+
+ // Japanese keyboard support
+ XK_Kanji, Qt::Key_Kanji,
+ XK_Muhenkan, Qt::Key_Muhenkan,
+ //XK_Henkan_Mode, Qt::Key_Henkan_Mode,
+ XK_Henkan_Mode, Qt::Key_Henkan,
+ XK_Henkan, Qt::Key_Henkan,
+ XK_Romaji, Qt::Key_Romaji,
+ XK_Hiragana, Qt::Key_Hiragana,
+ XK_Katakana, Qt::Key_Katakana,
+ XK_Hiragana_Katakana, Qt::Key_Hiragana_Katakana,
+ XK_Zenkaku, Qt::Key_Zenkaku,
+ XK_Hankaku, Qt::Key_Hankaku,
+ XK_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku,
+ XK_Touroku, Qt::Key_Touroku,
+ XK_Massyo, Qt::Key_Massyo,
+ XK_Kana_Lock, Qt::Key_Kana_Lock,
+ XK_Kana_Shift, Qt::Key_Kana_Shift,
+ XK_Eisu_Shift, Qt::Key_Eisu_Shift,
+ XK_Eisu_toggle, Qt::Key_Eisu_toggle,
+ //XK_Kanji_Bangou, Qt::Key_Kanji_Bangou,
+ //XK_Zen_Koho, Qt::Key_Zen_Koho,
+ //XK_Mae_Koho, Qt::Key_Mae_Koho,
+ XK_Kanji_Bangou, Qt::Key_Codeinput,
+ XK_Zen_Koho, Qt::Key_MultipleCandidate,
+ XK_Mae_Koho, Qt::Key_PreviousCandidate,
+
+#ifdef XK_KOREAN
+ // Korean keyboard support
+ XK_Hangul, Qt::Key_Hangul,
+ XK_Hangul_Start, Qt::Key_Hangul_Start,
+ XK_Hangul_End, Qt::Key_Hangul_End,
+ XK_Hangul_Hanja, Qt::Key_Hangul_Hanja,
+ XK_Hangul_Jamo, Qt::Key_Hangul_Jamo,
+ XK_Hangul_Romaja, Qt::Key_Hangul_Romaja,
+ //XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput,
+ XK_Hangul_Codeinput, Qt::Key_Codeinput,
+ XK_Hangul_Jeonja, Qt::Key_Hangul_Jeonja,
+ XK_Hangul_Banja, Qt::Key_Hangul_Banja,
+ XK_Hangul_PreHanja, Qt::Key_Hangul_PreHanja,
+ XK_Hangul_PostHanja, Qt::Key_Hangul_PostHanja,
+ //XK_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate,
+ //XK_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate,
+ //XK_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate,
+ XK_Hangul_SingleCandidate, Qt::Key_SingleCandidate,
+ XK_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate,
+ XK_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate,
+ XK_Hangul_Special, Qt::Key_Hangul_Special,
+ //XK_Hangul_switch, Qt::Key_Hangul_switch,
+ XK_Hangul_switch, Qt::Key_Mode_switch,
+#endif // XK_KOREAN
+
+ // dead keys
+ XK_dead_grave, Qt::Key_Dead_Grave,
+ XK_dead_acute, Qt::Key_Dead_Acute,
+ XK_dead_circumflex, Qt::Key_Dead_Circumflex,
+ XK_dead_tilde, Qt::Key_Dead_Tilde,
+ XK_dead_macron, Qt::Key_Dead_Macron,
+ XK_dead_breve, Qt::Key_Dead_Breve,
+ XK_dead_abovedot, Qt::Key_Dead_Abovedot,
+ XK_dead_diaeresis, Qt::Key_Dead_Diaeresis,
+ XK_dead_abovering, Qt::Key_Dead_Abovering,
+ XK_dead_doubleacute, Qt::Key_Dead_Doubleacute,
+ XK_dead_caron, Qt::Key_Dead_Caron,
+ XK_dead_cedilla, Qt::Key_Dead_Cedilla,
+ XK_dead_ogonek, Qt::Key_Dead_Ogonek,
+ XK_dead_iota, Qt::Key_Dead_Iota,
+ XK_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound,
+ XK_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound,
+ XK_dead_belowdot, Qt::Key_Dead_Belowdot,
+ XK_dead_hook, Qt::Key_Dead_Hook,
+ XK_dead_horn, Qt::Key_Dead_Horn,
+
+ // Special keys from X.org - This include multimedia keys,
+ // wireless/bluetooth/uwb keys, special launcher keys, etc.
+ XF86XK_Back, Qt::Key_Back,
+ XF86XK_Forward, Qt::Key_Forward,
+ XF86XK_Stop, Qt::Key_Stop,
+ XF86XK_Refresh, Qt::Key_Refresh,
+ XF86XK_Favorites, Qt::Key_Favorites,
+ XF86XK_AudioMedia, Qt::Key_LaunchMedia,
+ XF86XK_OpenURL, Qt::Key_OpenUrl,
+ XF86XK_HomePage, Qt::Key_HomePage,
+ XF86XK_Search, Qt::Key_Search,
+ XF86XK_AudioLowerVolume, Qt::Key_VolumeDown,
+ XF86XK_AudioMute, Qt::Key_VolumeMute,
+ XF86XK_AudioRaiseVolume, Qt::Key_VolumeUp,
+ XF86XK_AudioPlay, Qt::Key_MediaPlay,
+ XF86XK_AudioStop, Qt::Key_MediaStop,
+ XF86XK_AudioPrev, Qt::Key_MediaPrevious,
+ XF86XK_AudioNext, Qt::Key_MediaNext,
+ XF86XK_AudioRecord, Qt::Key_MediaRecord,
+ XF86XK_Mail, Qt::Key_LaunchMail,
+ XF86XK_MyComputer, Qt::Key_Launch0, // ### Qt 5: remap properly
+ XF86XK_Calculator, Qt::Key_Launch1,
+ XF86XK_Memo, Qt::Key_Memo,
+ XF86XK_ToDoList, Qt::Key_ToDoList,
+ XF86XK_Calendar, Qt::Key_Calendar,
+ XF86XK_PowerDown, Qt::Key_PowerDown,
+ XF86XK_ContrastAdjust, Qt::Key_ContrastAdjust,
+ XF86XK_Standby, Qt::Key_Standby,
+ XF86XK_MonBrightnessUp, Qt::Key_MonBrightnessUp,
+ XF86XK_MonBrightnessDown, Qt::Key_MonBrightnessDown,
+ XF86XK_KbdLightOnOff, Qt::Key_KeyboardLightOnOff,
+ XF86XK_KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp,
+ XF86XK_KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown,
+ XF86XK_PowerOff, Qt::Key_PowerOff,
+ XF86XK_WakeUp, Qt::Key_WakeUp,
+ XF86XK_Eject, Qt::Key_Eject,
+ XF86XK_ScreenSaver, Qt::Key_ScreenSaver,
+ XF86XK_WWW, Qt::Key_WWW,
+ XF86XK_Sleep, Qt::Key_Sleep,
+ XF86XK_LightBulb, Qt::Key_LightBulb,
+ XF86XK_Shop, Qt::Key_Shop,
+ XF86XK_History, Qt::Key_History,
+ XF86XK_AddFavorite, Qt::Key_AddFavorite,
+ XF86XK_HotLinks, Qt::Key_HotLinks,
+ XF86XK_BrightnessAdjust, Qt::Key_BrightnessAdjust,
+ XF86XK_Finance, Qt::Key_Finance,
+ XF86XK_Community, Qt::Key_Community,
+ XF86XK_AudioRewind, Qt::Key_AudioRewind,
+ XF86XK_BackForward, Qt::Key_BackForward,
+ XF86XK_ApplicationLeft, Qt::Key_ApplicationLeft,
+ XF86XK_ApplicationRight, Qt::Key_ApplicationRight,
+ XF86XK_Book, Qt::Key_Book,
+ XF86XK_CD, Qt::Key_CD,
+ XF86XK_Calculater, Qt::Key_Calculator,
+ XF86XK_Clear, Qt::Key_Clear,
+ XF86XK_ClearGrab, Qt::Key_ClearGrab,
+ XF86XK_Close, Qt::Key_Close,
+ XF86XK_Copy, Qt::Key_Copy,
+ XF86XK_Cut, Qt::Key_Cut,
+ XF86XK_Display, Qt::Key_Display,
+ XF86XK_DOS, Qt::Key_DOS,
+ XF86XK_Documents, Qt::Key_Documents,
+ XF86XK_Excel, Qt::Key_Excel,
+ XF86XK_Explorer, Qt::Key_Explorer,
+ XF86XK_Game, Qt::Key_Game,
+ XF86XK_Go, Qt::Key_Go,
+ XF86XK_iTouch, Qt::Key_iTouch,
+ XF86XK_LogOff, Qt::Key_LogOff,
+ XF86XK_Market, Qt::Key_Market,
+ XF86XK_Meeting, Qt::Key_Meeting,
+ XF86XK_MenuKB, Qt::Key_MenuKB,
+ XF86XK_MenuPB, Qt::Key_MenuPB,
+ XF86XK_MySites, Qt::Key_MySites,
+ XF86XK_News, Qt::Key_News,
+ XF86XK_OfficeHome, Qt::Key_OfficeHome,
+ XF86XK_Option, Qt::Key_Option,
+ XF86XK_Paste, Qt::Key_Paste,
+ XF86XK_Phone, Qt::Key_Phone,
+ XF86XK_Reply, Qt::Key_Reply,
+ XF86XK_Reload, Qt::Key_Reload,
+ XF86XK_RotateWindows, Qt::Key_RotateWindows,
+ XF86XK_RotationPB, Qt::Key_RotationPB,
+ XF86XK_RotationKB, Qt::Key_RotationKB,
+ XF86XK_Save, Qt::Key_Save,
+ XF86XK_Send, Qt::Key_Send,
+ XF86XK_Spell, Qt::Key_Spell,
+ XF86XK_SplitScreen, Qt::Key_SplitScreen,
+ XF86XK_Support, Qt::Key_Support,
+ XF86XK_TaskPane, Qt::Key_TaskPane,
+ XF86XK_Terminal, Qt::Key_Terminal,
+ XF86XK_Tools, Qt::Key_Tools,
+ XF86XK_Travel, Qt::Key_Travel,
+ XF86XK_Video, Qt::Key_Video,
+ XF86XK_Word, Qt::Key_Word,
+ XF86XK_Xfer, Qt::Key_Xfer,
+ XF86XK_ZoomIn, Qt::Key_ZoomIn,
+ XF86XK_ZoomOut, Qt::Key_ZoomOut,
+ XF86XK_Away, Qt::Key_Away,
+ XF86XK_Messenger, Qt::Key_Messenger,
+ XF86XK_WebCam, Qt::Key_WebCam,
+ XF86XK_MailForward, Qt::Key_MailForward,
+ XF86XK_Pictures, Qt::Key_Pictures,
+ XF86XK_Music, Qt::Key_Music,
+ XF86XK_Battery, Qt::Key_Battery,
+ XF86XK_Bluetooth, Qt::Key_Bluetooth,
+ XF86XK_WLAN, Qt::Key_WLAN,
+ XF86XK_UWB, Qt::Key_UWB,
+ XF86XK_AudioForward, Qt::Key_AudioForward,
+ XF86XK_AudioRepeat, Qt::Key_AudioRepeat,
+ XF86XK_AudioRandomPlay, Qt::Key_AudioRandomPlay,
+ XF86XK_Subtitle, Qt::Key_Subtitle,
+ XF86XK_AudioCycleTrack, Qt::Key_AudioCycleTrack,
+ XF86XK_Time, Qt::Key_Time,
+ XF86XK_Select, Qt::Key_Select,
+ XF86XK_View, Qt::Key_View,
+ XF86XK_TopMenu, Qt::Key_TopMenu,
+ XF86XK_Bluetooth, Qt::Key_Bluetooth,
+ XF86XK_Suspend, Qt::Key_Suspend,
+ XF86XK_Hibernate, Qt::Key_Hibernate,
+ XF86XK_Launch0, Qt::Key_Launch2, // ### Qt 5: remap properly
+ XF86XK_Launch1, Qt::Key_Launch3,
+ XF86XK_Launch2, Qt::Key_Launch4,
+ XF86XK_Launch3, Qt::Key_Launch5,
+ XF86XK_Launch4, Qt::Key_Launch6,
+ XF86XK_Launch5, Qt::Key_Launch7,
+ XF86XK_Launch6, Qt::Key_Launch8,
+ XF86XK_Launch7, Qt::Key_Launch9,
+ XF86XK_Launch8, Qt::Key_LaunchA,
+ XF86XK_Launch9, Qt::Key_LaunchB,
+ XF86XK_LaunchA, Qt::Key_LaunchC,
+ XF86XK_LaunchB, Qt::Key_LaunchD,
+ XF86XK_LaunchC, Qt::Key_LaunchE,
+ XF86XK_LaunchD, Qt::Key_LaunchF,
+ XF86XK_LaunchE, Qt::Key_LaunchG,
+ XF86XK_LaunchF, Qt::Key_LaunchH,
+
+ // Qtopia keys
+ QTOPIAXK_Select, Qt::Key_Select,
+ QTOPIAXK_Yes, Qt::Key_Yes,
+ QTOPIAXK_No, Qt::Key_No,
+ QTOPIAXK_Cancel, Qt::Key_Cancel,
+ QTOPIAXK_Printer, Qt::Key_Printer,
+ QTOPIAXK_Execute, Qt::Key_Execute,
+ QTOPIAXK_Sleep, Qt::Key_Sleep,
+ QTOPIAXK_Play, Qt::Key_Play,
+ QTOPIAXK_Zoom, Qt::Key_Zoom,
+ QTOPIAXK_Context1, Qt::Key_Context1,
+ QTOPIAXK_Context2, Qt::Key_Context2,
+ QTOPIAXK_Context3, Qt::Key_Context3,
+ QTOPIAXK_Context4, Qt::Key_Context4,
+ QTOPIAXK_Call, Qt::Key_Call,
+ QTOPIAXK_Hangup, Qt::Key_Hangup,
+ QTOPIAXK_Flip, Qt::Key_Flip,
+
+ 0, 0
+};
+
+static int translateKeySym(uint key)
+{
+ int code = -1;
+ int i = 0; // any other keys
+ while (KeyTbl[i]) {
+ if (key == KeyTbl[i]) {
+ code = (int)KeyTbl[i+1];
+ break;
+ }
+ i += 2;
+ }
+ if (qt_meta_mask) {
+ // translate Super/Hyper keys to Meta if we're using them as the MetaModifier
+ if (qt_meta_mask == qt_super_mask && (code == Qt::Key_Super_L || code == Qt::Key_Super_R)) {
+ code = Qt::Key_Meta;
+ } else if (qt_meta_mask == qt_hyper_mask && (code == Qt::Key_Hyper_L || code == Qt::Key_Hyper_R)) {
+ code = Qt::Key_Meta;
+ }
+ }
+ return code;
+}
+
+#if !defined(QT_NO_XIM)
+static const unsigned short katakanaKeysymsToUnicode[] = {
+ 0x0000, 0x3002, 0x300C, 0x300D, 0x3001, 0x30FB, 0x30F2, 0x30A1,
+ 0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30E3, 0x30E5, 0x30E7, 0x30C3,
+ 0x30FC, 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD,
+ 0x30AF, 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD,
+ 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, 0x30CB, 0x30CC,
+ 0x30CD, 0x30CE, 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, 0x30DE,
+ 0x30DF, 0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9,
+ 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F3, 0x309B, 0x309C
+};
+
+static const unsigned short cyrillicKeysymsToUnicode[] = {
+ 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0000, 0x045e, 0x045f,
+ 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407,
+ 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0000, 0x040e, 0x040f,
+ 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
+ 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
+ 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
+ 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a,
+ 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
+ 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
+ 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
+ 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a
+};
+
+static const unsigned short greekKeysymsToUnicode[] = {
+ 0x0000, 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c,
+ 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015,
+ 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc,
+ 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
+ 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
+ 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
+ 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+ 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
+ 0x03c8, 0x03c9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static const unsigned short technicalKeysymsToUnicode[] = {
+ 0x0000, 0x23B7, 0x250C, 0x2500, 0x2320, 0x2321, 0x2502, 0x23A1,
+ 0x23A3, 0x23A4, 0x23A6, 0x239B, 0x239D, 0x239E, 0x23A0, 0x23A8,
+ 0x23AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222B,
+ 0x2234, 0x221D, 0x221E, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000,
+ 0x223C, 0x2243, 0x0000, 0x0000, 0x0000, 0x21D4, 0x21D2, 0x2261,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221A, 0x0000,
+ 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222A, 0x2227, 0x2228,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2202,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193, 0x0000
+};
+
+static const unsigned short specialKeysymsToUnicode[] = {
+ 0x25C6, 0x2592, 0x2409, 0x240C, 0x240D, 0x240A, 0x0000, 0x0000,
+ 0x2424, 0x240B, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x23BA,
+ 0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251C, 0x2524, 0x2534, 0x252C,
+ 0x2502, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static const unsigned short publishingKeysymsToUnicode[] = {
+ 0x0000, 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009,
+ 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025,
+ 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a,
+ 0x2105, 0x0000, 0x0000, 0x2012, 0x2329, 0x0000, 0x232a, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000,
+ 0x0000, 0x2122, 0x2613, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25af,
+ 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033,
+ 0x0000, 0x271d, 0x0000, 0x25ac, 0x25c0, 0x25b6, 0x25cf, 0x25ae,
+ 0x25e6, 0x25ab, 0x25ad, 0x25b3, 0x25bd, 0x2606, 0x2022, 0x25aa,
+ 0x25b2, 0x25bc, 0x261c, 0x261e, 0x2663, 0x2666, 0x2665, 0x0000,
+ 0x2720, 0x2020, 0x2021, 0x2713, 0x2717, 0x266f, 0x266d, 0x2642,
+ 0x2640, 0x260e, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e, 0x0000
+};
+
+static const unsigned short aplKeysymsToUnicode[] = {
+ 0x0000, 0x0000, 0x0000, 0x003c, 0x0000, 0x0000, 0x003e, 0x0000,
+ 0x2228, 0x2227, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00af, 0x0000, 0x22a5, 0x2229, 0x230a, 0x0000, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x2218, 0x0000, 0x2395, 0x0000, 0x22a4, 0x25cb,
+ 0x0000, 0x0000, 0x0000, 0x2308, 0x0000, 0x0000, 0x222a, 0x0000,
+ 0x2283, 0x0000, 0x2282, 0x0000, 0x22a2, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x22a3, 0x0000, 0x0000, 0x0000
+};
+
+static const unsigned short koreanKeysymsToUnicode[] = {
+ 0x0000, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137,
+ 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f,
+ 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147,
+ 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x314f,
+ 0x3150, 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156, 0x3157,
+ 0x3158, 0x3159, 0x315a, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f,
+ 0x3160, 0x3161, 0x3162, 0x3163, 0x11a8, 0x11a9, 0x11aa, 0x11ab,
+ 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3,
+ 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb,
+ 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x316d,
+ 0x3171, 0x3178, 0x317f, 0x3181, 0x3184, 0x3186, 0x318d, 0x318e,
+ 0x11eb, 0x11f0, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9
+};
+
+static QChar keysymToUnicode(unsigned char byte3, unsigned char byte4)
+{
+ switch (byte3) {
+ case 0x04:
+ // katakana
+ if (byte4 > 0xa0 && byte4 < 0xe0)
+ return QChar(katakanaKeysymsToUnicode[byte4 - 0xa0]);
+ else if (byte4 == 0x7e)
+ return QChar(0x203e); // Overline
+ break;
+ case 0x06:
+ // russian, use lookup table
+ if (byte4 > 0xa0)
+ return QChar(cyrillicKeysymsToUnicode[byte4 - 0xa0]);
+ break;
+ case 0x07:
+ // greek
+ if (byte4 > 0xa0)
+ return QChar(greekKeysymsToUnicode[byte4 - 0xa0]);
+ break;
+ case 0x08:
+ // technical
+ if (byte4 > 0xa0)
+ return QChar(technicalKeysymsToUnicode[byte4 - 0xa0]);
+ break;
+ case 0x09:
+ // special
+ if (byte4 >= 0xe0)
+ return QChar(specialKeysymsToUnicode[byte4 - 0xe0]);
+ break;
+ case 0x0a:
+ // publishing
+ if (byte4 > 0xa0)
+ return QChar(publishingKeysymsToUnicode[byte4 - 0xa0]);
+ break;
+ case 0x0b:
+ // APL
+ if (byte4 > 0xa0)
+ return QChar(aplKeysymsToUnicode[byte4 - 0xa0]);
+ break;
+ case 0x0e:
+ // Korean
+ if (byte4 > 0xa0)
+ return QChar(koreanKeysymsToUnicode[byte4 - 0xa0]);
+ break;
+ default:
+ break;
+ }
+ return QChar(0x0);
+}
+#endif
+
+static QString translateKeySym(KeySym keysym, uint xmodifiers,
+ int &code, Qt::KeyboardModifiers &modifiers,
+ QByteArray &chars, int &count)
+{
+ // all keysyms smaller than 0xff00 are actally keys that can be mapped to unicode chars
+
+ extern QTextCodec *qt_input_mapper; // from qapplication_x11.cpp
+ QTextCodec *mapper = qt_input_mapper;
+ QChar converted;
+
+ if (count == 0 && keysym < 0xff00) {
+ unsigned char byte3 = (unsigned char)(keysym >> 8);
+ int mib = -1;
+ switch(byte3) {
+ case 0: // Latin 1
+ case 1: // Latin 2
+ case 2: //latin 3
+ case 3: // latin4
+ mib = byte3 + 4; break;
+ case 5: // arabic
+ mib = 82; break;
+ case 12: // Hebrew
+ mib = 85; break;
+ case 13: // Thai
+ mib = 2259; break;
+ case 4: // kana
+ case 6: // cyrillic
+ case 7: // greek
+ case 8: // technical, no mapping here at the moment
+ case 9: // Special
+ case 10: // Publishing
+ case 11: // APL
+ case 14: // Korean, no mapping
+ mib = -1; // manual conversion
+ mapper = 0;
+#if !defined(QT_NO_XIM)
+ converted = keysymToUnicode(byte3, keysym & 0xff);
+#endif
+ case 0x20:
+ // currency symbols
+ if (keysym >= 0x20a0 && keysym <= 0x20ac) {
+ mib = -1; // manual conversion
+ mapper = 0;
+ converted = (uint)keysym;
+ }
+ break;
+ default:
+ break;
+ }
+ if (mib != -1) {
+ mapper = QTextCodec::codecForMib(mib);
+ if (chars.isEmpty())
+ chars.resize(1);
+ chars[0] = (unsigned char) (keysym & 0xff); // get only the fourth bit for conversion later
+ count++;
+ }
+ } else if (keysym >= 0x1000000 && keysym <= 0x100ffff) {
+ converted = (ushort) (keysym - 0x1000000);
+ mapper = 0;
+ }
+ if (count < (int)chars.size()-1)
+ chars[count] = '\0';
+
+ QString text;
+ if (!mapper && converted.unicode() != 0x0) {
+ text = converted;
+ } else if (!chars.isEmpty()) {
+ // convert chars (8bit) to text (unicode).
+ if (mapper)
+ text = mapper->toUnicode(chars.data(), count, 0);
+ if (text.isEmpty()) {
+ // no mapper, or codec couldn't convert to unicode (this
+ // can happen when running in the C locale or with no LANG
+ // set). try converting from latin-1
+ text = QString::fromLatin1(chars);
+ }
+ }
+
+ modifiers = X11->translateModifiers(xmodifiers);
+
+ // Commentary in X11/keysymdef says that X codes match ASCII, so it
+ // is safe to use the locale functions to process X codes in ISO8859-1.
+ //
+ // This is mainly for compatibility - applications should not use the
+ // Qt keycodes between 128 and 255, but should rather use the
+ // QKeyEvent::text().
+ //
+ extern QTextCodec *qt_input_mapper; // from qapplication_x11.cpp
+ if (keysym < 128 || (keysym < 256 && (!qt_input_mapper || qt_input_mapper->mibEnum()==4))) {
+ // upper-case key, if known
+ code = isprint((int)keysym) ? toupper((int)keysym) : 0;
+ } else if (keysym >= XK_F1 && keysym <= XK_F35) {
+ // function keys
+ code = Qt::Key_F1 + ((int)keysym - XK_F1);
+ } else if (keysym >= XK_KP_Space && keysym <= XK_KP_9) {
+ if (keysym >= XK_KP_0) {
+ // numeric keypad keys
+ code = Qt::Key_0 + ((int)keysym - XK_KP_0);
+ } else {
+ code = translateKeySym(keysym);
+ }
+ modifiers |= Qt::KeypadModifier;
+ } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f && text.unicode()->unicode() != 0x7f && !(keysym >= XK_dead_grave && keysym <= XK_dead_horn)) {
+ code = text.unicode()->toUpper().unicode();
+ } else {
+ // any other keys
+ code = translateKeySym(keysym);
+
+ if (code == Qt::Key_Tab && (modifiers & Qt::ShiftModifier)) {
+ // map shift+tab to shift+backtab, QShortcutMap knows about it
+ // and will handle it.
+ code = Qt::Key_Backtab;
+ text = QString();
+ }
+ }
+
+ return text;
+}
+
+extern bool qt_use_rtl_extensions; // from qapplication_x11.cpp
+
+bool QKeyMapperPrivate::translateKeyEventInternal(QWidget *keyWidget,
+ const XEvent *event,
+ KeySym &keysym,
+ int& count,
+ QString& text,
+ Qt::KeyboardModifiers &modifiers,
+ int& code,
+ QEvent::Type &type,
+ bool statefulTranslation)
+{
+ XKeyEvent xkeyevent = event->xkey;
+ int keycode = event->xkey.keycode;
+ // save the modifier state, we will use the keystate uint later by passing
+ // it to translateButtonState
+ uint keystate = event->xkey.state;
+
+ type = (event->type == XKeyPress) ? QEvent::KeyPress : QEvent::KeyRelease;
+
+ static int directionKeyEvent = 0;
+ static unsigned int lastWinId = 0;
+
+ // translate pending direction change
+ if (statefulTranslation && qt_use_rtl_extensions && type == QEvent::KeyRelease) {
+ if (directionKeyEvent == Qt::Key_Direction_R || directionKeyEvent == Qt::Key_Direction_L) {
+ type = QEvent::KeyPress;
+ code = directionKeyEvent;
+ text = QString();
+ directionKeyEvent = 0;
+ lastWinId = 0;
+ return true;
+ } else {
+ directionKeyEvent = 0;
+ lastWinId = 0;
+ }
+ }
+
+ // some XmbLookupString implementations don't return buffer overflow correctly,
+ // so we increase the input buffer to allow for long strings...
+ // 256 chars * 2 bytes + 1 null-term == 513 bytes
+ QByteArray chars;
+ chars.resize(513);
+
+ count = XLookupString(&xkeyevent, chars.data(), chars.size(), &keysym, 0);
+ if (count && !keycode) {
+ extern int qt_ximComposingKeycode; // from qapplication_x11.cpp
+ keycode = qt_ximComposingKeycode;
+ qt_ximComposingKeycode = 0;
+ }
+
+ // translate the keysym + xmodifiers to Qt::Key_* + Qt::KeyboardModifiers
+ text = translateKeySym(keysym, keystate, code, modifiers, chars, count);
+
+ // Watch for keypresses and if its a key belonging to the Ctrl-Shift
+ // direction-changing accel, remember it.
+ // We keep track of those keys instead of using the event's state
+ // (to figure out whether the Ctrl modifier is held while Shift is pressed,
+ // or Shift is held while Ctrl is pressed) since the 'state' doesn't tell
+ // us whether the modifier held is Left or Right.
+ if (statefulTranslation && qt_use_rtl_extensions && type == QEvent::KeyPress) {
+ if (keysym == XK_Control_L || keysym == XK_Control_R
+ || keysym == XK_Shift_L || keysym == XK_Shift_R) {
+ if (!directionKeyEvent) {
+ directionKeyEvent = keysym;
+ // This code exists in order to check that
+ // the event is occurred in the same widget.
+ lastWinId = keyWidget->internalWinId();
+ }
+ } else {
+ // this can no longer be a direction-changing accel.
+ // if any other key was pressed.
+ directionKeyEvent = Qt::Key_Space;
+ }
+
+ if (directionKeyEvent && lastWinId == keyWidget->internalWinId()) {
+ if ((keysym == XK_Shift_L && directionKeyEvent == XK_Control_L)
+ || (keysym == XK_Control_L && directionKeyEvent == XK_Shift_L)) {
+ directionKeyEvent = Qt::Key_Direction_L;
+ } else if ((keysym == XK_Shift_R && directionKeyEvent == XK_Control_R)
+ || (keysym == XK_Control_R && directionKeyEvent == XK_Shift_R)) {
+ directionKeyEvent = Qt::Key_Direction_R;
+ }
+ } else if (directionKeyEvent == Qt::Key_Direction_L
+ || directionKeyEvent == Qt::Key_Direction_R) {
+ directionKeyEvent = Qt::Key_Space; // invalid
+ }
+ }
+
+ return true;
+}
+
+
+struct qt_auto_repeat_data
+{
+ // match the window and keycode with timestamp delta of 10 ms
+ Window window;
+ KeyCode keycode;
+ Time timestamp;
+
+ // queue scanner state
+ bool release;
+ bool error;
+};
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static Bool qt_keypress_scanner(Display *, XEvent *event, XPointer arg)
+{
+ if (event->type != XKeyPress && event->type != XKeyRelease)
+ return false;
+
+ qt_auto_repeat_data *data = (qt_auto_repeat_data *) arg;
+ if (data->error)
+ return false;
+
+ if (event->xkey.window != data->window ||
+ event->xkey.keycode != data->keycode) {
+ // deal breakers: key events in a different window or an event
+ // with a different key code
+ data->error = true;
+ return false;
+ }
+
+ if (event->type == XKeyPress) {
+ data->error = (! data->release || event->xkey.time - data->timestamp > 10);
+ return (! data->error);
+ }
+
+ // must be XKeyRelease event
+ if (data->release) {
+ // found a second release
+ data->error = true;
+ return false;
+ }
+
+ // found a single release
+ data->release = true;
+ data->timestamp = event->xkey.time;
+
+ return false;
+}
+
+static Bool qt_keyrelease_scanner(Display *, XEvent *event, XPointer arg)
+{
+ const qt_auto_repeat_data *data = (const qt_auto_repeat_data *) arg;
+ return (event->type == XKeyRelease &&
+ event->xkey.window == data->window &&
+ event->xkey.keycode == data->keycode);
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+bool QKeyMapperPrivate::translateKeyEvent(QWidget *keyWidget, const XEvent *event, bool grab)
+{
+ int code = -1;
+ int count = 0;
+ Qt::KeyboardModifiers modifiers;
+
+ if (qt_sm_blockUserInput) // block user interaction during session management
+ return true;
+
+ Display *dpy = X11->display;
+
+ if (!keyWidget->isEnabled())
+ return true;
+
+ QEvent::Type type;
+ bool autor = false;
+ QString text;
+
+ KeySym keysym = 0;
+ translateKeyEventInternal(keyWidget, event, keysym, count, text, modifiers, code, type);
+
+ // was this the last auto-repeater?
+ qt_auto_repeat_data auto_repeat_data;
+ auto_repeat_data.window = event->xkey.window;
+ auto_repeat_data.keycode = event->xkey.keycode;
+ auto_repeat_data.timestamp = event->xkey.time;
+
+ static uint curr_autorep = 0;
+ if (event->type == XKeyPress) {
+ if (curr_autorep == event->xkey.keycode) {
+ autor = true;
+ curr_autorep = 0;
+ }
+ } else {
+ // look ahead for auto-repeat
+ XEvent nextpress;
+
+ auto_repeat_data.release = true;
+ auto_repeat_data.error = false;
+ if (XCheckIfEvent(dpy, &nextpress, &qt_keypress_scanner,
+ (XPointer) &auto_repeat_data)) {
+ autor = true;
+
+ // Put it back... we COULD send the event now and not need
+ // the static curr_autorep variable.
+ XPutBackEvent(dpy,&nextpress);
+ }
+ curr_autorep = autor ? event->xkey.keycode : 0;
+ }
+
+#if defined QT3_SUPPORT && !defined(QT_NO_SHORTCUT)
+ // process accelerators before doing key compression
+ if (type == QEvent::KeyPress && !grab
+ && QApplicationPrivate::instance()->use_compat()) {
+ // send accel events if the keyboard is not grabbed
+ QKeyEventEx a(type, code, modifiers, text, autor, qMax(qMax(count,1), int(text.length())),
+ event->xkey.keycode, keysym, event->xkey.state);
+ if (QApplicationPrivate::instance()->qt_tryAccelEvent(keyWidget, &a))
+ return true;
+ }
+#endif
+
+#ifndef QT_NO_IM
+ QInputContext *qic = keyWidget->inputContext();
+#endif
+
+ // compress keys
+ if (!text.isEmpty() && keyWidget->testAttribute(Qt::WA_KeyCompression) &&
+#ifndef QT_NO_IM
+ // Ordinary input methods require discrete key events to work
+ // properly, so key compression has to be disabled when input
+ // context exists.
+ //
+ // And further consideration, some complex input method
+ // require all key press/release events discretely even if
+ // the input method awares of key compression and compressed
+ // keys are ordinary alphabets. For example, the uim project
+ // is planning to implement "combinational shift" feature for
+ // a Japanese input method, uim-skk. It will work as follows.
+ //
+ // 1. press "r"
+ // 2. press "u"
+ // 3. release both "r" and "u" in arbitrary order
+ // 4. above key sequence generates "Ru"
+ //
+ // Of course further consideration about other participants
+ // such as key repeat mechanism is required to implement such
+ // feature.
+ !qic &&
+#endif // QT_NO_IM
+ // do not compress keys if the key event we just got above matches
+ // one of the key ranges used to compute stopCompression
+ !((code >= Qt::Key_Escape && code <= Qt::Key_SysReq)
+ || (code >= Qt::Key_Home && code <= Qt::Key_PageDown)
+ || (code >= Qt::Key_Super_L && code <= Qt::Key_Direction_R)
+ || (code == 0)
+ || (text.length() == 1 && text.unicode()->unicode() == '\n'))) {
+ // the widget wants key compression so it gets it
+
+ // sync the event queue, this makes key compress work better
+ XSync(dpy, false);
+
+ for (;;) {
+ XEvent evRelease;
+ XEvent evPress;
+ if (!XCheckTypedWindowEvent(dpy,event->xkey.window,
+ XKeyRelease,&evRelease))
+ break;
+ if (!XCheckTypedWindowEvent(dpy,event->xkey.window,
+ XKeyPress,&evPress)) {
+ XPutBackEvent(dpy, &evRelease);
+ break;
+ }
+ QString textIntern;
+ int codeIntern = -1;
+ int countIntern = 0;
+ Qt::KeyboardModifiers modifiersIntern;
+ QEvent::Type t;
+ KeySym keySymIntern;
+ translateKeyEventInternal(keyWidget, &evPress, keySymIntern, countIntern, textIntern,
+ modifiersIntern, codeIntern, t);
+ // use stopCompression to stop key compression for the following
+ // key event ranges:
+ bool stopCompression =
+ // 1) misc keys
+ (codeIntern >= Qt::Key_Escape && codeIntern <= Qt::Key_SysReq)
+ // 2) cursor movement
+ || (codeIntern >= Qt::Key_Home && codeIntern <= Qt::Key_PageDown)
+ // 3) extra keys
+ || (codeIntern >= Qt::Key_Super_L && codeIntern <= Qt::Key_Direction_R)
+ // 4) something that a) doesn't translate to text or b) translates
+ // to newline text
+ || (codeIntern == 0)
+ || (textIntern.length() == 1 && textIntern.unicode()->unicode() == '\n')
+ || (codeIntern == Qt::Key_unknown);
+
+ if (modifiersIntern == modifiers && !textIntern.isEmpty() && !stopCompression) {
+ text += textIntern;
+ count += countIntern;
+ } else {
+ XPutBackEvent(dpy, &evPress);
+ XPutBackEvent(dpy, &evRelease);
+ break;
+ }
+ }
+ }
+
+ // autorepeat compression makes sense for all widgets (Windows
+ // does it automatically ....)
+ if (event->type == XKeyPress && text.length() <= 1
+#ifndef QT_NO_IM
+ // input methods need discrete key events
+ && !qic
+#endif// QT_NO_IM
+ ) {
+ XEvent dummy;
+
+ for (;;) {
+ auto_repeat_data.release = false;
+ auto_repeat_data.error = false;
+ if (! XCheckIfEvent(dpy, &dummy, &qt_keypress_scanner,
+ (XPointer) &auto_repeat_data))
+ break;
+ if (! XCheckIfEvent(dpy, &dummy, &qt_keyrelease_scanner,
+ (XPointer) &auto_repeat_data))
+ break;
+
+ count++;
+ if (!text.isEmpty())
+ text += text[0];
+ }
+ }
+
+ return QKeyMapper::sendKeyEvent(keyWidget, grab, type, code, modifiers, text, autor,
+ qMax(qMax(count,1), int(text.length())),
+ event->xkey.keycode, keysym, event->xkey.state);
+}
+
+bool QKeyMapper::sendKeyEvent(QWidget *keyWidget, bool grab,
+ QEvent::Type type, int code, Qt::KeyboardModifiers modifiers,
+ const QString &text, bool autorepeat, int count,
+ quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers,
+ bool *)
+{
+ // try the menukey first
+ if (type == QEvent::KeyPress && code == Qt::Key_Menu) {
+ QVariant v = keyWidget->inputMethodQuery(Qt::ImMicroFocus);
+ QPoint globalPos;
+ QPoint pos;
+ if (v.isNull()) {
+ globalPos = QCursor::pos();
+ pos = keyWidget->mapFromGlobal(globalPos);
+ } else {
+ pos = v.toRect().center();
+ globalPos = keyWidget->mapToGlobal(pos);
+ }
+ QContextMenuEvent e(QContextMenuEvent::Keyboard, pos, globalPos);
+ qt_sendSpontaneousEvent(keyWidget, &e);
+ if(e.isAccepted())
+ return true;
+ }
+
+ Q_UNUSED(grab);
+ QKeyEventEx e(type, code, modifiers, text, autorepeat, qMax(qMax(count,1), int(text.length())),
+ nativeScanCode, nativeVirtualKey, nativeModifiers);
+ return qt_sendSpontaneousEvent(keyWidget, &e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qkeymapper_x11_p.cpp b/src/widgets/platforms/x11/qkeymapper_x11_p.cpp
new file mode 100644
index 0000000000..2dbe1e77a4
--- /dev/null
+++ b/src/widgets/platforms/x11/qkeymapper_x11_p.cpp
@@ -0,0 +1,489 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+// This file is auto-generated, do not edit!
+// (Generated using util/xkbdatagen)
+
+static struct {
+ const char *layout;
+ const char *variant; // 0 means any variant
+ Qt::LayoutDirection direction;
+ QLocale::Language language;
+ QLocale::Country country;
+} xkbLayoutData[] = {
+ // name = us, description = U.S. English
+ { "us", "", Qt::LeftToRight, QLocale::English, QLocale::UnitedStates },
+ // name = us:intl, description = U.S. English
+ { "us", "intl", Qt::LeftToRight, QLocale::English, QLocale::UnitedStates },
+ // name = us:alt-intl, description = U.S. English
+ { "us", "alt-intl", Qt::LeftToRight, QLocale::English, QLocale::UnitedStates },
+ // name = us:dvorak, description = U.S. English
+ { "us", "dvorak", Qt::LeftToRight, QLocale::English, QLocale::UnitedStates },
+ // name = us:rus, description = U.S. English
+ { "us", "rus", Qt::LeftToRight, QLocale::Russian, QLocale::UnitedStates },
+ // name = ara, description = Arabic
+ { "ara", "", Qt::RightToLeft, QLocale::Arabic, QLocale::UnitedArabEmirates },
+ // name = ara:azerty, description = Arabic
+ { "ara", "azerty", Qt::RightToLeft, QLocale::Arabic, QLocale::UnitedArabEmirates },
+ // name = ara:azerty_digits, description = Arabic
+ { "ara", "azerty_digits", Qt::RightToLeft, QLocale::Arabic, QLocale::UnitedArabEmirates },
+ // name = ara:digits, description = Arabic
+ { "ara", "digits", Qt::RightToLeft, QLocale::Arabic, QLocale::UnitedArabEmirates },
+ // name = ara:qwerty, description = Arabic
+ { "ara", "qwerty", Qt::RightToLeft, QLocale::Arabic, QLocale::UnitedArabEmirates },
+ // name = ara:qwerty_digits, description = Arabic
+ { "ara", "qwerty_digits", Qt::RightToLeft, QLocale::Arabic, QLocale::UnitedArabEmirates },
+ // name = al, description = Albania
+ { "al", "", Qt::LeftToRight, QLocale::Albanian, QLocale::Albania },
+ // name = am, description = Armenia
+ { "am", "", Qt::LeftToRight, QLocale::Armenian, QLocale::Armenia },
+ // name = am:phonetic, description = Armenia
+ { "am", "phonetic", Qt::LeftToRight, QLocale::Armenian, QLocale::Armenia },
+ // name = az, description = Azerbaijan
+ { "az", "", Qt::LeftToRight, QLocale::Azerbaijani, QLocale::Azerbaijan },
+ // name = az:cyrillic, description = Azerbaijan
+ { "az", "cyrillic", Qt::LeftToRight, QLocale::Azerbaijani, QLocale::Azerbaijan },
+ // name = by, description = Belarus
+ { "by", "", Qt::LeftToRight, QLocale::Byelorussian, QLocale::Belarus },
+ // name = by:winkeys, description = Belarus
+ { "by", "winkeys", Qt::LeftToRight, QLocale::Byelorussian, QLocale::Belarus },
+ // name = be, description = Belgium
+ { "be", "", Qt::LeftToRight, QLocale::Dutch, QLocale::Belgium },
+ // name = be:iso-alternate, description = Belgium
+ { "be", "iso-alternate", Qt::LeftToRight, QLocale::Dutch, QLocale::Belgium },
+ // name = be:nodeadkeys, description = Belgium
+ { "be", "nodeadkeys", Qt::LeftToRight, QLocale::Dutch, QLocale::Belgium },
+ // name = be:sundeadkeys, description = Belgium
+ { "be", "sundeadkeys", Qt::LeftToRight, QLocale::Dutch, QLocale::Belgium },
+ // name = bd, description = Bangladesh
+ { "bd", "", Qt::LeftToRight, QLocale::Bengali, QLocale::Bangladesh },
+ // name = bd:probhat, description = Bangladesh
+ { "bd", "probhat", Qt::LeftToRight, QLocale::Bengali, QLocale::Bangladesh },
+ // name = in, description = India
+ { "in", "", Qt::LeftToRight, QLocale::Hindi, QLocale::India },
+ // name = in:ben, description = India
+ { "in", "ben", Qt::LeftToRight, QLocale::Bengali, QLocale::India },
+ // name = in:ben_probhat, description = India
+ { "in", "ben_probhat", Qt::LeftToRight, QLocale::Bengali, QLocale::India },
+ // name = in:guj, description = India
+ { "in", "guj", Qt::LeftToRight, QLocale::Gujarati, QLocale::India },
+ // name = in:guru, description = India
+ { "in", "guru", Qt::LeftToRight, QLocale::Punjabi, QLocale::India },
+ // name = in:kan, description = India
+ { "in", "kan", Qt::LeftToRight, QLocale::Kannada, QLocale::India },
+ // name = in:mal, description = India
+ { "in", "mal", Qt::LeftToRight, QLocale::Malayalam, QLocale::India },
+ // name = in:ori, description = India
+ { "in", "ori", Qt::LeftToRight, QLocale::Oriya, QLocale::India },
+ // name = in:tam_unicode, description = India
+ { "in", "tam_unicode", Qt::LeftToRight, QLocale::Tamil, QLocale::India },
+ // name = in:tam_TAB, description = India
+ { "in", "tam_TAB", Qt::LeftToRight, QLocale::Tamil, QLocale::India },
+ // name = in:tam_TSCII, description = India
+ { "in", "tam_TSCII", Qt::LeftToRight, QLocale::Tamil, QLocale::India },
+ // name = in:tam, description = India
+ { "in", "tam", Qt::LeftToRight, QLocale::Tamil, QLocale::India },
+ // name = in:tel, description = India
+ { "in", "tel", Qt::LeftToRight, QLocale::Telugu, QLocale::India },
+ // name = in:urd, description = India
+ { "in", "urd", Qt::RightToLeft, QLocale::Urdu, QLocale::India },
+ // name = ba, description = Bosnia and Herzegovina
+ { "ba", "", Qt::LeftToRight, QLocale::Bosnian, QLocale::BosniaAndHerzegowina },
+ // name = br, description = Brazil
+ { "br", "", Qt::LeftToRight, QLocale::Portuguese, QLocale::Brazil },
+ // name = br:nodeadkeys, description = Brazil
+ { "br", "nodeadkeys", Qt::LeftToRight, QLocale::Portuguese, QLocale::Brazil },
+ // name = bg, description = Bulgaria
+ { "bg", "", Qt::LeftToRight, QLocale::Bulgarian, QLocale::Bulgaria },
+ // name = bg:phonetic, description = Bulgaria
+ { "bg", "phonetic", Qt::LeftToRight, QLocale::Bulgarian, QLocale::Bulgaria },
+ // name = mm, description = Myanmar
+ { "mm", "", Qt::LeftToRight, QLocale::Burmese, QLocale::Myanmar },
+ // name = ca, description = Canada
+ { "ca", "", Qt::LeftToRight, QLocale::English, QLocale::Canada },
+ // name = ca:fr-dvorak, description = Canada
+ { "ca", "fr-dvorak", Qt::LeftToRight, QLocale::French, QLocale::Canada },
+ // name = ca:fr-legacy, description = Canada
+ { "ca", "fr-legacy", Qt::LeftToRight, QLocale::French, QLocale::Canada },
+ // name = ca:multi, description = Canada
+ { "ca", "multi", Qt::LeftToRight, QLocale::English, QLocale::Canada },
+ // name = ca:multi-2gr, description = Canada
+ { "ca", "multi-2gr", Qt::LeftToRight, QLocale::English, QLocale::Canada },
+ // name = ca:ike, description = Canada
+ { "ca", "ike", Qt::LeftToRight, QLocale::Inuktitut, QLocale::Canada },
+ // name = hr, description = Croatia
+ { "hr", "", Qt::LeftToRight, QLocale::Croatian, QLocale::Croatia },
+ // name = hr:us, description = Croatia
+ { "hr", "us", Qt::LeftToRight, QLocale::Croatian, QLocale::Croatia },
+ // name = cz, description = Czechia
+ { "cz", "", Qt::LeftToRight, QLocale::Czech, QLocale::CzechRepublic },
+ // name = cz:bksl, description = Czechia
+ { "cz", "bksl", Qt::LeftToRight, QLocale::Czech, QLocale::CzechRepublic },
+ // name = cz:qwerty, description = Czechia
+ { "cz", "qwerty", Qt::LeftToRight, QLocale::Czech, QLocale::CzechRepublic },
+ // name = cz:qwerty_bksl, description = Czechia
+ { "cz", "qwerty_bksl", Qt::LeftToRight, QLocale::Czech, QLocale::CzechRepublic },
+ // name = dk, description = Denmark
+ { "dk", "", Qt::LeftToRight, QLocale::Danish, QLocale::Denmark },
+ // name = dk:nodeadkeys, description = Denmark
+ { "dk", "nodeadkeys", Qt::LeftToRight, QLocale::Danish, QLocale::Denmark },
+ // name = nl, description = Netherlands
+ { "nl", "", Qt::LeftToRight, QLocale::Dutch, QLocale::Netherlands },
+ // name = bt, description = Bhutan
+ { "bt", "", Qt::LeftToRight, QLocale::Bhutani, QLocale::Bhutan },
+ // name = ee, description = Estonia
+ { "ee", "", Qt::LeftToRight, QLocale::Estonian, QLocale::Estonia },
+ // name = ee:nodeadkeys, description = Estonia
+ { "ee", "nodeadkeys", Qt::LeftToRight, QLocale::Estonian, QLocale::Estonia },
+ // name = ir, description = Iran
+ { "ir", "", Qt::RightToLeft, QLocale::Persian, QLocale::Iran },
+ // name = fo, description = Faroe Islands
+ { "fo", "", Qt::LeftToRight, QLocale::Faroese, QLocale::FaroeIslands },
+ // name = fo:nodeadkeys, description = Faroe Islands
+ { "fo", "nodeadkeys", Qt::LeftToRight, QLocale::Faroese, QLocale::FaroeIslands },
+ // name = fi, description = Finland
+ { "fi", "", Qt::LeftToRight, QLocale::Finnish, QLocale::Finland },
+ // name = fi:nodeadkeys, description = Finland
+ { "fi", "nodeadkeys", Qt::LeftToRight, QLocale::Finnish, QLocale::Finland },
+ // name = fi:smi, description = Finland
+ { "fi", "smi", Qt::LeftToRight, QLocale::Finnish, QLocale::Finland },
+ // name = fr, description = France
+ { "fr", "", Qt::LeftToRight, QLocale::French, QLocale::France },
+ // name = fr:nodeadkeys, description = France
+ { "fr", "nodeadkeys", Qt::LeftToRight, QLocale::French, QLocale::France },
+ // name = fr:sundeadkeys, description = France
+ { "fr", "sundeadkeys", Qt::LeftToRight, QLocale::French, QLocale::France },
+ // name = fr:latin9, description = France
+ { "fr", "latin9", Qt::LeftToRight, QLocale::French, QLocale::France },
+ // name = fr:latin9_nodeadkeys, description = France
+ { "fr", "latin9_nodeadkeys", Qt::LeftToRight, QLocale::French, QLocale::France },
+ // name = fr:latin9_sundeadkeys, description = France
+ { "fr", "latin9_sundeadkeys", Qt::LeftToRight, QLocale::French, QLocale::France },
+ // name = fr:dvorak, description = France
+ { "fr", "dvorak", Qt::LeftToRight, QLocale::French, QLocale::France },
+ // name = ge, description = Georgia
+ { "ge", "", Qt::LeftToRight, QLocale::Georgian, QLocale::Georgia },
+ // name = ge:ru, description = Georgia
+ { "ge", "ru", Qt::LeftToRight, QLocale::Russian, QLocale::Georgia },
+ // name = de, description = Germany
+ { "de", "", Qt::LeftToRight, QLocale::German, QLocale::Germany },
+ // name = de:deadacute, description = Germany
+ { "de", "deadacute", Qt::LeftToRight, QLocale::German, QLocale::Germany },
+ // name = de:deadgraveacute, description = Germany
+ { "de", "deadgraveacute", Qt::LeftToRight, QLocale::German, QLocale::Germany },
+ // name = de:nodeadkeys, description = Germany
+ { "de", "nodeadkeys", Qt::LeftToRight, QLocale::German, QLocale::Germany },
+ // name = de:ro, description = Germany
+ { "de", "ro", Qt::LeftToRight, QLocale::Romanian, QLocale::Germany },
+ // name = de:ro_nodeadkeys, description = Germany
+ { "de", "ro_nodeadkeys", Qt::LeftToRight, QLocale::Romanian, QLocale::Germany },
+ // name = de:dvorak, description = Germany
+ { "de", "dvorak", Qt::LeftToRight, QLocale::German, QLocale::Germany },
+ // name = gr, description = Greece
+ { "gr", "", Qt::LeftToRight, QLocale::Greek, QLocale::Greece },
+ // name = gr:extended, description = Greece
+ { "gr", "extended", Qt::LeftToRight, QLocale::Greek, QLocale::Greece },
+ // name = gr:nodeadkeys, description = Greece
+ { "gr", "nodeadkeys", Qt::LeftToRight, QLocale::Greek, QLocale::Greece },
+ // name = gr:polytonic, description = Greece
+ { "gr", "polytonic", Qt::LeftToRight, QLocale::Greek, QLocale::Greece },
+ // name = hu, description = Hungary
+ { "hu", "", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:standard, description = Hungary
+ { "hu", "standard", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:nodeadkeys, description = Hungary
+ { "hu", "nodeadkeys", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:qwerty, description = Hungary
+ { "hu", "qwerty", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:101_qwertz_comma_dead, description = Hungary
+ { "hu", "101_qwertz_comma_dead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:101_qwertz_comma_nodead, description = Hungary
+ { "hu", "101_qwertz_comma_nodead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:101_qwertz_dot_dead, description = Hungary
+ { "hu", "101_qwertz_dot_dead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:101_qwertz_dot_nodead, description = Hungary
+ { "hu", "101_qwertz_dot_nodead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:101_qwerty_comma_dead, description = Hungary
+ { "hu", "101_qwerty_comma_dead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:101_qwerty_comma_nodead, description = Hungary
+ { "hu", "101_qwerty_comma_nodead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:101_qwerty_dot_dead, description = Hungary
+ { "hu", "101_qwerty_dot_dead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:101_qwerty_dot_nodead, description = Hungary
+ { "hu", "101_qwerty_dot_nodead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:102_qwertz_comma_dead, description = Hungary
+ { "hu", "102_qwertz_comma_dead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:102_qwertz_comma_nodead, description = Hungary
+ { "hu", "102_qwertz_comma_nodead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:102_qwertz_dot_dead, description = Hungary
+ { "hu", "102_qwertz_dot_dead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:102_qwertz_dot_nodead, description = Hungary
+ { "hu", "102_qwertz_dot_nodead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:102_qwerty_comma_dead, description = Hungary
+ { "hu", "102_qwerty_comma_dead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:102_qwerty_comma_nodead, description = Hungary
+ { "hu", "102_qwerty_comma_nodead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:102_qwerty_dot_dead, description = Hungary
+ { "hu", "102_qwerty_dot_dead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = hu:102_qwerty_dot_nodead, description = Hungary
+ { "hu", "102_qwerty_dot_nodead", Qt::LeftToRight, QLocale::Hungarian, QLocale::Hungary },
+ // name = is, description = Iceland
+ { "is", "", Qt::LeftToRight, QLocale::Icelandic, QLocale::Iceland },
+ // name = is:Sundeadkeys, description = Iceland
+ { "is", "Sundeadkeys", Qt::LeftToRight, QLocale::Icelandic, QLocale::Iceland },
+ // name = is:nodeadkeys, description = Iceland
+ { "is", "nodeadkeys", Qt::LeftToRight, QLocale::Icelandic, QLocale::Iceland },
+ // name = il, description = Israel
+ { "il", "", Qt::RightToLeft, QLocale::Hebrew, QLocale::Israel },
+ // name = il:lyx, description = Israel
+ { "il", "lyx", Qt::RightToLeft, QLocale::Hebrew, QLocale::Israel },
+ // name = il:si1452, description = Israel
+ { "il", "si1452", Qt::RightToLeft, QLocale::Hebrew, QLocale::Israel },
+ // name = il:phonetic, description = Israel
+ { "il", "phonetic", Qt::RightToLeft, QLocale::Hebrew, QLocale::Israel },
+ // name = it, description = Italy
+ { "it", "", Qt::LeftToRight, QLocale::Italian, QLocale::Italy },
+ // name = it:nodeadkeys, description = Italy
+ { "it", "nodeadkeys", Qt::LeftToRight, QLocale::Italian, QLocale::Italy },
+ // name = jp, description = Japan
+ { "jp", "", Qt::LeftToRight, QLocale::Japanese, QLocale::Japan },
+ // name = kg, description = Kyrgyzstan
+ { "kg", "", Qt::LeftToRight, QLocale::Kirghiz, QLocale::Kyrgyzstan },
+ // name = la, description = Laos
+ { "la", "", Qt::LeftToRight, QLocale::Laothian, QLocale::Lao },
+ // name = latam, description = Latin American
+ { "latam", "", Qt::LeftToRight, QLocale::Spanish, QLocale::Mexico },
+ // name = latam:nodeadkeys, description = Latin American
+ { "latam", "nodeadkeys", Qt::LeftToRight, QLocale::Spanish, QLocale::Mexico },
+ // name = latam:sundeadkeys, description = Latin American
+ { "latam", "sundeadkeys", Qt::LeftToRight, QLocale::Spanish, QLocale::Mexico },
+ // name = lt, description = Lithuania
+ { "lt", "", Qt::LeftToRight, QLocale::Lithuanian, QLocale::Lithuania },
+ // name = lt:std, description = Lithuania
+ { "lt", "std", Qt::LeftToRight, QLocale::Lithuanian, QLocale::Lithuania },
+ // name = lt:us, description = Lithuania
+ { "lt", "us", Qt::LeftToRight, QLocale::Lithuanian, QLocale::Lithuania },
+ // name = lv, description = Latvia
+ { "lv", "", Qt::LeftToRight, QLocale::Latvian, QLocale::Latvia },
+ // name = lv:apostrophe, description = Latvia
+ { "lv", "apostrophe", Qt::LeftToRight, QLocale::Latvian, QLocale::Latvia },
+ // name = lv:tilde, description = Latvia
+ { "lv", "tilde", Qt::LeftToRight, QLocale::Latvian, QLocale::Latvia },
+ // name = lv:fkey, description = Latvia
+ { "lv", "fkey", Qt::LeftToRight, QLocale::Latvian, QLocale::Latvia },
+ // name = mao, description = Maori
+ { "mao", "", Qt::LeftToRight, QLocale::Maori, QLocale::NewZealand },
+ // name = mkd, description = Macedonian
+ { "mkd", "", Qt::LeftToRight, QLocale::Macedonian, QLocale::Macedonia },
+ // name = mkd:nodeadkeys, description = Macedonian
+ { "mkd", "nodeadkeys", Qt::LeftToRight, QLocale::Macedonian, QLocale::Macedonia },
+ // name = mt, description = Malta
+ { "mt", "", Qt::LeftToRight, QLocale::Maltese, QLocale::Malta },
+ // name = mt:us, description = Malta
+ { "mt", "us", Qt::LeftToRight, QLocale::Maltese, QLocale::Malta },
+ // name = mn, description = Mongolia
+ { "mn", "", Qt::LeftToRight, QLocale::Mongolian, QLocale::Mongolia },
+ // name = no, description = Norway
+ { "no", "", Qt::LeftToRight, QLocale::Norwegian, QLocale::Norway },
+ // name = no:nodeadkeys, description = Norway
+ { "no", "nodeadkeys", Qt::LeftToRight, QLocale::Norwegian, QLocale::Norway },
+ // name = no:dvorak, description = Norway
+ { "no", "dvorak", Qt::LeftToRight, QLocale::Norwegian, QLocale::Norway },
+ // name = no:smi, description = Norway
+ { "no", "smi", Qt::LeftToRight, QLocale::Norwegian, QLocale::Norway },
+ // name = no:smi_nodeadkeys, description = Norway
+ { "no", "smi_nodeadkeys", Qt::LeftToRight, QLocale::Norwegian, QLocale::Norway },
+ // name = pl, description = Poland
+ { "pl", "", Qt::LeftToRight, QLocale::Polish, QLocale::Poland },
+ // name = pl:qwertz, description = Poland
+ { "pl", "qwertz", Qt::LeftToRight, QLocale::Polish, QLocale::Poland },
+ // name = pl:dvorak, description = Poland
+ { "pl", "dvorak", Qt::LeftToRight, QLocale::Polish, QLocale::Poland },
+ // name = pl:dvorak_quotes, description = Poland
+ { "pl", "dvorak_quotes", Qt::LeftToRight, QLocale::Polish, QLocale::Poland },
+ // name = pl:dvorak_altquotes, description = Poland
+ { "pl", "dvorak_altquotes", Qt::LeftToRight, QLocale::Polish, QLocale::Poland },
+ // name = pt, description = Portugal
+ { "pt", "", Qt::LeftToRight, QLocale::Portuguese, QLocale::Portugal },
+ // name = pt:nodeadkeys, description = Portugal
+ { "pt", "nodeadkeys", Qt::LeftToRight, QLocale::Portuguese, QLocale::Portugal },
+ // name = pt:sundeadkeys, description = Portugal
+ { "pt", "sundeadkeys", Qt::LeftToRight, QLocale::Portuguese, QLocale::Portugal },
+ // name = ro, description = Romania
+ { "ro", "", Qt::LeftToRight, QLocale::Romanian, QLocale::Romania },
+ // name = ro:us, description = Romania
+ { "ro", "us", Qt::LeftToRight, QLocale::English, QLocale::Romania },
+ // name = ro:de, description = Romania
+ { "ro", "de", Qt::LeftToRight, QLocale::German, QLocale::Romania },
+ // name = ru, description = Russia
+ { "ru", "", Qt::LeftToRight, QLocale::Russian, QLocale::RussianFederation },
+ // name = ru:phonetic, description = Russia
+ { "ru", "phonetic", Qt::LeftToRight, QLocale::Russian, QLocale::RussianFederation },
+ // name = ru:typewriter, description = Russia
+ { "ru", "typewriter", Qt::LeftToRight, QLocale::Russian, QLocale::RussianFederation },
+ // name = ru:winkeys, description = Russia
+ { "ru", "winkeys", Qt::LeftToRight, QLocale::Russian, QLocale::RussianFederation },
+ // name = srp, description = Serbian
+ { "srp", "", Qt::LeftToRight, QLocale::Serbian, QLocale::SerbiaAndMontenegro },
+ // name = srp:yz, description = Serbian
+ { "srp", "yz", Qt::LeftToRight, QLocale::Serbian, QLocale::SerbiaAndMontenegro },
+ // name = srp:latin, description = Serbian
+ { "srp", "latin", Qt::LeftToRight, QLocale::Serbian, QLocale::SerbiaAndMontenegro },
+ // name = srp:latinunicode, description = Serbian
+ { "srp", "latinunicode", Qt::LeftToRight, QLocale::Serbian, QLocale::SerbiaAndMontenegro },
+ // name = srp:latinyz, description = Serbian
+ { "srp", "latinyz", Qt::LeftToRight, QLocale::Serbian, QLocale::SerbiaAndMontenegro },
+ // name = srp:latinunicodeyz, description = Serbian
+ { "srp", "latinunicodeyz", Qt::LeftToRight, QLocale::Serbian, QLocale::SerbiaAndMontenegro },
+ // name = srp:alternatequotes, description = Serbian
+ { "srp", "alternatequotes", Qt::LeftToRight, QLocale::Serbian, QLocale::SerbiaAndMontenegro },
+ // name = srp:latinalternatequotes, description = Serbian
+ { "srp", "latinalternatequotes", Qt::LeftToRight, QLocale::Serbian, QLocale::SerbiaAndMontenegro },
+ // name = si, description = Slovenia
+ { "si", "", Qt::LeftToRight, QLocale::Slovenian, QLocale::Slovenia },
+ // name = sk, description = Slovakia
+ { "sk", "", Qt::LeftToRight, QLocale::Slovak, QLocale::Slovakia },
+ // name = sk:bksl, description = Slovakia
+ { "sk", "bksl", Qt::LeftToRight, QLocale::Slovak, QLocale::Slovakia },
+ // name = sk:qwerty, description = Slovakia
+ { "sk", "qwerty", Qt::LeftToRight, QLocale::Slovak, QLocale::Slovakia },
+ // name = sk:qwerty_bksl, description = Slovakia
+ { "sk", "qwerty_bksl", Qt::LeftToRight, QLocale::Slovak, QLocale::Slovakia },
+ // name = es, description = Spain
+ { "es", "", Qt::LeftToRight, QLocale::Spanish, QLocale::Spain },
+ // name = es:nodeadkeys, description = Spain
+ { "es", "nodeadkeys", Qt::LeftToRight, QLocale::Spanish, QLocale::Spain },
+ // name = es:sundeadkeys, description = Spain
+ { "es", "sundeadkeys", Qt::LeftToRight, QLocale::Spanish, QLocale::Spain },
+ // name = es:dvorak, description = Spain
+ { "es", "dvorak", Qt::LeftToRight, QLocale::Spanish, QLocale::Spain },
+ // name = se, description = Sweden
+ { "se", "", Qt::LeftToRight, QLocale::Swedish, QLocale::Sweden },
+ // name = se:nodeadkeys, description = Sweden
+ { "se", "nodeadkeys", Qt::LeftToRight, QLocale::Swedish, QLocale::Sweden },
+ // name = se:dvorak, description = Sweden
+ { "se", "dvorak", Qt::LeftToRight, QLocale::Swedish, QLocale::Sweden },
+ // name = se:rus, description = Sweden
+ { "se", "rus", Qt::LeftToRight, QLocale::Russian, QLocale::Sweden },
+ // name = se:rus_nodeadkeys, description = Sweden
+ { "se", "rus_nodeadkeys", Qt::LeftToRight, QLocale::Russian, QLocale::Sweden },
+ // name = se:smi, description = Sweden
+ { "se", "smi", Qt::LeftToRight, QLocale::Swedish, QLocale::Sweden },
+ // name = ch, description = Switzerland
+ { "ch", "", Qt::LeftToRight, QLocale::German, QLocale::Switzerland },
+ // name = ch:de_nodeadkeys, description = Switzerland
+ { "ch", "de_nodeadkeys", Qt::LeftToRight, QLocale::German, QLocale::Switzerland },
+ // name = ch:de_sundeadkeys, description = Switzerland
+ { "ch", "de_sundeadkeys", Qt::LeftToRight, QLocale::German, QLocale::Switzerland },
+ // name = ch:fr, description = Switzerland
+ { "ch", "fr", Qt::LeftToRight, QLocale::French, QLocale::Switzerland },
+ // name = ch:fr_nodeadkeys, description = Switzerland
+ { "ch", "fr_nodeadkeys", Qt::LeftToRight, QLocale::French, QLocale::Switzerland },
+ // name = ch:fr_sundeadkeys, description = Switzerland
+ { "ch", "fr_sundeadkeys", Qt::LeftToRight, QLocale::French, QLocale::Switzerland },
+ // name = sy, description = Syria
+ { "sy", "", Qt::RightToLeft, QLocale::Syriac, QLocale::SyrianArabRepublic },
+ // name = sy:syc, description = Syria
+ { "sy", "syc", Qt::RightToLeft, QLocale::Syriac, QLocale::SyrianArabRepublic },
+ // name = sy:syc_phonetic, description = Syria
+ { "sy", "syc_phonetic", Qt::RightToLeft, QLocale::Syriac, QLocale::SyrianArabRepublic },
+ // name = tj, description = Tajikistan
+ { "tj", "", Qt::LeftToRight, QLocale::Tajik, QLocale::Tajikistan },
+ // name = lk, description = Sri Lanka
+ { "lk", "", Qt::LeftToRight, QLocale::Singhalese, QLocale::SriLanka },
+ // name = lk:tam_unicode, description = Sri Lanka
+ { "lk", "tam_unicode", Qt::LeftToRight, QLocale::Tamil, QLocale::SriLanka },
+ // name = lk:tam_TAB, description = Sri Lanka
+ { "lk", "tam_TAB", Qt::LeftToRight, QLocale::Tamil, QLocale::SriLanka },
+ // name = lk:tam_TSCII, description = Sri Lanka
+ { "lk", "tam_TSCII", Qt::LeftToRight, QLocale::Tamil, QLocale::SriLanka },
+ // name = lk:sin_phonetic, description = Sri Lanka
+ { "lk", "sin_phonetic", Qt::LeftToRight, QLocale::Singhalese, QLocale::SriLanka },
+ // name = th, description = Thailand
+ { "th", "", Qt::LeftToRight, QLocale::Thai, QLocale::Thailand },
+ // name = th:tis, description = Thailand
+ { "th", "tis", Qt::LeftToRight, QLocale::Thai, QLocale::Thailand },
+ // name = th:pat, description = Thailand
+ { "th", "pat", Qt::LeftToRight, QLocale::Thai, QLocale::Thailand },
+ // name = tr, description = Turkish
+ { "tr", "", Qt::LeftToRight, QLocale::Turkish, QLocale::Turkey },
+ // name = tr:f, description = Turkish
+ { "tr", "f", Qt::LeftToRight, QLocale::Turkish, QLocale::Turkey },
+ // name = tr:alt, description = Turkish
+ { "tr", "alt", Qt::LeftToRight, QLocale::Turkish, QLocale::Turkey },
+ // name = ua, description = Ukraine
+ { "ua", "", Qt::LeftToRight, QLocale::Ukrainian, QLocale::Ukraine },
+ // name = ua:phonetic, description = Ukraine
+ { "ua", "phonetic", Qt::LeftToRight, QLocale::Ukrainian, QLocale::Ukraine },
+ // name = ua:typewriter, description = Ukraine
+ { "ua", "typewriter", Qt::LeftToRight, QLocale::Ukrainian, QLocale::Ukraine },
+ // name = ua:winkeys, description = Ukraine
+ { "ua", "winkeys", Qt::LeftToRight, QLocale::Ukrainian, QLocale::Ukraine },
+ // name = ua:rstu, description = Ukraine
+ { "ua", "rstu", Qt::LeftToRight, QLocale::Ukrainian, QLocale::Ukraine },
+ // name = ua:rstu_ru, description = Ukraine
+ { "ua", "rstu_ru", Qt::LeftToRight, QLocale::Ukrainian, QLocale::Ukraine },
+ // name = gb, description = United Kingdom
+ { "gb", "", Qt::LeftToRight, QLocale::English, QLocale::UnitedKingdom },
+ // name = gb:intl, description = United Kingdom
+ { "gb", "intl", Qt::LeftToRight, QLocale::English, QLocale::UnitedKingdom },
+ // name = gb:dvorak, description = United Kingdom
+ { "gb", "dvorak", Qt::LeftToRight, QLocale::English, QLocale::UnitedKingdom },
+ // name = uz, description = Uzbekistan
+ { "uz", "", Qt::LeftToRight, QLocale::Uzbek, QLocale::Uzbekistan },
+ // name = vn, description = Vietnam
+ { "vn", "", Qt::LeftToRight, QLocale::Vietnamese, QLocale::VietNam },
+ // name = nec_vndr/jp, description = PC-98xx Series
+ { "nec_vndr/jp", "", Qt::LeftToRight, QLocale::Japanese, QLocale::Japan },
+ // name = ie, description = Ireland
+ { "ie", "", Qt::LeftToRight, QLocale::Irish, QLocale::Ireland },
+ // name = ie:CloGaelach, description = Ireland
+ { "ie", "CloGaelach", Qt::LeftToRight, QLocale::Gaelic, QLocale::Ireland },
+ // name = ie:UnicodeExpert, description = Ireland
+ { "ie", "UnicodeExpert", Qt::LeftToRight, QLocale::Irish, QLocale::Ireland },
+ // name = ie:ogam, description = Ireland
+ { "ie", "ogam", Qt::LeftToRight, QLocale::Gaelic, QLocale::Ireland },
+ // name = ie:ogam_is434, description = Ireland
+ { "ie", "ogam_is434", Qt::LeftToRight, QLocale::Gaelic, QLocale::Ireland },
+ // name = pk, description = Pakistan
+ { "pk", "", Qt::RightToLeft, QLocale::Urdu, QLocale::Pakistan },
+ { 0, 0, Qt::LeftToRight, QLocale::C, QLocale::AnyCountry }
+};
diff --git a/src/widgets/platforms/x11/qmotifdnd_x11.cpp b/src/widgets/platforms/x11/qmotifdnd_x11.cpp
new file mode 100644
index 0000000000..eef4cc470b
--- /dev/null
+++ b/src/widgets/platforms/x11/qmotifdnd_x11.cpp
@@ -0,0 +1,1031 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+/* The following copyright notice pertains to the code as contributed
+to Qt, not to Nokia's modifications. It is replicated
+in doc/dnd.doc, where the documentation system can see it. */
+
+/* Copyright 1996 Daniel Dardailler.
+
+ Permission to use, copy, modify, distribute, and sell this software
+ for any purpose is hereby granted without fee, 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 Daniel Dardailler not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission. Daniel Dardailler makes no representations
+ about the suitability of this software for any purpose. It is
+ provided "as is" without express or implied warranty.
+
+ Modifications Copyright 1999 Matt Koss, under the same license as
+ above.
+************************************************************/
+
+/***********************************************************/
+/* Motif Drag&Drop Dynamic Protocol messaging API code */
+/* Only requires Xlib layer - not MT safe */
+/* Author: Daniel Dardailler, daniel@x.org */
+/* Adapted by: Matt Koss, koss@napri.sk */
+/* Further adaptions by: Nokia Corporation and/or its subsidiary(-ies) */
+/***********************************************************/
+
+#include "qplatformdefs.h"
+
+#include "qapplication.h"
+
+#ifndef QT_NO_DRAGANDDROP
+
+#include "qdebug.h"
+#include "qtextcodec.h"
+#include "qwidget.h"
+#include "qevent.h"
+#include "qt_x11_p.h"
+#include "qx11info_x11.h"
+#include "qiodevice.h"
+#include "qdnd_p.h"
+
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+static Window sourceWindow = XNone;
+static QWidget *dropWidget = 0;
+static Qt::DropAction lastAcceptedAction = Qt::IgnoreAction;
+
+static Atom Dnd_selection = 0;
+static Time Dnd_selection_time;
+
+static Atom * src_targets ;
+static ushort num_src_targets ;
+
+// Motif definitions
+#define DndVersion 1
+#define DndRevision 0
+#define DndIncludeVersion (DndVersion * 10 + DndRevision)
+
+/* The following values are used in the DndData structure */
+
+/* protocol style */
+#define DND_DRAG_NONE 0
+#define DND_DRAG_DROP_ONLY 1
+#define DND_DRAG_DYNAMIC 5
+
+/* message type */
+#define DND_TOP_LEVEL_ENTER 0
+#define DND_TOP_LEVEL_LEAVE 1
+#define DND_DRAG_MOTION 2
+#define DND_DROP_SITE_ENTER 3
+#define DND_DROP_SITE_LEAVE 4
+#define DND_DROP_START 5
+#define DND_OPERATION_CHANGED 8
+
+/* operation(s) */
+#define DND_NOOP 0L
+#define DND_MOVE (1L << 0)
+#define DND_COPY (1L << 1)
+#define DND_LINK (1L << 2)
+
+static Qt::DropActions DndOperationsToQtDropActions(uchar op)
+{
+ Qt::DropActions actions = Qt::IgnoreAction;
+ if (op | DND_MOVE)
+ actions |= Qt::MoveAction;
+ if (op | DND_COPY)
+ actions |= Qt::CopyAction;
+ if (op | DND_LINK)
+ actions |= Qt::LinkAction;
+ return actions;
+}
+
+static uchar QtDropActionToDndOperation(Qt::DropAction action)
+{
+ switch (action & Qt::ActionMask) {
+ case Qt::CopyAction:
+ default:
+ return DND_COPY;
+ case Qt::MoveAction:
+ return DND_MOVE;
+ case Qt::LinkAction:
+ return DND_LINK;
+ }
+}
+
+
+/* status */
+#define DND_NO_DROP_SITE 1
+#define DND_INVALID_DROP_SITE 2
+#define DND_VALID_DROP_SITE 3
+
+/* completion */
+#define DND_DROP 0
+#define DND_DROP_HELP 1
+#define DND_DROP_CANCEL 2
+
+#define BYTE unsigned char
+#define CARD32 unsigned int
+#define CARD16 unsigned short
+#define INT16 signed short
+
+/* Client side structure used in the API */
+typedef struct {
+ unsigned char reason; /* message type: DND_TOP_LEVEL_ENTER, etc */
+ Time time ;
+ unsigned char operation;
+ unsigned char operations;
+ unsigned char status;
+ unsigned char completion;
+ short x ;
+ short y ;
+ Window src_window ;
+ Atom property ;
+} DndData ;
+
+
+typedef struct _DndSrcProp {
+ BYTE byte_order ;
+ BYTE protocol_version ;
+ CARD16 target_index ;
+ CARD32 selection ;
+} DndSrcProp ;
+
+typedef struct _DndReceiverProp {
+ BYTE byte_order ;
+ BYTE protocol_version ;
+ BYTE protocol_style ;
+ BYTE pad1;
+ CARD32 proxy_window;
+ CARD16 num_drop_sites ;
+ CARD16 pad2;
+ CARD32 total_size;
+} DndReceiverProp ;
+
+/* need to use some union hack since window and property are in
+ different order depending on the message ... */
+typedef struct _DndTop {
+ CARD32 src_window;
+ CARD32 property;
+} DndTop ;
+
+typedef struct _DndPot {
+ INT16 x;
+ INT16 y;
+ CARD32 property;
+ CARD32 src_window;
+} DndPot ;
+
+typedef struct _DndMessage {
+ BYTE reason;
+ BYTE byte_order;
+ CARD16 flags;
+ CARD32 time;
+ union {
+ DndTop top ;
+ DndPot pot ;
+ } data ;
+} DndMessage ;
+
+typedef struct {
+ BYTE byte_order;
+ BYTE protocol_version;
+ CARD16 num_target_lists;
+ CARD32 data_size;
+ /* then come series of CARD16,CARD32,CARD32,CARD32... */
+} DndTargets;
+
+
+/* protocol version */
+#define DND_PROTOCOL_VERSION 0
+
+
+#define DND_EVENT_TYPE_MASK ((BYTE)0x80)
+#define DND_EVENT_TYPE_SHIFT 7
+#define DND_CLEAR_EVENT_TYPE ((BYTE)0x7F)
+
+/* message_type is data[0] of the client_message
+ this return 1 (receiver bit up) or 0 (initiator) */
+#define DND_GET_EVENT_TYPE(message_type) \
+((char) (((message_type) & DND_EVENT_TYPE_MASK) >> DND_EVENT_TYPE_SHIFT))
+
+/* event_type can be 0 (initiator) or 1 (receiver) */
+#define DND_SET_EVENT_TYPE(event_type) \
+(((BYTE)(event_type) << DND_EVENT_TYPE_SHIFT) & DND_EVENT_TYPE_MASK)
+
+
+#define DND_OPERATION_MASK ((CARD16) 0x000F)
+#define DND_OPERATION_SHIFT 0
+#define DND_STATUS_MASK ((CARD16) 0x00F0)
+#define DND_STATUS_SHIFT 4
+#define DND_OPERATIONS_MASK ((CARD16) 0x0F00)
+#define DND_OPERATIONS_SHIFT 8
+#define DND_COMPLETION_MASK ((CARD16) 0xF000)
+#define DND_COMPLETION_SHIFT 12
+
+#define DND_GET_OPERATION(flags) \
+((unsigned char) \
+(((flags) & DND_OPERATION_MASK) >> DND_OPERATION_SHIFT))
+
+#define DND_SET_OPERATION(operation) \
+(((CARD16)(operation) << DND_OPERATION_SHIFT)\
+& DND_OPERATION_MASK)
+
+#define DND_GET_STATUS(flags) \
+((unsigned char) \
+(((flags) & DND_STATUS_MASK) >> DND_STATUS_SHIFT))
+
+#define DND_SET_STATUS(status) \
+(((CARD16)(status) << DND_STATUS_SHIFT)\
+& DND_STATUS_MASK)
+
+#define DND_GET_OPERATIONS(flags) \
+((unsigned char) \
+(((flags) & DND_OPERATIONS_MASK) >> DND_OPERATIONS_SHIFT))
+
+#define DND_SET_OPERATIONS(operation) \
+(((CARD16)(operation) << DND_OPERATIONS_SHIFT)\
+& DND_OPERATIONS_MASK)
+
+#define DND_GET_COMPLETION(flags) \
+((unsigned char) \
+(((flags) & DND_COMPLETION_MASK) >> DND_COMPLETION_SHIFT))
+
+#define DND_SET_COMPLETION(completion) \
+(((CARD16)(completion) << DND_COMPLETION_SHIFT)\
+& DND_COMPLETION_MASK)
+
+
+#define SWAP4BYTES(l) {\
+struct { unsigned t :32;} bit32;\
+char n, *tp = (char *) &bit32;\
+bit32.t = l;\
+n = tp[0]; tp[0] = tp[3]; tp[3] = n;\
+n = tp[1]; tp[1] = tp[2]; tp[2] = n;\
+l = bit32.t;\
+}
+
+#define SWAP2BYTES(s) {\
+struct { unsigned t :16; } bit16;\
+char n, *tp = (char *) &bit16;\
+bit16.t = s;\
+n = tp[0]; tp[0] = tp[1]; tp[1] = n;\
+s = bit16.t;\
+}
+
+
+/** Private extern functions */
+
+static unsigned char DndByteOrder ();
+
+
+/***** Targets/Index stuff */
+
+typedef struct {
+ int num_targets;
+ Atom *targets;
+} DndTargetsTableEntryRec, * DndTargetsTableEntry;
+
+typedef struct {
+ int num_entries;
+ DndTargetsTableEntry entries;
+} DndTargetsTableRec, * DndTargetsTable;
+
+
+static ushort _DndIndexToTargets(Display * display,
+ int index,
+ Atom ** targets);
+
+extern void qt_x11_intern_atom(const char *, Atom *);
+
+/////////////////////////////////////////////////////////////////
+
+static unsigned char DndByteOrder ()
+{
+ static unsigned char byte_order = 0;
+
+ if (!byte_order) {
+ unsigned int endian = 1;
+ byte_order = (*((char *)&endian))?'l':'B';
+ }
+ return byte_order ;
+}
+
+
+
+static void DndReadSourceProperty(Display * dpy,
+ Window window, Atom dnd_selection,
+ Atom ** targets, unsigned short * num_targets)
+{
+ unsigned char *retval = 0;
+ Atom type ;
+ int format ;
+ unsigned long bytesafter, lengthRtn;
+
+ if ((XGetWindowProperty (dpy, window, dnd_selection, 0L, 100000L,
+ False, ATOM(_MOTIF_DRAG_INITIATOR_INFO), &type,
+ &format, &lengthRtn, &bytesafter,
+ &retval) != Success)
+ || (type == XNone)) {
+ *num_targets = 0;
+ return ;
+ }
+
+ DndSrcProp * src_prop = (DndSrcProp *)retval;
+
+ if (src_prop->byte_order != DndByteOrder()) {
+ SWAP2BYTES(src_prop->target_index);
+ SWAP4BYTES(src_prop->selection);
+ }
+
+ *num_targets = _DndIndexToTargets(dpy, src_prop->target_index, targets);
+
+ XFree((char*)src_prop);
+}
+
+
+/* Position the _MOTIF_DRAG_RECEIVER_INFO property on the dropsite window.
+ Called by the receiver of the drop to indicate the
+ supported protocol style : dynamic, drop_only or none */
+static void DndWriteReceiverProperty(Display * dpy, Window window,
+ unsigned char protocol_style)
+{
+ DndReceiverProp receiver_prop;
+
+ // squelch potential valgrind errors about uninitialized reads
+ memset(&receiver_prop, 0, sizeof(receiver_prop));
+
+ receiver_prop.byte_order = DndByteOrder() ;
+ receiver_prop.protocol_version = DND_PROTOCOL_VERSION;
+ receiver_prop.protocol_style = protocol_style ;
+ receiver_prop.proxy_window = XNone ;
+ receiver_prop.num_drop_sites = 0 ;
+ receiver_prop.total_size = sizeof(DndReceiverProp);
+
+ /* write the buffer to the property */
+ XChangeProperty (dpy, window, ATOM(_MOTIF_DRAG_RECEIVER_INFO), ATOM(_MOTIF_DRAG_RECEIVER_INFO),
+ 8, PropModeReplace,
+ (unsigned char *)&receiver_prop,
+ sizeof(DndReceiverProp));
+}
+
+
+/* protocol style equiv (preregister stuff really) */
+#define DND_DRAG_DROP_ONLY_EQUIV 3
+#define DND_DRAG_DYNAMIC_EQUIV1 2
+#define DND_DRAG_DYNAMIC_EQUIV2 4
+
+
+/* Produce a client message to be sent by the caller */
+static void DndFillClientMessage(Display * dpy, Window window,
+ XClientMessageEvent *cm,
+ DndData * dnd_data,
+ char receiver)
+{
+ DndMessage * dnd_message = (DndMessage*)&cm->data.b[0] ;
+
+ cm->display = dpy;
+ cm->type = ClientMessage;
+ cm->serial = LastKnownRequestProcessed(dpy);
+ cm->send_event = True;
+ cm->window = window;
+ cm->format = 8;
+ cm->message_type = ATOM(_MOTIF_DRAG_AND_DROP_MESSAGE);
+
+ dnd_message->reason = dnd_data->reason | DND_SET_EVENT_TYPE(receiver);
+
+ dnd_message->byte_order = DndByteOrder();
+
+ /* we're filling in flags with more stuff that necessary,
+ depending on the reason, but it doesn't matter */
+ dnd_message->flags = 0 ;
+ dnd_message->flags |= DND_SET_STATUS(dnd_data->status) ;
+ dnd_message->flags |= DND_SET_OPERATION(dnd_data->operation) ;
+ dnd_message->flags |= DND_SET_OPERATIONS(dnd_data->operations) ;
+ dnd_message->flags |= DND_SET_COMPLETION(dnd_data->completion) ;
+
+ dnd_message->time = dnd_data->time ;
+
+ switch(dnd_data->reason) {
+ case DND_DROP_SITE_LEAVE: break ;
+ case DND_TOP_LEVEL_ENTER:
+ case DND_TOP_LEVEL_LEAVE:
+ dnd_message->data.top.src_window = dnd_data->src_window ;
+ dnd_message->data.top.property = dnd_data->property ;
+ break ; /* cannot fall through since the byte layout is different in
+ both set of messages, see top and pot union stuff */
+
+ case DND_DRAG_MOTION:
+ case DND_OPERATION_CHANGED:
+ case DND_DROP_SITE_ENTER:
+ case DND_DROP_START:
+ dnd_message->data.pot.x = dnd_data->x ; /* mouse position */
+ dnd_message->data.pot.y = dnd_data->y ;
+ dnd_message->data.pot.src_window = dnd_data->src_window ;
+ dnd_message->data.pot.property = dnd_data->property ;
+ break ;
+ default:
+ break ;
+ }
+
+}
+
+static Bool DndParseClientMessage(XClientMessageEvent *cm, DndData * dnd_data,
+ char * receiver)
+{
+ DndMessage * dnd_message = (DndMessage*)&cm->data.b[0] ;
+
+ if (cm->message_type != ATOM(_MOTIF_DRAG_AND_DROP_MESSAGE)) {
+ return False ;
+ }
+
+ if (dnd_message->byte_order != DndByteOrder()) {
+ SWAP2BYTES(dnd_message->flags);
+ SWAP4BYTES(dnd_message->time);
+ } /* do the rest in the switch */
+
+ dnd_data->reason = dnd_message->reason ;
+ if (DND_GET_EVENT_TYPE(dnd_data->reason))
+ *receiver = 1 ;
+ else
+ *receiver = 0 ;
+ dnd_data->reason &= DND_CLEAR_EVENT_TYPE ;
+
+ dnd_data->time = dnd_message->time ;
+
+ /* we're reading in more stuff that necessary. but who cares */
+ dnd_data->status = DND_GET_STATUS(dnd_message->flags) ;
+ dnd_data->operation = DND_GET_OPERATION(dnd_message->flags) ;
+ dnd_data->operations = DND_GET_OPERATIONS(dnd_message->flags) ;
+ dnd_data->completion = DND_GET_COMPLETION(dnd_message->flags) ;
+
+ switch(dnd_data->reason) {
+ case DND_TOP_LEVEL_ENTER:
+ case DND_TOP_LEVEL_LEAVE:
+ if (dnd_message->byte_order != DndByteOrder()) {
+ SWAP4BYTES(dnd_message->data.top.src_window);
+ SWAP4BYTES(dnd_message->data.top.property);
+ }
+ dnd_data->src_window = dnd_message->data.top.src_window ;
+ dnd_data->property = dnd_message->data.top.property ;
+ break ; /* cannot fall through, see above comment in write msg */
+
+ case DND_DRAG_MOTION:
+ case DND_OPERATION_CHANGED:
+ case DND_DROP_SITE_ENTER:
+ case DND_DROP_START:
+ if (dnd_message->byte_order != DndByteOrder()) {
+ SWAP2BYTES(dnd_message->data.pot.x);
+ SWAP2BYTES(dnd_message->data.pot.y);
+ SWAP4BYTES(dnd_message->data.pot.property);
+ SWAP4BYTES(dnd_message->data.pot.src_window);
+ }
+ dnd_data->x = dnd_message->data.pot.x ;
+ dnd_data->y = dnd_message->data.pot.y ;
+ dnd_data->property = dnd_message->data.pot.property ;
+ dnd_data->src_window = dnd_message->data.pot.src_window ;
+ break ;
+
+ case DND_DROP_SITE_LEAVE:
+ break;
+ default:
+ break ;
+ }
+
+ return True ;
+}
+
+
+static Window MotifWindow(Display *display)
+{
+ Atom type;
+ int format;
+ unsigned long size;
+ unsigned long bytes_after;
+ unsigned char *property = 0;
+ Window motif_window ;
+
+ /* this version does no caching, so it's slow: round trip each time */
+
+ if ((XGetWindowProperty (display, RootWindow(display, 0),
+ ATOM(_MOTIF_DRAG_WINDOW),
+ 0L, 100000L, False, AnyPropertyType,
+ &type, &format, &size, &bytes_after,
+ &property) == Success) &&
+ (type != XNone)) {
+ motif_window = *(Window *)property;
+ } else {
+ XSetWindowAttributes sAttributes;
+
+ /* really, this should be done on a separate connection,
+ with XSetCloseDownMode (RetainPermanent), so that
+ others don't have to recreate it; hopefully, some real
+ Motif application will be around to do it */
+
+ sAttributes.override_redirect = True;
+ sAttributes.event_mask = PropertyChangeMask;
+ motif_window = XCreateWindow (display,
+ RootWindow (display, 0),
+ -170, -560, 1, 1, 0, 0,
+ InputOnly, CopyFromParent,
+ (CWOverrideRedirect |CWEventMask),
+ &sAttributes);
+ XMapWindow (display, motif_window);
+ }
+
+ if (property) {
+ XFree ((char *)property);
+ }
+
+ return (motif_window);
+}
+
+
+static DndTargetsTable TargetsTable(Display *display)
+{
+ Atom type;
+ int format;
+ unsigned long size;
+ unsigned long bytes_after;
+ Window motif_window = MotifWindow(display) ;
+ unsigned char *retval;
+ DndTargetsTable targets_table ;
+ int i,j ;
+ char * target_data ;
+
+ /* this version does no caching, so it's slow: round trip each time */
+ /* ideally, register for property notify on this target_list
+ atom and update when necessary only */
+
+ if ((XGetWindowProperty (display, motif_window,
+ ATOM(_MOTIF_DRAG_TARGETS), 0L, 100000L,
+ False, ATOM(_MOTIF_DRAG_TARGETS),
+ &type, &format, &size, &bytes_after,
+ &retval) != Success) ||
+ type == XNone) {
+ qWarning("QMotifDND: Cannot get property on Motif window");
+ return 0;
+ }
+
+ DndTargets * target_prop = (DndTargets *)retval;
+
+ if (target_prop->protocol_version != DND_PROTOCOL_VERSION) {
+ qWarning("QMotifDND: Protocol mismatch");
+ }
+
+ if (target_prop->byte_order != DndByteOrder()) {
+ /* need to swap num_target_lists and size */
+ SWAP2BYTES(target_prop->num_target_lists);
+ SWAP4BYTES(target_prop->data_size);
+ }
+
+ /* now parse DndTarget prop data in a TargetsTable */
+
+ targets_table = (DndTargetsTable)malloc(sizeof(DndTargetsTableRec));
+ targets_table->num_entries = target_prop->num_target_lists ;
+ targets_table->entries = (DndTargetsTableEntry)
+ malloc(sizeof(DndTargetsTableEntryRec) * target_prop->num_target_lists);
+
+ target_data = (char*)target_prop + sizeof(*target_prop) ;
+
+ for (i = 0 ; i < targets_table->num_entries; i++) {
+ CARD16 num_targets ;
+ CARD32 atom ;
+
+ memcpy(&num_targets, target_data, 2);
+ target_data += 2;
+
+ /* potential swap needed here */
+ if (target_prop->byte_order != DndByteOrder())
+ SWAP2BYTES(num_targets);
+
+ targets_table->entries[i].num_targets = num_targets ;
+ targets_table->entries[i].targets = (Atom *)
+ malloc(sizeof(Atom) * targets_table->entries[i].num_targets);
+
+
+ for (j = 0; j < num_targets; j++) {
+ memcpy(&atom, target_data, 4);
+ target_data += 4;
+
+ /* another potential swap needed here */
+ if (target_prop->byte_order != DndByteOrder())
+ SWAP4BYTES(atom);
+
+ targets_table->entries[i].targets[j] = (Atom) atom ;
+ }
+ }
+
+ if (target_prop) {
+ XFree((char *)target_prop);
+ }
+
+ return targets_table ;
+}
+
+
+static ushort _DndIndexToTargets(Display * display,
+ int index,
+ Atom ** targets)
+{
+ DndTargetsTable targets_table;
+ int i ;
+
+ /* again, slow: no caching here, alloc/free each time */
+
+ if (!(targets_table = TargetsTable (display)) ||
+ (index >= targets_table->num_entries)) {
+ if (targets_table)
+ XFree((char*)targets_table);
+ return 0;
+ }
+
+ /* transfer the correct target list index */
+ *targets = (Atom*)malloc(sizeof(Atom)*targets_table->
+ entries[index].num_targets);
+ memcpy((char*)*targets,
+ (char*)targets_table->entries[index].targets,
+ sizeof(Atom)*targets_table->entries[index].num_targets);
+
+ /* free the target table and its guts */
+ for (i=0 ; i < targets_table->num_entries; i++)
+ XFree((char*)targets_table->entries[i].targets);
+
+ int tmp = targets_table->entries[index].num_targets;
+ XFree((char*)targets_table);
+
+ return tmp; // targets_table->entries[index].num_targets;
+}
+
+
+QByteArray QX11Data::motifdndFormat(int n)
+{
+ if (!motifdnd_active)
+ return 0; // should not happen
+
+ if (n >= num_src_targets)
+ return 0;
+
+ Atom target = src_targets[n];
+
+ if (target == XA_STRING)
+ return "text/plain;charset=ISO-8859-1";
+ if (target == ATOM(UTF8_STRING))
+ return "text/plain;charset=UTF-8";
+ if (target == ATOM(COMPOUND_TEXT))
+ return QByteArray("text/plain;charset=") + QTextCodec::codecForLocale()->name();
+ if (target == ATOM(TEXT))
+ return "text/plain";
+
+ return ("x-motif-dnd/" + X11->xdndAtomToString(target));
+}
+
+
+QVariant QX11Data::motifdndObtainData(const char *mimeType)
+{
+ QByteArray result;
+
+ if (Dnd_selection == 0 || !dropWidget)
+ return result;
+
+ // try to convert the selection to the requested property
+ // qDebug("trying to convert to '%s'", mimeType);
+
+ int n=0;
+ QByteArray f;
+ do {
+ f = motifdndFormat(n);
+ if (f.isEmpty())
+ return result;
+ n++;
+ } while(qstricmp(mimeType, f.data()));
+
+ Atom conversion_type = XNone;
+ if (f == "text/plain;charset=ISO-8859-1") {
+ conversion_type = XA_STRING;
+ } else if (f == "text/plain;charset=UTF-8") {
+ conversion_type = ATOM(UTF8_STRING);
+ } else if (f == (QByteArray("text/plain;charset=") + QTextCodec::codecForLocale()->name())) {
+ conversion_type = ATOM(COMPOUND_TEXT);
+ } else if (f == "text/plain") {
+ conversion_type = ATOM(TEXT);
+ } else if (f.startsWith("x-motif-dnd/")) {
+ // strip off the "x-motif-dnd/" prefix
+ conversion_type = X11->xdndStringToAtom(f.remove(0, 12));
+ }
+
+ if (XGetSelectionOwner(X11->display, Dnd_selection) == XNone) {
+ return result; // should never happen?
+ }
+
+ QWidget* tw = dropWidget;
+ if ((dropWidget->windowType() == Qt::Desktop)) {
+ tw = new QWidget;
+ }
+
+ // convert selection to the appropriate type
+ XConvertSelection (X11->display, Dnd_selection, conversion_type,
+ Dnd_selection, tw->internalWinId(), Dnd_selection_time);
+
+ XFlush(X11->display);
+
+ XEvent xevent;
+ bool got=X11->clipboardWaitForEvent(tw->internalWinId(), SelectionNotify, &xevent, 5000);
+ if (got) {
+ Atom type;
+
+ if (X11->clipboardReadProperty(tw->internalWinId(), Dnd_selection, true, &result, 0, &type, 0)) {
+ }
+ }
+
+ // we have to convert selection in order to indicate success to the initiator
+ XConvertSelection (X11->display, Dnd_selection, ATOM(XmTRANSFER_SUCCESS),
+ Dnd_selection, tw->internalWinId(), Dnd_selection_time);
+
+ // wait again for SelectionNotify event
+ X11->clipboardWaitForEvent(tw->internalWinId(), SelectionNotify, &xevent, 5000);
+
+ if ((dropWidget->windowType() == Qt::Desktop)) {
+ delete tw;
+ }
+
+ return result;
+}
+
+
+void QX11Data::motifdndEnable(QWidget *widget, bool)
+{
+ DndWriteReceiverProperty(display, widget->internalWinId(), DND_DRAG_DYNAMIC);
+}
+
+
+void QX11Data::motifdndHandle(QWidget *widget, const XEvent * xe, bool /* passive */)
+{
+ XEvent event = *xe;
+ XClientMessageEvent cm ;
+ DndData dnd_data ;
+ char receiver ;
+
+ if (!(DndParseClientMessage ((XClientMessageEvent*)&event,
+ &dnd_data, &receiver))) {
+ return;
+ }
+
+ switch (dnd_data.reason) {
+
+ case DND_DRAG_MOTION:
+ {
+ QPoint p = widget->mapFromGlobal(QPoint(dnd_data.x, dnd_data.y));
+ QWidget *c = widget->childAt(p);
+
+ if (!c || !c->acceptDrops()) {
+ // not over a drop site
+ if (dropWidget) {
+ QDragLeaveEvent dragLeaveEvent;
+ QApplication::sendEvent(dropWidget, &dragLeaveEvent);
+
+ dropWidget = 0;
+ lastAcceptedAction = Qt::IgnoreAction;
+
+ dnd_data.reason = DND_DROP_SITE_LEAVE;
+ dnd_data.time = X11->time;
+ DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver);
+ XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm) ;
+ } else {
+ dnd_data.reason = DND_DRAG_MOTION;
+ dnd_data.status = DND_NO_DROP_SITE;
+ dnd_data.time = X11->time;
+ dnd_data.operation = DND_NOOP;
+ dnd_data.operations = DND_NOOP;
+ DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver);
+ XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm) ;
+ }
+ } else {
+ Q_ASSERT(c != 0);
+ p = c->mapFrom(widget, p);
+
+ if (dropWidget != c) {
+ if (dropWidget) {
+ QDragLeaveEvent le;
+ QApplication::sendEvent(dropWidget, &le);
+ }
+
+ dropWidget = c;
+ lastAcceptedAction = Qt::IgnoreAction;
+
+ const Qt::DropActions possibleActions =
+ DndOperationsToQtDropActions(dnd_data.operations);
+ QDragEnterEvent de(p, possibleActions, QDragManager::self()->dropData,
+ QApplication::mouseButtons(), QApplication::keyboardModifiers());
+ QApplication::sendEvent(dropWidget, &de);
+
+ dnd_data.reason = DND_DROP_SITE_ENTER;
+ dnd_data.time = X11->time;
+ if (de.isAccepted()) {
+ lastAcceptedAction = de.dropAction();
+
+ dnd_data.status = DND_VALID_DROP_SITE;
+ dnd_data.operation = QtDropActionToDndOperation(lastAcceptedAction);
+ } else {
+ dnd_data.status = DND_INVALID_DROP_SITE;
+ dnd_data.operation = DND_NOOP;
+ dnd_data.operations = DND_NOOP;
+ }
+ DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver);
+ XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm);
+ } else {
+ const Qt::DropActions possibleActions =
+ DndOperationsToQtDropActions(dnd_data.operations);
+ QDragMoveEvent me(p, possibleActions, QDragManager::self()->dropData,
+ QApplication::mouseButtons(), QApplication::keyboardModifiers());
+ if (lastAcceptedAction != Qt::IgnoreAction) {
+ me.setDropAction(lastAcceptedAction);
+ me.accept();
+ }
+ QApplication::sendEvent(dropWidget, &me);
+
+ dnd_data.reason = DND_DRAG_MOTION;
+ dnd_data.time = X11->time;
+
+ if (me.isAccepted()) {
+ lastAcceptedAction = me.dropAction();
+
+ dnd_data.status = DND_VALID_DROP_SITE;
+ dnd_data.operation = QtDropActionToDndOperation(lastAcceptedAction);
+ } else {
+ dnd_data.status = DND_INVALID_DROP_SITE;
+ dnd_data.operation = DND_NOOP;
+ dnd_data.operations = DND_NOOP;
+ }
+
+ DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, receiver);
+ XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm);
+ }
+ }
+
+ break;
+ }
+
+ case DND_TOP_LEVEL_ENTER:
+ {
+ /* get the size of our drop site for later use */
+
+ motifdnd_active = true;
+ sourceWindow = dnd_data.src_window;
+
+ /* no answer needed, just read source property */
+ DndReadSourceProperty (event.xclient.display,
+ sourceWindow,
+ dnd_data.property,
+ &src_targets, &num_src_targets);
+
+ break;
+ }
+
+ case DND_TOP_LEVEL_LEAVE:
+ {
+ XEvent nextEvent;
+ if (XCheckTypedWindowEvent(X11->display, widget->winId(), ClientMessage, &nextEvent)) {
+ // we just want to check, not eat (should use XPeekIfEvent)
+ XPutBackEvent(X11->display, &nextEvent);
+
+ if (DndParseClientMessage (&nextEvent.xclient, &dnd_data, &receiver)
+ && dnd_data.reason == DND_DROP_START) {
+ // expecting drop next, keeping DnD alive
+ break;
+ }
+ }
+
+ // not expecting drop, need to send drag leave events and such here
+ if (dropWidget) {
+ QDragLeaveEvent le;
+ QApplication::sendEvent(dropWidget, &le);
+ }
+
+ sourceWindow = XNone;
+ dropWidget = 0;
+ lastAcceptedAction = Qt::IgnoreAction;
+
+ motifdnd_active = false;
+
+ break;
+ }
+
+ case DND_OPERATION_CHANGED:
+ // ### need to echo
+ break;
+
+ case DND_DROP_START:
+ {
+ Q_ASSERT(motifdnd_active);
+ Q_ASSERT(sourceWindow == dnd_data.src_window);
+
+ if (!dropWidget || lastAcceptedAction == Qt::IgnoreAction) {
+ // echo DROP_START
+ dnd_data.reason = DND_DROP_START;
+ dnd_data.status = DND_NO_DROP_SITE;
+ dnd_data.operation = DND_NOOP;
+ dnd_data.operations = DND_NOOP;
+ DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, 0);
+ XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm);
+
+ // we have to convert selection in order to indicate failure to the initiator
+ XConvertSelection (X11->display, dnd_data.property, ATOM(XmTRANSFER_FAILURE),
+ dnd_data.property, dnd_data.src_window, dnd_data.time);
+
+ if (dropWidget) {
+ QDragLeaveEvent e;
+ QApplication::sendEvent(dropWidget, &e);
+ }
+
+ motifdnd_active = false;
+ sourceWindow = XNone;
+ dropWidget = 0;
+ lastAcceptedAction = Qt::IgnoreAction;
+
+ return;
+ }
+
+ // store selection and its time
+ Dnd_selection = dnd_data.property;
+ Dnd_selection_time = dnd_data.time;
+
+ QPoint p(dnd_data.x, dnd_data.y);
+ QDropEvent de(dropWidget->mapFromGlobal(p), Qt::CopyAction, QDragManager::self()->dropData,
+ QApplication::mouseButtons(), QApplication::keyboardModifiers());
+ if (lastAcceptedAction != Qt::IgnoreAction) {
+ de.setDropAction(lastAcceptedAction);
+ de.accept();
+ }
+ QApplication::sendEvent(dropWidget, &de);
+
+ // reset
+ Dnd_selection = XNone;
+ Dnd_selection_time = 0;
+
+ // echo DROP_START depending on the result of the dropEvent
+ if (de.isAccepted()) {
+ dnd_data.reason = DND_DROP_START;
+ dnd_data.status = DND_VALID_DROP_SITE;
+ dnd_data.operation = QtDropActionToDndOperation(de.dropAction());
+ } else {
+ dnd_data.reason = DND_DROP_START;
+ dnd_data.status = DND_NO_DROP_SITE;
+ dnd_data.operation = DND_NOOP;
+ dnd_data.operations = DND_NOOP;
+ }
+ DndFillClientMessage (event.xclient.display, sourceWindow, &cm, &dnd_data, 0);
+ XSendEvent(event.xbutton.display, sourceWindow, False, 0, (XEvent *)&cm);
+
+ sourceWindow = XNone;
+ dropWidget = 0;
+ lastAcceptedAction = Qt::IgnoreAction;
+
+ motifdnd_active = false;
+
+ break;
+ }
+
+ default:
+ break;
+ } // end of switch (dnd_data.reason)
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DRAGANDDROP
diff --git a/src/widgets/platforms/x11/qpaintdevice_x11.cpp b/src/widgets/platforms/x11/qpaintdevice_x11.cpp
new file mode 100644
index 0000000000..690dea99d7
--- /dev/null
+++ b/src/widgets/platforms/x11/qpaintdevice_x11.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qpaintdevice.h"
+#include "qpainter.h"
+#include "qwidget.h"
+#include "qbitmap.h"
+#include "qapplication.h"
+#include <private/qt_x11_p.h>
+#include "qx11info_x11.h"
+
+QT_BEGIN_NAMESPACE
+
+/*! \internal
+
+ Returns the X11 Drawable of the paint device. 0 is returned if it
+ can't be obtained.
+*/
+
+Drawable Q_GUI_EXPORT qt_x11Handle(const QPaintDevice *pd)
+{
+ if (!pd) return 0;
+ if (pd->devType() == QInternal::Widget)
+ return static_cast<const QWidget *>(pd)->handle();
+ else if (pd->devType() == QInternal::Pixmap)
+ return static_cast<const QPixmap *>(pd)->handle();
+ return 0;
+}
+
+/*!
+ \relates QPaintDevice
+
+ Returns the QX11Info structure for the \a pd paint device. 0 is
+ returned if it can't be obtained.
+*/
+const Q_GUI_EXPORT QX11Info *qt_x11Info(const QPaintDevice *pd)
+{
+ if (!pd) return 0;
+ if (pd->devType() == QInternal::Widget)
+ return &static_cast<const QWidget *>(pd)->x11Info();
+ else if (pd->devType() == QInternal::Pixmap)
+ return &static_cast<const QPixmap *>(pd)->x11Info();
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qpaintengine_x11.cpp b/src/widgets/platforms/x11/qpaintengine_x11.cpp
new file mode 100644
index 0000000000..1256996491
--- /dev/null
+++ b/src/widgets/platforms/x11/qpaintengine_x11.cpp
@@ -0,0 +1,2507 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "private/qpixmap_x11_p.h"
+
+#include "qapplication.h"
+#include "qdebug.h"
+#include "qfont.h"
+#include "qwidget.h"
+#include "qbitmap.h"
+#include "qpixmapcache.h"
+#include "qtextcodec.h"
+#include "qcoreevent.h"
+#include "qiodevice.h"
+#include <qmath.h>
+
+#include "qpainter_p.h"
+#include <qtextlayout.h>
+#include <qvarlengtharray.h>
+#include <private/qfont_p.h>
+#include <private/qtextengine_p.h>
+#include <private/qpaintengine_x11_p.h>
+#include <private/qfontengine_x11_p.h>
+#include <private/qwidget_p.h>
+#include <private/qpainterpath_p.h>
+
+#include "qpen.h"
+#include "qcolor.h"
+#include "qcolormap.h"
+
+#include <private/qpaintengine_p.h>
+#include "qpaintengine_x11_p.h"
+
+#include <private/qt_x11_p.h>
+#include <private/qnumeric_p.h>
+#include <limits.h>
+
+#ifndef QT_NO_XRENDER
+#include <private/qtessellator_p.h>
+#endif
+
+#include <private/qhexstring_p.h>
+
+QT_BEGIN_NAMESPACE
+
+extern Drawable qt_x11Handle(const QPaintDevice *pd);
+extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
+extern QPixmap qt_pixmapForBrush(int brushStyle, bool invert); //in qbrush.cpp
+extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap);
+
+// use the same rounding as in qrasterizer.cpp (6 bit fixed point)
+static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
+
+#undef X11 // defined in qt_x11_p.h
+/*!
+ Returns the X11 specific pen GC for the painter \a p. Note that
+ QPainter::begin() must be called before this function returns a
+ valid GC.
+*/
+Q_GUI_EXPORT GC qt_x11_get_pen_gc(QPainter *p)
+{
+ if (p && p->paintEngine()
+ && p->paintEngine()->isActive()
+ && p->paintEngine()->type() == QPaintEngine::X11) {
+ return static_cast<QX11PaintEngine *>(p->paintEngine())->d_func()->gc;
+ }
+ return 0;
+}
+
+/*!
+ Returns the X11 specific brush GC for the painter \a p. Note that
+ QPainter::begin() must be called before this function returns a
+ valid GC.
+*/
+Q_GUI_EXPORT GC qt_x11_get_brush_gc(QPainter *p)
+{
+ if (p && p->paintEngine()
+ && p->paintEngine()->isActive()
+ && p->paintEngine()->type() == QPaintEngine::X11) {
+ return static_cast<QX11PaintEngine *>(p->paintEngine())->d_func()->gc_brush;
+ }
+ return 0;
+}
+#define X11 qt_x11Data
+
+#ifndef QT_NO_XRENDER
+static const int compositionModeToRenderOp[QPainter::CompositionMode_Xor + 1] = {
+ PictOpOver, //CompositionMode_SourceOver,
+ PictOpOverReverse, //CompositionMode_DestinationOver,
+ PictOpClear, //CompositionMode_Clear,
+ PictOpSrc, //CompositionMode_Source,
+ PictOpDst, //CompositionMode_Destination,
+ PictOpIn, //CompositionMode_SourceIn,
+ PictOpInReverse, //CompositionMode_DestinationIn,
+ PictOpOut, //CompositionMode_SourceOut,
+ PictOpOutReverse, //CompositionMode_DestinationOut,
+ PictOpAtop, //CompositionMode_SourceAtop,
+ PictOpAtopReverse, //CompositionMode_DestinationAtop,
+ PictOpXor //CompositionMode_Xor
+};
+
+static inline int qpainterOpToXrender(QPainter::CompositionMode mode)
+{
+ Q_ASSERT(mode <= QPainter::CompositionMode_Xor);
+ return compositionModeToRenderOp[mode];
+}
+#endif
+
+// hack, so we don't have to make QRegion::clipRectangles() public or include
+// X11 headers in qregion.h
+Q_GUI_EXPORT void *qt_getClipRects(const QRegion &r, int &num)
+{
+ return r.clipRectangles(num);
+}
+
+static inline void x11SetClipRegion(Display *dpy, GC gc, GC gc2,
+#ifndef QT_NO_XRENDER
+ Picture picture,
+#else
+ Qt::HANDLE picture,
+#endif
+ const QRegion &r)
+{
+ int num;
+ XRectangle *rects = (XRectangle *)qt_getClipRects(r, num);
+
+ if (gc)
+ XSetClipRectangles( dpy, gc, 0, 0, rects, num, YXBanded );
+ if (gc2)
+ XSetClipRectangles( dpy, gc2, 0, 0, rects, num, YXBanded );
+
+#ifndef QT_NO_XRENDER
+ if (picture)
+ XRenderSetPictureClipRectangles(dpy, picture, 0, 0, rects, num);
+#else
+ Q_UNUSED(picture);
+#endif // QT_NO_XRENDER
+}
+
+
+static inline void x11ClearClipRegion(Display *dpy, GC gc, GC gc2,
+#ifndef QT_NO_XRENDER
+ Picture picture
+#else
+ Qt::HANDLE picture
+#endif
+ )
+{
+ if (gc)
+ XSetClipMask(dpy, gc, XNone);
+ if (gc2)
+ XSetClipMask(dpy, gc2, XNone);
+
+#ifndef QT_NO_XRENDER
+ if (picture) {
+ XRenderPictureAttributes attrs;
+ attrs.clip_mask = XNone;
+ XRenderChangePicture (dpy, picture, CPClipMask, &attrs);
+ }
+#else
+ Q_UNUSED(picture);
+#endif // QT_NO_XRENDER
+}
+
+
+#define DITHER_SIZE 16
+static const uchar base_dither_matrix[DITHER_SIZE][DITHER_SIZE] = {
+ { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
+ { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
+ { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
+ { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
+ { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
+ { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
+ { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
+ { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
+ { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
+ { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
+ { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
+ { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
+ { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
+ { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
+ { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
+ { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
+};
+
+static QPixmap qt_patternForAlpha(uchar alpha, int screen)
+{
+ QPixmap pm;
+ QString key = QLatin1Literal("$qt-alpha-brush$")
+ % HexString<uchar>(alpha)
+ % HexString<int>(screen);
+
+ if (!QPixmapCache::find(key, pm)) {
+ // #### why not use a mono image here????
+ QImage pattern(DITHER_SIZE, DITHER_SIZE, QImage::Format_ARGB32);
+ pattern.fill(0xffffffff);
+ for (int y = 0; y < DITHER_SIZE; ++y) {
+ for (int x = 0; x < DITHER_SIZE; ++x) {
+ if (base_dither_matrix[x][y] <= alpha)
+ pattern.setPixel(x, y, 0x00000000);
+ }
+ }
+ pm = QBitmap::fromImage(pattern);
+ pm.x11SetScreen(screen);
+ QPixmapCache::insert(key, pm);
+ }
+ return pm;
+}
+
+#if !defined(QT_NO_XRENDER)
+
+class QXRenderTessellator : public QTessellator
+{
+public:
+ QXRenderTessellator() : traps(0), allocated(0), size(0) {}
+ ~QXRenderTessellator() { free(traps); }
+ XTrapezoid *traps;
+ int allocated;
+ int size;
+ void addTrap(const Trapezoid &trap);
+ QRect tessellate(const QPointF *points, int nPoints, bool winding) {
+ size = 0;
+ setWinding(winding);
+ return QTessellator::tessellate(points, nPoints).toRect();
+ }
+ void done() {
+ if (allocated > 64) {
+ free(traps);
+ traps = 0;
+ allocated = 0;
+ }
+ }
+};
+
+void QXRenderTessellator::addTrap(const Trapezoid &trap)
+{
+ if (size == allocated) {
+ allocated = qMax(2*allocated, 64);
+ traps = q_check_ptr((XTrapezoid *)realloc(traps, allocated * sizeof(XTrapezoid)));
+ }
+ traps[size].top = Q27Dot5ToXFixed(trap.top);
+ traps[size].bottom = Q27Dot5ToXFixed(trap.bottom);
+ traps[size].left.p1.x = Q27Dot5ToXFixed(trap.topLeft->x);
+ traps[size].left.p1.y = Q27Dot5ToXFixed(trap.topLeft->y);
+ traps[size].left.p2.x = Q27Dot5ToXFixed(trap.bottomLeft->x);
+ traps[size].left.p2.y = Q27Dot5ToXFixed(trap.bottomLeft->y);
+ traps[size].right.p1.x = Q27Dot5ToXFixed(trap.topRight->x);
+ traps[size].right.p1.y = Q27Dot5ToXFixed(trap.topRight->y);
+ traps[size].right.p2.x = Q27Dot5ToXFixed(trap.bottomRight->x);
+ traps[size].right.p2.y = Q27Dot5ToXFixed(trap.bottomRight->y);
+ ++size;
+}
+
+#endif // !defined(QT_NO_XRENDER)
+
+
+#ifndef QT_NO_XRENDER
+static Picture getPatternFill(int screen, const QBrush &b)
+{
+ if (!X11->use_xrender)
+ return XNone;
+
+ XRenderColor color = X11->preMultiply(b.color());
+ XRenderColor bg_color;
+
+ bg_color = X11->preMultiply(QColor(0, 0, 0, 0));
+
+ for (int i = 0; i < X11->pattern_fill_count; ++i) {
+ if (X11->pattern_fills[i].screen == screen
+ && X11->pattern_fills[i].opaque == false
+ && X11->pattern_fills[i].style == b.style()
+ && X11->pattern_fills[i].color.alpha == color.alpha
+ && X11->pattern_fills[i].color.red == color.red
+ && X11->pattern_fills[i].color.green == color.green
+ && X11->pattern_fills[i].color.blue == color.blue
+ && X11->pattern_fills[i].bg_color.alpha == bg_color.alpha
+ && X11->pattern_fills[i].bg_color.red == bg_color.red
+ && X11->pattern_fills[i].bg_color.green == bg_color.green
+ && X11->pattern_fills[i].bg_color.blue == bg_color.blue)
+ return X11->pattern_fills[i].picture;
+ }
+ // none found, replace one
+ int i = qrand() % 16;
+
+ if (X11->pattern_fills[i].screen != screen && X11->pattern_fills[i].picture) {
+ XRenderFreePicture (X11->display, X11->pattern_fills[i].picture);
+ X11->pattern_fills[i].picture = 0;
+ }
+
+ if (!X11->pattern_fills[i].picture) {
+ Pixmap pixmap = XCreatePixmap (X11->display, RootWindow (X11->display, screen), 8, 8, 32);
+ XRenderPictureAttributes attrs;
+ attrs.repeat = True;
+ X11->pattern_fills[i].picture = XRenderCreatePicture (X11->display, pixmap,
+ XRenderFindStandardFormat(X11->display, PictStandardARGB32),
+ CPRepeat, &attrs);
+ XFreePixmap (X11->display, pixmap);
+ }
+
+ X11->pattern_fills[i].screen = screen;
+ X11->pattern_fills[i].color = color;
+ X11->pattern_fills[i].bg_color = bg_color;
+ X11->pattern_fills[i].opaque = false;
+ X11->pattern_fills[i].style = b.style();
+
+ XRenderFillRectangle(X11->display, PictOpSrc, X11->pattern_fills[i].picture, &bg_color, 0, 0, 8, 8);
+
+ QPixmap pattern(qt_pixmapForBrush(b.style(), true));
+ XRenderPictureAttributes attrs;
+ attrs.repeat = true;
+ XRenderChangePicture(X11->display, pattern.x11PictureHandle(), CPRepeat, &attrs);
+
+ Picture fill_fg = X11->getSolidFill(screen, b.color());
+ XRenderComposite(X11->display, PictOpOver, fill_fg, pattern.x11PictureHandle(),
+ X11->pattern_fills[i].picture,
+ 0, 0, 0, 0, 0, 0, 8, 8);
+
+ return X11->pattern_fills[i].picture;
+}
+
+static void qt_render_bitmap(Display *dpy, int scrn, Picture src, Picture dst,
+ int sx, int sy, int x, int y, int sw, int sh,
+ const QPen &pen)
+{
+ Picture fill_fg = X11->getSolidFill(scrn, pen.color());
+ XRenderComposite(dpy, PictOpOver,
+ fill_fg, src, dst, sx, sy, sx, sy, x, y, sw, sh);
+}
+#endif
+
+void QX11PaintEnginePrivate::init()
+{
+ dpy = 0;
+ scrn = 0;
+ hd = 0;
+ picture = 0;
+ xinfo = 0;
+#ifndef QT_NO_XRENDER
+ current_brush = 0;
+ composition_mode = PictOpOver;
+ tessellator = new QXRenderTessellator;
+#endif
+}
+
+void QX11PaintEnginePrivate::setupAdaptedOrigin(const QPoint &p)
+{
+ if (adapted_pen_origin)
+ XSetTSOrigin(dpy, gc, p.x(), p.y());
+ if (adapted_brush_origin)
+ XSetTSOrigin(dpy, gc_brush, p.x(), p.y());
+}
+
+void QX11PaintEnginePrivate::resetAdaptedOrigin()
+{
+ if (adapted_pen_origin)
+ XSetTSOrigin(dpy, gc, 0, 0);
+ if (adapted_brush_origin)
+ XSetTSOrigin(dpy, gc_brush, 0, 0);
+}
+
+void QX11PaintEnginePrivate::clipPolygon_dev(const QPolygonF &poly, QPolygonF *clipped_poly)
+{
+ int clipped_count = 0;
+ qt_float_point *clipped_points = 0;
+ polygonClipper.clipPolygon((qt_float_point *) poly.data(), poly.size(),
+ &clipped_points, &clipped_count);
+ clipped_poly->resize(clipped_count);
+ for (int i=0; i<clipped_count; ++i)
+ (*clipped_poly)[i] = *((QPointF *)(&clipped_points[i]));
+}
+
+void QX11PaintEnginePrivate::systemStateChanged()
+{
+ Q_Q(QX11PaintEngine);
+ QPainter *painter = q->state ? static_cast<QPainterState *>(q->state)->painter : 0;
+ if (painter && painter->hasClipping()) {
+ if (q->testDirty(QPaintEngine::DirtyTransform))
+ q->updateMatrix(q->state->transform());
+ QPolygonF clip_poly_dev(matrix.map(painter->clipPath().toFillPolygon()));
+ QPolygonF clipped_poly_dev;
+ clipPolygon_dev(clip_poly_dev, &clipped_poly_dev);
+ q->updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon()), Qt::ReplaceClip);
+ } else {
+ q->updateClipRegion_dev(QRegion(), Qt::NoClip);
+ }
+}
+
+static QPaintEngine::PaintEngineFeatures qt_decide_features()
+{
+ QPaintEngine::PaintEngineFeatures features =
+ QPaintEngine::PrimitiveTransform
+ | QPaintEngine::PatternBrush
+ | QPaintEngine::AlphaBlend
+ | QPaintEngine::PainterPaths
+ | QPaintEngine::RasterOpModes;
+
+ if (X11->use_xrender) {
+ features |= QPaintEngine::Antialiasing;
+ features |= QPaintEngine::PorterDuff;
+ features |= QPaintEngine::MaskedBrush;
+#if 0
+ if (X11->xrender_version > 10) {
+ features |= QPaintEngine::LinearGradientFill;
+ // ###
+ }
+#endif
+ }
+
+ return features;
+}
+
+/*
+ * QX11PaintEngine members
+ */
+
+QX11PaintEngine::QX11PaintEngine()
+ : QPaintEngine(*(new QX11PaintEnginePrivate), qt_decide_features())
+{
+ d_func()->init();
+}
+
+QX11PaintEngine::QX11PaintEngine(QX11PaintEnginePrivate &dptr)
+ : QPaintEngine(dptr, qt_decide_features())
+{
+ d_func()->init();
+}
+
+QX11PaintEngine::~QX11PaintEngine()
+{
+#ifndef QT_NO_XRENDER
+ Q_D(QX11PaintEngine);
+ delete d->tessellator;
+#endif
+}
+
+bool QX11PaintEngine::begin(QPaintDevice *pdev)
+{
+ Q_D(QX11PaintEngine);
+ d->xinfo = qt_x11Info(pdev);
+ QWidget *w = d->pdev->devType() == QInternal::Widget ? static_cast<QWidget *>(d->pdev) : 0;
+ const bool isAlienWidget = w && !w->internalWinId() && w->testAttribute(Qt::WA_WState_Created);
+#ifndef QT_NO_XRENDER
+ if (w) {
+ if (isAlienWidget)
+ d->picture = (::Picture)w->nativeParentWidget()->x11PictureHandle();
+ else
+ d->picture = (::Picture)w->x11PictureHandle();
+ } else if (pdev->devType() == QInternal::Pixmap) {
+ const QPixmap *pm = static_cast<const QPixmap *>(pdev);
+ QX11PixmapData *data = static_cast<QX11PixmapData*>(pm->data.data());
+ if (X11->use_xrender && data->depth() != 32 && data->x11_mask)
+ data->convertToARGB32();
+ d->picture = (::Picture)static_cast<const QPixmap *>(pdev)->x11PictureHandle();
+ }
+#else
+ d->picture = 0;
+#endif
+ d->hd = !isAlienWidget ? qt_x11Handle(pdev) : qt_x11Handle(w->nativeParentWidget());
+
+ Q_ASSERT(d->xinfo != 0);
+ d->dpy = d->xinfo->display(); // get display variable
+ d->scrn = d->xinfo->screen(); // get screen variable
+
+ d->crgn = QRegion();
+ d->gc = XCreateGC(d->dpy, d->hd, 0, 0);
+ d->gc_brush = XCreateGC(d->dpy, d->hd, 0, 0);
+ d->has_alpha_brush = false;
+ d->has_alpha_pen = false;
+ d->has_clipping = false;
+ d->has_complex_xform = false;
+ d->has_scaling_xform = false;
+ d->has_non_scaling_xform = true;
+ d->xform_scale = 1;
+ d->has_custom_pen = false;
+ d->matrix = QTransform();
+ d->pdev_depth = d->pdev->depth();
+ d->render_hints = 0;
+ d->txop = QTransform::TxNone;
+ d->use_path_fallback = false;
+#if !defined(QT_NO_XRENDER)
+ d->composition_mode = PictOpOver;
+#endif
+ d->xlibMaxLinePoints = 32762; // a safe number used to avoid, call to XMaxRequestSize(d->dpy) - 3;
+ d->opacity = 1;
+
+ // Set up the polygon clipper. Note: This will only work in
+ // polyline mode as long as we have a buffer zone, since a
+ // polyline may be clipped into several non-connected polylines.
+ const int BUFFERZONE = 1000;
+ QRect devClipRect(-BUFFERZONE, -BUFFERZONE,
+ pdev->width() + 2*BUFFERZONE, pdev->height() + 2*BUFFERZONE);
+ d->polygonClipper.setBoundingRect(devClipRect);
+
+ if (isAlienWidget) {
+ // Set system clip for alien widgets painting outside the paint event.
+ // This is not a problem with native windows since the windowing system
+ // will handle the clip.
+ QWidgetPrivate *wd = w->d_func();
+ QRegion widgetClip(wd->clipRect());
+ wd->clipToEffectiveMask(widgetClip);
+ wd->subtractOpaqueSiblings(widgetClip);
+ widgetClip.translate(w->mapTo(w->nativeParentWidget(), QPoint()));
+ setSystemClip(widgetClip);
+ }
+
+ QPixmap::x11SetDefaultScreen(d->xinfo->screen());
+
+ if (w && w->testAttribute(Qt::WA_PaintUnclipped)) { // paint direct on device
+ updatePen(QPen(Qt::black));
+ updateBrush(QBrush(Qt::white), QPoint());
+ XSetSubwindowMode(d->dpy, d->gc, IncludeInferiors);
+ XSetSubwindowMode(d->dpy, d->gc_brush, IncludeInferiors);
+#ifndef QT_NO_XRENDER
+ XRenderPictureAttributes attrs;
+ attrs.subwindow_mode = IncludeInferiors;
+ XRenderChangePicture(d->dpy, d->picture, CPSubwindowMode, &attrs);
+#endif
+ }
+
+ setDirty(QPaintEngine::DirtyClipRegion);
+ setDirty(QPaintEngine::DirtyPen);
+ setDirty(QPaintEngine::DirtyBrush);
+ setDirty(QPaintEngine::DirtyBackground);
+
+ return true;
+}
+
+bool QX11PaintEngine::end()
+{
+ Q_D(QX11PaintEngine);
+
+#if !defined(QT_NO_XRENDER)
+ if (d->picture) {
+ // reset clipping/subwindow mode on our render picture
+ XRenderPictureAttributes attrs;
+ attrs.subwindow_mode = ClipByChildren;
+ attrs.clip_mask = XNone;
+ XRenderChangePicture(d->dpy, d->picture, CPClipMask|CPSubwindowMode, &attrs);
+ }
+#endif
+
+ if (d->gc_brush && d->pdev->painters < 2) {
+ XFreeGC(d->dpy, d->gc_brush);
+ d->gc_brush = 0;
+ }
+
+ if (d->gc && d->pdev->painters < 2) {
+ XFreeGC(d->dpy, d->gc);
+ d->gc = 0;
+ }
+
+ // Restore system clip for alien widgets painting outside the paint event.
+ if (d->pdev->devType() == QInternal::Widget && !static_cast<QWidget *>(d->pdev)->internalWinId())
+ setSystemClip(QRegion());
+
+ return true;
+}
+
+static bool clipLine(QLineF *line, const QRect &rect)
+{
+ qreal x1 = line->x1();
+ qreal x2 = line->x2();
+ qreal y1 = line->y1();
+ qreal y2 = line->y2();
+
+ qreal left = rect.x();
+ qreal right = rect.x() + rect.width() - 1;
+ qreal top = rect.y();
+ qreal bottom = rect.y() + rect.height() - 1;
+
+ enum { Left, Right, Top, Bottom };
+ // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
+ int p1 = ((x1 < left) << Left)
+ | ((x1 > right) << Right)
+ | ((y1 < top) << Top)
+ | ((y1 > bottom) << Bottom);
+ int p2 = ((x2 < left) << Left)
+ | ((x2 > right) << Right)
+ | ((y2 < top) << Top)
+ | ((y2 > bottom) << Bottom);
+
+ if (p1 & p2)
+ // completely outside
+ return false;
+
+ if (p1 | p2) {
+ qreal dx = x2 - x1;
+ qreal dy = y2 - y1;
+
+ // clip x coordinates
+ if (x1 < left) {
+ y1 += dy/dx * (left - x1);
+ x1 = left;
+ } else if (x1 > right) {
+ y1 -= dy/dx * (x1 - right);
+ x1 = right;
+ }
+ if (x2 < left) {
+ y2 += dy/dx * (left - x2);
+ x2 = left;
+ } else if (x2 > right) {
+ y2 -= dy/dx * (x2 - right);
+ x2 = right;
+ }
+ p1 = ((y1 < top) << Top)
+ | ((y1 > bottom) << Bottom);
+ p2 = ((y2 < top) << Top)
+ | ((y2 > bottom) << Bottom);
+ if (p1 & p2)
+ return false;
+ // clip y coordinates
+ if (y1 < top) {
+ x1 += dx/dy * (top - y1);
+ y1 = top;
+ } else if (y1 > bottom) {
+ x1 -= dx/dy * (y1 - bottom);
+ y1 = bottom;
+ }
+ if (y2 < top) {
+ x2 += dx/dy * (top - y2);
+ y2 = top;
+ } else if (y2 > bottom) {
+ x2 -= dx/dy * (y2 - bottom);
+ y2 = bottom;
+ }
+ *line = QLineF(QPointF(x1, y1), QPointF(x2, y2));
+ }
+ return true;
+}
+
+void QX11PaintEngine::drawLines(const QLine *lines, int lineCount)
+{
+ Q_ASSERT(lines);
+ Q_ASSERT(lineCount);
+ Q_D(QX11PaintEngine);
+ if (d->has_alpha_brush
+ || d->has_alpha_pen
+ || d->has_custom_pen
+ || (d->cpen.widthF() > 0 && d->has_complex_xform
+ && !d->has_non_scaling_xform)
+ || (d->render_hints & QPainter::Antialiasing)) {
+ for (int i = 0; i < lineCount; ++i) {
+ QPainterPath path(lines[i].p1());
+ path.lineTo(lines[i].p2());
+ drawPath(path);
+ }
+ return;
+ }
+
+ if (d->has_pen) {
+ for (int i = 0; i < lineCount; ++i) {
+ QLineF linef;
+ if (d->txop == QTransform::TxNone) {
+ linef = lines[i];
+ } else {
+ linef = d->matrix.map(QLineF(lines[i]));
+ }
+ if (clipLine(&linef, d->polygonClipper.boundingRect())) {
+ int x1 = qRound(linef.x1() + aliasedCoordinateDelta);
+ int y1 = qRound(linef.y1() + aliasedCoordinateDelta);
+ int x2 = qRound(linef.x2() + aliasedCoordinateDelta);
+ int y2 = qRound(linef.y2() + aliasedCoordinateDelta);
+
+ XDrawLine(d->dpy, d->hd, d->gc, x1, y1, x2, y2);
+ }
+ }
+ }
+}
+
+void QX11PaintEngine::drawLines(const QLineF *lines, int lineCount)
+{
+ Q_ASSERT(lines);
+ Q_ASSERT(lineCount);
+ Q_D(QX11PaintEngine);
+ if (d->has_alpha_brush
+ || d->has_alpha_pen
+ || d->has_custom_pen
+ || (d->cpen.widthF() > 0 && d->has_complex_xform
+ && !d->has_non_scaling_xform)
+ || (d->render_hints & QPainter::Antialiasing)) {
+ for (int i = 0; i < lineCount; ++i) {
+ QPainterPath path(lines[i].p1());
+ path.lineTo(lines[i].p2());
+ drawPath(path);
+ }
+ return;
+ }
+
+ if (d->has_pen) {
+ for (int i = 0; i < lineCount; ++i) {
+ QLineF linef = d->matrix.map(lines[i]);
+ if (clipLine(&linef, d->polygonClipper.boundingRect())) {
+ int x1 = qRound(linef.x1() + aliasedCoordinateDelta);
+ int y1 = qRound(linef.y1() + aliasedCoordinateDelta);
+ int x2 = qRound(linef.x2() + aliasedCoordinateDelta);
+ int y2 = qRound(linef.y2() + aliasedCoordinateDelta);
+
+ XDrawLine(d->dpy, d->hd, d->gc, x1, y1, x2, y2);
+ }
+ }
+ }
+}
+
+static inline QLine clipStraightLine(const QRect &clip, const QLine &l)
+{
+ if (l.p1().x() == l.p2().x()) {
+ int x = qBound(clip.left(), l.p1().x(), clip.right());
+ int y1 = qBound(clip.top(), l.p1().y(), clip.bottom());
+ int y2 = qBound(clip.top(), l.p2().y(), clip.bottom());
+
+ return QLine(x, y1, x, y2);
+ } else {
+ Q_ASSERT(l.p1().y() == l.p2().y());
+
+ int x1 = qBound(clip.left(), l.p1().x(), clip.right());
+ int x2 = qBound(clip.left(), l.p2().x(), clip.right());
+ int y = qBound(clip.top(), l.p1().y(), clip.bottom());
+
+ return QLine(x1, y, x2, y);
+ }
+}
+
+void QX11PaintEngine::drawRects(const QRectF *rects, int rectCount)
+{
+ Q_D(QX11PaintEngine);
+ Q_ASSERT(rects);
+ Q_ASSERT(rectCount);
+
+ if (rectCount != 1
+ || d->has_pen
+ || d->has_alpha_brush
+ || d->has_complex_xform
+ || d->has_custom_pen
+ || d->cbrush.style() != Qt::SolidPattern)
+ {
+ QPaintEngine::drawRects(rects, rectCount);
+ return;
+ }
+
+ QPoint alignedOffset;
+ if (d->txop == QTransform::TxTranslate) {
+ QPointF offset(d->matrix.dx(), d->matrix.dy());
+ alignedOffset = offset.toPoint();
+ if (offset != QPointF(alignedOffset)) {
+ QPaintEngine::drawRects(rects, rectCount);
+ return;
+ }
+ }
+
+ const QRectF& r = rects[0];
+ QRect alignedRect = r.toAlignedRect();
+ if (r != QRectF(alignedRect)) {
+ QPaintEngine::drawRects(rects, rectCount);
+ return;
+ }
+ alignedRect.translate(alignedOffset);
+
+ QRect clip(d->polygonClipper.boundingRect());
+ alignedRect = alignedRect.intersected(clip);
+ if (alignedRect.isEmpty())
+ return;
+
+ // simple-case:
+ // the rectangle is pixel-aligned
+ // the fill brush is just a solid non-alpha color
+ // the painter transform is only integer translation
+ // ignore: antialiasing and just XFillRectangles directly
+ XRectangle xrect;
+ xrect.x = short(alignedRect.x());
+ xrect.y = short(alignedRect.y());
+ xrect.width = ushort(alignedRect.width());
+ xrect.height = ushort(alignedRect.height());
+ XFillRectangles(d->dpy, d->hd, d->gc_brush, &xrect, 1);
+}
+
+void QX11PaintEngine::drawRects(const QRect *rects, int rectCount)
+{
+ Q_D(QX11PaintEngine);
+ Q_ASSERT(rects);
+ Q_ASSERT(rectCount);
+
+ if (d->has_alpha_pen
+ || d->has_complex_xform
+ || d->has_custom_pen
+ || (d->render_hints & QPainter::Antialiasing))
+ {
+ for (int i = 0; i < rectCount; ++i) {
+ QPainterPath path;
+ path.addRect(rects[i]);
+ drawPath(path);
+ }
+ return;
+ }
+
+ QRect clip(d->polygonClipper.boundingRect());
+ QPoint offset(qRound(d->matrix.dx()), qRound(d->matrix.dy()));
+#if !defined(QT_NO_XRENDER)
+ ::Picture pict = d->picture;
+
+ if (X11->use_xrender && pict && d->has_brush && d->pdev_depth != 1
+ && (d->has_texture || d->has_alpha_brush))
+ {
+ XRenderColor xc;
+ if (!d->has_texture && !d->has_pattern)
+ xc = X11->preMultiply(d->cbrush.color());
+
+ for (int i = 0; i < rectCount; ++i) {
+ QRect r(rects[i]);
+ if (d->txop == QTransform::TxTranslate)
+ r.translate(offset);
+
+ if (r.width() == 0 || r.height() == 0) {
+ if (d->has_pen) {
+ const QLine l = clipStraightLine(clip, QLine(r.left(), r.top(), r.left() + r.width(), r.top() + r.height()));
+ XDrawLine(d->dpy, d->hd, d->gc, l.p1().x(), l.p1().y(), l.p2().x(), l.p2().y());
+ }
+ continue;
+ }
+
+ r = r.intersected(clip);
+ if (r.isEmpty())
+ continue;
+ if (d->has_texture || d->has_pattern) {
+ XRenderComposite(d->dpy, d->composition_mode, d->current_brush, 0, pict,
+ qRound(r.x() - d->bg_origin.x()), qRound(r.y() - d->bg_origin.y()),
+ 0, 0, r.x(), r.y(), r.width(), r.height());
+ } else {
+ XRenderFillRectangle(d->dpy, d->composition_mode, pict, &xc, r.x(), r.y(), r.width(), r.height());
+ }
+ if (d->has_pen)
+ XDrawRectangle(d->dpy, d->hd, d->gc, r.x(), r.y(), r.width(), r.height());
+ }
+ } else
+#endif // !QT_NO_XRENDER
+ {
+ if (d->has_brush && d->has_pen) {
+ for (int i = 0; i < rectCount; ++i) {
+ QRect r(rects[i]);
+ if (d->txop == QTransform::TxTranslate)
+ r.translate(offset);
+
+ if (r.width() == 0 || r.height() == 0) {
+ const QLine l = clipStraightLine(clip, QLine(r.left(), r.top(), r.left() + r.width(), r.top() + r.height()));
+ XDrawLine(d->dpy, d->hd, d->gc, l.p1().x(), l.p1().y(), l.p2().x(), l.p2().y());
+ continue;
+ }
+
+ r = r.intersected(clip);
+ if (r.isEmpty())
+ continue;
+ d->setupAdaptedOrigin(r.topLeft());
+ XFillRectangle(d->dpy, d->hd, d->gc_brush, r.x(), r.y(), r.width(), r.height());
+ XDrawRectangle(d->dpy, d->hd, d->gc, r.x(), r.y(), r.width(), r.height());
+ }
+ d->resetAdaptedOrigin();
+ } else {
+ QVarLengthArray<XRectangle> xrects(rectCount);
+ int numClipped = rectCount;
+ for (int i = 0; i < rectCount; ++i) {
+ QRect r(rects[i]);
+ if (d->txop == QTransform::TxTranslate)
+ r.translate(offset);
+
+ if (r.width() == 0 || r.height() == 0) {
+ --numClipped;
+ if (d->has_pen) {
+ const QLine l = clipStraightLine(clip, QLine(r.left(), r.top(), r.left() + r.width(), r.top() + r.height()));
+ XDrawLine(d->dpy, d->hd, d->gc, l.p1().x(), l.p1().y(), l.p2().x(), l.p2().y());
+ }
+ continue;
+ }
+
+ r = r.intersected(clip);
+ if (r.isEmpty()) {
+ --numClipped;
+ continue;
+ }
+ xrects[i].x = short(r.x());
+ xrects[i].y = short(r.y());
+ xrects[i].width = ushort(r.width());
+ xrects[i].height = ushort(r.height());
+ }
+ if (numClipped) {
+ d->setupAdaptedOrigin(rects[0].topLeft());
+ if (d->has_brush)
+ XFillRectangles(d->dpy, d->hd, d->gc_brush, xrects.data(), numClipped);
+ else if (d->has_pen)
+ XDrawRectangles(d->dpy, d->hd, d->gc, xrects.data(), numClipped);
+ d->resetAdaptedOrigin();
+ }
+ }
+ }
+}
+
+static inline void setCapStyle(int cap_style, GC gc)
+{
+ ulong mask = GCCapStyle;
+ XGCValues vals;
+ vals.cap_style = cap_style;
+ XChangeGC(X11->display, gc, mask, &vals);
+}
+
+void QX11PaintEngine::drawPoints(const QPoint *points, int pointCount)
+{
+ Q_ASSERT(points);
+ Q_ASSERT(pointCount);
+ Q_D(QX11PaintEngine);
+
+ if (!d->has_pen)
+ return;
+
+ // use the same test here as in drawPath to ensure that we don't use the path fallback
+ // and end up in XDrawLines for pens with width <= 1
+ if (d->cpen.widthF() > 1.0f
+ || (X11->use_xrender && (d->has_alpha_pen || (d->render_hints & QPainter::Antialiasing)))
+ || (!d->cpen.isCosmetic() && d->txop > QTransform::TxTranslate))
+ {
+ Qt::PenCapStyle capStyle = d->cpen.capStyle();
+ if (capStyle == Qt::FlatCap) {
+ setCapStyle(CapProjecting, d->gc);
+ d->cpen.setCapStyle(Qt::SquareCap);
+ }
+ const QPoint *end = points + pointCount;
+ while (points < end) {
+ QPainterPath path;
+ path.moveTo(*points);
+ path.lineTo(points->x()+.005, points->y());
+ drawPath(path);
+ ++points;
+ }
+
+ if (capStyle == Qt::FlatCap) {
+ setCapStyle(CapButt, d->gc);
+ d->cpen.setCapStyle(capStyle);
+ }
+ return;
+ }
+
+ static const int BUF_SIZE = 1024;
+ XPoint xPoints[BUF_SIZE];
+ int i = 0, j = 0;
+ while (i < pointCount) {
+ while (i < pointCount && j < BUF_SIZE) {
+ const QPoint &xformed = d->matrix.map(points[i]);
+ int x = xformed.x();
+ int y = xformed.y();
+ if (x >= SHRT_MIN && y >= SHRT_MIN && x < SHRT_MAX && y < SHRT_MAX) {
+ xPoints[j].x = x;
+ xPoints[j].y = y;
+ ++j;
+ }
+ ++i;
+ }
+ if (j)
+ XDrawPoints(d->dpy, d->hd, d->gc, xPoints, j, CoordModeOrigin);
+
+ j = 0;
+ }
+}
+
+void QX11PaintEngine::drawPoints(const QPointF *points, int pointCount)
+{
+ Q_ASSERT(points);
+ Q_ASSERT(pointCount);
+ Q_D(QX11PaintEngine);
+
+ if (!d->has_pen)
+ return;
+
+ // use the same test here as in drawPath to ensure that we don't use the path fallback
+ // and end up in XDrawLines for pens with width <= 1
+ if (d->cpen.widthF() > 1.0f
+ || (X11->use_xrender && (d->has_alpha_pen || (d->render_hints & QPainter::Antialiasing)))
+ || (!d->cpen.isCosmetic() && d->txop > QTransform::TxTranslate))
+ {
+ Qt::PenCapStyle capStyle = d->cpen.capStyle();
+ if (capStyle == Qt::FlatCap) {
+ setCapStyle(CapProjecting, d->gc);
+ d->cpen.setCapStyle(Qt::SquareCap);
+ }
+
+ const QPointF *end = points + pointCount;
+ while (points < end) {
+ QPainterPath path;
+ path.moveTo(*points);
+ path.lineTo(points->x() + 0.005, points->y());
+ drawPath(path);
+ ++points;
+ }
+ if (capStyle == Qt::FlatCap) {
+ setCapStyle(CapButt, d->gc);
+ d->cpen.setCapStyle(capStyle);
+ }
+ return;
+ }
+
+ static const int BUF_SIZE = 1024;
+ XPoint xPoints[BUF_SIZE];
+ int i = 0, j = 0;
+ while (i < pointCount) {
+ while (i < pointCount && j < BUF_SIZE) {
+ const QPointF &xformed = d->matrix.map(points[i]);
+ int x = qFloor(xformed.x());
+ int y = qFloor(xformed.y());
+
+ if (x >= SHRT_MIN && y >= SHRT_MIN && x < SHRT_MAX && y < SHRT_MAX) {
+ xPoints[j].x = x;
+ xPoints[j].y = y;
+ ++j;
+ }
+ ++i;
+ }
+ if (j)
+ XDrawPoints(d->dpy, d->hd, d->gc, xPoints, j, CoordModeOrigin);
+
+ j = 0;
+ }
+}
+
+QPainter::RenderHints QX11PaintEngine::supportedRenderHints() const
+{
+#if !defined(QT_NO_XRENDER)
+ if (X11->use_xrender)
+ return QPainter::Antialiasing;
+#endif
+ return QFlag(0);
+}
+
+void QX11PaintEngine::updateState(const QPaintEngineState &state)
+{
+ Q_D(QX11PaintEngine);
+ QPaintEngine::DirtyFlags flags = state.state();
+
+
+ if (flags & DirtyOpacity) {
+ d->opacity = state.opacity();
+ // Force update pen/brush as to get proper alpha colors propagated
+ flags |= DirtyPen;
+ flags |= DirtyBrush;
+ }
+
+ if (flags & DirtyTransform) updateMatrix(state.transform());
+ if (flags & DirtyPen) updatePen(state.pen());
+ if (flags & (DirtyBrush | DirtyBrushOrigin)) updateBrush(state.brush(), state.brushOrigin());
+ if (flags & DirtyFont) updateFont(state.font());
+
+ if (state.state() & DirtyClipEnabled) {
+ if (state.isClipEnabled()) {
+ QPolygonF clip_poly_dev(d->matrix.map(painter()->clipPath().toFillPolygon()));
+ QPolygonF clipped_poly_dev;
+ d->clipPolygon_dev(clip_poly_dev, &clipped_poly_dev);
+ updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon()), Qt::ReplaceClip);
+ } else {
+ updateClipRegion_dev(QRegion(), Qt::NoClip);
+ }
+ }
+
+ if (flags & DirtyClipPath) {
+ QPolygonF clip_poly_dev(d->matrix.map(state.clipPath().toFillPolygon()));
+ QPolygonF clipped_poly_dev;
+ d->clipPolygon_dev(clip_poly_dev, &clipped_poly_dev);
+ updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon(), state.clipPath().fillRule()),
+ state.clipOperation());
+ } else if (flags & DirtyClipRegion) {
+ extern QPainterPath qt_regionToPath(const QRegion &region);
+ QPainterPath clip_path = qt_regionToPath(state.clipRegion());
+ QPolygonF clip_poly_dev(d->matrix.map(clip_path.toFillPolygon()));
+ QPolygonF clipped_poly_dev;
+ d->clipPolygon_dev(clip_poly_dev, &clipped_poly_dev);
+ updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon()), state.clipOperation());
+ }
+ if (flags & DirtyHints) updateRenderHints(state.renderHints());
+ if (flags & DirtyCompositionMode) {
+ int function = GXcopy;
+ if (state.compositionMode() >= QPainter::RasterOp_SourceOrDestination) {
+ switch (state.compositionMode()) {
+ case QPainter::RasterOp_SourceOrDestination:
+ function = GXor;
+ break;
+ case QPainter::RasterOp_SourceAndDestination:
+ function = GXand;
+ break;
+ case QPainter::RasterOp_SourceXorDestination:
+ function = GXxor;
+ break;
+ case QPainter::RasterOp_NotSourceAndNotDestination:
+ function = GXnor;
+ break;
+ case QPainter::RasterOp_NotSourceOrNotDestination:
+ function = GXnand;
+ break;
+ case QPainter::RasterOp_NotSourceXorDestination:
+ function = GXequiv;
+ break;
+ case QPainter::RasterOp_NotSource:
+ function = GXcopyInverted;
+ break;
+ case QPainter::RasterOp_SourceAndNotDestination:
+ function = GXandReverse;
+ break;
+ case QPainter::RasterOp_NotSourceAndDestination:
+ function = GXandInverted;
+ break;
+ default:
+ function = GXcopy;
+ }
+ }
+#if !defined(QT_NO_XRENDER)
+ else {
+ d->composition_mode =
+ qpainterOpToXrender(state.compositionMode());
+ }
+#endif
+ XSetFunction(X11->display, d->gc, function);
+ XSetFunction(X11->display, d->gc_brush, function);
+ }
+ d->decidePathFallback();
+ d->decideCoordAdjust();
+}
+
+void QX11PaintEngine::updateRenderHints(QPainter::RenderHints hints)
+{
+ Q_D(QX11PaintEngine);
+ d->render_hints = hints;
+
+#if !defined(QT_NO_XRENDER)
+ if (X11->use_xrender && d->picture) {
+ XRenderPictureAttributes attrs;
+ attrs.poly_edge = (hints & QPainter::Antialiasing) ? PolyEdgeSmooth : PolyEdgeSharp;
+ XRenderChangePicture(d->dpy, d->picture, CPPolyEdge, &attrs);
+ }
+#endif
+}
+
+void QX11PaintEngine::updatePen(const QPen &pen)
+{
+ Q_D(QX11PaintEngine);
+ d->cpen = pen;
+ int cp = CapButt;
+ int jn = JoinMiter;
+ int ps = pen.style();
+
+ if (d->opacity < 1.0) {
+ QColor c = d->cpen.color();
+ c.setAlpha(qRound(c.alpha()*d->opacity));
+ d->cpen.setColor(c);
+ }
+
+ d->has_pen = (ps != Qt::NoPen);
+ d->has_alpha_pen = (pen.color().alpha() != 255);
+
+ switch (pen.capStyle()) {
+ case Qt::SquareCap:
+ cp = CapProjecting;
+ break;
+ case Qt::RoundCap:
+ cp = CapRound;
+ break;
+ case Qt::FlatCap:
+ default:
+ cp = CapButt;
+ break;
+ }
+ switch (pen.joinStyle()) {
+ case Qt::BevelJoin:
+ jn = JoinBevel;
+ break;
+ case Qt::RoundJoin:
+ jn = JoinRound;
+ break;
+ case Qt::MiterJoin:
+ default:
+ jn = JoinMiter;
+ break;
+ }
+
+ d->adapted_pen_origin = false;
+
+ char dashes[10]; // custom pen dashes
+ int dash_len = 0; // length of dash list
+ int xStyle = LineSolid;
+
+ /*
+ We are emulating Windows here. Windows treats cpen.width() == 1
+ (or 0) as a very special case. The fudge variable unifies this
+ case with the general case.
+ */
+ qreal pen_width = pen.widthF();
+ int scale = qRound(pen_width < 1 ? 1 : pen_width);
+ int space = (pen_width < 1 && pen_width > 0 ? 1 : (2 * scale));
+ int dot = 1 * scale;
+ int dash = 4 * scale;
+
+ d->has_custom_pen = false;
+
+ switch (ps) {
+ case Qt::NoPen:
+ case Qt::SolidLine:
+ xStyle = LineSolid;
+ break;
+ case Qt::DashLine:
+ dashes[0] = dash;
+ dashes[1] = space;
+ dash_len = 2;
+ xStyle = LineOnOffDash;
+ break;
+ case Qt::DotLine:
+ dashes[0] = dot;
+ dashes[1] = space;
+ dash_len = 2;
+ xStyle = LineOnOffDash;
+ break;
+ case Qt::DashDotLine:
+ dashes[0] = dash;
+ dashes[1] = space;
+ dashes[2] = dot;
+ dashes[3] = space;
+ dash_len = 4;
+ xStyle = LineOnOffDash;
+ break;
+ case Qt::DashDotDotLine:
+ dashes[0] = dash;
+ dashes[1] = space;
+ dashes[2] = dot;
+ dashes[3] = space;
+ dashes[4] = dot;
+ dashes[5] = space;
+ dash_len = 6;
+ xStyle = LineOnOffDash;
+ break;
+ case Qt::CustomDashLine:
+ d->has_custom_pen = true;
+ break;
+ }
+
+ ulong mask = GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth
+ | GCCapStyle | GCJoinStyle | GCLineStyle;
+ XGCValues vals;
+ vals.graphics_exposures = false;
+ if (d->pdev_depth == 1) {
+ vals.foreground = qGray(pen.color().rgb()) > 127 ? 0 : 1;
+ vals.background = qGray(QColor(Qt::transparent).rgb()) > 127 ? 0 : 1;
+ } else if (d->pdev->devType() == QInternal::Pixmap && d->pdev_depth == 32
+ && X11->use_xrender) {
+ vals.foreground = pen.color().rgba();
+ vals.background = QColor(Qt::transparent).rgba();
+ } else {
+ QColormap cmap = QColormap::instance(d->scrn);
+ vals.foreground = cmap.pixel(pen.color());
+ vals.background = cmap.pixel(QColor(Qt::transparent));
+ }
+
+
+ vals.line_width = qRound(pen.widthF());
+ vals.cap_style = cp;
+ vals.join_style = jn;
+ vals.line_style = xStyle;
+
+ XChangeGC(d->dpy, d->gc, mask, &vals);
+
+ if (dash_len) { // make dash list
+ XSetDashes(d->dpy, d->gc, 0, dashes, dash_len);
+ }
+
+ if (!d->has_clipping) { // if clipping is set the paintevent clip region is merged with the clip region
+ QRegion sysClip = systemClip();
+ if (!sysClip.isEmpty())
+ x11SetClipRegion(d->dpy, d->gc, 0, d->picture, sysClip);
+ else
+ x11ClearClipRegion(d->dpy, d->gc, 0, d->picture);
+ }
+}
+
+void QX11PaintEngine::updateBrush(const QBrush &brush, const QPointF &origin)
+{
+ Q_D(QX11PaintEngine);
+ d->cbrush = brush;
+ d->bg_origin = origin;
+ d->adapted_brush_origin = false;
+#if !defined(QT_NO_XRENDER)
+ d->current_brush = 0;
+#endif
+ if (d->opacity < 1.0) {
+ QColor c = d->cbrush.color();
+ c.setAlpha(qRound(c.alpha()*d->opacity));
+ d->cbrush.setColor(c);
+ }
+
+ int s = FillSolid;
+ int bs = d->cbrush.style();
+ d->has_brush = (bs != Qt::NoBrush);
+ d->has_pattern = bs >= Qt::Dense1Pattern && bs <= Qt::DiagCrossPattern;
+ d->has_texture = bs == Qt::TexturePattern;
+ d->has_alpha_brush = brush.color().alpha() != 255;
+ d->has_alpha_texture = d->has_texture && d->cbrush.texture().hasAlphaChannel();
+
+ ulong mask = GCForeground | GCBackground | GCGraphicsExposures
+ | GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle;
+ XGCValues vals;
+ vals.graphics_exposures = false;
+ if (d->pdev_depth == 1) {
+ vals.foreground = qGray(d->cbrush.color().rgb()) > 127 ? 0 : 1;
+ vals.background = qGray(QColor(Qt::transparent).rgb()) > 127 ? 0 : 1;
+ } else if (X11->use_xrender && d->pdev->devType() == QInternal::Pixmap
+ && d->pdev_depth == 32) {
+ vals.foreground = d->cbrush.color().rgba();
+ vals.background = QColor(Qt::transparent).rgba();
+ } else {
+ QColormap cmap = QColormap::instance(d->scrn);
+ vals.foreground = cmap.pixel(d->cbrush.color());
+ vals.background = cmap.pixel(QColor(Qt::transparent));
+
+ if (!X11->use_xrender && d->has_brush && !d->has_pattern && !brush.isOpaque()) {
+ QPixmap pattern = qt_patternForAlpha(brush.color().alpha(), d->scrn);
+ mask |= GCStipple;
+ vals.stipple = pattern.handle();
+ s = FillStippled;
+ d->adapted_brush_origin = true;
+ }
+ }
+ vals.cap_style = CapButt;
+ vals.join_style = JoinMiter;
+ vals.line_style = LineSolid;
+
+ if (d->has_pattern || d->has_texture) {
+ if (bs == Qt::TexturePattern) {
+ d->brush_pm = qt_toX11Pixmap(d->cbrush.texture());
+#if !defined(QT_NO_XRENDER)
+ if (X11->use_xrender) {
+ XRenderPictureAttributes attrs;
+ attrs.repeat = true;
+ XRenderChangePicture(d->dpy, d->brush_pm.x11PictureHandle(), CPRepeat, &attrs);
+ QX11PixmapData *data = static_cast<QX11PixmapData*>(d->brush_pm.data.data());
+ if (data->mask_picture)
+ XRenderChangePicture(d->dpy, data->mask_picture, CPRepeat, &attrs);
+ }
+#endif
+ } else {
+ d->brush_pm = qt_toX11Pixmap(qt_pixmapForBrush(bs, true));
+ }
+ d->brush_pm.x11SetScreen(d->scrn);
+ if (d->brush_pm.depth() == 1) {
+ mask |= GCStipple;
+ vals.stipple = d->brush_pm.handle();
+ s = FillStippled;
+#if !defined(QT_NO_XRENDER)
+ if (X11->use_xrender) {
+ d->bitmap_texture = QPixmap(d->brush_pm.size());
+ d->bitmap_texture.fill(Qt::transparent);
+ d->bitmap_texture = qt_toX11Pixmap(d->bitmap_texture);
+ d->bitmap_texture.x11SetScreen(d->scrn);
+
+ ::Picture src = X11->getSolidFill(d->scrn, d->cbrush.color());
+ XRenderComposite(d->dpy, PictOpSrc, src, d->brush_pm.x11PictureHandle(),
+ d->bitmap_texture.x11PictureHandle(),
+ 0, 0, d->brush_pm.width(), d->brush_pm.height(),
+ 0, 0, d->brush_pm.width(), d->brush_pm.height());
+
+ XRenderPictureAttributes attrs;
+ attrs.repeat = true;
+ XRenderChangePicture(d->dpy, d->bitmap_texture.x11PictureHandle(), CPRepeat, &attrs);
+
+ d->current_brush = d->bitmap_texture.x11PictureHandle();
+ }
+#endif
+ } else {
+ mask |= GCTile;
+#ifndef QT_NO_XRENDER
+ if (d->pdev_depth == 32 && d->brush_pm.depth() != 32) {
+ d->brush_pm.detach();
+ QX11PixmapData *brushData = static_cast<QX11PixmapData*>(d->brush_pm.data.data());
+ brushData->convertToARGB32();
+ }
+#endif
+ vals.tile = (d->brush_pm.depth() == d->pdev_depth
+ ? d->brush_pm.handle()
+ : static_cast<QX11PixmapData*>(d->brush_pm.data.data())->x11ConvertToDefaultDepth());
+ s = FillTiled;
+#if !defined(QT_NO_XRENDER)
+ d->current_brush = d->cbrush.texture().x11PictureHandle();
+#endif
+ }
+
+ mask |= GCTileStipXOrigin | GCTileStipYOrigin;
+ vals.ts_x_origin = qRound(origin.x());
+ vals.ts_y_origin = qRound(origin.y());
+ }
+#if !defined(QT_NO_XRENDER)
+ else if (d->has_alpha_brush) {
+ d->current_brush = X11->getSolidFill(d->scrn, d->cbrush.color());
+ }
+#endif
+
+ vals.fill_style = s;
+ XChangeGC(d->dpy, d->gc_brush, mask, &vals);
+ if (!d->has_clipping) {
+ QRegion sysClip = systemClip();
+ if (!sysClip.isEmpty())
+ x11SetClipRegion(d->dpy, d->gc_brush, 0, d->picture, sysClip);
+ else
+ x11ClearClipRegion(d->dpy, d->gc_brush, 0, d->picture);
+ }
+}
+
+void QX11PaintEngine::drawEllipse(const QRectF &rect)
+{
+ QRect aligned = rect.toAlignedRect();
+ if (aligned == rect)
+ drawEllipse(aligned);
+ else
+ QPaintEngine::drawEllipse(rect);
+}
+
+void QX11PaintEngine::drawEllipse(const QRect &rect)
+{
+ if (rect.isEmpty()) {
+ drawRects(&rect, 1);
+ return;
+ }
+
+ Q_D(QX11PaintEngine);
+ QRect devclip(SHRT_MIN, SHRT_MIN, SHRT_MAX*2 - 1, SHRT_MAX*2 - 1);
+ QRect r(rect);
+ if (d->txop < QTransform::TxRotate) {
+ r = d->matrix.mapRect(rect);
+ } else if (d->txop == QTransform::TxRotate && rect.width() == rect.height()) {
+ QPainterPath path;
+ path.addEllipse(rect);
+ r = d->matrix.map(path).boundingRect().toRect();
+ }
+
+ if (d->has_alpha_brush || d->has_alpha_pen || d->has_custom_pen || (d->render_hints & QPainter::Antialiasing)
+ || d->has_alpha_texture || devclip.intersected(r) != r
+ || (d->has_complex_xform
+ && !(d->has_non_scaling_xform && rect.width() == rect.height())))
+ {
+ QPainterPath path;
+ path.addEllipse(rect);
+ drawPath(path);
+ return;
+ }
+
+ int x = r.x();
+ int y = r.y();
+ int w = r.width();
+ int h = r.height();
+ if (w < 1 || h < 1)
+ return;
+ if (w == 1 && h == 1) {
+ XDrawPoint(d->dpy, d->hd, d->has_pen ? d->gc : d->gc_brush, x, y);
+ return;
+ }
+ d->setupAdaptedOrigin(rect.topLeft());
+ if (d->has_brush) { // draw filled ellipse
+ XFillArc(d->dpy, d->hd, d->gc_brush, x, y, w, h, 0, 360*64);
+ if (!d->has_pen) // make smoother outline
+ XDrawArc(d->dpy, d->hd, d->gc_brush, x, y, w-1, h-1, 0, 360*64);
+ }
+ if (d->has_pen) // draw outline
+ XDrawArc(d->dpy, d->hd, d->gc, x, y, w, h, 0, 360*64);
+ d->resetAdaptedOrigin();
+}
+
+
+
+void QX11PaintEnginePrivate::fillPolygon_translated(const QPointF *polygonPoints, int pointCount,
+ QX11PaintEnginePrivate::GCMode gcMode,
+ QPaintEngine::PolygonDrawMode mode)
+{
+
+ QVarLengthArray<QPointF> translated_points(pointCount);
+ QPointF offset(matrix.dx(), matrix.dy());
+
+ qreal offs = adjust_coords ? aliasedCoordinateDelta : 0.0;
+ if (!X11->use_xrender || !(render_hints & QPainter::Antialiasing))
+ offset += QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
+
+ for (int i = 0; i < pointCount; ++i) {
+ translated_points[i] = polygonPoints[i] + offset;
+
+ translated_points[i].rx() = qRound(translated_points[i].x()) + offs;
+ translated_points[i].ry() = qRound(translated_points[i].y()) + offs;
+ }
+
+ fillPolygon_dev(translated_points.data(), pointCount, gcMode, mode);
+}
+
+#ifndef QT_NO_XRENDER
+static void qt_XRenderCompositeTrapezoids(Display *dpy,
+ int op,
+ Picture src,
+ Picture dst,
+ _Xconst XRenderPictFormat *maskFormat,
+ int xSrc,
+ int ySrc,
+ const XTrapezoid *traps, int size)
+{
+ const int MAX_TRAPS = 50000;
+ while (size) {
+ int to_draw = size;
+ if (to_draw > MAX_TRAPS)
+ to_draw = MAX_TRAPS;
+ XRenderCompositeTrapezoids(dpy, op, src, dst,
+ maskFormat,
+ xSrc, ySrc,
+ traps, to_draw);
+ size -= to_draw;
+ traps += to_draw;
+ }
+}
+#endif
+
+void QX11PaintEnginePrivate::fillPolygon_dev(const QPointF *polygonPoints, int pointCount,
+ QX11PaintEnginePrivate::GCMode gcMode,
+ QPaintEngine::PolygonDrawMode mode)
+{
+ Q_Q(QX11PaintEngine);
+
+ int clippedCount = 0;
+ qt_float_point *clippedPoints = 0;
+
+#ifndef QT_NO_XRENDER
+ //can change if we switch to pen if gcMode != BrushGC
+ bool has_fill_texture = has_texture;
+ bool has_fill_pattern = has_pattern;
+ ::Picture src;
+#endif
+ QBrush fill;
+ GC fill_gc;
+ if (gcMode == BrushGC) {
+ fill = cbrush;
+ fill_gc = gc_brush;
+#ifndef QT_NO_XRENDER
+ if (current_brush)
+ src = current_brush;
+ else
+ src = X11->getSolidFill(scrn, fill.color());
+#endif
+ } else {
+ fill = QBrush(cpen.brush());
+ fill_gc = gc;
+#ifndef QT_NO_XRENDER
+ //we use the pens brush
+ has_fill_texture = (fill.style() == Qt::TexturePattern);
+ has_fill_pattern = (fill.style() >= Qt::Dense1Pattern && fill.style() <= Qt::DiagCrossPattern);
+ if (has_fill_texture)
+ src = fill.texture().x11PictureHandle();
+ else if (has_fill_pattern)
+ src = getPatternFill(scrn, fill);
+ else
+ src = X11->getSolidFill(scrn, fill.color());
+#endif
+ }
+
+ polygonClipper.clipPolygon((qt_float_point *) polygonPoints, pointCount,
+ &clippedPoints, &clippedCount);
+
+#ifndef QT_NO_XRENDER
+ bool solid_fill = fill.color().alpha() == 255;
+ if (has_fill_texture && fill.texture().depth() == 1 && solid_fill) {
+ has_fill_texture = false;
+ has_fill_pattern = true;
+ }
+
+ bool antialias = render_hints & QPainter::Antialiasing;
+
+ if (X11->use_xrender
+ && picture
+ && !has_fill_pattern
+ && (clippedCount > 0)
+ && (fill.style() != Qt::NoBrush)
+ && ((has_fill_texture && fill.texture().hasAlpha()) || antialias || !solid_fill || has_alpha_pen != has_alpha_brush))
+ {
+ QRect br = tessellator->tessellate((QPointF *)clippedPoints, clippedCount,
+ mode == QPaintEngine::WindingMode);
+ if (tessellator->size > 0) {
+ XRenderPictureAttributes attrs;
+ attrs.poly_edge = antialias ? PolyEdgeSmooth : PolyEdgeSharp;
+ XRenderChangePicture(dpy, picture, CPPolyEdge, &attrs);
+ int x_offset = int(XFixedToDouble(tessellator->traps[0].left.p1.x) - bg_origin.x());
+ int y_offset = int(XFixedToDouble(tessellator->traps[0].left.p1.y) - bg_origin.y());
+ qt_XRenderCompositeTrapezoids(dpy, composition_mode, src, picture,
+ antialias
+ ? XRenderFindStandardFormat(dpy, PictStandardA8)
+ : XRenderFindStandardFormat(dpy, PictStandardA1),
+ x_offset, y_offset,
+ tessellator->traps, tessellator->size);
+ tessellator->done();
+ }
+ } else
+#endif
+ if (fill.style() != Qt::NoBrush) {
+ if (clippedCount > 200000) {
+ QPolygon poly;
+ for (int i = 0; i < clippedCount; ++i)
+ poly << QPoint(qFloor(clippedPoints[i].x), qFloor(clippedPoints[i].y));
+
+ const QRect bounds = poly.boundingRect();
+ const QRect aligned = bounds
+ & QRect(QPoint(), QSize(pdev->width(), pdev->height()));
+
+ QImage img(aligned.size(), QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+
+ QPainter painter(&img);
+ painter.translate(-aligned.x(), -aligned.y());
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(fill);
+ if (gcMode == BrushGC)
+ painter.setBrushOrigin(q->painter()->brushOrigin());
+ painter.drawPolygon(poly);
+ painter.end();
+
+ q->drawImage(aligned, img, img.rect(), Qt::AutoColor);
+ } else if (clippedCount > 0) {
+ QVarLengthArray<XPoint> xpoints(clippedCount);
+ for (int i = 0; i < clippedCount; ++i) {
+ xpoints[i].x = qFloor(clippedPoints[i].x);
+ xpoints[i].y = qFloor(clippedPoints[i].y);
+ }
+ if (mode == QPaintEngine::WindingMode)
+ XSetFillRule(dpy, fill_gc, WindingRule);
+ setupAdaptedOrigin(QPoint(xpoints[0].x, xpoints[0].y));
+ XFillPolygon(dpy, hd, fill_gc,
+ xpoints.data(), clippedCount,
+ mode == QPaintEngine::ConvexMode ? Convex : Complex, CoordModeOrigin);
+ resetAdaptedOrigin();
+ if (mode == QPaintEngine::WindingMode)
+ XSetFillRule(dpy, fill_gc, EvenOddRule);
+ }
+ }
+}
+
+void QX11PaintEnginePrivate::strokePolygon_translated(const QPointF *polygonPoints, int pointCount, bool close)
+{
+ QVarLengthArray<QPointF> translated_points(pointCount);
+ QPointF offset(matrix.dx(), matrix.dy());
+ for (int i = 0; i < pointCount; ++i)
+ translated_points[i] = polygonPoints[i] + offset;
+ strokePolygon_dev(translated_points.data(), pointCount, close);
+}
+
+void QX11PaintEnginePrivate::strokePolygon_dev(const QPointF *polygonPoints, int pointCount, bool close)
+{
+ int clippedCount = 0;
+ qt_float_point *clippedPoints = 0;
+ polygonClipper.clipPolygon((qt_float_point *) polygonPoints, pointCount,
+ &clippedPoints, &clippedCount, close);
+
+ if (clippedCount > 0) {
+ QVarLengthArray<XPoint> xpoints(clippedCount);
+ for (int i = 0; i < clippedCount; ++i) {
+ xpoints[i].x = qRound(clippedPoints[i].x + aliasedCoordinateDelta);
+ xpoints[i].y = qRound(clippedPoints[i].y + aliasedCoordinateDelta);
+ }
+ uint numberPoints = qMin(clippedCount, xlibMaxLinePoints);
+ XPoint *pts = xpoints.data();
+ XDrawLines(dpy, hd, gc, pts, numberPoints, CoordModeOrigin);
+ pts += numberPoints;
+ clippedCount -= numberPoints;
+ numberPoints = qMin(clippedCount, xlibMaxLinePoints-1);
+ while (clippedCount) {
+ XDrawLines(dpy, hd, gc, pts-1, numberPoints+1, CoordModeOrigin);
+ pts += numberPoints;
+ clippedCount -= numberPoints;
+ numberPoints = qMin(clippedCount, xlibMaxLinePoints-1);
+ }
+ }
+}
+
+void QX11PaintEngine::drawPolygon(const QPointF *polygonPoints, int pointCount, PolygonDrawMode mode)
+{
+ Q_D(QX11PaintEngine);
+ if (d->use_path_fallback) {
+ QPainterPath path(polygonPoints[0]);
+ for (int i = 1; i < pointCount; ++i)
+ path.lineTo(polygonPoints[i]);
+ if (mode == PolylineMode) {
+ QBrush oldBrush = d->cbrush;
+ d->cbrush = QBrush(Qt::NoBrush);
+ path.setFillRule(Qt::WindingFill);
+ drawPath(path);
+ d->cbrush = oldBrush;
+ } else {
+ path.setFillRule(mode == OddEvenMode ? Qt::OddEvenFill : Qt::WindingFill);
+ path.closeSubpath();
+ drawPath(path);
+ }
+ return;
+ }
+ if (mode != PolylineMode && d->has_brush)
+ d->fillPolygon_translated(polygonPoints, pointCount, QX11PaintEnginePrivate::BrushGC, mode);
+
+ if (d->has_pen)
+ d->strokePolygon_translated(polygonPoints, pointCount, mode != PolylineMode);
+}
+
+
+void QX11PaintEnginePrivate::fillPath(const QPainterPath &path, QX11PaintEnginePrivate::GCMode gc_mode, bool transform)
+{
+ qreal offs = adjust_coords ? aliasedCoordinateDelta : 0.0;
+
+ QPainterPath clippedPath;
+ QPainterPath clipPath;
+ clipPath.addRect(polygonClipper.boundingRect());
+
+ if (transform)
+ clippedPath = (path*matrix).intersected(clipPath);
+ else
+ clippedPath = path.intersected(clipPath);
+
+ QList<QPolygonF> polys = clippedPath.toFillPolygons();
+ for (int i = 0; i < polys.size(); ++i) {
+ QVarLengthArray<QPointF> translated_points(polys.at(i).size());
+
+ for (int j = 0; j < polys.at(i).size(); ++j) {
+ translated_points[j] = polys.at(i).at(j);
+ if (!X11->use_xrender || !(render_hints & QPainter::Antialiasing)) {
+ translated_points[j].rx() = qRound(translated_points[j].rx() + aliasedCoordinateDelta) + offs;
+ translated_points[j].ry() = qRound(translated_points[j].ry() + aliasedCoordinateDelta) + offs;
+ }
+ }
+
+ fillPolygon_dev(translated_points.data(), polys.at(i).size(), gc_mode,
+ path.fillRule() == Qt::OddEvenFill ? QPaintEngine::OddEvenMode : QPaintEngine::WindingMode);
+ }
+}
+
+void QX11PaintEngine::drawPath(const QPainterPath &path)
+{
+ Q_D(QX11PaintEngine);
+ if (path.isEmpty())
+ return;
+ QTransform old_matrix = d->matrix;
+
+ if (d->has_brush)
+ d->fillPath(path, QX11PaintEnginePrivate::BrushGC, true);
+ if (d->has_pen
+ && ((X11->use_xrender && (d->has_alpha_pen || (d->render_hints & QPainter::Antialiasing)))
+ || (!d->cpen.isCosmetic() && d->txop > QTransform::TxTranslate
+ && !d->has_non_scaling_xform)
+ || (d->cpen.style() == Qt::CustomDashLine))) {
+ QPainterPathStroker stroker;
+ if (d->cpen.style() == Qt::CustomDashLine) {
+ stroker.setDashPattern(d->cpen.dashPattern());
+ stroker.setDashOffset(d->cpen.dashOffset());
+ } else {
+ stroker.setDashPattern(d->cpen.style());
+ }
+ stroker.setCapStyle(d->cpen.capStyle());
+ stroker.setJoinStyle(d->cpen.joinStyle());
+ QPainterPath stroke;
+ qreal width = d->cpen.widthF();
+ QPolygonF poly;
+ QRectF deviceRect(0, 0, d->pdev->width(), d->pdev->height());
+ // necessary to get aliased alphablended primitives to be drawn correctly
+ if (d->cpen.isCosmetic() || d->has_scaling_xform) {
+ if (d->cpen.isCosmetic())
+ stroker.setWidth(width == 0 ? 1 : width);
+ else
+ stroker.setWidth(width * d->xform_scale);
+ stroker.d_ptr->stroker.setClipRect(deviceRect);
+ stroke = stroker.createStroke(path * d->matrix);
+ if (stroke.isEmpty())
+ return;
+ stroke.setFillRule(Qt::WindingFill);
+ d->fillPath(stroke, QX11PaintEnginePrivate::PenGC, false);
+ } else {
+ stroker.setWidth(width);
+ stroker.d_ptr->stroker.setClipRect(d->matrix.inverted().mapRect(deviceRect));
+ stroke = stroker.createStroke(path);
+ if (stroke.isEmpty())
+ return;
+ stroke.setFillRule(Qt::WindingFill);
+ d->fillPath(stroke, QX11PaintEnginePrivate::PenGC, true);
+ }
+ } else if (d->has_pen) {
+ // if we have a cosmetic pen - use XDrawLine() for speed
+ QList<QPolygonF> polys = path.toSubpathPolygons(d->matrix);
+ for (int i = 0; i < polys.size(); ++i)
+ d->strokePolygon_dev(polys.at(i).data(), polys.at(i).size(), false);
+ }
+}
+
+Q_GUI_EXPORT void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image,
+ Drawable hd, GC gc, Display *dpy, Visual *visual, int depth)
+{
+ Q_ASSERT(image.format() == QImage::Format_RGB32);
+ Q_ASSERT(image.depth() == 32);
+
+ XImage *xi;
+ // Note: this code assumes either RGB or BGR, 8 bpc server layouts
+ const uint red_mask = (uint) visual->red_mask;
+ bool bgr_layout = (red_mask == 0xff);
+
+ const int w = rect.width();
+ const int h = rect.height();
+
+ QImage im;
+ int image_byte_order = ImageByteOrder(X11->display);
+ if ((QSysInfo::ByteOrder == QSysInfo::BigEndian && ((image_byte_order == LSBFirst) || bgr_layout))
+ || (image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian)
+ || (image_byte_order == LSBFirst && bgr_layout))
+ {
+ im = image.copy(rect);
+ const int iw = im.bytesPerLine() / 4;
+ uint *data = (uint *)im.bits();
+ for (int i=0; i < h; i++) {
+ uint *p = data;
+ uint *end = p + w;
+ if (bgr_layout && image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
+ while (p < end) {
+ *p = ((*p << 8) & 0xffffff00) | ((*p >> 24) & 0x000000ff);
+ p++;
+ }
+ } else if ((image_byte_order == LSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ || (image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) {
+ while (p < end) {
+ *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
+ | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
+ p++;
+ }
+ } else if ((image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ || (image_byte_order == LSBFirst && bgr_layout))
+ {
+ while (p < end) {
+ *p = ((*p << 16) & 0x00ff0000) | ((*p >> 16) & 0x000000ff)
+ | ((*p ) & 0xff00ff00);
+ p++;
+ }
+ }
+ data += iw;
+ }
+ xi = XCreateImage(dpy, visual, depth, ZPixmap,
+ 0, (char *) im.bits(), w, h, 32, im.bytesPerLine());
+ } else {
+ xi = XCreateImage(dpy, visual, depth, ZPixmap,
+ 0, (char *) image.scanLine(rect.y())+rect.x()*sizeof(uint), w, h, 32, image.bytesPerLine());
+ }
+ XPutImage(dpy, hd, gc, xi, 0, 0, pos.x(), pos.y(), w, h);
+ xi->data = 0; // QImage owns these bits
+ XDestroyImage(xi);
+}
+
+void QX11PaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags)
+{
+ Q_D(QX11PaintEngine);
+
+ if (image.format() == QImage::Format_RGB32
+ && d->pdev_depth >= 24 && image.depth() == 32
+ && r.size() == sr.size())
+ {
+ int sx = qRound(sr.x());
+ int sy = qRound(sr.y());
+ int x = qRound(r.x());
+ int y = qRound(r.y());
+ int w = qRound(r.width());
+ int h = qRound(r.height());
+
+ qt_x11_drawImage(QRect(sx, sy, w, h), QPoint(x, y), image, d->hd, d->gc, d->dpy,
+ (Visual *)d->xinfo->visual(), d->pdev_depth);
+ } else {
+ QPaintEngine::drawImage(r, image, sr, flags);
+ }
+}
+
+void QX11PaintEngine::drawPixmap(const QRectF &r, const QPixmap &px, const QRectF &_sr)
+{
+ Q_D(QX11PaintEngine);
+ QRectF sr = _sr;
+ int x = qRound(r.x());
+ int y = qRound(r.y());
+ int sx = qRound(sr.x());
+ int sy = qRound(sr.y());
+ int sw = qRound(sr.width());
+ int sh = qRound(sr.height());
+
+ QPixmap pixmap = qt_toX11Pixmap(px);
+ if(pixmap.isNull())
+ return;
+
+ if ((d->xinfo && d->xinfo->screen() != pixmap.x11Info().screen())
+ || (pixmap.x11Info().screen() != DefaultScreen(X11->display))) {
+ QPixmap* p = const_cast<QPixmap *>(&pixmap);
+ p->x11SetScreen(d->xinfo ? d->xinfo->screen() : DefaultScreen(X11->display));
+ }
+
+ QPixmap::x11SetDefaultScreen(pixmap.x11Info().screen());
+
+#ifndef QT_NO_XRENDER
+ ::Picture src_pict = static_cast<QX11PixmapData*>(pixmap.data.data())->picture;
+ if (src_pict && d->picture) {
+ const int pDepth = pixmap.depth();
+ if (pDepth == 1 && (d->has_alpha_pen)) {
+ qt_render_bitmap(d->dpy, d->scrn, src_pict, d->picture,
+ sx, sy, x, y, sw, sh, d->cpen);
+ return;
+ } else if (pDepth != 1 && (pDepth == 32 || pDepth != d->pdev_depth)) {
+ XRenderComposite(d->dpy, d->composition_mode,
+ src_pict, 0, d->picture, sx, sy, 0, 0, x, y, sw, sh);
+ return;
+ }
+ }
+#endif
+
+ bool mono_src = pixmap.depth() == 1;
+ bool mono_dst = d->pdev_depth == 1;
+ bool restore_clip = false;
+
+ if (static_cast<QX11PixmapData*>(pixmap.data.data())->x11_mask) { // pixmap has a mask
+ QBitmap comb(sw, sh);
+ GC cgc = XCreateGC(d->dpy, comb.handle(), 0, 0);
+ XSetForeground(d->dpy, cgc, 0);
+ XFillRectangle(d->dpy, comb.handle(), cgc, 0, 0, sw, sh);
+ XSetBackground(d->dpy, cgc, 0);
+ XSetForeground(d->dpy, cgc, 1);
+ if (!d->crgn.isEmpty()) {
+ int num;
+ XRectangle *rects = (XRectangle *)qt_getClipRects(d->crgn, num);
+ XSetClipRectangles(d->dpy, cgc, -x, -y, rects, num, Unsorted);
+ } else if (d->has_clipping) {
+ XSetClipRectangles(d->dpy, cgc, 0, 0, 0, 0, Unsorted);
+ }
+ XSetFillStyle(d->dpy, cgc, FillOpaqueStippled);
+ XSetTSOrigin(d->dpy, cgc, -sx, -sy);
+ XSetStipple(d->dpy, cgc,
+ static_cast<QX11PixmapData*>(pixmap.data.data())->x11_mask);
+ XFillRectangle(d->dpy, comb.handle(), cgc, 0, 0, sw, sh);
+ XFreeGC(d->dpy, cgc);
+
+ XSetClipOrigin(d->dpy, d->gc, x, y);
+ XSetClipMask(d->dpy, d->gc, comb.handle());
+ restore_clip = true;
+ }
+
+ if (mono_src) {
+ if (!d->crgn.isEmpty()) {
+ Pixmap comb = XCreatePixmap(d->dpy, d->hd, sw, sh, 1);
+ GC cgc = XCreateGC(d->dpy, comb, 0, 0);
+ XSetForeground(d->dpy, cgc, 0);
+ XFillRectangle(d->dpy, comb, cgc, 0, 0, sw, sh);
+ int num;
+ XRectangle *rects = (XRectangle *)qt_getClipRects(d->crgn, num);
+ XSetClipRectangles(d->dpy, cgc, -x, -y, rects, num, Unsorted);
+ XCopyArea(d->dpy, pixmap.handle(), comb, cgc, sx, sy, sw, sh, 0, 0);
+ XFreeGC(d->dpy, cgc);
+
+ XSetClipMask(d->dpy, d->gc, comb);
+ XSetClipOrigin(d->dpy, d->gc, x, y);
+ XFreePixmap(d->dpy, comb);
+ } else {
+ XSetClipMask(d->dpy, d->gc, pixmap.handle());
+ XSetClipOrigin(d->dpy, d->gc, x - sx, y - sy);
+ }
+
+ if (mono_dst) {
+ XSetForeground(d->dpy, d->gc, qGray(d->cpen.color().rgb()) > 127 ? 0 : 1);
+ } else {
+ QColormap cmap = QColormap::instance(d->scrn);
+ XSetForeground(d->dpy, d->gc, cmap.pixel(d->cpen.color()));
+ }
+ XFillRectangle(d->dpy, d->hd, d->gc, x, y, sw, sh);
+ restore_clip = true;
+ } else if (mono_dst && !mono_src) {
+ QBitmap bitmap(pixmap);
+ XCopyArea(d->dpy, bitmap.handle(), d->hd, d->gc, sx, sy, sw, sh, x, y);
+ } else {
+ XCopyArea(d->dpy, pixmap.handle(), d->hd, d->gc, sx, sy, sw, sh, x, y);
+ }
+
+ if (d->pdev->devType() == QInternal::Pixmap) {
+ const QPixmap *px = static_cast<const QPixmap*>(d->pdev);
+ Pixmap src_mask = static_cast<QX11PixmapData*>(pixmap.data.data())->x11_mask;
+ Pixmap dst_mask = static_cast<QX11PixmapData*>(px->data.data())->x11_mask;
+ if (dst_mask) {
+ GC cgc = XCreateGC(d->dpy, dst_mask, 0, 0);
+ if (src_mask) { // copy src mask into dst mask
+ XCopyArea(d->dpy, src_mask, dst_mask, cgc, sx, sy, sw, sh, x, y);
+ } else { // no src mask, but make sure the area copied is opaque in dest
+ XSetBackground(d->dpy, cgc, 0);
+ XSetForeground(d->dpy, cgc, 1);
+ XFillRectangle(d->dpy, dst_mask, cgc, x, y, sw, sh);
+ }
+ XFreeGC(d->dpy, cgc);
+ }
+ }
+
+ if (restore_clip) {
+ XSetClipOrigin(d->dpy, d->gc, 0, 0);
+ int num;
+ XRectangle *rects = (XRectangle *)qt_getClipRects(d->crgn, num);
+ if (num == 0)
+ XSetClipMask(d->dpy, d->gc, XNone);
+ else
+ XSetClipRectangles(d->dpy, d->gc, 0, 0, rects, num, Unsorted);
+ }
+}
+
+void QX11PaintEngine::updateMatrix(const QTransform &mtx)
+{
+ Q_D(QX11PaintEngine);
+ d->txop = mtx.type();
+ d->matrix = mtx;
+
+ d->has_complex_xform = (d->txop > QTransform::TxTranslate);
+
+ extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
+ bool scaling = qt_scaleForTransform(d->matrix, &d->xform_scale);
+ d->has_scaling_xform = scaling && d->xform_scale != 1.0;
+ d->has_non_scaling_xform = scaling && d->xform_scale == 1.0;
+}
+
+/*
+ NB! the clip region is expected to be in dev coordinates
+*/
+void QX11PaintEngine::updateClipRegion_dev(const QRegion &clipRegion, Qt::ClipOperation op)
+{
+ Q_D(QX11PaintEngine);
+ QRegion sysClip = systemClip();
+ if (op == Qt::NoClip) {
+ d->has_clipping = false;
+ d->crgn = sysClip;
+ if (!sysClip.isEmpty()) {
+ x11SetClipRegion(d->dpy, d->gc, d->gc_brush, d->picture, sysClip);
+ } else {
+ x11ClearClipRegion(d->dpy, d->gc, d->gc_brush, d->picture);
+ }
+ return;
+ }
+
+ switch (op) {
+ case Qt::IntersectClip:
+ if (d->has_clipping) {
+ d->crgn &= clipRegion;
+ break;
+ }
+ // fall through
+ case Qt::ReplaceClip:
+ if (!sysClip.isEmpty())
+ d->crgn = clipRegion.intersected(sysClip);
+ else
+ d->crgn = clipRegion;
+ break;
+ case Qt::UniteClip:
+ d->crgn |= clipRegion;
+ if (!sysClip.isEmpty())
+ d->crgn = d->crgn.intersected(sysClip);
+ break;
+ default:
+ break;
+ }
+ d->has_clipping = true;
+ x11SetClipRegion(d->dpy, d->gc, d->gc_brush, d->picture, d->crgn);
+}
+
+void QX11PaintEngine::updateFont(const QFont &)
+{
+}
+
+Qt::HANDLE QX11PaintEngine::handle() const
+{
+ Q_D(const QX11PaintEngine);
+ Q_ASSERT(isActive());
+ Q_ASSERT(d->hd);
+ return d->hd;
+}
+
+extern void qt_draw_tile(QPaintEngine *, qreal, qreal, qreal, qreal, const QPixmap &,
+ qreal, qreal);
+
+void QX11PaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &p)
+{
+ int x = qRound(r.x());
+ int y = qRound(r.y());
+ int w = qRound(r.width());
+ int h = qRound(r.height());
+ int sx = qRound(p.x());
+ int sy = qRound(p.y());
+
+ bool mono_src = pixmap.depth() == 1;
+ Q_D(QX11PaintEngine);
+
+ if ((d->xinfo && d->xinfo->screen() != pixmap.x11Info().screen())
+ || (pixmap.x11Info().screen() != DefaultScreen(X11->display))) {
+ QPixmap* p = const_cast<QPixmap *>(&pixmap);
+ p->x11SetScreen(d->xinfo ? d->xinfo->screen() : DefaultScreen(X11->display));
+ }
+
+ QPixmap::x11SetDefaultScreen(pixmap.x11Info().screen());
+
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender && d->picture && pixmap.x11PictureHandle()) {
+#if 0
+ // ### Qt 5: enable this
+ XRenderPictureAttributes attrs;
+ attrs.repeat = true;
+ XRenderChangePicture(d->dpy, pixmap.x11PictureHandle(), CPRepeat, &attrs);
+
+ if (mono_src) {
+ qt_render_bitmap(d->dpy, d->scrn, pixmap.x11PictureHandle(), d->picture,
+ sx, sy, x, y, w, h, d->cpen);
+ } else {
+ XRenderComposite(d->dpy, d->composition_mode,
+ pixmap.x11PictureHandle(), XNone, d->picture,
+ sx, sy, 0, 0, x, y, w, h);
+ }
+#else
+ const int numTiles = (w / pixmap.width()) * (h / pixmap.height());
+ if (numTiles < 100) {
+ // this is essentially qt_draw_tile(), inlined for
+ // the XRenderComposite call
+ int yPos, xPos, drawH, drawW, yOff, xOff;
+ yPos = y;
+ yOff = sy;
+ while(yPos < y + h) {
+ drawH = pixmap.height() - yOff; // Cropping first row
+ if (yPos + drawH > y + h) // Cropping last row
+ drawH = y + h - yPos;
+ xPos = x;
+ xOff = sx;
+ while(xPos < x + w) {
+ drawW = pixmap.width() - xOff; // Cropping first column
+ if (xPos + drawW > x + w) // Cropping last column
+ drawW = x + w - xPos;
+ if (mono_src) {
+ qt_render_bitmap(d->dpy, d->scrn, pixmap.x11PictureHandle(), d->picture,
+ xOff, yOff, xPos, yPos, drawW, drawH, d->cpen);
+ } else {
+ XRenderComposite(d->dpy, d->composition_mode,
+ pixmap.x11PictureHandle(), XNone, d->picture,
+ xOff, yOff, 0, 0, xPos, yPos, drawW, drawH);
+ }
+ xPos += drawW;
+ xOff = 0;
+ }
+ yPos += drawH;
+ yOff = 0;
+ }
+ } else {
+ w = qMin(w, d->pdev->width() - x);
+ h = qMin(h, d->pdev->height() - y);
+ if (w <= 0 || h <= 0)
+ return;
+
+ const int pw = w + sx;
+ const int ph = h + sy;
+ QPixmap pm(pw, ph);
+ if (pixmap.hasAlpha() || mono_src)
+ pm.fill(Qt::transparent);
+
+ const int mode = pixmap.hasAlpha() ? PictOpOver : PictOpSrc;
+ const ::Picture pmPicture = pm.x11PictureHandle();
+
+ // first tile
+ XRenderComposite(d->dpy, mode,
+ pixmap.x11PictureHandle(), XNone, pmPicture,
+ 0, 0, 0, 0, 0, 0, qMin(pw, pixmap.width()), qMin(ph, pixmap.height()));
+
+ // first row of tiles
+ int xPos = pixmap.width();
+ const int sh = qMin(ph, pixmap.height());
+ while (xPos < pw) {
+ const int sw = qMin(xPos, pw - xPos);
+ XRenderComposite(d->dpy, mode,
+ pmPicture, XNone, pmPicture,
+ 0, 0, 0, 0, xPos, 0, sw, sh);
+ xPos *= 2;
+ }
+
+ // remaining rows
+ int yPos = pixmap.height();
+ const int sw = pw;
+ while (yPos < ph) {
+ const int sh = qMin(yPos, ph - yPos);
+ XRenderComposite(d->dpy, mode,
+ pmPicture, XNone, pmPicture,
+ 0, 0, 0, 0, 0, yPos, sw, sh);
+ yPos *= 2;
+ }
+
+ // composite
+ if (mono_src)
+ qt_render_bitmap(d->dpy, d->scrn, pmPicture, d->picture,
+ sx, sy, x, y, w, h, d->cpen);
+ else
+ XRenderComposite(d->dpy, d->composition_mode,
+ pmPicture, XNone, d->picture,
+ sx, sy, 0, 0, x, y, w, h);
+ }
+#endif
+ } else
+#endif // !QT_NO_XRENDER
+ if (pixmap.depth() > 1 && !static_cast<QX11PixmapData*>(pixmap.data.data())->x11_mask) {
+ XSetTile(d->dpy, d->gc, pixmap.handle());
+ XSetFillStyle(d->dpy, d->gc, FillTiled);
+ XSetTSOrigin(d->dpy, d->gc, x-sx, y-sy);
+ XFillRectangle(d->dpy, d->hd, d->gc, x, y, w, h);
+ XSetTSOrigin(d->dpy, d->gc, 0, 0);
+ XSetFillStyle(d->dpy, d->gc, FillSolid);
+ } else {
+ qt_draw_tile(this, x, y, w, h, pixmap, sx, sy);
+ }
+}
+
+void QX11PaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
+{
+ const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
+
+ switch(ti.fontEngine->type()) {
+ case QFontEngine::TestFontEngine:
+ case QFontEngine::Box:
+ d_func()->drawBoxTextItem(p, ti);
+ break;
+ case QFontEngine::XLFD:
+ drawXLFD(p, ti);
+ break;
+#ifndef QT_NO_FONTCONFIG
+ case QFontEngine::Freetype:
+ drawFreetype(p, ti);
+ break;
+#endif
+ default:
+ Q_ASSERT(false);
+ }
+}
+
+void QX11PaintEngine::drawXLFD(const QPointF &p, const QTextItemInt &ti)
+{
+ Q_D(QX11PaintEngine);
+
+ if (d->txop > QTransform::TxTranslate) {
+ // XServer or font don't support server side transformations, need to do it by hand
+ QPaintEngine::drawTextItem(p, ti);
+ return;
+ }
+
+ if (!ti.glyphs.numGlyphs)
+ return;
+
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> glyphs;
+ QTransform matrix = d->matrix;
+ matrix.translate(p.x(), p.y());
+ ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+ if (glyphs.size() == 0)
+ return;
+
+ QFontEngineXLFD *xlfd = static_cast<QFontEngineXLFD *>(ti.fontEngine);
+ Qt::HANDLE font_id = xlfd->fontStruct()->fid;
+
+ XSetFont(d->dpy, d->gc, font_id);
+
+ const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
+ for (int i = 0; i < glyphs.size(); i++) {
+ int xp = qRound(positions[i].x + offs);
+ int yp = qRound(positions[i].y + offs);
+ if (xp < SHRT_MAX && xp > SHRT_MIN && yp > SHRT_MIN && yp < SHRT_MAX) {
+ XChar2b ch;
+ ch.byte1 = glyphs[i] >> 8;
+ ch.byte2 = glyphs[i] & 0xff;
+ XDrawString16(d->dpy, d->hd, d->gc, xp, yp, &ch, 1);
+ }
+ }
+}
+
+#ifndef QT_NO_FONTCONFIG
+static QPainterPath path_for_glyphs(const QVarLengthArray<glyph_t> &glyphs,
+ const QVarLengthArray<QFixedPoint> &positions,
+ const QFontEngineFT *ft)
+{
+ QPainterPath path;
+ path.setFillRule(Qt::WindingFill);
+ ft->lockFace();
+ int i = 0;
+ while (i < glyphs.size()) {
+ QFontEngineFT::Glyph *glyph = ft->loadGlyph(glyphs[i], QFontEngineFT::Format_Mono);
+ // #### fix case where we don't get a glyph
+ if (!glyph)
+ break;
+
+ Q_ASSERT(glyph->format == QFontEngineFT::Format_Mono);
+ int n = 0;
+ int h = glyph->height;
+ int xp = qRound(positions[i].x);
+ int yp = qRound(positions[i].y);
+
+ xp += glyph->x;
+ yp += -glyph->y + glyph->height;
+ int pitch = ((glyph->width + 31) & ~31) >> 3;
+
+ uchar *src = glyph->data;
+ while (h--) {
+ for (int x = 0; x < glyph->width; ++x) {
+ bool set = src[x >> 3] & (0x80 >> (x & 7));
+ if (set) {
+ QRect r(xp + x, yp - h, 1, 1);
+ while (x < glyph->width-1 && src[(x+1) >> 3] & (0x80 >> ((x+1) & 7))) {
+ ++x;
+ r.setRight(r.right()+1);
+ }
+
+ path.addRect(r);
+ ++n;
+ }
+ }
+ src += pitch;
+ }
+ ++i;
+ }
+ ft->unlockFace();
+ return path;
+}
+
+void QX11PaintEngine::drawFreetype(const QPointF &p, const QTextItemInt &ti)
+{
+ Q_D(QX11PaintEngine);
+ if (!ti.glyphs.numGlyphs)
+ return;
+
+ QFontEngineX11FT *ft = static_cast<QFontEngineX11FT *>(ti.fontEngine);
+
+ if (!d->cpen.isSolid()) {
+ QPaintEngine::drawTextItem(p, ti);
+ return;
+ }
+
+ const bool xrenderPath = (X11->use_xrender
+ && !(d->pdev->devType() == QInternal::Pixmap
+ && static_cast<const QPixmap *>(d->pdev)->data->pixelType() == QPixmapData::BitmapType));
+
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> glyphs;
+ QTransform matrix;
+
+ if (xrenderPath)
+ matrix = d->matrix;
+ matrix.translate(p.x(), p.y());
+ ft->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+ if (glyphs.count() == 0)
+ return;
+
+#ifndef QT_NO_XRENDER
+ QFontEngineFT::QGlyphSet *set = ft->defaultGlyphs();
+ if (d->txop >= QTransform::TxScale && xrenderPath)
+ set = ft->loadTransformedGlyphSet(d->matrix);
+
+ if (!set || set->outline_drawing
+ || !ft->loadGlyphs(set, glyphs.constData(), glyphs.size(), positions.constData(), QFontEngineFT::Format_Render))
+ {
+ QPaintEngine::drawTextItem(p, ti);
+ return;
+ }
+
+ if (xrenderPath) {
+ GlyphSet glyphSet = set->id;
+ const QColor &pen = d->cpen.color();
+ ::Picture src = X11->getSolidFill(d->scrn, pen);
+ XRenderPictFormat *maskFormat = 0;
+ if (ft->xglyph_format != PictStandardA1)
+ maskFormat = XRenderFindStandardFormat(X11->display, ft->xglyph_format);
+
+ enum { t_min = SHRT_MIN, t_max = SHRT_MAX };
+
+ int i = 0;
+ for (; i < glyphs.size()
+ && (positions[i].x < t_min || positions[i].x > t_max
+ || positions[i].y < t_min || positions[i].y > t_max);
+ ++i)
+ ;
+
+ if (i >= glyphs.size())
+ return;
+ ++i;
+
+ QFixed xp = positions[i - 1].x;
+ QFixed yp = positions[i - 1].y;
+ QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
+
+ XGlyphElt32 elt;
+ elt.glyphset = glyphSet;
+ elt.chars = &glyphs[i - 1];
+ elt.nchars = 1;
+ elt.xOff = qRound(xp + offs);
+ elt.yOff = qRound(yp + offs);
+ for (; i < glyphs.size(); ++i) {
+ if (positions[i].x < t_min || positions[i].x > t_max
+ || positions[i].y < t_min || positions[i].y > t_max) {
+ break;
+ }
+ QFontEngineFT::Glyph *g = ft->cachedGlyph(glyphs[i - 1]);
+ if (g
+ && positions[i].x == xp + g->advance
+ && positions[i].y == yp
+ && elt.nchars < 253 // don't draw more than 253 characters as some X servers
+ // hang with it
+ ) {
+ elt.nchars++;
+ xp += g->advance;
+ } else {
+ xp = positions[i].x;
+ yp = positions[i].y;
+
+ XRenderCompositeText32(X11->display, PictOpOver, src, d->picture,
+ maskFormat, 0, 0, 0, 0,
+ &elt, 1);
+ elt.chars = &glyphs[i];
+ elt.nchars = 1;
+ elt.xOff = qRound(xp + offs);
+ elt.yOff = qRound(yp + offs);
+ }
+ }
+ XRenderCompositeText32(X11->display, PictOpOver, src, d->picture,
+ maskFormat, 0, 0, 0, 0,
+ &elt, 1);
+
+ return;
+
+ }
+#endif
+
+ QPainterPath path = path_for_glyphs(glyphs, positions, ft);
+ if (path.elementCount() <= 1)
+ return;
+ Q_ASSERT((path.elementCount() % 5) == 0);
+ if (d->txop >= QTransform::TxScale) {
+ painter()->save();
+ painter()->setBrush(d->cpen.brush());
+ painter()->setPen(Qt::NoPen);
+ painter()->drawPath(path);
+ painter()->restore();
+ return;
+ }
+
+ const int rectcount = 256;
+ XRectangle rects[rectcount];
+ int num_rects = 0;
+
+ QPoint delta(qRound(d->matrix.dx()), qRound(d->matrix.dy()));
+ QRect clip(d->polygonClipper.boundingRect());
+ for (int i=0; i < path.elementCount(); i+=5) {
+ int x = qRound(path.elementAt(i).x);
+ int y = qRound(path.elementAt(i).y);
+ int w = qRound(path.elementAt(i+1).x) - x;
+ int h = qRound(path.elementAt(i+2).y) - y;
+
+ QRect rect = QRect(x + delta.x(), y + delta.y(), w, h);
+ rect = rect.intersected(clip);
+ if (rect.isEmpty())
+ continue;
+
+ rects[num_rects].x = short(rect.x());
+ rects[num_rects].y = short(rect.y());
+ rects[num_rects].width = ushort(rect.width());
+ rects[num_rects].height = ushort(rect.height());
+ ++num_rects;
+ if (num_rects == rectcount) {
+ XFillRectangles(d->dpy, d->hd, d->gc, rects, num_rects);
+ num_rects = 0;
+ }
+ }
+ if (num_rects > 0)
+ XFillRectangles(d->dpy, d->hd, d->gc, rects, num_rects);
+
+}
+#endif // !QT_NO_XRENDER
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qpaintengine_x11_p.h b/src/widgets/platforms/x11/qpaintengine_x11_p.h
new file mode 100644
index 0000000000..897c69f122
--- /dev/null
+++ b/src/widgets/platforms/x11/qpaintengine_x11_p.h
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QPAINTENGINE_X11_P_H
+#define QPAINTENGINE_X11_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/qpaintengine.h"
+#include "QtGui/qregion.h"
+#include "QtGui/qpen.h"
+#include "QtCore/qpoint.h"
+#include "private/qpaintengine_p.h"
+#include "private/qpainter_p.h"
+#include "private/qpolygonclipper_p.h"
+
+typedef unsigned long Picture;
+
+QT_BEGIN_NAMESPACE
+
+class QX11PaintEnginePrivate;
+class QFontEngineFT;
+class QXRenderTessellator;
+
+struct qt_float_point
+{
+ qreal x, y;
+};
+
+class QX11PaintEngine : public QPaintEngine
+{
+ Q_DECLARE_PRIVATE(QX11PaintEngine)
+public:
+ QX11PaintEngine();
+ ~QX11PaintEngine();
+
+ bool begin(QPaintDevice *pdev);
+ bool end();
+
+ void updateState(const QPaintEngineState &state);
+
+ void updatePen(const QPen &pen);
+ void updateBrush(const QBrush &brush, const QPointF &pt);
+ void updateRenderHints(QPainter::RenderHints hints);
+ void updateFont(const QFont &font);
+ void updateMatrix(const QTransform &matrix);
+ void updateClipRegion_dev(const QRegion &region, Qt::ClipOperation op);
+
+ void drawLines(const QLine *lines, int lineCount);
+ void drawLines(const QLineF *lines, int lineCount);
+
+ void drawRects(const QRect *rects, int rectCount);
+ void drawRects(const QRectF *rects, int rectCount);
+
+ void drawPoints(const QPoint *points, int pointCount);
+ void drawPoints(const QPointF *points, int pointCount);
+
+ void drawEllipse(const QRect &r);
+ void drawEllipse(const QRectF &r);
+
+ virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode);
+ inline void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
+ { QPaintEngine::drawPolygon(points, pointCount, mode); }
+
+ void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
+ void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
+ void drawPath(const QPainterPath &path);
+ void drawTextItem(const QPointF &p, const QTextItem &textItem);
+ void drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
+ Qt::ImageConversionFlags flags = Qt::AutoColor);
+
+ virtual Qt::HANDLE handle() const;
+ inline Type type() const { return QPaintEngine::X11; }
+
+ QPainter::RenderHints supportedRenderHints() const;
+
+protected:
+ QX11PaintEngine(QX11PaintEnginePrivate &dptr);
+
+ void drawXLFD(const QPointF &p, const QTextItemInt &si);
+#ifndef QT_NO_FONTCONFIG
+ void drawFreetype(const QPointF &p, const QTextItemInt &si);
+#endif
+
+ friend class QPixmap;
+ friend class QFontEngineBox;
+ friend Q_GUI_EXPORT GC qt_x11_get_pen_gc(QPainter *);
+ friend Q_GUI_EXPORT GC qt_x11_get_brush_gc(QPainter *);
+
+private:
+ Q_DISABLE_COPY(QX11PaintEngine)
+};
+
+class QX11PaintEnginePrivate : public QPaintEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QX11PaintEngine)
+public:
+ QX11PaintEnginePrivate()
+ {
+ scrn = -1;
+ hd = 0;
+ picture = 0;
+ gc = gc_brush = 0;
+ dpy = 0;
+ xinfo = 0;
+ txop = QTransform::TxNone;
+ has_clipping = false;
+ render_hints = 0;
+ xform_scale = 1;
+#ifndef QT_NO_XRENDER
+ tessellator = 0;
+#endif
+ }
+ enum GCMode {
+ PenGC,
+ BrushGC
+ };
+
+ void init();
+ void fillPolygon_translated(const QPointF *points, int pointCount, GCMode gcMode,
+ QPaintEngine::PolygonDrawMode mode);
+ void fillPolygon_dev(const QPointF *points, int pointCount, GCMode gcMode,
+ QPaintEngine::PolygonDrawMode mode);
+ void fillPath(const QPainterPath &path, GCMode gcmode, bool transform);
+ void strokePolygon_dev(const QPointF *points, int pointCount, bool close);
+ void strokePolygon_translated(const QPointF *points, int pointCount, bool close);
+ void setupAdaptedOrigin(const QPoint &p);
+ void resetAdaptedOrigin();
+ void decidePathFallback() {
+ use_path_fallback = has_alpha_brush
+ || has_alpha_pen
+ || has_custom_pen
+ || has_complex_xform
+ || (render_hints & QPainter::Antialiasing);
+ }
+ void decideCoordAdjust() {
+ adjust_coords = !(render_hints & QPainter::Antialiasing)
+ && (has_alpha_pen
+ || (has_alpha_brush && has_pen && !has_alpha_pen)
+ || (cpen.style() > Qt::SolidLine));
+ }
+ void clipPolygon_dev(const QPolygonF &poly, QPolygonF *clipped_poly);
+ void systemStateChanged();
+
+ Display *dpy;
+ int scrn;
+ int pdev_depth;
+ Qt::HANDLE hd;
+ QPixmap brush_pm;
+#if !defined (QT_NO_XRENDER)
+ Qt::HANDLE picture;
+ Qt::HANDLE current_brush;
+ QPixmap bitmap_texture;
+ int composition_mode;
+#else
+ Qt::HANDLE picture;
+#endif
+ GC gc;
+ GC gc_brush;
+
+ QPen cpen;
+ QBrush cbrush;
+ QRegion crgn;
+ QTransform matrix;
+ qreal opacity;
+
+ uint has_complex_xform : 1;
+ uint has_scaling_xform : 1;
+ uint has_non_scaling_xform : 1;
+ uint has_custom_pen : 1;
+ uint use_path_fallback : 1;
+ uint adjust_coords : 1;
+ uint has_clipping : 1;
+ uint adapted_brush_origin : 1;
+ uint adapted_pen_origin : 1;
+ uint has_pen : 1;
+ uint has_brush : 1;
+ uint has_texture : 1;
+ uint has_alpha_texture : 1;
+ uint has_pattern : 1;
+ uint has_alpha_pen : 1;
+ uint has_alpha_brush : 1;
+ uint render_hints;
+
+ const QX11Info *xinfo;
+ QPointF bg_origin;
+ QTransform::TransformationType txop;
+ qreal xform_scale;
+ QPolygonClipper<qt_float_point, qt_float_point, float> polygonClipper;
+
+ int xlibMaxLinePoints;
+#ifndef QT_NO_XRENDER
+ QXRenderTessellator *tessellator;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif // QPAINTENGINE_X11_P_H
diff --git a/src/widgets/platforms/x11/qpixmap_x11.cpp b/src/widgets/platforms/x11/qpixmap_x11.cpp
new file mode 100644
index 0000000000..bc468cb7ec
--- /dev/null
+++ b/src/widgets/platforms/x11/qpixmap_x11.cpp
@@ -0,0 +1,2419 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+// Uncomment the next line to enable the MIT Shared Memory extension
+//
+// WARNING: This has some problems:
+//
+// 1. Consumes a 800x600 pixmap
+// 2. Qt does not handle the ShmCompletion message, so you will
+// get strange effects if you xForm() repeatedly.
+//
+// #define QT_MITSHM
+
+#if defined(Q_OS_WIN32) && defined(QT_MITSHM)
+#undef QT_MITSHM
+#endif
+
+#include "qplatformdefs.h"
+
+#include "qdebug.h"
+#include "qiodevice.h"
+#include "qpixmap_x11_p.h"
+#include "qbitmap.h"
+#include "qcolormap.h"
+#include "qimage.h"
+#include "qmatrix.h"
+#include "qapplication.h"
+#include <private/qpaintengine_x11_p.h>
+#include <private/qt_x11_p.h>
+#include "qx11info_x11.h"
+#include <private/qdrawhelper_p.h>
+#include <private/qimage_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
+
+#include <stdlib.h>
+
+#if defined(Q_CC_MIPS)
+# define for if(0){}else for
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QPixmap qt_toX11Pixmap(const QImage &image)
+{
+ QPixmapData *data =
+ new QX11PixmapData(image.depth() == 1
+ ? QPixmapData::BitmapType
+ : QPixmapData::PixmapType);
+
+ data->fromImage(image, Qt::AutoColor);
+
+ return QPixmap(data);
+}
+
+QPixmap qt_toX11Pixmap(const QPixmap &pixmap)
+{
+ if (pixmap.isNull())
+ return QPixmap();
+
+ if (QPixmap(pixmap).data_ptr()->classId() == QPixmapData::X11Class)
+ return pixmap;
+
+ return qt_toX11Pixmap(pixmap.toImage());
+}
+
+// For thread-safety:
+// image->data does not belong to X11, so we must free it ourselves.
+
+inline static void qSafeXDestroyImage(XImage *x)
+{
+ if (x->data) {
+ free(x->data);
+ x->data = 0;
+ }
+ XDestroyImage(x);
+}
+
+QBitmap QX11PixmapData::mask_to_bitmap(int screen) const
+{
+ if (!x11_mask)
+ return QBitmap();
+ QPixmap::x11SetDefaultScreen(screen);
+ QBitmap bm(w, h);
+ GC gc = XCreateGC(X11->display, bm.handle(), 0, 0);
+ XCopyArea(X11->display, x11_mask, bm.handle(), gc, 0, 0,
+ bm.data->width(), bm.data->height(), 0, 0);
+ XFreeGC(X11->display, gc);
+ return bm;
+}
+
+Qt::HANDLE QX11PixmapData::bitmap_to_mask(const QBitmap &bitmap, int screen)
+{
+ if (bitmap.isNull())
+ return 0;
+ QBitmap bm = bitmap;
+ bm.x11SetScreen(screen);
+
+ Pixmap mask = XCreatePixmap(X11->display, RootWindow(X11->display, screen),
+ bm.data->width(), bm.data->height(), 1);
+ GC gc = XCreateGC(X11->display, mask, 0, 0);
+ XCopyArea(X11->display, bm.handle(), mask, gc, 0, 0,
+ bm.data->width(), bm.data->height(), 0, 0);
+ XFreeGC(X11->display, gc);
+ return mask;
+}
+
+
+/*****************************************************************************
+ MIT Shared Memory Extension support: makes xForm noticeably (~20%) faster.
+ *****************************************************************************/
+
+#if defined(QT_MITSHM)
+
+static bool xshminit = false;
+static XShmSegmentInfo xshminfo;
+static XImage *xshmimg = 0;
+static Pixmap xshmpm = 0;
+
+static void qt_cleanup_mitshm()
+{
+ if (xshmimg == 0)
+ return;
+ Display *dpy = QX11Info::appDisplay();
+ if (xshmpm) {
+ XFreePixmap(dpy, xshmpm);
+ xshmpm = 0;
+ }
+ XShmDetach(dpy, &xshminfo); xshmimg->data = 0;
+ qSafeXDestroyImage(xshmimg); xshmimg = 0;
+ shmdt(xshminfo.shmaddr);
+ shmctl(xshminfo.shmid, IPC_RMID, 0);
+}
+
+static bool qt_create_mitshm_buffer(const QPaintDevice* dev, int w, int h)
+{
+ static int major, minor;
+ static Bool pixmaps_ok;
+ Display *dpy = dev->data->xinfo->display();
+ int dd = dev->x11Depth();
+ Visual *vis = (Visual*)dev->x11Visual();
+
+ if (xshminit) {
+ qt_cleanup_mitshm();
+ } else {
+ if (!XShmQueryVersion(dpy, &major, &minor, &pixmaps_ok))
+ return false; // MIT Shm not supported
+ qAddPostRoutine(qt_cleanup_mitshm);
+ xshminit = true;
+ }
+
+ xshmimg = XShmCreateImage(dpy, vis, dd, ZPixmap, 0, &xshminfo, w, h);
+ if (!xshmimg)
+ return false;
+
+ bool ok;
+ xshminfo.shmid = shmget(IPC_PRIVATE,
+ xshmimg->bytes_per_line * xshmimg->height,
+ IPC_CREAT | 0777);
+ ok = xshminfo.shmid != -1;
+ if (ok) {
+ xshmimg->data = (char*)shmat(xshminfo.shmid, 0, 0);
+ xshminfo.shmaddr = xshmimg->data;
+ ok = (xshminfo.shmaddr != (char*)-1);
+ }
+ xshminfo.readOnly = false;
+ if (ok)
+ ok = XShmAttach(dpy, &xshminfo);
+ if (!ok) {
+ qSafeXDestroyImage(xshmimg);
+ xshmimg = 0;
+ if (xshminfo.shmaddr)
+ shmdt(xshminfo.shmaddr);
+ if (xshminfo.shmid != -1)
+ shmctl(xshminfo.shmid, IPC_RMID, 0);
+ return false;
+ }
+ if (pixmaps_ok)
+ xshmpm = XShmCreatePixmap(dpy, DefaultRootWindow(dpy), xshmimg->data,
+ &xshminfo, w, h, dd);
+
+ return true;
+}
+
+#else
+
+// If extern, need a dummy.
+//
+// static bool qt_create_mitshm_buffer(QPaintDevice*, int, int)
+// {
+// return false;
+// }
+
+#endif // QT_MITSHM
+
+
+/*****************************************************************************
+ Internal functions
+ *****************************************************************************/
+
+extern const uchar *qt_get_bitflip_array(); // defined in qimage.cpp
+
+// Returns position of highest bit set or -1 if none
+static int highest_bit(uint v)
+{
+ int i;
+ uint b = (uint)1 << 31;
+ for (i=31; ((b & v) == 0) && i>=0; i--)
+ b >>= 1;
+ return i;
+}
+
+// Returns position of lowest set bit in 'v' as an integer (0-31), or -1
+static int lowest_bit(uint v)
+{
+ int i;
+ ulong lb;
+ lb = 1;
+ for (i=0; ((v & lb) == 0) && i<32; i++, lb<<=1) {}
+ return i==32 ? -1 : i;
+}
+
+// Counts the number of bits set in 'v'
+static uint n_bits(uint v)
+{
+ int i = 0;
+ while (v) {
+ v = v & (v - 1);
+ i++;
+ }
+ return i;
+}
+
+static uint *red_scale_table = 0;
+static uint *green_scale_table = 0;
+static uint *blue_scale_table = 0;
+
+static void cleanup_scale_tables()
+{
+ delete[] red_scale_table;
+ delete[] green_scale_table;
+ delete[] blue_scale_table;
+}
+
+/*
+ Could do smart bitshifting, but the "obvious" algorithm only works for
+ nBits >= 4. This is more robust.
+*/
+static void build_scale_table(uint **table, uint nBits)
+{
+ if (nBits > 7) {
+ qWarning("build_scale_table: internal error, nBits = %i", nBits);
+ return;
+ }
+ if (!*table) {
+ static bool firstTable = true;
+ if (firstTable) {
+ qAddPostRoutine(cleanup_scale_tables);
+ firstTable = false;
+ }
+ *table = new uint[256];
+ }
+ int maxVal = (1 << nBits) - 1;
+ int valShift = 8 - nBits;
+ int i;
+ for(i = 0 ; i < maxVal + 1 ; i++)
+ (*table)[i << valShift] = i*255/maxVal;
+}
+
+static int defaultScreen = -1;
+
+/*****************************************************************************
+ QPixmap member functions
+ *****************************************************************************/
+
+QBasicAtomicInt qt_pixmap_serial = Q_BASIC_ATOMIC_INITIALIZER(0);
+int Q_GUI_EXPORT qt_x11_preferred_pixmap_depth = 0;
+
+QX11PixmapData::QX11PixmapData(PixelType type)
+ : QPixmapData(type, X11Class), gl_surface(0), hd(0),
+ flags(Uninitialized), x11_mask(0), picture(0), mask_picture(0), hd2(0),
+ share_mode(QPixmap::ImplicitlyShared), pengine(0)
+{
+}
+
+QPixmapData *QX11PixmapData::createCompatiblePixmapData() const
+{
+ return new QX11PixmapData(pixelType());
+}
+
+void QX11PixmapData::resize(int width, int height)
+{
+ setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
+
+ w = width;
+ h = height;
+ is_null = (w <= 0 || h <= 0);
+
+ if (defaultScreen >= 0 && defaultScreen != xinfo.screen()) {
+ QX11InfoData* xd = xinfo.getX11Data(true);
+ xd->screen = defaultScreen;
+ xd->depth = QX11Info::appDepth(xd->screen);
+ xd->cells = QX11Info::appCells(xd->screen);
+ xd->colormap = QX11Info::appColormap(xd->screen);
+ xd->defaultColormap = QX11Info::appDefaultColormap(xd->screen);
+ xd->visual = (Visual *)QX11Info::appVisual(xd->screen);
+ xd->defaultVisual = QX11Info::appDefaultVisual(xd->screen);
+ xinfo.setX11Data(xd);
+ }
+
+ int dd = xinfo.depth();
+
+ if (qt_x11_preferred_pixmap_depth)
+ dd = qt_x11_preferred_pixmap_depth;
+
+ bool make_null = w <= 0 || h <= 0; // create null pixmap
+ d = (pixelType() == BitmapType ? 1 : dd);
+ if (make_null || d == 0) {
+ w = 0;
+ h = 0;
+ is_null = true;
+ hd = 0;
+ picture = 0;
+ d = 0;
+ if (!make_null)
+ qWarning("QPixmap: Invalid pixmap parameters");
+ return;
+ }
+ hd = (Qt::HANDLE)XCreatePixmap(X11->display,
+ RootWindow(X11->display, xinfo.screen()),
+ w, h, d);
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender) {
+ XRenderPictFormat *format = d == 1
+ ? XRenderFindStandardFormat(X11->display, PictStandardA1)
+ : XRenderFindVisualFormat(X11->display, (Visual *)xinfo.visual());
+ picture = XRenderCreatePicture(X11->display, hd, format, 0, 0);
+ }
+#endif // QT_NO_XRENDER
+}
+
+struct QX11AlphaDetector
+{
+ bool hasAlpha() const {
+ if (checked)
+ return has;
+ // Will implicitly also check format and return quickly for opaque types...
+ checked = true;
+ has = image->isNull() ? false : const_cast<QImage *>(image)->data_ptr()->checkForAlphaPixels();
+ return has;
+ }
+
+ bool hasXRenderAndAlpha() const {
+ if (!X11->use_xrender)
+ return false;
+ return hasAlpha();
+ }
+
+ QX11AlphaDetector(const QImage *i, Qt::ImageConversionFlags flags)
+ : image(i), checked(false), has(false)
+ {
+ if (flags & Qt::NoOpaqueDetection) {
+ checked = true;
+ has = image->hasAlphaChannel();
+ }
+ }
+
+ const QImage *image;
+ mutable bool checked;
+ mutable bool has;
+};
+
+void QX11PixmapData::fromImage(const QImage &img,
+ Qt::ImageConversionFlags flags)
+{
+ setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
+
+ w = img.width();
+ h = img.height();
+ d = img.depth();
+ is_null = (w <= 0 || h <= 0);
+
+ if (is_null) {
+ w = h = 0;
+ return;
+ }
+
+ if (defaultScreen >= 0 && defaultScreen != xinfo.screen()) {
+ QX11InfoData* xd = xinfo.getX11Data(true);
+ xd->screen = defaultScreen;
+ xd->depth = QX11Info::appDepth(xd->screen);
+ xd->cells = QX11Info::appCells(xd->screen);
+ xd->colormap = QX11Info::appColormap(xd->screen);
+ xd->defaultColormap = QX11Info::appDefaultColormap(xd->screen);
+ xd->visual = (Visual *)QX11Info::appVisual(xd->screen);
+ xd->defaultVisual = QX11Info::appDefaultVisual(xd->screen);
+ xinfo.setX11Data(xd);
+ }
+
+ if (pixelType() == BitmapType) {
+ bitmapFromImage(img);
+ return;
+ }
+
+ if (uint(w) >= 32768 || uint(h) >= 32768) {
+ w = h = 0;
+ is_null = true;
+ return;
+ }
+
+ QX11AlphaDetector alphaCheck(&img, flags);
+ int dd = alphaCheck.hasXRenderAndAlpha() ? 32 : xinfo.depth();
+
+ if (qt_x11_preferred_pixmap_depth)
+ dd = qt_x11_preferred_pixmap_depth;
+
+ QImage image = img;
+
+ // must be monochrome
+ if (dd == 1 || (flags & Qt::ColorMode_Mask) == Qt::MonoOnly) {
+ if (d != 1) {
+ // dither
+ image = image.convertToFormat(QImage::Format_MonoLSB, flags);
+ d = 1;
+ }
+ } else { // can be both
+ bool conv8 = false;
+ if (d > 8 && dd <= 8) { // convert to 8 bit
+ if ((flags & Qt::DitherMode_Mask) == Qt::AutoDither)
+ flags = (flags & ~Qt::DitherMode_Mask)
+ | Qt::PreferDither;
+ conv8 = true;
+ } else if ((flags & Qt::ColorMode_Mask) == Qt::ColorOnly) {
+ conv8 = (d == 1); // native depth wanted
+ } else if (d == 1) {
+ if (image.colorCount() == 2) {
+ QRgb c0 = image.color(0); // Auto: convert to best
+ QRgb c1 = image.color(1);
+ conv8 = qMin(c0,c1) != qRgb(0,0,0) || qMax(c0,c1) != qRgb(255,255,255);
+ } else {
+ // eg. 1-color monochrome images (they do exist).
+ conv8 = true;
+ }
+ }
+ if (conv8) {
+ image = image.convertToFormat(QImage::Format_Indexed8, flags);
+ d = 8;
+ }
+ }
+
+ if (d == 1 || d == 16 || d == 24) {
+ image = image.convertToFormat(QImage::Format_RGB32, flags);
+ fromImage(image, Qt::AutoColor);
+ return;
+ }
+
+ Display *dpy = X11->display;
+ Visual *visual = (Visual *)xinfo.visual();
+ XImage *xi = 0;
+ bool trucol = (visual->c_class >= TrueColor);
+ int nbytes = image.byteCount();
+ uchar *newbits= 0;
+
+#ifndef QT_NO_XRENDER
+ if (alphaCheck.hasXRenderAndAlpha()) {
+ const QImage &cimage = image;
+
+ d = 32;
+
+ if (QX11Info::appDepth() != d) {
+ if (xinfo.x11data) {
+ xinfo.x11data->depth = d;
+ } else {
+ QX11InfoData *xd = xinfo.getX11Data(true);
+ xd->screen = QX11Info::appScreen();
+ xd->depth = d;
+ xd->cells = QX11Info::appCells();
+ xd->colormap = QX11Info::appColormap();
+ xd->defaultColormap = QX11Info::appDefaultColormap();
+ xd->visual = (Visual *)QX11Info::appVisual();
+ xd->defaultVisual = QX11Info::appDefaultVisual();
+ xinfo.setX11Data(xd);
+ }
+ }
+
+ hd = (Qt::HANDLE)XCreatePixmap(dpy, RootWindow(dpy, xinfo.screen()),
+ w, h, d);
+ picture = XRenderCreatePicture(X11->display, hd,
+ XRenderFindStandardFormat(X11->display, PictStandardARGB32), 0, 0);
+
+ xi = XCreateImage(dpy, visual, d, ZPixmap, 0, 0, w, h, 32, 0);
+ Q_CHECK_PTR(xi);
+ newbits = (uchar *)malloc(xi->bytes_per_line*h);
+ Q_CHECK_PTR(newbits);
+ xi->data = (char *)newbits;
+
+ switch(cimage.format()) {
+ case QImage::Format_Indexed8: {
+ QVector<QRgb> colorTable = cimage.colorTable();
+ uint *xidata = (uint *)xi->data;
+ for (int y = 0; y < h; ++y) {
+ const uchar *p = cimage.scanLine(y);
+ for (int x = 0; x < w; ++x) {
+ const QRgb rgb = colorTable[p[x]];
+ const int a = qAlpha(rgb);
+ if (a == 0xff)
+ *xidata = rgb;
+ else
+ // RENDER expects premultiplied alpha
+ *xidata = qRgba(qt_div_255(qRed(rgb) * a),
+ qt_div_255(qGreen(rgb) * a),
+ qt_div_255(qBlue(rgb) * a),
+ a);
+ ++xidata;
+ }
+ }
+ }
+ break;
+ case QImage::Format_RGB32: {
+ uint *xidata = (uint *)xi->data;
+ for (int y = 0; y < h; ++y) {
+ const QRgb *p = (const QRgb *) cimage.scanLine(y);
+ for (int x = 0; x < w; ++x)
+ *xidata++ = p[x] | 0xff000000;
+ }
+ }
+ break;
+ case QImage::Format_ARGB32: {
+ uint *xidata = (uint *)xi->data;
+ for (int y = 0; y < h; ++y) {
+ const QRgb *p = (const QRgb *) cimage.scanLine(y);
+ for (int x = 0; x < w; ++x) {
+ const QRgb rgb = p[x];
+ const int a = qAlpha(rgb);
+ if (a == 0xff)
+ *xidata = rgb;
+ else
+ // RENDER expects premultiplied alpha
+ *xidata = qRgba(qt_div_255(qRed(rgb) * a),
+ qt_div_255(qGreen(rgb) * a),
+ qt_div_255(qBlue(rgb) * a),
+ a);
+ ++xidata;
+ }
+ }
+
+ }
+ break;
+ case QImage::Format_ARGB32_Premultiplied: {
+ uint *xidata = (uint *)xi->data;
+ for (int y = 0; y < h; ++y) {
+ const QRgb *p = (const QRgb *) cimage.scanLine(y);
+ memcpy(xidata, p, w*sizeof(QRgb));
+ xidata += w;
+ }
+ }
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+
+ if ((xi->byte_order == MSBFirst) != (QSysInfo::ByteOrder == QSysInfo::BigEndian)) {
+ uint *xidata = (uint *)xi->data;
+ uint *xiend = xidata + w*h;
+ while (xidata < xiend) {
+ *xidata = (*xidata >> 24)
+ | ((*xidata >> 8) & 0xff00)
+ | ((*xidata << 8) & 0xff0000)
+ | (*xidata << 24);
+ ++xidata;
+ }
+ }
+
+ GC gc = XCreateGC(dpy, hd, 0, 0);
+ XPutImage(dpy, hd, gc, xi, 0, 0, 0, 0, w, h);
+ XFreeGC(dpy, gc);
+
+ qSafeXDestroyImage(xi);
+
+ return;
+ }
+#endif // QT_NO_XRENDER
+
+ if (trucol) { // truecolor display
+ if (image.format() == QImage::Format_ARGB32_Premultiplied)
+ image = image.convertToFormat(QImage::Format_ARGB32);
+
+ const QImage &cimage = image;
+ QRgb pix[256]; // pixel translation table
+ const bool d8 = (d == 8);
+ const uint red_mask = (uint)visual->red_mask;
+ const uint green_mask = (uint)visual->green_mask;
+ const uint blue_mask = (uint)visual->blue_mask;
+ const int red_shift = highest_bit(red_mask) - 7;
+ const int green_shift = highest_bit(green_mask) - 7;
+ const int blue_shift = highest_bit(blue_mask) - 7;
+ const uint rbits = highest_bit(red_mask) - lowest_bit(red_mask) + 1;
+ const uint gbits = highest_bit(green_mask) - lowest_bit(green_mask) + 1;
+ const uint bbits = highest_bit(blue_mask) - lowest_bit(blue_mask) + 1;
+
+ if (d8) { // setup pixel translation
+ QVector<QRgb> ctable = cimage.colorTable();
+ for (int i=0; i < cimage.colorCount(); i++) {
+ int r = qRed (ctable[i]);
+ int g = qGreen(ctable[i]);
+ int b = qBlue (ctable[i]);
+ r = red_shift > 0 ? r << red_shift : r >> -red_shift;
+ g = green_shift > 0 ? g << green_shift : g >> -green_shift;
+ b = blue_shift > 0 ? b << blue_shift : b >> -blue_shift;
+ pix[i] = (b & blue_mask) | (g & green_mask) | (r & red_mask)
+ | ~(blue_mask | green_mask | red_mask);
+ }
+ }
+
+ xi = XCreateImage(dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0);
+ Q_CHECK_PTR(xi);
+ newbits = (uchar *)malloc(xi->bytes_per_line*h);
+ Q_CHECK_PTR(newbits);
+ if (!newbits) // no memory
+ return;
+ int bppc = xi->bits_per_pixel;
+
+ bool contig_bits = n_bits(red_mask) == rbits &&
+ n_bits(green_mask) == gbits &&
+ n_bits(blue_mask) == bbits;
+ bool dither_tc =
+ // Want it?
+ (flags & Qt::Dither_Mask) != Qt::ThresholdDither &&
+ (flags & Qt::DitherMode_Mask) != Qt::AvoidDither &&
+ // Need it?
+ bppc < 24 && !d8 &&
+ // Can do it? (Contiguous bits?)
+ contig_bits;
+
+ static bool init=false;
+ static int D[16][16];
+ if (dither_tc && !init) {
+ // I also contributed this code to XV - WWA.
+ /*
+ The dither matrix, D, is obtained with this formula:
+
+ D2 = [0 2]
+ [3 1]
+
+
+ D2*n = [4*Dn 4*Dn+2*Un]
+ [4*Dn+3*Un 4*Dn+1*Un]
+ */
+ int n,i,j;
+ init=1;
+
+ /* Set D2 */
+ D[0][0]=0;
+ D[1][0]=2;
+ D[0][1]=3;
+ D[1][1]=1;
+
+ /* Expand using recursive definition given above */
+ for (n=2; n<16; n*=2) {
+ for (i=0; i<n; i++) {
+ for (j=0; j<n; j++) {
+ D[i][j]*=4;
+ D[i+n][j]=D[i][j]+2;
+ D[i][j+n]=D[i][j]+3;
+ D[i+n][j+n]=D[i][j]+1;
+ }
+ }
+ }
+ init=true;
+ }
+
+ enum { BPP8,
+ BPP16_565, BPP16_555,
+ BPP16_MSB, BPP16_LSB,
+ BPP24_888,
+ BPP24_MSB, BPP24_LSB,
+ BPP32_8888,
+ BPP32_MSB, BPP32_LSB
+ } mode = BPP8;
+
+ bool same_msb_lsb = (xi->byte_order == MSBFirst) == (QSysInfo::ByteOrder == QSysInfo::BigEndian);
+
+ if(bppc == 8) // 8 bit
+ mode = BPP8;
+ else if(bppc == 16) { // 16 bit MSB/LSB
+ if(red_shift == 8 && green_shift == 3 && blue_shift == -3 && !d8 && same_msb_lsb)
+ mode = BPP16_565;
+ else if(red_shift == 7 && green_shift == 2 && blue_shift == -3 && !d8 && same_msb_lsb)
+ mode = BPP16_555;
+ else
+ mode = (xi->byte_order == LSBFirst) ? BPP16_LSB : BPP16_MSB;
+ } else if(bppc == 24) { // 24 bit MSB/LSB
+ if (red_shift == 16 && green_shift == 8 && blue_shift == 0 && !d8 && same_msb_lsb)
+ mode = BPP24_888;
+ else
+ mode = (xi->byte_order == LSBFirst) ? BPP24_LSB : BPP24_MSB;
+ } else if(bppc == 32) { // 32 bit MSB/LSB
+ if(red_shift == 16 && green_shift == 8 && blue_shift == 0 && !d8 && same_msb_lsb)
+ mode = BPP32_8888;
+ else
+ mode = (xi->byte_order == LSBFirst) ? BPP32_LSB : BPP32_MSB;
+ } else
+ qFatal("Logic error 3");
+
+#define GET_PIXEL \
+ uint pixel; \
+ if (d8) pixel = pix[*src++]; \
+ else { \
+ int r = qRed (*p); \
+ int g = qGreen(*p); \
+ int b = qBlue (*p++); \
+ r = red_shift > 0 \
+ ? r << red_shift : r >> -red_shift; \
+ g = green_shift > 0 \
+ ? g << green_shift : g >> -green_shift; \
+ b = blue_shift > 0 \
+ ? b << blue_shift : b >> -blue_shift; \
+ pixel = (r & red_mask)|(g & green_mask) | (b & blue_mask) \
+ | ~(blue_mask | green_mask | red_mask); \
+ }
+
+#define GET_PIXEL_DITHER_TC \
+ int r = qRed (*p); \
+ int g = qGreen(*p); \
+ int b = qBlue (*p++); \
+ const int thres = D[x%16][y%16]; \
+ if (r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \
+ > thres) \
+ r += (1<<(8-rbits)); \
+ if (g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \
+ > thres) \
+ g += (1<<(8-gbits)); \
+ if (b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \
+ > thres) \
+ b += (1<<(8-bbits)); \
+ r = red_shift > 0 \
+ ? r << red_shift : r >> -red_shift; \
+ g = green_shift > 0 \
+ ? g << green_shift : g >> -green_shift; \
+ b = blue_shift > 0 \
+ ? b << blue_shift : b >> -blue_shift; \
+ uint pixel = (r & red_mask)|(g & green_mask) | (b & blue_mask);
+
+// again, optimized case
+// can't be optimized that much :(
+#define GET_PIXEL_DITHER_TC_OPT(red_shift,green_shift,blue_shift,red_mask,green_mask,blue_mask, \
+ rbits,gbits,bbits) \
+ const int thres = D[x%16][y%16]; \
+ int r = qRed (*p); \
+ if (r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \
+ > thres) \
+ r += (1<<(8-rbits)); \
+ int g = qGreen(*p); \
+ if (g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \
+ > thres) \
+ g += (1<<(8-gbits)); \
+ int b = qBlue (*p++); \
+ if (b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \
+ > thres) \
+ b += (1<<(8-bbits)); \
+ uint pixel = ((r red_shift) & red_mask) \
+ | ((g green_shift) & green_mask) \
+ | ((b blue_shift) & blue_mask);
+
+#define CYCLE(body) \
+ for (int y=0; y<h; y++) { \
+ const uchar* src = cimage.scanLine(y); \
+ uchar* dst = newbits + xi->bytes_per_line*y; \
+ const QRgb* p = (const QRgb *)src; \
+ body \
+ }
+
+ if (dither_tc) {
+ switch (mode) {
+ case BPP16_565:
+ CYCLE(
+ quint16* dst16 = (quint16*)dst;
+ for (int x=0; x<w; x++) {
+ GET_PIXEL_DITHER_TC_OPT(<<8,<<3,>>3,0xf800,0x7e0,0x1f,5,6,5)
+ *dst16++ = pixel;
+ }
+ )
+ break;
+ case BPP16_555:
+ CYCLE(
+ quint16* dst16 = (quint16*)dst;
+ for (int x=0; x<w; x++) {
+ GET_PIXEL_DITHER_TC_OPT(<<7,<<2,>>3,0x7c00,0x3e0,0x1f,5,5,5)
+ *dst16++ = pixel;
+ }
+ )
+ break;
+ case BPP16_MSB: // 16 bit MSB
+ CYCLE(
+ for (int x=0; x<w; x++) {
+ GET_PIXEL_DITHER_TC
+ *dst++ = (pixel >> 8);
+ *dst++ = pixel;
+ }
+ )
+ break;
+ case BPP16_LSB: // 16 bit LSB
+ CYCLE(
+ for (int x=0; x<w; x++) {
+ GET_PIXEL_DITHER_TC
+ *dst++ = pixel;
+ *dst++ = pixel >> 8;
+ }
+ )
+ break;
+ default:
+ qFatal("Logic error");
+ }
+ } else {
+ switch (mode) {
+ case BPP8: // 8 bit
+ CYCLE(
+ Q_UNUSED(p);
+ for (int x=0; x<w; x++)
+ *dst++ = pix[*src++];
+ )
+ break;
+ case BPP16_565:
+ CYCLE(
+ quint16* dst16 = (quint16*)dst;
+ for (int x = 0; x < w; x++) {
+ *dst16++ = ((*p >> 8) & 0xf800)
+ | ((*p >> 5) & 0x7e0)
+ | ((*p >> 3) & 0x1f);
+ ++p;
+ }
+ )
+ break;
+ case BPP16_555:
+ CYCLE(
+ quint16* dst16 = (quint16*)dst;
+ for (int x=0; x<w; x++) {
+ *dst16++ = ((*p >> 9) & 0x7c00)
+ | ((*p >> 6) & 0x3e0)
+ | ((*p >> 3) & 0x1f);
+ ++p;
+ }
+ )
+ break;
+ case BPP16_MSB: // 16 bit MSB
+ CYCLE(
+ for (int x=0; x<w; x++) {
+ GET_PIXEL
+ *dst++ = (pixel >> 8);
+ *dst++ = pixel;
+ }
+ )
+ break;
+ case BPP16_LSB: // 16 bit LSB
+ CYCLE(
+ for (int x=0; x<w; x++) {
+ GET_PIXEL
+ *dst++ = pixel;
+ *dst++ = pixel >> 8;
+ }
+ )
+ break;
+ case BPP24_888: // 24 bit MSB
+ CYCLE(
+ for (int x=0; x<w; x++) {
+ *dst++ = qRed (*p);
+ *dst++ = qGreen(*p);
+ *dst++ = qBlue (*p++);
+ }
+ )
+ break;
+ case BPP24_MSB: // 24 bit MSB
+ CYCLE(
+ for (int x=0; x<w; x++) {
+ GET_PIXEL
+ *dst++ = pixel >> 16;
+ *dst++ = pixel >> 8;
+ *dst++ = pixel;
+ }
+ )
+ break;
+ case BPP24_LSB: // 24 bit LSB
+ CYCLE(
+ for (int x=0; x<w; x++) {
+ GET_PIXEL
+ *dst++ = pixel;
+ *dst++ = pixel >> 8;
+ *dst++ = pixel >> 16;
+ }
+ )
+ break;
+ case BPP32_8888:
+ CYCLE(
+ memcpy(dst, p, w * 4);
+ )
+ break;
+ case BPP32_MSB: // 32 bit MSB
+ CYCLE(
+ for (int x=0; x<w; x++) {
+ GET_PIXEL
+ *dst++ = pixel >> 24;
+ *dst++ = pixel >> 16;
+ *dst++ = pixel >> 8;
+ *dst++ = pixel;
+ }
+ )
+ break;
+ case BPP32_LSB: // 32 bit LSB
+ CYCLE(
+ for (int x=0; x<w; x++) {
+ GET_PIXEL
+ *dst++ = pixel;
+ *dst++ = pixel >> 8;
+ *dst++ = pixel >> 16;
+ *dst++ = pixel >> 24;
+ }
+ )
+ break;
+ default:
+ qFatal("Logic error 2");
+ }
+ }
+ xi->data = (char *)newbits;
+ }
+
+ if (d == 8 && !trucol) { // 8 bit pixmap
+ int pop[256]; // pixel popularity
+
+ if (image.colorCount() == 0)
+ image.setColorCount(1);
+
+ const QImage &cimage = image;
+ memset(pop, 0, sizeof(int)*256); // reset popularity array
+ for (int i = 0; i < h; i++) { // for each scanline...
+ const uchar* p = cimage.scanLine(i);
+ const uchar *end = p + w;
+ while (p < end) // compute popularity
+ pop[*p++]++;
+ }
+
+ newbits = (uchar *)malloc(nbytes); // copy image into newbits
+ Q_CHECK_PTR(newbits);
+ if (!newbits) // no memory
+ return;
+ uchar* p = newbits;
+ memcpy(p, cimage.bits(), nbytes); // copy image data into newbits
+
+ /*
+ * The code below picks the most important colors. It is based on the
+ * diversity algorithm, implemented in XV 3.10. XV is (C) by John Bradley.
+ */
+
+ struct PIX { // pixel sort element
+ uchar r,g,b,n; // color + pad
+ int use; // popularity
+ int index; // index in colormap
+ int mindist;
+ };
+ int ncols = 0;
+ for (int i=0; i< cimage.colorCount(); i++) { // compute number of colors
+ if (pop[i] > 0)
+ ncols++;
+ }
+ for (int i = cimage.colorCount(); i < 256; i++) // ignore out-of-range pixels
+ pop[i] = 0;
+
+ // works since we make sure above to have at least
+ // one color in the image
+ if (ncols == 0)
+ ncols = 1;
+
+ PIX pixarr[256]; // pixel array
+ PIX pixarr_sorted[256]; // pixel array (sorted)
+ memset(pixarr, 0, ncols*sizeof(PIX));
+ PIX *px = &pixarr[0];
+ int maxpop = 0;
+ int maxpix = 0;
+ uint j = 0;
+ QVector<QRgb> ctable = cimage.colorTable();
+ for (int i = 0; i < 256; i++) { // init pixel array
+ if (pop[i] > 0) {
+ px->r = qRed (ctable[i]);
+ px->g = qGreen(ctable[i]);
+ px->b = qBlue (ctable[i]);
+ px->n = 0;
+ px->use = pop[i];
+ if (pop[i] > maxpop) { // select most popular entry
+ maxpop = pop[i];
+ maxpix = j;
+ }
+ px->index = i;
+ px->mindist = 1000000;
+ px++;
+ j++;
+ }
+ }
+ pixarr_sorted[0] = pixarr[maxpix];
+ pixarr[maxpix].use = 0;
+
+ for (int i = 1; i < ncols; i++) { // sort pixels
+ int minpix = -1, mindist = -1;
+ px = &pixarr_sorted[i-1];
+ int r = px->r;
+ int g = px->g;
+ int b = px->b;
+ int dist;
+ if ((i & 1) || i<10) { // sort on max distance
+ for (int j=0; j<ncols; j++) {
+ px = &pixarr[j];
+ if (px->use) {
+ dist = (px->r - r)*(px->r - r) +
+ (px->g - g)*(px->g - g) +
+ (px->b - b)*(px->b - b);
+ if (px->mindist > dist)
+ px->mindist = dist;
+ if (px->mindist > mindist) {
+ mindist = px->mindist;
+ minpix = j;
+ }
+ }
+ }
+ } else { // sort on max popularity
+ for (int j=0; j<ncols; j++) {
+ px = &pixarr[j];
+ if (px->use) {
+ dist = (px->r - r)*(px->r - r) +
+ (px->g - g)*(px->g - g) +
+ (px->b - b)*(px->b - b);
+ if (px->mindist > dist)
+ px->mindist = dist;
+ if (px->use > mindist) {
+ mindist = px->use;
+ minpix = j;
+ }
+ }
+ }
+ }
+ pixarr_sorted[i] = pixarr[minpix];
+ pixarr[minpix].use = 0;
+ }
+
+ QColormap cmap = QColormap::instance(xinfo.screen());
+ uint pix[256]; // pixel translation table
+ px = &pixarr_sorted[0];
+ for (int i = 0; i < ncols; i++) { // allocate colors
+ QColor c(px->r, px->g, px->b);
+ pix[px->index] = cmap.pixel(c);
+ px++;
+ }
+
+ p = newbits;
+ for (int i = 0; i < nbytes; i++) { // translate pixels
+ *p = pix[*p];
+ p++;
+ }
+ }
+
+ if (!xi) { // X image not created
+ xi = XCreateImage(dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0);
+ if (xi->bits_per_pixel == 16) { // convert 8 bpp ==> 16 bpp
+ ushort *p2;
+ int p2inc = xi->bytes_per_line/sizeof(ushort);
+ ushort *newerbits = (ushort *)malloc(xi->bytes_per_line * h);
+ Q_CHECK_PTR(newerbits);
+ if (!newerbits) // no memory
+ return;
+ uchar* p = newbits;
+ for (int y = 0; y < h; y++) { // OOPS: Do right byte order!!
+ p2 = newerbits + p2inc*y;
+ for (int x = 0; x < w; x++)
+ *p2++ = *p++;
+ }
+ free(newbits);
+ newbits = (uchar *)newerbits;
+ } else if (xi->bits_per_pixel != 8) {
+ qWarning("QPixmap::fromImage: Display not supported "
+ "(bpp=%d)", xi->bits_per_pixel);
+ }
+ xi->data = (char *)newbits;
+ }
+
+ hd = (Qt::HANDLE)XCreatePixmap(X11->display,
+ RootWindow(X11->display, xinfo.screen()),
+ w, h, dd);
+
+ GC gc = XCreateGC(dpy, hd, 0, 0);
+ XPutImage(dpy, hd, gc, xi, 0, 0, 0, 0, w, h);
+ XFreeGC(dpy, gc);
+
+ qSafeXDestroyImage(xi);
+ d = dd;
+
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender) {
+ XRenderPictFormat *format = d == 1
+ ? XRenderFindStandardFormat(X11->display, PictStandardA1)
+ : XRenderFindVisualFormat(X11->display, (Visual *)xinfo.visual());
+ picture = XRenderCreatePicture(X11->display, hd, format, 0, 0);
+ }
+#endif
+
+ if (alphaCheck.hasAlpha()) {
+ QBitmap m = QBitmap::fromImage(image.createAlphaMask(flags));
+ setMask(m);
+ }
+}
+
+Qt::HANDLE QX11PixmapData::createBitmapFromImage(const QImage &image)
+{
+ QImage img = image.convertToFormat(QImage::Format_MonoLSB);
+ const QRgb c0 = QColor(Qt::black).rgb();
+ const QRgb c1 = QColor(Qt::white).rgb();
+ if (img.color(0) == c0 && img.color(1) == c1) {
+ img.invertPixels();
+ img.setColor(0, c1);
+ img.setColor(1, c0);
+ }
+
+ char *bits;
+ uchar *tmp_bits;
+ int w = img.width();
+ int h = img.height();
+ int bpl = (w + 7) / 8;
+ int ibpl = img.bytesPerLine();
+ if (bpl != ibpl) {
+ tmp_bits = new uchar[bpl*h];
+ bits = (char *)tmp_bits;
+ uchar *p, *b;
+ int y;
+ b = tmp_bits;
+ p = img.scanLine(0);
+ for (y = 0; y < h; y++) {
+ memcpy(b, p, bpl);
+ b += bpl;
+ p += ibpl;
+ }
+ } else {
+ bits = (char *)img.bits();
+ tmp_bits = 0;
+ }
+ Qt::HANDLE hd = (Qt::HANDLE)XCreateBitmapFromData(X11->display,
+ QX11Info::appRootWindow(),
+ bits, w, h);
+ if (tmp_bits) // Avoid purify complaint
+ delete [] tmp_bits;
+ return hd;
+}
+
+void QX11PixmapData::bitmapFromImage(const QImage &image)
+{
+ w = image.width();
+ h = image.height();
+ d = 1;
+ is_null = (w <= 0 || h <= 0);
+ hd = createBitmapFromImage(image);
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender)
+ picture = XRenderCreatePicture(X11->display, hd,
+ XRenderFindStandardFormat(X11->display, PictStandardA1), 0, 0);
+#endif // QT_NO_XRENDER
+}
+
+void QX11PixmapData::fill(const QColor &fillColor)
+{
+ if (fillColor.alpha() != 255) {
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender) {
+ if (!picture || d != 32)
+ convertToARGB32(/*preserveContents = */false);
+
+ ::Picture src = X11->getSolidFill(xinfo.screen(), fillColor);
+ XRenderComposite(X11->display, PictOpSrc, src, 0, picture,
+ 0, 0, width(), height(),
+ 0, 0, width(), height());
+ } else
+#endif
+ {
+ QImage im(width(), height(), QImage::Format_ARGB32_Premultiplied);
+ im.fill(PREMUL(fillColor.rgba()));
+ release();
+ fromImage(im, Qt::AutoColor | Qt::OrderedAlphaDither);
+ }
+ return;
+ }
+
+ GC gc = XCreateGC(X11->display, hd, 0, 0);
+ if (depth() == 1) {
+ XSetForeground(X11->display, gc, qGray(fillColor.rgb()) > 127 ? 0 : 1);
+ } else if (X11->use_xrender && d >= 24) {
+ XSetForeground(X11->display, gc, fillColor.rgba());
+ } else {
+ XSetForeground(X11->display, gc,
+ QColormap::instance(xinfo.screen()).pixel(fillColor));
+ }
+ XFillRectangle(X11->display, hd, gc, 0, 0, width(), height());
+ XFreeGC(X11->display, gc);
+}
+
+QX11PixmapData::~QX11PixmapData()
+{
+ // Cleanup hooks have to be called before the handles are freed
+ if (is_cached) {
+ QImagePixmapCleanupHooks::executePixmapDataDestructionHooks(this);
+ is_cached = false;
+ }
+
+ release();
+}
+
+void QX11PixmapData::release()
+{
+ delete pengine;
+ pengine = 0;
+
+ if (!X11) {
+ // At this point, the X server will already have freed our resources,
+ // so there is nothing to do.
+ return;
+ }
+
+ if (x11_mask) {
+#ifndef QT_NO_XRENDER
+ if (mask_picture)
+ XRenderFreePicture(X11->display, mask_picture);
+ mask_picture = 0;
+#endif
+ XFreePixmap(X11->display, x11_mask);
+ x11_mask = 0;
+ }
+
+ if (hd) {
+#ifndef QT_NO_XRENDER
+ if (picture) {
+ XRenderFreePicture(X11->display, picture);
+ picture = 0;
+ }
+#endif // QT_NO_XRENDER
+
+ if (hd2) {
+ XFreePixmap(xinfo.display(), hd2);
+ hd2 = 0;
+ }
+ if (!(flags & Readonly))
+ XFreePixmap(xinfo.display(), hd);
+ hd = 0;
+ }
+}
+
+QPixmap QX11PixmapData::alphaChannel() const
+{
+ if (!hasAlphaChannel()) {
+ QPixmap pm(w, h);
+ pm.fill(Qt::white);
+ return pm;
+ }
+ QImage im(toImage());
+ return QPixmap::fromImage(im.alphaChannel(), Qt::OrderedDither);
+}
+
+void QX11PixmapData::setAlphaChannel(const QPixmap &alpha)
+{
+ QImage image(toImage());
+ image.setAlphaChannel(alpha.toImage());
+ release();
+ fromImage(image, Qt::OrderedDither | Qt::OrderedAlphaDither);
+}
+
+
+QBitmap QX11PixmapData::mask() const
+{
+ QBitmap mask;
+#ifndef QT_NO_XRENDER
+ if (picture && d == 32) {
+ // #### slow - there must be a better way..
+ mask = QBitmap::fromImage(toImage().createAlphaMask());
+ } else
+#endif
+ if (d == 1) {
+ QX11PixmapData *that = const_cast<QX11PixmapData*>(this);
+ mask = QPixmap(that);
+ } else {
+ mask = mask_to_bitmap(xinfo.screen());
+ }
+ return mask;
+}
+
+/*!
+ Sets a mask bitmap.
+
+ The \a newmask bitmap defines the clip mask for this pixmap. Every
+ pixel in \a newmask corresponds to a pixel in this pixmap. Pixel
+ value 1 means opaque and pixel value 0 means transparent. The mask
+ must have the same size as this pixmap.
+
+ \warning Setting the mask on a pixmap will cause any alpha channel
+ data to be cleared. For example:
+ \snippet doc/src/snippets/image/image.cpp 2
+ Now, alpha and alphacopy are visually different.
+
+ Setting a null mask resets the mask.
+
+ The effect of this function is undefined when the pixmap is being
+ painted on.
+
+ \sa mask(), {QPixmap#Pixmap Transformations}{Pixmap
+ Transformations}, QBitmap
+*/
+void QX11PixmapData::setMask(const QBitmap &newmask)
+{
+ if (newmask.isNull()) { // clear mask
+#ifndef QT_NO_XRENDER
+ if (picture && d == 32) {
+ QX11PixmapData newData(pixelType());
+ newData.resize(w, h);
+ newData.fill(Qt::black);
+ XRenderComposite(X11->display, PictOpOver,
+ picture, 0, newData.picture,
+ 0, 0, 0, 0, 0, 0, w, h);
+ release();
+ *this = newData;
+ // the new QX11PixmapData object isn't referenced yet, so
+ // ref it
+ ref.ref();
+
+ // the below is to make sure the QX11PixmapData destructor
+ // doesn't delete our newly created render picture
+ newData.hd = 0;
+ newData.x11_mask = 0;
+ newData.picture = 0;
+ newData.mask_picture = 0;
+ newData.hd2 = 0;
+ } else
+#endif
+ if (x11_mask) {
+#ifndef QT_NO_XRENDER
+ if (picture) {
+ XRenderPictureAttributes attrs;
+ attrs.alpha_map = 0;
+ XRenderChangePicture(X11->display, picture, CPAlphaMap,
+ &attrs);
+ }
+ if (mask_picture)
+ XRenderFreePicture(X11->display, mask_picture);
+ mask_picture = 0;
+#endif
+ XFreePixmap(X11->display, x11_mask);
+ x11_mask = 0;
+ }
+ return;
+ }
+
+#ifndef QT_NO_XRENDER
+ if (picture && d == 32) {
+ XRenderComposite(X11->display, PictOpSrc,
+ picture, newmask.x11PictureHandle(),
+ picture, 0, 0, 0, 0, 0, 0, w, h);
+ } else
+#endif
+ if (depth() == 1) {
+ XGCValues vals;
+ vals.function = GXand;
+ GC gc = XCreateGC(X11->display, hd, GCFunction, &vals);
+ XCopyArea(X11->display, newmask.handle(), hd, gc, 0, 0,
+ width(), height(), 0, 0);
+ XFreeGC(X11->display, gc);
+ } else {
+ // ##### should or the masks together
+ if (x11_mask) {
+ XFreePixmap(X11->display, x11_mask);
+#ifndef QT_NO_XRENDER
+ if (mask_picture)
+ XRenderFreePicture(X11->display, mask_picture);
+#endif
+ }
+ x11_mask = QX11PixmapData::bitmap_to_mask(newmask, xinfo.screen());
+#ifndef QT_NO_XRENDER
+ if (picture) {
+ mask_picture = XRenderCreatePicture(X11->display, x11_mask,
+ XRenderFindStandardFormat(X11->display, PictStandardA1), 0, 0);
+ XRenderPictureAttributes attrs;
+ attrs.alpha_map = mask_picture;
+ XRenderChangePicture(X11->display, picture, CPAlphaMap, &attrs);
+ }
+#endif
+ }
+}
+
+int QX11PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
+{
+ switch (metric) {
+ case QPaintDevice::PdmWidth:
+ return w;
+ case QPaintDevice::PdmHeight:
+ return h;
+ case QPaintDevice::PdmNumColors:
+ return 1 << d;
+ case QPaintDevice::PdmDepth:
+ return d;
+ case QPaintDevice::PdmWidthMM: {
+ const int screen = xinfo.screen();
+ const int mm = DisplayWidthMM(X11->display, screen) * w
+ / DisplayWidth(X11->display, screen);
+ return mm;
+ }
+ case QPaintDevice::PdmHeightMM: {
+ const int screen = xinfo.screen();
+ const int mm = (DisplayHeightMM(X11->display, screen) * h)
+ / DisplayHeight(X11->display, screen);
+ return mm;
+ }
+ case QPaintDevice::PdmDpiX:
+ case QPaintDevice::PdmPhysicalDpiX:
+ return QX11Info::appDpiX(xinfo.screen());
+ case QPaintDevice::PdmDpiY:
+ case QPaintDevice::PdmPhysicalDpiY:
+ return QX11Info::appDpiY(xinfo.screen());
+ default:
+ qWarning("QX11PixmapData::metric(): Invalid metric");
+ return 0;
+ }
+}
+
+struct QXImageWrapper
+{
+ XImage *xi;
+};
+
+bool QX11PixmapData::canTakeQImageFromXImage(const QXImageWrapper &xiWrapper) const
+{
+ XImage *xi = xiWrapper.xi;
+
+ // ARGB32_Premultiplied
+ if (picture && depth() == 32)
+ return true;
+
+ Visual *visual = (Visual *)xinfo.visual();
+
+ // RGB32
+ if (depth() == 24 && xi->bits_per_pixel == 32 && visual->red_mask == 0xff0000
+ && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
+ return true;
+
+ // RGB16
+ if (depth() == 16 && xi->bits_per_pixel == 16 && visual->red_mask == 0xf800
+ && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f)
+ return true;
+
+ return false;
+}
+
+QImage QX11PixmapData::takeQImageFromXImage(const QXImageWrapper &xiWrapper) const
+{
+ XImage *xi = xiWrapper.xi;
+
+ QImage::Format format = QImage::Format_ARGB32_Premultiplied;
+ if (depth() == 24)
+ format = QImage::Format_RGB32;
+ else if (depth() == 16)
+ format = QImage::Format_RGB16;
+
+ QImage image((uchar *)xi->data, xi->width, xi->height, xi->bytes_per_line, format);
+ // take ownership
+ image.data_ptr()->own_data = true;
+ xi->data = 0;
+
+ // we may have to swap the byte order
+ if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst)
+ || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst))
+ {
+ for (int i=0; i < image.height(); i++) {
+ if (depth() == 16) {
+ ushort *p = (ushort*)image.scanLine(i);
+ ushort *end = p + image.width();
+ while (p < end) {
+ *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
+ p++;
+ }
+ } else {
+ uint *p = (uint*)image.scanLine(i);
+ uint *end = p + image.width();
+ while (p < end) {
+ *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
+ | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
+ p++;
+ }
+ }
+ }
+ }
+
+ // fix-up alpha channel
+ if (format == QImage::Format_RGB32) {
+ QRgb *p = (QRgb *)image.bits();
+ for (int y = 0; y < xi->height; ++y) {
+ for (int x = 0; x < xi->width; ++x)
+ p[x] |= 0xff000000;
+ p += xi->bytes_per_line / 4;
+ }
+ }
+
+ XDestroyImage(xi);
+ return image;
+}
+
+QImage QX11PixmapData::toImage(const QRect &rect) const
+{
+ QXImageWrapper xiWrapper;
+ xiWrapper.xi = XGetImage(X11->display, hd, rect.x(), rect.y(), rect.width(), rect.height(),
+ AllPlanes, (depth() == 1) ? XYPixmap : ZPixmap);
+
+ Q_CHECK_PTR(xiWrapper.xi);
+ if (!xiWrapper.xi)
+ return QImage();
+
+ if (!x11_mask && canTakeQImageFromXImage(xiWrapper))
+ return takeQImageFromXImage(xiWrapper);
+
+ QImage image = toImage(xiWrapper, rect);
+ qSafeXDestroyImage(xiWrapper.xi);
+ return image;
+}
+
+/*!
+ Converts the pixmap to a QImage. Returns a null image if the
+ conversion fails.
+
+ If the pixmap has 1-bit depth, the returned image will also be 1
+ bit deep. If the pixmap has 2- to 8-bit depth, the returned image
+ has 8-bit depth. If the pixmap has greater than 8-bit depth, the
+ returned image has 32-bit depth.
+
+ Note that for the moment, alpha masks on monochrome images are
+ ignored.
+
+ \sa fromImage(), {QImage#Image Formats}{Image Formats}
+*/
+
+QImage QX11PixmapData::toImage() const
+{
+ return toImage(QRect(0, 0, w, h));
+}
+
+QImage QX11PixmapData::toImage(const QXImageWrapper &xiWrapper, const QRect &rect) const
+{
+ XImage *xi = xiWrapper.xi;
+
+ int d = depth();
+ Visual *visual = (Visual *)xinfo.visual();
+ bool trucol = (visual->c_class >= TrueColor) && d > 1;
+
+ QImage::Format format = QImage::Format_Mono;
+ if (d > 1 && d <= 8) {
+ d = 8;
+ format = QImage::Format_Indexed8;
+ }
+ // we could run into the situation where d == 8 AND trucol is true, which can
+ // cause problems when converting to and from images. in this case, always treat
+ // the depth as 32...
+ if (d > 8 || trucol) {
+ d = 32;
+ format = QImage::Format_RGB32;
+ }
+
+ if (d == 1 && xi->bitmap_bit_order == LSBFirst)
+ format = QImage::Format_MonoLSB;
+ if (x11_mask && format == QImage::Format_RGB32)
+ format = QImage::Format_ARGB32;
+
+ QImage image(xi->width, xi->height, format);
+ if (image.isNull()) // could not create image
+ return image;
+
+ QImage alpha;
+ if (x11_mask) {
+ if (rect.contains(QRect(0, 0, w, h)))
+ alpha = mask().toImage();
+ else
+ alpha = mask().toImage().copy(rect);
+ }
+ bool ale = alpha.format() == QImage::Format_MonoLSB;
+
+ if (trucol) { // truecolor
+ const uint red_mask = (uint)visual->red_mask;
+ const uint green_mask = (uint)visual->green_mask;
+ const uint blue_mask = (uint)visual->blue_mask;
+ const int red_shift = highest_bit(red_mask) - 7;
+ const int green_shift = highest_bit(green_mask) - 7;
+ const int blue_shift = highest_bit(blue_mask) - 7;
+
+ const uint red_bits = n_bits(red_mask);
+ const uint green_bits = n_bits(green_mask);
+ const uint blue_bits = n_bits(blue_mask);
+
+ static uint red_table_bits = 0;
+ static uint green_table_bits = 0;
+ static uint blue_table_bits = 0;
+
+ if (red_bits < 8 && red_table_bits != red_bits) {
+ build_scale_table(&red_scale_table, red_bits);
+ red_table_bits = red_bits;
+ }
+ if (blue_bits < 8 && blue_table_bits != blue_bits) {
+ build_scale_table(&blue_scale_table, blue_bits);
+ blue_table_bits = blue_bits;
+ }
+ if (green_bits < 8 && green_table_bits != green_bits) {
+ build_scale_table(&green_scale_table, green_bits);
+ green_table_bits = green_bits;
+ }
+
+ int r, g, b;
+
+ QRgb *dst;
+ uchar *src;
+ uint pixel;
+ int bppc = xi->bits_per_pixel;
+
+ if (bppc > 8 && xi->byte_order == LSBFirst)
+ bppc++;
+
+ for (int y = 0; y < xi->height; ++y) {
+ uchar* asrc = x11_mask ? alpha.scanLine(y) : 0;
+ dst = (QRgb *)image.scanLine(y);
+ src = (uchar *)xi->data + xi->bytes_per_line*y;
+ for (int x = 0; x < xi->width; x++) {
+ switch (bppc) {
+ case 8:
+ pixel = *src++;
+ break;
+ case 16: // 16 bit MSB
+ pixel = src[1] | (uint)src[0] << 8;
+ src += 2;
+ break;
+ case 17: // 16 bit LSB
+ pixel = src[0] | (uint)src[1] << 8;
+ src += 2;
+ break;
+ case 24: // 24 bit MSB
+ pixel = src[2] | (uint)src[1] << 8 | (uint)src[0] << 16;
+ src += 3;
+ break;
+ case 25: // 24 bit LSB
+ pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16;
+ src += 3;
+ break;
+ case 32: // 32 bit MSB
+ pixel = src[3] | (uint)src[2] << 8 | (uint)src[1] << 16 | (uint)src[0] << 24;
+ src += 4;
+ break;
+ case 33: // 32 bit LSB
+ pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16 | (uint)src[3] << 24;
+ src += 4;
+ break;
+ default: // should not really happen
+ x = xi->width; // leave loop
+ y = xi->height;
+ pixel = 0; // eliminate compiler warning
+ qWarning("QPixmap::convertToImage: Invalid depth %d", bppc);
+ }
+ if (red_shift > 0)
+ r = (pixel & red_mask) >> red_shift;
+ else
+ r = (pixel & red_mask) << -red_shift;
+ if (green_shift > 0)
+ g = (pixel & green_mask) >> green_shift;
+ else
+ g = (pixel & green_mask) << -green_shift;
+ if (blue_shift > 0)
+ b = (pixel & blue_mask) >> blue_shift;
+ else
+ b = (pixel & blue_mask) << -blue_shift;
+
+ if (red_bits < 8)
+ r = red_scale_table[r];
+ if (green_bits < 8)
+ g = green_scale_table[g];
+ if (blue_bits < 8)
+ b = blue_scale_table[b];
+
+ if (x11_mask) {
+ if (ale) {
+ *dst++ = (asrc[x >> 3] & (1 << (x & 7))) ? qRgba(r, g, b, 0xff) : 0;
+ } else {
+ *dst++ = (asrc[x >> 3] & (0x80 >> (x & 7))) ? qRgba(r, g, b, 0xff) : 0;
+ }
+ } else {
+ *dst++ = qRgb(r, g, b);
+ }
+ }
+ }
+ } else if (xi->bits_per_pixel == d) { // compatible depth
+ char *xidata = xi->data; // copy each scanline
+ int bpl = qMin(image.bytesPerLine(),xi->bytes_per_line);
+ for (int y=0; y<xi->height; y++) {
+ memcpy(image.scanLine(y), xidata, bpl);
+ xidata += xi->bytes_per_line;
+ }
+ } else {
+ /* Typically 2 or 4 bits display depth */
+ qWarning("QPixmap::convertToImage: Display not supported (bpp=%d)",
+ xi->bits_per_pixel);
+ return QImage();
+ }
+
+ if (d == 1) { // bitmap
+ image.setColorCount(2);
+ image.setColor(0, qRgb(255,255,255));
+ image.setColor(1, qRgb(0,0,0));
+ } else if (!trucol) { // pixmap with colormap
+ register uchar *p;
+ uchar *end;
+ uchar use[256]; // pixel-in-use table
+ uchar pix[256]; // pixel translation table
+ int ncols, bpl;
+ memset(use, 0, 256);
+ memset(pix, 0, 256);
+ bpl = image.bytesPerLine();
+
+ if (x11_mask) { // which pixels are used?
+ for (int i = 0; i < xi->height; i++) {
+ uchar* asrc = alpha.scanLine(i);
+ p = image.scanLine(i);
+ if (ale) {
+ for (int x = 0; x < xi->width; x++) {
+ if (asrc[x >> 3] & (1 << (x & 7)))
+ use[*p] = 1;
+ ++p;
+ }
+ } else {
+ for (int x = 0; x < xi->width; x++) {
+ if (asrc[x >> 3] & (0x80 >> (x & 7)))
+ use[*p] = 1;
+ ++p;
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < xi->height; i++) {
+ p = image.scanLine(i);
+ end = p + bpl;
+ while (p < end)
+ use[*p++] = 1;
+ }
+ }
+ ncols = 0;
+ for (int i = 0; i < 256; i++) { // build translation table
+ if (use[i])
+ pix[i] = ncols++;
+ }
+ for (int i = 0; i < xi->height; i++) { // translate pixels
+ p = image.scanLine(i);
+ end = p + bpl;
+ while (p < end) {
+ *p = pix[*p];
+ p++;
+ }
+ }
+ if (x11_mask) {
+ int trans;
+ if (ncols < 256) {
+ trans = ncols++;
+ image.setColorCount(ncols); // create color table
+ image.setColor(trans, 0x00000000);
+ } else {
+ image.setColorCount(ncols); // create color table
+ // oh dear... no spare "transparent" pixel.
+ // use first pixel in image (as good as any).
+ trans = image.scanLine(0)[0];
+ }
+ for (int i = 0; i < xi->height; i++) {
+ uchar* asrc = alpha.scanLine(i);
+ p = image.scanLine(i);
+ if (ale) {
+ for (int x = 0; x < xi->width; x++) {
+ if (!(asrc[x >> 3] & (1 << (x & 7))))
+ *p = trans;
+ ++p;
+ }
+ } else {
+ for (int x = 0; x < xi->width; x++) {
+ if (!(asrc[x >> 3] & (1 << (7 -(x & 7)))))
+ *p = trans;
+ ++p;
+ }
+ }
+ }
+ } else {
+ image.setColorCount(ncols); // create color table
+ }
+ QVector<QColor> colors = QColormap::instance(xinfo.screen()).colormap();
+ int j = 0;
+ for (int i=0; i<colors.size(); i++) { // translate pixels
+ if (use[i])
+ image.setColor(j++, 0xff000000 | colors.at(i).rgb());
+ }
+ }
+
+ return image;
+}
+
+/*!
+ Returns a copy of the pixmap that is transformed using the given
+ transformation \a matrix and transformation \a mode. The original
+ pixmap is not changed.
+
+ The transformation \a matrix is internally adjusted to compensate
+ for unwanted translation; i.e. the pixmap produced is the smallest
+ pixmap that contains all the transformed points of the original
+ pixmap. Use the trueMatrix() function to retrieve the actual
+ matrix used for transforming the pixmap.
+
+ This function is slow because it involves transformation to a
+ QImage, non-trivial computations and a transformation back to a
+ QPixmap.
+
+ \sa trueMatrix(), {QPixmap#Pixmap Transformations}{Pixmap
+ Transformations}
+*/
+QPixmap QX11PixmapData::transformed(const QTransform &transform,
+ Qt::TransformationMode mode ) const
+{
+ if (mode == Qt::SmoothTransformation || transform.type() >= QTransform::TxProject) {
+ QImage image = toImage();
+ return QPixmap::fromImage(image.transformed(transform, mode));
+ }
+
+ uint w = 0;
+ uint h = 0; // size of target pixmap
+ uint ws, hs; // size of source pixmap
+ uchar *dptr; // data in target pixmap
+ uint dbpl, dbytes; // bytes per line/bytes total
+ uchar *sptr; // data in original pixmap
+ int sbpl; // bytes per line in original
+ int bpp; // bits per pixel
+ bool depth1 = depth() == 1;
+ Display *dpy = X11->display;
+
+ ws = width();
+ hs = height();
+
+ QTransform mat(transform.m11(), transform.m12(), transform.m13(),
+ transform.m21(), transform.m22(), transform.m23(),
+ 0., 0., 1);
+ bool complex_xform = false;
+ qreal scaledWidth;
+ qreal scaledHeight;
+
+ if (mat.type() <= QTransform::TxScale) {
+ scaledHeight = qAbs(mat.m22()) * hs + 0.9999;
+ scaledWidth = qAbs(mat.m11()) * ws + 0.9999;
+ h = qAbs(int(scaledHeight));
+ w = qAbs(int(scaledWidth));
+ } else { // rotation or shearing
+ QPolygonF a(QRectF(0, 0, ws, hs));
+ a = mat.map(a);
+ QRect r = a.boundingRect().toAlignedRect();
+ w = r.width();
+ h = r.height();
+ scaledWidth = w;
+ scaledHeight = h;
+ complex_xform = true;
+ }
+ mat = QPixmap::trueMatrix(mat, ws, hs); // true matrix
+
+ bool invertible;
+ mat = mat.inverted(&invertible); // invert matrix
+
+ if (h == 0 || w == 0 || !invertible
+ || qAbs(scaledWidth) >= 32768 || qAbs(scaledHeight) >= 32768 )
+ // error, return null pixmap
+ return QPixmap();
+
+#if defined(QT_MITSHM)
+ static bool try_once = true;
+ if (try_once) {
+ try_once = false;
+ if (!xshminit)
+ qt_create_mitshm_buffer(this, 800, 600);
+ }
+
+ bool use_mitshm = xshmimg && !depth1 &&
+ xshmimg->width >= w && xshmimg->height >= h;
+#endif
+ XImage *xi = XGetImage(X11->display, handle(), 0, 0, ws, hs, AllPlanes,
+ depth1 ? XYPixmap : ZPixmap);
+
+ if (!xi)
+ return QPixmap();
+
+ sbpl = xi->bytes_per_line;
+ sptr = (uchar *)xi->data;
+ bpp = xi->bits_per_pixel;
+
+ if (depth1)
+ dbpl = (w+7)/8;
+ else
+ dbpl = ((w*bpp+31)/32)*4;
+ dbytes = dbpl*h;
+
+#if defined(QT_MITSHM)
+ if (use_mitshm) {
+ dptr = (uchar *)xshmimg->data;
+ uchar fillbyte = bpp == 8 ? white.pixel() : 0xff;
+ for (int y=0; y<h; y++)
+ memset(dptr + y*xshmimg->bytes_per_line, fillbyte, dbpl);
+ } else {
+#endif
+ dptr = (uchar *)malloc(dbytes); // create buffer for bits
+ Q_CHECK_PTR(dptr);
+ if (depth1) // fill with zeros
+ memset(dptr, 0, dbytes);
+ else if (bpp == 8) // fill with background color
+ memset(dptr, WhitePixel(X11->display, xinfo.screen()), dbytes);
+ else
+ memset(dptr, 0, dbytes);
+#if defined(QT_MITSHM)
+ }
+#endif
+
+ // #define QT_DEBUG_XIMAGE
+#if defined(QT_DEBUG_XIMAGE)
+ qDebug("----IMAGE--INFO--------------");
+ qDebug("width............. %d", xi->width);
+ qDebug("height............ %d", xi->height);
+ qDebug("xoffset........... %d", xi->xoffset);
+ qDebug("format............ %d", xi->format);
+ qDebug("byte order........ %d", xi->byte_order);
+ qDebug("bitmap unit....... %d", xi->bitmap_unit);
+ qDebug("bitmap bit order.. %d", xi->bitmap_bit_order);
+ qDebug("depth............. %d", xi->depth);
+ qDebug("bytes per line.... %d", xi->bytes_per_line);
+ qDebug("bits per pixel.... %d", xi->bits_per_pixel);
+#endif
+
+ int type;
+ if (xi->bitmap_bit_order == MSBFirst)
+ type = QT_XFORM_TYPE_MSBFIRST;
+ else
+ type = QT_XFORM_TYPE_LSBFIRST;
+ int xbpl, p_inc;
+ if (depth1) {
+ xbpl = (w+7)/8;
+ p_inc = dbpl - xbpl;
+ } else {
+ xbpl = (w*bpp)/8;
+ p_inc = dbpl - xbpl;
+#if defined(QT_MITSHM)
+ if (use_mitshm)
+ p_inc = xshmimg->bytes_per_line - xbpl;
+#endif
+ }
+
+ if (!qt_xForm_helper(mat, xi->xoffset, type, bpp, dptr, xbpl, p_inc, h, sptr, sbpl, ws, hs)){
+ qWarning("QPixmap::transform: display not supported (bpp=%d)",bpp);
+ QPixmap pm;
+ return pm;
+ }
+
+ qSafeXDestroyImage(xi);
+
+ if (depth1) { // mono bitmap
+ QBitmap bm = QBitmap::fromData(QSize(w, h), dptr,
+ BitmapBitOrder(X11->display) == MSBFirst
+ ? QImage::Format_Mono
+ : QImage::Format_MonoLSB);
+ free(dptr);
+ return bm;
+ } else { // color pixmap
+ QX11PixmapData *x11Data = new QX11PixmapData(QPixmapData::PixmapType);
+ QPixmap pm(x11Data);
+ x11Data->flags &= ~QX11PixmapData::Uninitialized;
+ x11Data->xinfo = xinfo;
+ x11Data->d = d;
+ x11Data->w = w;
+ x11Data->h = h;
+ x11Data->is_null = (w <= 0 || h <= 0);
+ x11Data->hd = (Qt::HANDLE)XCreatePixmap(X11->display,
+ RootWindow(X11->display, xinfo.screen()),
+ w, h, d);
+ x11Data->setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
+
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender) {
+ XRenderPictFormat *format = x11Data->d == 32
+ ? XRenderFindStandardFormat(X11->display, PictStandardARGB32)
+ : XRenderFindVisualFormat(X11->display, (Visual *) x11Data->xinfo.visual());
+ x11Data->picture = XRenderCreatePicture(X11->display, x11Data->hd, format, 0, 0);
+ }
+#endif // QT_NO_XRENDER
+
+ GC gc = XCreateGC(X11->display, x11Data->hd, 0, 0);
+#if defined(QT_MITSHM)
+ if (use_mitshm) {
+ XCopyArea(dpy, xshmpm, x11Data->hd, gc, 0, 0, w, h, 0, 0);
+ } else
+#endif
+ {
+ xi = XCreateImage(dpy, (Visual*)x11Data->xinfo.visual(),
+ x11Data->d,
+ ZPixmap, 0, (char *)dptr, w, h, 32, 0);
+ XPutImage(dpy, pm.handle(), gc, xi, 0, 0, 0, 0, w, h);
+ qSafeXDestroyImage(xi);
+ }
+ XFreeGC(X11->display, gc);
+
+ if (x11_mask) { // xform mask, too
+ pm.setMask(mask_to_bitmap(xinfo.screen()).transformed(transform));
+ } else if (d != 32 && complex_xform) { // need a mask!
+ QBitmap mask(ws, hs);
+ mask.fill(Qt::color1);
+ pm.setMask(mask.transformed(transform));
+ }
+ return pm;
+ }
+}
+
+int QPixmap::x11SetDefaultScreen(int screen)
+{
+ int old = defaultScreen;
+ defaultScreen = screen;
+ return old;
+}
+
+void QPixmap::x11SetScreen(int screen)
+{
+ if (paintingActive()) {
+ qWarning("QPixmap::x11SetScreen(): Cannot change screens during painting");
+ return;
+ }
+
+ if (isNull())
+ return;
+
+ if (data->classId() != QPixmapData::X11Class)
+ return;
+
+ if (screen < 0)
+ screen = QX11Info::appScreen();
+
+ QX11PixmapData *x11Data = static_cast<QX11PixmapData*>(data.data());
+ if (screen == x11Data->xinfo.screen())
+ return; // nothing to do
+
+ if (isNull()) {
+ QX11InfoData* xd = x11Data->xinfo.getX11Data(true);
+ xd->screen = screen;
+ xd->depth = QX11Info::appDepth(screen);
+ xd->cells = QX11Info::appCells(screen);
+ xd->colormap = QX11Info::appColormap(screen);
+ xd->defaultColormap = QX11Info::appDefaultColormap(screen);
+ xd->visual = (Visual *)QX11Info::appVisual(screen);
+ xd->defaultVisual = QX11Info::appDefaultVisual(screen);
+ x11Data->xinfo.setX11Data(xd);
+ return;
+ }
+#if 0
+ qDebug("QPixmap::x11SetScreen for %p from %d to %d. Size is %d/%d", x11Data, x11Data->xinfo.screen(), screen, width(), height());
+#endif
+
+ x11SetDefaultScreen(screen);
+ *this = qt_toX11Pixmap(toImage());
+}
+
+QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h)
+{
+ if (w == 0 || h == 0)
+ return QPixmap();
+
+ Display *dpy = X11->display;
+ XWindowAttributes window_attr;
+ if (!XGetWindowAttributes(dpy, window, &window_attr))
+ return QPixmap();
+
+ if (w < 0)
+ w = window_attr.width - x;
+ if (h < 0)
+ h = window_attr.height - y;
+
+ // determine the screen
+ int scr;
+ for (scr = 0; scr < ScreenCount(dpy); ++scr) {
+ if (window_attr.root == RootWindow(dpy, scr)) // found it
+ break;
+ }
+ if (scr >= ScreenCount(dpy)) // sanity check
+ return QPixmap();
+
+
+ // get the depth of the root window
+ XWindowAttributes root_attr;
+ if (!XGetWindowAttributes(dpy, window_attr.root, &root_attr))
+ return QPixmap();
+
+ if (window_attr.depth == root_attr.depth) {
+ // if the depth of the specified window and the root window are the
+ // same, grab pixels from the root window (so that we get the any
+ // overlapping windows and window manager frames)
+
+ // map x and y to the root window
+ WId unused;
+ if (!XTranslateCoordinates(dpy, window, window_attr.root, x, y,
+ &x, &y, &unused))
+ return QPixmap();
+
+ window = window_attr.root;
+ window_attr = root_attr;
+ }
+
+ QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType);
+
+ void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const XWindowAttributes &a);
+ qt_x11_getX11InfoForWindow(&data->xinfo,window_attr);
+
+ data->resize(w, h);
+
+ QPixmap pm(data);
+
+ data->flags &= ~QX11PixmapData::Uninitialized;
+ pm.x11SetScreen(scr);
+
+ GC gc = XCreateGC(dpy, pm.handle(), 0, 0);
+ XSetSubwindowMode(dpy, gc, IncludeInferiors);
+ XCopyArea(dpy, window, pm.handle(), gc, x, y, w, h, 0, 0);
+ XFreeGC(dpy, gc);
+
+ return pm;
+}
+
+bool QX11PixmapData::hasAlphaChannel() const
+{
+ return d == 32;
+}
+
+const QX11Info &QPixmap::x11Info() const
+{
+ if (data && data->classId() == QPixmapData::X11Class)
+ return static_cast<QX11PixmapData*>(data.data())->xinfo;
+ else {
+ static QX11Info nullX11Info;
+ return nullX11Info;
+ }
+}
+
+#if !defined(QT_NO_XRENDER)
+static XRenderPictFormat *qt_renderformat_for_depth(const QX11Info &xinfo, int depth)
+{
+ if (depth == 1)
+ return XRenderFindStandardFormat(X11->display, PictStandardA1);
+ else if (depth == 32)
+ return XRenderFindStandardFormat(X11->display, PictStandardARGB32);
+ else
+ return XRenderFindVisualFormat(X11->display, (Visual *)xinfo.visual());
+}
+#endif
+
+QPaintEngine* QX11PixmapData::paintEngine() const
+{
+ QX11PixmapData *that = const_cast<QX11PixmapData*>(this);
+
+ if ((flags & Readonly) && share_mode == QPixmap::ImplicitlyShared) {
+ // if someone wants to draw onto us, copy the shared contents
+ // and turn it into a fully fledged QPixmap
+ ::Pixmap hd_copy = XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()),
+ w, h, d);
+#if !defined(QT_NO_XRENDER)
+ XRenderPictFormat *format = qt_renderformat_for_depth(xinfo, d);
+ ::Picture picture_copy = XRenderCreatePicture(X11->display, hd_copy, format, 0, 0);
+
+ if (picture && d == 32) {
+ XRenderComposite(X11->display, PictOpSrc, picture, 0, picture_copy,
+ 0, 0, 0, 0, 0, 0, w, h);
+ XRenderFreePicture(X11->display, picture);
+ that->picture = picture_copy;
+ } else
+#endif
+ {
+ GC gc = XCreateGC(X11->display, hd_copy, 0, 0);
+ XCopyArea(X11->display, hd, hd_copy, gc, 0, 0, w, h, 0, 0);
+ XFreeGC(X11->display, gc);
+ }
+ that->hd = hd_copy;
+ that->flags &= ~QX11PixmapData::Readonly;
+ }
+
+ if (!that->pengine)
+ that->pengine = new QX11PaintEngine;
+ return that->pengine;
+}
+
+Qt::HANDLE QPixmap::x11PictureHandle() const
+{
+#ifndef QT_NO_XRENDER
+ if (data && data->classId() == QPixmapData::X11Class)
+ return static_cast<const QX11PixmapData*>(data.data())->picture;
+ else
+ return 0;
+#else
+ return 0;
+#endif // QT_NO_XRENDER
+}
+
+Qt::HANDLE QX11PixmapData::x11ConvertToDefaultDepth()
+{
+#ifndef QT_NO_XRENDER
+ if (d == QX11Info::appDepth() || !X11->use_xrender)
+ return hd;
+ if (!hd2) {
+ hd2 = XCreatePixmap(xinfo.display(), hd, w, h, QX11Info::appDepth());
+ XRenderPictFormat *format = XRenderFindVisualFormat(xinfo.display(),
+ (Visual*) xinfo.visual());
+ Picture pic = XRenderCreatePicture(xinfo.display(), hd2, format, 0, 0);
+ XRenderComposite(xinfo.display(), PictOpSrc, picture,
+ XNone, pic, 0, 0, 0, 0, 0, 0, w, h);
+ XRenderFreePicture(xinfo.display(), pic);
+ }
+ return hd2;
+#else
+ return hd;
+#endif
+}
+
+void QX11PixmapData::copy(const QPixmapData *data, const QRect &rect)
+{
+ if (data->pixelType() == BitmapType) {
+ fromImage(data->toImage().copy(rect), Qt::AutoColor);
+ return;
+ }
+
+ const QX11PixmapData *x11Data = static_cast<const QX11PixmapData*>(data);
+
+ setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
+
+ flags &= ~Uninitialized;
+ xinfo = x11Data->xinfo;
+ d = x11Data->d;
+ w = rect.width();
+ h = rect.height();
+ is_null = (w <= 0 || h <= 0);
+ hd = (Qt::HANDLE)XCreatePixmap(X11->display,
+ RootWindow(X11->display, x11Data->xinfo.screen()),
+ w, h, d);
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender) {
+ XRenderPictFormat *format = d == 32
+ ? XRenderFindStandardFormat(X11->display, PictStandardARGB32)
+ : XRenderFindVisualFormat(X11->display, (Visual *)xinfo.visual());
+ picture = XRenderCreatePicture(X11->display, hd, format, 0, 0);
+ }
+#endif // QT_NO_XRENDER
+ if (x11Data->x11_mask) {
+ x11_mask = XCreatePixmap(X11->display, hd, w, h, 1);
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender) {
+ mask_picture = XRenderCreatePicture(X11->display, x11_mask,
+ XRenderFindStandardFormat(X11->display, PictStandardA1), 0, 0);
+ XRenderPictureAttributes attrs;
+ attrs.alpha_map = x11Data->mask_picture;
+ XRenderChangePicture(X11->display, x11Data->picture, CPAlphaMap, &attrs);
+ }
+#endif
+ }
+
+#if !defined(QT_NO_XRENDER)
+ if (x11Data->picture && x11Data->d == 32) {
+ XRenderComposite(X11->display, PictOpSrc,
+ x11Data->picture, 0, picture,
+ rect.x(), rect.y(), 0, 0, 0, 0, w, h);
+ } else
+#endif
+ {
+ GC gc = XCreateGC(X11->display, hd, 0, 0);
+ XCopyArea(X11->display, x11Data->hd, hd, gc,
+ rect.x(), rect.y(), w, h, 0, 0);
+ if (x11Data->x11_mask) {
+ GC monogc = XCreateGC(X11->display, x11_mask, 0, 0);
+ XCopyArea(X11->display, x11Data->x11_mask, x11_mask, monogc,
+ rect.x(), rect.y(), w, h, 0, 0);
+ XFreeGC(X11->display, monogc);
+ }
+ XFreeGC(X11->display, gc);
+ }
+}
+
+bool QX11PixmapData::scroll(int dx, int dy, const QRect &rect)
+{
+ GC gc = XCreateGC(X11->display, hd, 0, 0);
+ XCopyArea(X11->display, hd, hd, gc,
+ rect.left(), rect.top(), rect.width(), rect.height(),
+ rect.left() + dx, rect.top() + dy);
+ XFreeGC(X11->display, gc);
+ return true;
+}
+
+#if !defined(QT_NO_XRENDER)
+void QX11PixmapData::convertToARGB32(bool preserveContents)
+{
+ if (!X11->use_xrender)
+ return;
+
+ // Q_ASSERT(count == 1);
+ if ((flags & Readonly) && share_mode == QPixmap::ExplicitlyShared)
+ return;
+
+ Pixmap pm = XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()),
+ w, h, 32);
+ Picture p = XRenderCreatePicture(X11->display, pm,
+ XRenderFindStandardFormat(X11->display, PictStandardARGB32), 0, 0);
+ if (picture) {
+ if (preserveContents)
+ XRenderComposite(X11->display, PictOpSrc, picture, 0, p, 0, 0, 0, 0, 0, 0, w, h);
+ if (!(flags & Readonly))
+ XRenderFreePicture(X11->display, picture);
+ }
+ if (hd && !(flags & Readonly))
+ XFreePixmap(X11->display, hd);
+ if (x11_mask) {
+ XFreePixmap(X11->display, x11_mask);
+ if (mask_picture)
+ XRenderFreePicture(X11->display, mask_picture);
+ x11_mask = 0;
+ mask_picture = 0;
+ }
+ hd = pm;
+ picture = p;
+ d = 32;
+}
+#endif
+
+QPixmap QPixmap::fromX11Pixmap(Qt::HANDLE pixmap, QPixmap::ShareMode mode)
+{
+ Window root;
+ int x;
+ int y;
+ uint width;
+ uint height;
+ uint border_width;
+ uint depth;
+ XWindowAttributes win_attribs;
+ int num_screens = ScreenCount(X11->display);
+ int screen = 0;
+
+ XGetGeometry(X11->display, pixmap, &root, &x, &y, &width, &height, &border_width, &depth);
+ XGetWindowAttributes(X11->display, root, &win_attribs);
+
+ for (; screen < num_screens; ++screen) {
+ if (win_attribs.screen == ScreenOfDisplay(X11->display, screen))
+ break;
+ }
+
+ QX11PixmapData *data = new QX11PixmapData(depth == 1 ? QPixmapData::BitmapType : QPixmapData::PixmapType);
+ data->setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
+ data->flags = QX11PixmapData::Readonly;
+ data->share_mode = mode;
+ data->w = width;
+ data->h = height;
+ data->is_null = (width <= 0 || height <= 0);
+ data->d = depth;
+ data->hd = pixmap;
+
+ if (defaultScreen >= 0 && defaultScreen != screen) {
+ QX11InfoData* xd = data->xinfo.getX11Data(true);
+ xd->screen = defaultScreen;
+ xd->depth = QX11Info::appDepth(xd->screen);
+ xd->cells = QX11Info::appCells(xd->screen);
+ xd->colormap = QX11Info::appColormap(xd->screen);
+ xd->defaultColormap = QX11Info::appDefaultColormap(xd->screen);
+ xd->visual = (Visual *)QX11Info::appVisual(xd->screen);
+ xd->defaultVisual = QX11Info::appDefaultVisual(xd->screen);
+ data->xinfo.setX11Data(xd);
+ }
+
+#ifndef QT_NO_XRENDER
+ if (X11->use_xrender) {
+ XRenderPictFormat *format = qt_renderformat_for_depth(data->xinfo, depth);
+ data->picture = XRenderCreatePicture(X11->display, data->hd, format, 0, 0);
+ }
+#endif // QT_NO_XRENDER
+
+ return QPixmap(data);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qpixmap_x11_p.h b/src/widgets/platforms/x11/qpixmap_x11_p.h
new file mode 100644
index 0000000000..eb8e5819ad
--- /dev/null
+++ b/src/widgets/platforms/x11/qpixmap_x11_p.h
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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_X11_P_H
+#define QPIXMAPDATA_X11_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>
+
+#include "QtGui/qx11info_x11.h"
+
+QT_BEGIN_NAMESPACE
+
+class QX11PaintEngine;
+
+struct QXImageWrapper;
+
+class Q_GUI_EXPORT QX11PixmapData : public QPixmapData
+{
+public:
+ QX11PixmapData(PixelType type);
+// QX11PixmapData(PixelType type, int width, int height);
+// QX11PixmapData(PixelType type, const QImage &image,
+// Qt::ImageConversionFlags flags);
+ ~QX11PixmapData();
+
+ 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;
+ QImage toImage(const QRect &rect) const;
+ QPaintEngine* paintEngine() const;
+
+ Qt::HANDLE handle() const { return hd; }
+ Qt::HANDLE x11ConvertToDefaultDepth();
+
+ static Qt::HANDLE createBitmapFromImage(const QImage &image);
+
+ void* gl_surface;
+#ifndef QT_NO_XRENDER
+ void convertToARGB32(bool preserveContents = true);
+#endif
+
+protected:
+ int metric(QPaintDevice::PaintDeviceMetric metric) const;
+
+private:
+ friend class QPixmap;
+ friend class QBitmap;
+ friend class QX11PaintEngine;
+ friend class QX11WindowSurface;
+ 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 QX11GLPixmapData; // Needs gl_surface
+ friend class QMeeGoLivePixmapData; // Needs gl_surface and flags
+ friend bool qt_createEGLSurfaceForPixmap(QPixmapData*, bool); // Needs gl_surface
+
+ void release();
+
+ QImage toImage(const QXImageWrapper &xi, const QRect &rect) const;
+
+ QBitmap mask_to_bitmap(int screen) const;
+ static Qt::HANDLE bitmap_to_mask(const QBitmap &, int screen);
+ void bitmapFromImage(const QImage &image);
+
+ bool canTakeQImageFromXImage(const QXImageWrapper &xi) const;
+ QImage takeQImageFromXImage(const QXImageWrapper &xi) const;
+
+ Qt::HANDLE hd;
+
+ enum Flag {
+ NoFlags = 0x0,
+ Uninitialized = 0x1,
+ Readonly = 0x2,
+ InvertedWhenBoundToTexture = 0x4,
+ GlSurfaceCreatedWithAlpha = 0x8
+ };
+ uint flags;
+
+ QX11Info xinfo;
+ Qt::HANDLE x11_mask;
+ Qt::HANDLE picture;
+ Qt::HANDLE mask_picture;
+ Qt::HANDLE hd2; // sorted in the default display depth
+ QPixmap::ShareMode share_mode;
+
+ QX11PaintEngine *pengine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPIXMAPDATA_X11_P_H
+
diff --git a/src/widgets/platforms/x11/qregion_x11.cpp b/src/widgets/platforms/x11/qregion_x11.cpp
new file mode 100644
index 0000000000..ef4e844bfa
--- /dev/null
+++ b/src/widgets/platforms/x11/qregion_x11.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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/qt_x11_p.h>
+
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+QRegion::QRegionData QRegion::shared_empty = {Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, 0};
+
+void QRegion::updateX11Region() const
+{
+ d->rgn = XCreateRegion();
+ if (!d->qt_rgn)
+ return;
+
+ int n = d->qt_rgn->numRects;
+ const QRect *rect = (n == 1 ? &d->qt_rgn->extents : d->qt_rgn->rects.constData());
+ while (n--) {
+ XRectangle r;
+ r.x = qMax(SHRT_MIN, rect->x());
+ r.y = qMax(SHRT_MIN, rect->y());
+ r.width = qMin((int)USHRT_MAX, rect->width());
+ r.height = qMin((int)USHRT_MAX, rect->height());
+ XUnionRectWithRegion(&r, d->rgn, d->rgn);
+ ++rect;
+ }
+}
+
+void *QRegion::clipRectangles(int &num) const
+{
+ if (!d->xrectangles && !(d == &shared_empty || d->qt_rgn->numRects == 0)) {
+ XRectangle *r = static_cast<XRectangle*>(malloc(d->qt_rgn->numRects * sizeof(XRectangle)));
+ d->xrectangles = r;
+ int n = d->qt_rgn->numRects;
+ const QRect *rect = (n == 1 ? &d->qt_rgn->extents : d->qt_rgn->rects.constData());
+ while (n--) {
+ r->x = qMax(SHRT_MIN, rect->x());
+ r->y = qMax(SHRT_MIN, rect->y());
+ r->width = qMin((int)USHRT_MAX, rect->width());
+ r->height = qMin((int)USHRT_MAX, rect->height());
+ ++r;
+ ++rect;
+ }
+ }
+ if (d == &shared_empty || d->qt_rgn->numRects == 0)
+ num = 0;
+ else
+ num = d->qt_rgn->numRects;
+ return d->xrectangles;
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qsound_x11.cpp b/src/widgets/platforms/x11/qsound_x11.cpp
new file mode 100644
index 0000000000..12c06f0aa1
--- /dev/null
+++ b/src/widgets/platforms/x11/qsound_x11.cpp
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qsound.h"
+
+#ifndef QT_NO_SOUND
+
+#include "qhash.h"
+#include "qsocketnotifier.h"
+#include "qapplication.h"
+#include "qsound_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_NAS
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <audio/audiolib.h>
+#include <audio/soundlib.h>
+QT_END_INCLUDE_NAMESPACE
+
+static AuServer *nas=0;
+
+static AuBool eventPred(AuServer *, AuEvent *e, AuPointer p)
+{
+ if (e && (e->type == AuEventTypeElementNotify)) {
+ if (e->auelementnotify.flow == *((AuFlowID *)p))
+ return true;
+ }
+ return false;
+}
+
+class QAuBucketNAS : public QAuBucket {
+public:
+ QAuBucketNAS(AuBucketID b, AuFlowID f = 0) : id(b), flow(f), stopped(true), numplaying(0) { }
+ ~QAuBucketNAS()
+ {
+ if (nas) {
+ AuSync(nas, false);
+ AuDestroyBucket(nas, id, NULL);
+
+ AuEvent ev;
+ while (AuScanEvents(nas, AuEventsQueuedAfterFlush, true, eventPred, &flow, &ev))
+ ;
+ }
+ }
+
+ AuBucketID id;
+ AuFlowID flow;
+ bool stopped;
+ int numplaying;
+};
+
+class QAuServerNAS : public QAuServer {
+ Q_OBJECT
+
+ QSocketNotifier* sn;
+
+public:
+ QAuServerNAS(QObject* parent);
+ ~QAuServerNAS();
+
+ void init(QSound*);
+ void play(const QString& filename);
+ void play(QSound*);
+ void stop(QSound*);
+ bool okay();
+ void setDone(QSound*);
+
+public slots:
+ void dataReceived();
+ void soundDestroyed(QObject *o);
+
+private:
+ QAuBucketNAS* bucket(QSound* s)
+ {
+ return (QAuBucketNAS*)QAuServer::bucket(s);
+ }
+};
+
+QAuServerNAS::QAuServerNAS(QObject* parent) :
+ QAuServer(parent)
+{
+ setObjectName(QLatin1String("Network Audio System"));
+ nas = AuOpenServer(NULL, 0, NULL, 0, NULL, NULL);
+ if (nas) {
+ AuSetCloseDownMode(nas, AuCloseDownDestroy, NULL);
+ // Ask Qt for async messages...
+ sn=new QSocketNotifier(AuServerConnectionNumber(nas),
+ QSocketNotifier::Read);
+ QObject::connect(sn, SIGNAL(activated(int)),
+ this, SLOT(dataReceived()));
+ } else {
+ sn = 0;
+ }
+}
+
+QAuServerNAS::~QAuServerNAS()
+{
+ if (nas)
+ AuCloseServer(nas);
+ delete sn;
+ nas = 0;
+}
+
+typedef QHash<void*,QAuServerNAS*> AuServerHash;
+static AuServerHash *inprogress=0;
+
+void QAuServerNAS::soundDestroyed(QObject *o)
+{
+ if (inprogress) {
+ QSound *so = static_cast<QSound *>(o);
+ while (inprogress->remove(so))
+ ; // Loop while remove returns true
+ }
+}
+
+void QAuServerNAS::play(const QString& filename)
+{
+ if (nas) {
+ int iv=100;
+ AuFixedPoint volume=AuFixedPointFromFraction(iv,100);
+ AuSoundPlayFromFile(nas, filename.toLocal8Bit().constData(), AuNone, volume,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ AuFlush(nas);
+ dataReceived();
+ AuFlush(nas);
+ qApp->flush();
+ }
+}
+
+static void callback(AuServer*, AuEventHandlerRec*, AuEvent* e, AuPointer p)
+{
+ if (inprogress->contains(p) && e) {
+ if (e->type==AuEventTypeElementNotify &&
+ e->auelementnotify.kind==AuElementNotifyKindState) {
+ if (e->auelementnotify.cur_state == AuStateStop) {
+ AuServerHash::Iterator it = inprogress->find(p);
+ if (it != inprogress->end())
+ (*it)->setDone((QSound*)p);
+ }
+ }
+ }
+}
+
+void QAuServerNAS::setDone(QSound* s)
+{
+ if (nas) {
+ decLoop(s);
+ if (s->loopsRemaining() && !bucket(s)->stopped) {
+ bucket(s)->stopped = true;
+ play(s);
+ } else {
+ if (--(bucket(s)->numplaying) == 0)
+ bucket(s)->stopped = true;
+ inprogress->remove(s);
+ }
+ }
+}
+
+void QAuServerNAS::play(QSound* s)
+{
+ if (nas) {
+ ++(bucket(s)->numplaying);
+ if (!bucket(s)->stopped) {
+ stop(s);
+ }
+
+ bucket(s)->stopped = false;
+ if (!inprogress)
+ inprogress = new AuServerHash;
+ inprogress->insert(s,this);
+ int iv=100;
+ AuFixedPoint volume=AuFixedPointFromFraction(iv,100);
+ QAuBucketNAS *b = bucket(s);
+ AuSoundPlayFromBucket(nas, b->id, AuNone, volume,
+ callback, s, 0, &b->flow, NULL, NULL, NULL);
+ AuFlush(nas);
+ dataReceived();
+ AuFlush(nas);
+ qApp->flush();
+ }
+}
+
+void QAuServerNAS::stop(QSound* s)
+{
+ if (nas && !bucket(s)->stopped) {
+ bucket(s)->stopped = true;
+ AuStopFlow(nas, bucket(s)->flow, NULL);
+ AuFlush(nas);
+ dataReceived();
+ AuFlush(nas);
+ qApp->flush();
+ }
+}
+
+void QAuServerNAS::init(QSound* s)
+{
+ connect(s, SIGNAL(destroyed(QObject*)),
+ this, SLOT(soundDestroyed(QObject*)));
+
+ if (nas) {
+ AuBucketID b_id =
+ AuSoundCreateBucketFromFile(nas, s->fileName().toLocal8Bit().constData(),
+ 0 /*AuAccessAllMasks*/, NULL, NULL);
+ setBucket(s, new QAuBucketNAS(b_id));
+ }
+}
+
+bool QAuServerNAS::okay()
+{
+ return !!nas;
+}
+
+void QAuServerNAS::dataReceived()
+{
+ AuHandleEvents(nas);
+}
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "qsound_x11.moc"
+QT_END_INCLUDE_NAMESPACE
+
+#endif
+
+
+class QAuServerNull : public QAuServer
+{
+public:
+ QAuServerNull(QObject* parent);
+
+ void play(const QString&) { }
+ void play(QSound*s) { while(decLoop(s) > 0) /* nothing */ ; }
+ void stop(QSound*) { }
+ bool okay() { return false; }
+};
+
+QAuServerNull::QAuServerNull(QObject* parent)
+ : QAuServer(parent)
+{
+}
+
+
+QAuServer* qt_new_audio_server()
+{
+#ifndef QT_NO_NAS
+ QAuServer* s = new QAuServerNAS(qApp);
+ if (s->okay())
+ return s;
+ else
+ delete s;
+#endif
+ return new QAuServerNull(qApp);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SOUND
diff --git a/src/widgets/platforms/x11/qt_x11_p.h b/src/widgets/platforms/x11/qt_x11_p.h
new file mode 100644
index 0000000000..69079cfaad
--- /dev/null
+++ b/src/widgets/platforms/x11/qt_x11_p.h
@@ -0,0 +1,757 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QT_X11_P_H
+#define QT_X11_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/qwindowdefs.h"
+#include "QtCore/qlist.h"
+#include "QtCore/qvariant.h"
+
+// the following is necessary to work around breakage in many versions
+// of XFree86's Xlib.h still in use
+// ### which versions?
+#if defined(_XLIB_H_) // crude hack, but...
+#error "cannot include <X11/Xlib.h> before this file"
+#endif
+#define XRegisterIMInstantiateCallback qt_XRegisterIMInstantiateCallback
+#define XUnregisterIMInstantiateCallback qt_XUnregisterIMInstantiateCallback
+#define XSetIMValues qt_XSetIMValues
+#include <X11/Xlib.h>
+#undef XRegisterIMInstantiateCallback
+#undef XUnregisterIMInstantiateCallback
+#undef XSetIMValues
+
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#ifdef index
+# undef index
+#endif
+#ifdef rindex
+# undef rindex
+#endif
+#ifdef Q_OS_VXWORS
+# ifdef open
+# undef open
+# endif
+# ifdef getpid
+# undef getpid
+# endif
+#endif // Q_OS_VXWORKS
+#include <X11/Xatom.h>
+
+//#define QT_NO_SHAPE
+#ifdef QT_NO_SHAPE
+# define XShapeCombineRegion(a,b,c,d,e,f,g)
+# define XShapeCombineMask(a,b,c,d,e,f,g)
+#else
+# include <X11/extensions/shape.h>
+#endif // QT_NO_SHAPE
+
+
+#if !defined (QT_NO_TABLET)
+# include <X11/extensions/XInput.h>
+#if defined (Q_OS_IRIX)
+# include <X11/extensions/SGIMisc.h>
+# include <wacom.h>
+#endif
+#endif // QT_NO_TABLET
+
+
+// #define QT_NO_XINERAMA
+#ifndef QT_NO_XINERAMA
+# if 0 // ### Xsun, but how to detect it?
+// Xinerama is only supported in Solaris 7 with patches 107648/108376 and
+// Solaris 8 or above which introduce the X11R6.4 Xserver.
+// To switch the Xinerama functionality on, you need to add the "+xinerama"
+// argument to the Xsun start line.
+// At least Solaris 7 and 8 are missing Xinerama system headers and function
+// declarations (bug 4284701).
+// The Xinerama API is not documented. In theory it could change but it
+// probably won't because Sun are using it in at least dtlogin (bug 4221829).
+extern "C" Bool XPanoramiXQueryExtension(
+ Display*,
+ int*,
+ int*
+);
+extern "C" Status XPanoramiXQueryVersion(
+ Display*,
+ int*,
+ int*
+);
+extern "C" Status XPanoramiXGetState(
+ Display*,
+ Drawable,
+ XPanoramiXInfo*
+);
+extern "C" Status XPanoramiXGetScreenCount(
+ Display *,
+ Drawable,
+ XPanoramiXInfo*
+);
+extern "C" Status XPanoramiXGetScreenSize(
+ Display*,
+ Drawable,
+ int,
+ XPanoramiXInfo*
+);
+# else // XFree86
+// XFree86 does not C++ify Xinerama (at least up to XFree86 4.0.3).
+extern "C" {
+# include <X11/extensions/Xinerama.h>
+}
+# endif
+#endif // QT_NO_XINERAMA
+
+// #define QT_NO_XRANDR
+#ifndef QT_NO_XRANDR
+# include <X11/extensions/Xrandr.h>
+#endif // QT_NO_XRANDR
+
+// #define QT_NO_XRENDER
+#ifndef QT_NO_XRENDER
+# include <X11/extensions/Xrender.h>
+#endif // QT_NO_XRENDER
+
+#ifndef QT_NO_XSYNC
+extern "C" {
+# include "X11/extensions/sync.h"
+}
+#endif
+
+// #define QT_NO_XKB
+#ifndef QT_NO_XKB
+# include <X11/XKBlib.h>
+#endif // QT_NO_XKB
+
+
+#if !defined(XlibSpecificationRelease)
+# define X11R4
+typedef char *XPointer;
+#else
+# undef X11R4
+#endif
+
+// #define QT_NO_XIM
+#if defined(X11R4)
+// X11R4 does not have XIM
+#define QT_NO_XIM
+#elif defined(Q_OS_OSF) && (XlibSpecificationRelease < 6)
+// broken in Xlib up to OSF/1 3.2
+#define QT_NO_XIM
+#elif defined(Q_OS_AIX)
+// broken in Xlib up to what version of AIX?
+#define QT_NO_XIM
+#elif defined(QT_NO_DEBUG) && defined(Q_OS_IRIX)
+// XmbLookupString broken on IRIX
+// XCreateIC broken when compiling -64 on IRIX 6.5.2
+#define QT_NO_XIM
+#elif defined(Q_OS_HPUX) && defined(__LP64__)
+// XCreateIC broken when compiling 64-bit ELF on HP-UX 11.0
+#define QT_NO_XIM
+#elif defined(Q_OS_SCO)
+// ### suggested by user...
+// ### #define QT_NO_XIM
+#endif // QT_NO_XIM
+
+#ifndef QT_NO_XFIXES
+typedef Bool (*PtrXFixesQueryExtension)(Display *, int *, int *);
+typedef Status (*PtrXFixesQueryVersion)(Display *, int *, int *);
+typedef void (*PtrXFixesSetCursorName)(Display *dpy, Cursor cursor, const char *name);
+typedef void (*PtrXFixesSelectSelectionInput)(Display *dpy, Window win, Atom selection, unsigned long eventMask);
+#endif // QT_NO_XFIXES
+
+#ifndef QT_NO_XCURSOR
+#include <X11/Xcursor/Xcursor.h>
+typedef Cursor (*PtrXcursorLibraryLoadCursor)(Display *, const char *);
+#endif // QT_NO_XCURSOR
+
+#ifndef QT_NO_XINERAMA
+typedef Bool (*PtrXineramaQueryExtension)(Display *dpy, int *event_base, int *error_base);
+typedef Bool (*PtrXineramaIsActive)(Display *dpy);
+typedef XineramaScreenInfo *(*PtrXineramaQueryScreens)(Display *dpy, int *number);
+#endif // QT_NO_XINERAMA
+
+#ifndef QT_NO_XRANDR
+typedef void (*PtrXRRSelectInput)(Display *, Window, int);
+typedef int (*PtrXRRUpdateConfiguration)(XEvent *);
+typedef int (*PtrXRRRootToScreen)(Display *, Window);
+typedef Bool (*PtrXRRQueryExtension)(Display *, int *, int *);
+typedef XRRScreenSize *(*PtrXRRSizes)(Display *, int, int *);
+#endif // QT_NO_XRANDR
+
+#ifndef QT_NO_XINPUT
+typedef int (*PtrXCloseDevice)(Display *, XDevice *);
+typedef XDeviceInfo* (*PtrXListInputDevices)(Display *, int *);
+typedef XDevice* (*PtrXOpenDevice)(Display *, XID);
+typedef void (*PtrXFreeDeviceList)(XDeviceInfo *);
+typedef int (*PtrXSelectExtensionEvent)(Display *, Window, XEventClass *, int);
+#endif // QT_NO_XINPUT
+
+/*
+ * Solaris patch 108652-47 and higher fixes crases in
+ * XRegisterIMInstantiateCallback, but the function doesn't seem to
+ * work.
+ *
+ * Instead, we disabled R6 input, and open the input method
+ * immediately at application start.
+ */
+#if !defined(QT_NO_XIM) && (XlibSpecificationRelease >= 6) && \
+ !defined(Q_OS_SOLARIS)
+#define USE_X11R6_XIM
+
+//######### XFree86 has wrong declarations for XRegisterIMInstantiateCallback
+//######### and XUnregisterIMInstantiateCallback in at least version 3.3.2.
+//######### Many old X11R6 header files lack XSetIMValues.
+//######### Therefore, we have to declare these functions ourselves.
+
+extern "C" Bool XRegisterIMInstantiateCallback(
+ Display*,
+ struct _XrmHashBucketRec*,
+ char*,
+ char*,
+ XIMProc, //XFree86 has XIDProc, which has to be wrong
+ XPointer
+);
+
+extern "C" Bool XUnregisterIMInstantiateCallback(
+ Display*,
+ struct _XrmHashBucketRec*,
+ char*,
+ char*,
+ XIMProc, //XFree86 has XIDProc, which has to be wrong
+ XPointer
+);
+
+extern "C" char *XSetIMValues(XIM /* im */, ...);
+
+#endif
+
+#ifndef QT_NO_FONTCONFIG
+#include <fontconfig/fontconfig.h>
+#endif
+
+#ifndef QT_NO_XIM
+// some platforms (eg. Solaris 2.51) don't have these defines in Xlib.h
+#ifndef XNResetState
+#define XNResetState "resetState"
+#endif
+#ifndef XIMPreserveState
+#define XIMPreserveState (1L<<1)
+#endif
+#endif
+
+
+#ifndef X11R4
+# include <X11/Xlocale.h>
+#endif // X11R4
+
+
+#ifndef QT_NO_MITSHM
+# include <X11/extensions/XShm.h>
+#endif // QT_NO_MITSHM
+
+QT_BEGIN_NAMESPACE
+
+class QWidget;
+
+struct QX11InfoData {
+ uint ref;
+ int screen;
+ int dpiX;
+ int dpiY;
+ int depth;
+ int cells;
+ Colormap colormap;
+ Visual *visual;
+ bool defaultColormap;
+ bool defaultVisual;
+ int subpixel;
+};
+
+class QDrag;
+struct QXdndDropTransaction
+{
+ Time timestamp;
+ Window target;
+ Window proxy_target;
+ QWidget *targetWidget;
+ QWidget *embedding_widget;
+ QDrag *object;
+};
+
+class QMimeData;
+
+struct QX11Data;
+extern Q_GUI_EXPORT QX11Data *qt_x11Data;
+
+enum DesktopEnvironment {
+ DE_UNKNOWN,
+ DE_KDE,
+ DE_GNOME,
+ DE_CDE,
+ DE_MEEGO_COMPOSITOR,
+ DE_4DWM
+};
+
+struct QX11Data
+{
+ static Qt::KeyboardModifiers translateModifiers(int s);
+
+ Window findClientWindow(Window, Atom, bool);
+
+ // from qclipboard_x11.cpp
+ bool clipboardWaitForEvent(Window win, int type, XEvent *event, int timeout);
+ bool clipboardReadProperty(Window win, Atom property, bool deleteProperty,
+ QByteArray *buffer, int *size, Atom *type, int *format);
+ QByteArray clipboardReadIncrementalProperty(Window win, Atom property, int nbytes, bool nullterm);
+
+ // from qdnd_x11.cpp
+ bool dndEnable(QWidget* w, bool on);
+ static void xdndSetup();
+ void xdndHandleEnter(QWidget *, const XEvent *, bool);
+ void xdndHandlePosition(QWidget *, const XEvent *, bool);
+ void xdndHandleStatus(QWidget *, const XEvent *, bool);
+ void xdndHandleLeave(QWidget *, const XEvent *, bool);
+ void xdndHandleDrop(QWidget *, const XEvent *, bool);
+ void xdndHandleFinished(QWidget *, const XEvent *, bool);
+ void xdndHandleSelectionRequest(const XSelectionRequestEvent *);
+ static bool xdndHandleBadwindow();
+ QByteArray xdndAtomToString(Atom a);
+ Atom xdndStringToAtom(const char *);
+
+ QString xdndMimeAtomToString(Atom a);
+ Atom xdndMimeStringToAtom(const QString &mimeType);
+ QStringList xdndMimeFormatsForAtom(Atom a);
+ bool xdndMimeDataForAtom(Atom a, QMimeData *mimeData, QByteArray *data, Atom *atomFormat, int *dataFormat);
+ QList<Atom> xdndMimeAtomsForFormat(const QString &format);
+ QVariant xdndMimeConvertToFormat(Atom a, const QByteArray &data, const QString &format, QVariant::Type requestedType, const QByteArray &encoding);
+ Atom xdndMimeAtomForFormat(const QString &format, QVariant::Type requestedType, const QList<Atom> &atoms, QByteArray *requestedEncoding);
+
+ QList<QXdndDropTransaction> dndDropTransactions;
+
+ // from qmotifdnd_x11.cpp
+ void motifdndHandle(QWidget *, const XEvent *, bool);
+ void motifdndEnable(QWidget *, bool);
+ QVariant motifdndObtainData(const char *format);
+ QByteArray motifdndFormat(int n);
+ bool motifdnd_active;
+
+ Display *display;
+ char *displayName;
+ bool foreignDisplay;
+ // current focus model
+ enum {
+ FM_Unknown = -1,
+ FM_Other = 0,
+ FM_PointerRoot = 1
+ };
+ int focus_model;
+
+ // true if Qt is compiled w/ RANDR support and RANDR is supported on the connected Display
+ bool use_xrandr;
+ int xrandr_major;
+ int xrandr_eventbase;
+ int xrandr_errorbase;
+
+ // true if Qt is compiled w/ RENDER support and RENDER is supported on the connected Display
+ bool use_xrender;
+ int xrender_major;
+ int xrender_version;
+
+ // true if Qt is compiled w/ XFIXES support and XFIXES is supported on the connected Display
+ bool use_xfixes;
+ int xfixes_major;
+ int xfixes_eventbase;
+ int xfixes_errorbase;
+
+#ifndef QT_NO_XFIXES
+ PtrXFixesQueryExtension ptrXFixesQueryExtension;
+ PtrXFixesQueryVersion ptrXFixesQueryVersion;
+ PtrXFixesSetCursorName ptrXFixesSetCursorName;
+ PtrXFixesSelectSelectionInput ptrXFixesSelectSelectionInput;
+#endif
+
+#ifndef QT_NO_XINPUT
+ PtrXCloseDevice ptrXCloseDevice;
+ PtrXListInputDevices ptrXListInputDevices;
+ PtrXOpenDevice ptrXOpenDevice;
+ PtrXFreeDeviceList ptrXFreeDeviceList;
+ PtrXSelectExtensionEvent ptrXSelectExtensionEvent;
+#endif // QT_NO_XINPUT
+
+
+ // true if Qt is compiled w/ MIT-SHM support and MIT-SHM is supported on the connected Display
+ bool use_mitshm;
+ bool use_mitshm_pixmaps;
+ int mitshm_major;
+
+ // true if Qt is compiled w/ Tablet support and we have a tablet.
+ bool use_xinput;
+ int xinput_major;
+ int xinput_eventbase;
+ int xinput_errorbase;
+
+ // for XKEYBOARD support
+ bool use_xkb;
+ int xkb_major;
+ int xkb_eventbase;
+ int xkb_errorbase;
+
+ QList<QWidget *> deferred_map;
+ struct ScrollInProgress {
+ long id;
+ QWidget* scrolled_widget;
+ int dx, dy;
+ };
+ long sip_serial;
+ QList<ScrollInProgress> sip_list;
+
+ // window managers list of supported "stuff"
+ Atom *net_supported_list;
+ // list of virtual root windows
+ Window *net_virtual_root_list;
+ // client leader window
+ Window wm_client_leader;
+
+ QX11InfoData *screens;
+ Visual **argbVisuals;
+ Colormap *argbColormaps;
+ int screenCount;
+ int defaultScreen;
+
+ Time time;
+ Time userTime;
+
+ QString default_im;
+
+ // starts to ignore bad window errors from X
+ static inline void ignoreBadwindow() {
+ qt_x11Data->ignore_badwindow = true;
+ qt_x11Data->seen_badwindow = false;
+ }
+
+ // ends ignoring bad window errors and returns whether an error had happened.
+ static inline bool badwindow() {
+ qt_x11Data->ignore_badwindow = false;
+ return qt_x11Data->seen_badwindow;
+ }
+
+ bool ignore_badwindow;
+ bool seen_badwindow;
+
+ // options
+ int visual_class;
+ int visual_id;
+ int color_count;
+ bool custom_cmap;
+
+ // outside visual/colormap
+ Visual *visual;
+ Colormap colormap;
+
+#ifndef QT_NO_XRENDER
+ enum { solid_fill_count = 16 };
+ struct SolidFills {
+ XRenderColor color;
+ int screen;
+ Picture picture;
+ } solid_fills[solid_fill_count];
+ enum { pattern_fill_count = 16 };
+ struct PatternFills {
+ XRenderColor color;
+ XRenderColor bg_color;
+ int screen;
+ int style;
+ bool opaque;
+ Picture picture;
+ } pattern_fills[pattern_fill_count];
+ Picture getSolidFill(int screen, const QColor &c);
+ XRenderColor preMultiply(const QColor &c);
+#endif
+
+ bool has_fontconfig;
+ qreal fc_scale;
+ bool fc_antialias;
+ int fc_hint_style;
+
+ char *startupId;
+
+ DesktopEnvironment desktopEnvironment : 8;
+ uint desktopVersion : 8; /* Used only for KDE */
+
+ /* Warning: if you modify this list, modify the names of atoms in qapplication_x11.cpp as well! */
+ enum X11Atom {
+ // window-manager <-> client protocols
+ WM_PROTOCOLS,
+ WM_DELETE_WINDOW,
+ WM_TAKE_FOCUS,
+ _NET_WM_PING,
+ _NET_WM_CONTEXT_HELP,
+ _NET_WM_SYNC_REQUEST,
+ _NET_WM_SYNC_REQUEST_COUNTER,
+
+ // ICCCM window state
+ WM_STATE,
+ WM_CHANGE_STATE,
+
+ // Session management
+ WM_CLIENT_LEADER,
+ WM_WINDOW_ROLE,
+ SM_CLIENT_ID,
+
+ // Clipboard
+ CLIPBOARD,
+ INCR,
+ TARGETS,
+ MULTIPLE,
+ TIMESTAMP,
+ SAVE_TARGETS,
+ CLIP_TEMPORARY,
+ _QT_SELECTION,
+ _QT_CLIPBOARD_SENTINEL,
+ _QT_SELECTION_SENTINEL,
+ CLIPBOARD_MANAGER,
+
+ RESOURCE_MANAGER,
+
+ _XSETROOT_ID,
+
+ _QT_SCROLL_DONE,
+ _QT_INPUT_ENCODING,
+
+ _MOTIF_WM_HINTS,
+
+ DTWM_IS_RUNNING,
+ ENLIGHTENMENT_DESKTOP,
+ _DT_SAVE_MODE,
+ _SGI_DESKS_MANAGER,
+
+ // EWMH (aka NETWM)
+ _NET_SUPPORTED,
+ _NET_VIRTUAL_ROOTS,
+ _NET_WORKAREA,
+
+ _NET_MOVERESIZE_WINDOW,
+ _NET_WM_MOVERESIZE,
+
+ _NET_WM_NAME,
+ _NET_WM_ICON_NAME,
+ _NET_WM_ICON,
+
+ _NET_WM_PID,
+
+ _NET_WM_WINDOW_OPACITY,
+
+ _NET_WM_STATE,
+ _NET_WM_STATE_ABOVE,
+ _NET_WM_STATE_BELOW,
+ _NET_WM_STATE_FULLSCREEN,
+ _NET_WM_STATE_MAXIMIZED_HORZ,
+ _NET_WM_STATE_MAXIMIZED_VERT,
+ _NET_WM_STATE_MODAL,
+ _NET_WM_STATE_STAYS_ON_TOP,
+ _NET_WM_STATE_DEMANDS_ATTENTION,
+
+ _NET_WM_USER_TIME,
+ _NET_WM_USER_TIME_WINDOW,
+ _NET_WM_FULL_PLACEMENT,
+
+ _NET_WM_WINDOW_TYPE,
+ _NET_WM_WINDOW_TYPE_DESKTOP,
+ _NET_WM_WINDOW_TYPE_DOCK,
+ _NET_WM_WINDOW_TYPE_TOOLBAR,
+ _NET_WM_WINDOW_TYPE_MENU,
+ _NET_WM_WINDOW_TYPE_UTILITY,
+ _NET_WM_WINDOW_TYPE_SPLASH,
+ _NET_WM_WINDOW_TYPE_DIALOG,
+ _NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
+ _NET_WM_WINDOW_TYPE_POPUP_MENU,
+ _NET_WM_WINDOW_TYPE_TOOLTIP,
+ _NET_WM_WINDOW_TYPE_NOTIFICATION,
+ _NET_WM_WINDOW_TYPE_COMBO,
+ _NET_WM_WINDOW_TYPE_DND,
+ _NET_WM_WINDOW_TYPE_NORMAL,
+ _KDE_NET_WM_WINDOW_TYPE_OVERRIDE,
+
+ _KDE_NET_WM_FRAME_STRUT,
+
+ _NET_STARTUP_INFO,
+ _NET_STARTUP_INFO_BEGIN,
+
+ _NET_SUPPORTING_WM_CHECK,
+
+ _NET_WM_CM_S0,
+
+ _NET_SYSTEM_TRAY_VISUAL,
+
+ _NET_ACTIVE_WINDOW,
+
+ // Property formats
+ COMPOUND_TEXT,
+ TEXT,
+ UTF8_STRING,
+
+ // Xdnd
+ XdndEnter,
+ XdndPosition,
+ XdndStatus,
+ XdndLeave,
+ XdndDrop,
+ XdndFinished,
+ XdndTypelist,
+ XdndActionList,
+
+ XdndSelection,
+
+ XdndAware,
+ XdndProxy,
+
+ XdndActionCopy,
+ XdndActionLink,
+ XdndActionMove,
+ XdndActionPrivate,
+
+ // Motif DND
+ _MOTIF_DRAG_AND_DROP_MESSAGE,
+ _MOTIF_DRAG_INITIATOR_INFO,
+ _MOTIF_DRAG_RECEIVER_INFO,
+ _MOTIF_DRAG_WINDOW,
+ _MOTIF_DRAG_TARGETS,
+
+ XmTRANSFER_SUCCESS,
+ XmTRANSFER_FAILURE,
+
+ // Xkb
+ _XKB_RULES_NAMES,
+
+ // XEMBED
+ _XEMBED,
+ _XEMBED_INFO,
+
+ XWacomStylus,
+ XWacomCursor,
+ XWacomEraser,
+
+ XTabletStylus,
+ XTabletEraser,
+
+ NPredefinedAtoms,
+
+ _QT_SETTINGS_TIMESTAMP = NPredefinedAtoms,
+ NAtoms
+ };
+ Atom atoms[NAtoms];
+
+ bool isSupportedByWM(Atom atom);
+
+ bool compositingManagerRunning;
+
+#ifndef QT_NO_XCURSOR
+ PtrXcursorLibraryLoadCursor ptrXcursorLibraryLoadCursor;
+#endif // QT_NO_XCURSOR
+
+#ifndef QT_NO_XINERAMA
+ PtrXineramaQueryExtension ptrXineramaQueryExtension;
+ PtrXineramaIsActive ptrXineramaIsActive;
+ PtrXineramaQueryScreens ptrXineramaQueryScreens;
+#endif // QT_NO_XINERAMA
+
+#ifndef QT_NO_XRANDR
+ PtrXRRSelectInput ptrXRRSelectInput;
+ PtrXRRUpdateConfiguration ptrXRRUpdateConfiguration;
+ PtrXRRRootToScreen ptrXRRRootToScreen;
+ PtrXRRQueryExtension ptrXRRQueryExtension;
+ PtrXRRSizes ptrXRRSizes;
+#endif // QT_NO_XRANDR
+};
+
+extern QX11Data *qt_x11Data;
+#define ATOM(x) qt_x11Data->atoms[QX11Data::x]
+#define X11 qt_x11Data
+
+// rename a couple of X defines to get rid of name clashes
+// resolve the conflict between X11's FocusIn and QEvent::FocusIn
+enum {
+ XFocusOut = FocusOut,
+ XFocusIn = FocusIn,
+ XKeyPress = KeyPress,
+ XKeyRelease = KeyRelease,
+ XNone = None,
+ XRevertToParent = RevertToParent,
+ XGrayScale = GrayScale,
+ XCursorShape = CursorShape
+};
+#undef FocusOut
+#undef FocusIn
+#undef KeyPress
+#undef KeyRelease
+#undef None
+#undef RevertToParent
+#undef GrayScale
+#undef CursorShape
+
+#ifdef FontChange
+#undef FontChange
+#endif
+
+Q_DECLARE_TYPEINFO(XPoint, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(XRectangle, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(XChar2b, Q_PRIMITIVE_TYPE);
+#ifndef QT_NO_XRENDER
+Q_DECLARE_TYPEINFO(XGlyphElt32, Q_PRIMITIVE_TYPE);
+#endif
+
+
+QT_END_NAMESPACE
+
+#endif // QT_X11_P_H
diff --git a/src/widgets/platforms/x11/qwidget_x11.cpp b/src/widgets/platforms/x11/qwidget_x11.cpp
new file mode 100644
index 0000000000..5ece7d65c6
--- /dev/null
+++ b/src/widgets/platforms/x11/qwidget_x11.cpp
@@ -0,0 +1,3146 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qevent.h"
+#include "qwidget.h"
+#include "qdesktopwidget.h"
+#include "qapplication.h"
+#include "qapplication_p.h"
+#include "qnamespace.h"
+#include "qpainter.h"
+#include "qbitmap.h"
+#include "qlayout.h"
+#include "qtextcodec.h"
+#include "qelapsedtimer.h"
+#include "qcursor.h"
+#include "qstack.h"
+#include "qcolormap.h"
+#include "qdebug.h"
+#include "qmenu.h"
+#include "private/qmenu_p.h"
+#include "private/qbackingstore_p.h"
+#include "private/qwindowsurface_x11_p.h"
+
+//extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); //qapplication_x11.cpp
+
+#include <private/qpixmap_x11_p.h>
+#include <private/qpaintengine_x11_p.h>
+#include "qt_x11_p.h"
+#include "qx11info_x11.h"
+
+#include <stdlib.h>
+
+//#define ALIEN_DEBUG
+
+// defined in qapplication_x11.cpp
+//bool qt_wstate_iconified(WId);
+//void qt_updated_rootinfo();
+
+
+#if !defined(QT_NO_IM)
+#include "qinputcontext.h"
+#include "qinputcontextfactory.h"
+#endif
+
+#include "qwidget_p.h"
+
+#define XCOORD_MAX 16383
+#define WRECT_MAX 8191
+
+QT_BEGIN_NAMESPACE
+
+extern bool qt_nograb();
+
+QWidget *QWidgetPrivate::mouseGrabber = 0;
+QWidget *QWidgetPrivate::keyboardGrabber = 0;
+
+void qt_net_remove_user_time(QWidget *tlw);
+void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp);
+
+int qt_x11_create_desktop_on_screen = -1;
+
+extern void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp);
+
+// MWM support
+struct QtMWMHints {
+ ulong flags, functions, decorations;
+ long input_mode;
+ ulong status;
+};
+
+enum {
+ MWM_HINTS_FUNCTIONS = (1L << 0),
+
+ MWM_FUNC_ALL = (1L << 0),
+ MWM_FUNC_RESIZE = (1L << 1),
+ MWM_FUNC_MOVE = (1L << 2),
+ MWM_FUNC_MINIMIZE = (1L << 3),
+ MWM_FUNC_MAXIMIZE = (1L << 4),
+ MWM_FUNC_CLOSE = (1L << 5),
+
+ MWM_HINTS_DECORATIONS = (1L << 1),
+
+ MWM_DECOR_ALL = (1L << 0),
+ MWM_DECOR_BORDER = (1L << 1),
+ MWM_DECOR_RESIZEH = (1L << 2),
+ MWM_DECOR_TITLE = (1L << 3),
+ MWM_DECOR_MENU = (1L << 4),
+ MWM_DECOR_MINIMIZE = (1L << 5),
+ MWM_DECOR_MAXIMIZE = (1L << 6),
+
+ MWM_HINTS_INPUT_MODE = (1L << 2),
+
+ MWM_INPUT_MODELESS = 0L,
+ MWM_INPUT_PRIMARY_APPLICATION_MODAL = 1L,
+ MWM_INPUT_FULL_APPLICATION_MODAL = 3L
+};
+
+
+static QtMWMHints GetMWMHints(Display *display, Window window)
+{
+ QtMWMHints mwmhints;
+
+ Atom type;
+ int format;
+ ulong nitems, bytesLeft;
+ uchar *data = 0;
+ if ((XGetWindowProperty(display, window, ATOM(_MOTIF_WM_HINTS), 0, 5, false,
+ ATOM(_MOTIF_WM_HINTS), &type, &format, &nitems, &bytesLeft,
+ &data) == Success)
+ && (type == ATOM(_MOTIF_WM_HINTS)
+ && format == 32
+ && nitems >= 5)) {
+ mwmhints = *(reinterpret_cast<QtMWMHints *>(data));
+ } else {
+ mwmhints.flags = 0L;
+ mwmhints.functions = MWM_FUNC_ALL;
+ mwmhints.decorations = MWM_DECOR_ALL;
+ mwmhints.input_mode = 0L;
+ mwmhints.status = 0L;
+ }
+
+ if (data)
+ XFree(data);
+
+ return mwmhints;
+}
+
+static void SetMWMHints(Display *display, Window window, const QtMWMHints &mwmhints)
+{
+ if (mwmhints.flags != 0l) {
+ XChangeProperty(display, window, ATOM(_MOTIF_WM_HINTS), ATOM(_MOTIF_WM_HINTS), 32,
+ PropModeReplace, (unsigned char *) &mwmhints, 5);
+ } else {
+ XDeleteProperty(display, window, ATOM(_MOTIF_WM_HINTS));
+ }
+}
+
+// Returns true if we should set WM_TRANSIENT_FOR on \a w
+static inline bool isTransient(const QWidget *w)
+{
+ return ((w->windowType() == Qt::Dialog
+ || w->windowType() == Qt::Sheet
+ || w->windowType() == Qt::Tool
+ || w->windowType() == Qt::SplashScreen
+ || w->windowType() == Qt::ToolTip
+ || w->windowType() == Qt::Drawer
+ || w->windowType() == Qt::Popup)
+ && !w->testAttribute(Qt::WA_X11BypassTransientForHint));
+}
+
+static void do_size_hints(QWidget* widget, QWExtra *x);
+
+/*****************************************************************************
+ QWidget member functions
+ *****************************************************************************/
+
+const uint stdWidgetEventMask = // X event mask
+ (uint)(
+ KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ KeymapStateMask |
+ ButtonMotionMask | PointerMotionMask |
+ EnterWindowMask | LeaveWindowMask |
+ FocusChangeMask |
+ ExposureMask |
+ PropertyChangeMask |
+ StructureNotifyMask
+ );
+
+const uint stdDesktopEventMask = // X event mask
+ (uint)(
+ KeymapStateMask |
+ EnterWindowMask | LeaveWindowMask |
+ PropertyChangeMask
+ );
+
+
+/*
+ The qt_ functions below are implemented in qwidgetcreate_x11.cpp.
+*/
+
+Window qt_XCreateWindow(const QWidget *creator,
+ Display *display, Window parent,
+ int x, int y, uint w, uint h,
+ int borderwidth, int depth,
+ uint windowclass, Visual *visual,
+ ulong valuemask, XSetWindowAttributes *attributes);
+Window qt_XCreateSimpleWindow(const QWidget *creator,
+ Display *display, Window parent,
+ int x, int y, uint w, uint h, int borderwidth,
+ ulong border, ulong background);
+void qt_XDestroyWindow(const QWidget *destroyer,
+ Display *display, Window window);
+
+
+static void qt_insert_sip(QWidget* scrolled_widget, int dx, int dy)
+{
+ if (!scrolled_widget->isWindow() && !scrolled_widget->internalWinId())
+ return;
+ QX11Data::ScrollInProgress sip = { X11->sip_serial++, scrolled_widget, dx, dy };
+ X11->sip_list.append(sip);
+
+ XClientMessageEvent client_message;
+ client_message.type = ClientMessage;
+ client_message.window = scrolled_widget->internalWinId();
+ client_message.format = 32;
+ client_message.message_type = ATOM(_QT_SCROLL_DONE);
+ client_message.data.l[0] = sip.id;
+
+ XSendEvent(X11->display, scrolled_widget->internalWinId(), False, NoEventMask,
+ (XEvent*)&client_message);
+}
+
+static int qt_sip_count(QWidget* scrolled_widget)
+{
+ int sips=0;
+
+ for (int i = 0; i < X11->sip_list.size(); ++i) {
+ const QX11Data::ScrollInProgress &sip = X11->sip_list.at(i);
+ if (sip.scrolled_widget == scrolled_widget)
+ sips++;
+ }
+
+ return sips;
+}
+
+static void create_wm_client_leader()
+{
+ if (X11->wm_client_leader) return;
+
+ X11->wm_client_leader =
+ XCreateSimpleWindow(X11->display,
+ QX11Info::appRootWindow(),
+ 0, 0, 1, 1, 0, 0, 0);
+
+ // set client leader property to itself
+ XChangeProperty(X11->display,
+ X11->wm_client_leader, ATOM(WM_CLIENT_LEADER),
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)&X11->wm_client_leader, 1);
+
+#ifndef QT_NO_SESSIONMANAGER
+ // If we are session managed, inform the window manager about it
+ QByteArray session = qApp->sessionId().toLatin1();
+ if (!session.isEmpty()) {
+ XChangeProperty(X11->display,
+ X11->wm_client_leader, ATOM(SM_CLIENT_ID),
+ XA_STRING, 8, PropModeReplace,
+ (unsigned char *)session.data(), session.size());
+ }
+#endif
+}
+
+/*!
+ \internal
+ Update the X11 cursor of the widget w.
+ \a force is true if this function is called from dispatchEnterLeave, it means that the
+ mouse is actually directly under this widget.
+ */
+void qt_x11_enforce_cursor(QWidget * w, bool force)
+{
+ if (!w->testAttribute(Qt::WA_WState_Created))
+ return;
+
+ static QPointer<QWidget> lastUnderMouse = 0;
+ if (force) {
+ lastUnderMouse = w;
+ } else if (lastUnderMouse && lastUnderMouse->effectiveWinId() == w->effectiveWinId()) {
+ w = lastUnderMouse;
+ } else if (!w->internalWinId()) {
+ return; //the mouse is not under this widget, and it's not native, so don't change it
+ }
+
+ while (!w->internalWinId() && w->parentWidget() && !w->isWindow() && !w->testAttribute(Qt::WA_SetCursor))
+ w = w->parentWidget();
+
+ QWidget *nativeParent = w;
+ if (!w->internalWinId())
+ nativeParent = w->nativeParentWidget();
+ // This does the same as effectiveWinId(), but since it is possible
+ // to not have a native parent widget due to a special hack in
+ // qwidget for reparenting widgets to a different X11 screen,
+ // added additional check to make sure native parent widget exists.
+ if (!nativeParent || !nativeParent->internalWinId())
+ return;
+ WId winid = nativeParent->internalWinId();
+
+ if (w->isWindow() || w->testAttribute(Qt::WA_SetCursor)) {
+#ifndef QT_NO_CURSOR
+ QCursor *oc = QApplication::overrideCursor();
+ if (oc) {
+ XDefineCursor(X11->display, winid, oc->handle());
+ } else if (w->isEnabled()) {
+ XDefineCursor(X11->display, winid, w->cursor().handle());
+ } else {
+ // enforce the windows behavior of clearing the cursor on
+ // disabled widgets
+ XDefineCursor(X11->display, winid, XNone);
+ }
+#endif
+ } else {
+ XDefineCursor(X11->display, winid, XNone);
+ }
+}
+
+Q_GUI_EXPORT void qt_x11_enforce_cursor(QWidget * w)
+{
+ qt_x11_enforce_cursor(w, false);
+}
+
+void qt_x11_wait_for_window_manager(QWidget *w, bool sendPostedEvents)
+{
+ if (!w || (!w->isWindow() && !w->internalWinId()))
+ return;
+ QApplication::flush();
+ XEvent ev;
+ QElapsedTimer t;
+ t.start();
+ static const int maximumWaitTime = 2000;
+ if (!w->testAttribute(Qt::WA_WState_Created))
+ return;
+
+ WId winid = w->internalWinId();
+
+ // first deliver events that are already in the local queue
+ if (sendPostedEvents)
+ QApplication::sendPostedEvents();
+
+ // the normal sequence is:
+ // ... ConfigureNotify ... ReparentNotify ... MapNotify ... Expose
+ // with X11BypassWindowManagerHint:
+ // ConfigureNotify ... MapNotify ... Expose
+
+ enum State {
+ Initial, Mapped
+ } state = Initial;
+
+ do {
+ if (XEventsQueued(X11->display, QueuedAlready)) {
+ XNextEvent(X11->display, &ev);
+ qApp->x11ProcessEvent(&ev);
+
+ switch (state) {
+ case Initial:
+ if (ev.type == MapNotify && ev.xany.window == winid)
+ state = Mapped;
+ break;
+ case Mapped:
+ if (ev.type == Expose && ev.xany.window == winid)
+ return;
+ break;
+ }
+ } else {
+ if (!XEventsQueued(X11->display, QueuedAfterFlush))
+ qApp->syncX(); // non-busy wait
+ }
+ if (t.elapsed() > maximumWaitTime)
+ return;
+ } while(1);
+}
+
+Q_GUI_EXPORT void qt_x11_wait_for_window_manager(QWidget *w)
+{
+ qt_x11_wait_for_window_manager(w, true);
+}
+
+void qt_change_net_wm_state(const QWidget* w, bool set, Atom one, Atom two = 0)
+{
+ if (!w->isVisible()) // not managed by the window manager
+ return;
+
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = ATOM(_NET_WM_STATE);
+ e.xclient.display = X11->display;
+ e.xclient.window = w->internalWinId();
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = set ? 1 : 0;
+ e.xclient.data.l[1] = one;
+ e.xclient.data.l[2] = two;
+ e.xclient.data.l[3] = 0;
+ e.xclient.data.l[4] = 0;
+ XSendEvent(X11->display, RootWindow(X11->display, w->x11Info().screen()),
+ false, (SubstructureNotifyMask | SubstructureRedirectMask), &e);
+}
+
+struct QX11WindowAttributes {
+ const XWindowAttributes *att;
+};
+
+void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const XWindowAttributes &a)
+{
+ QX11WindowAttributes att;
+ att.att = &a;
+ qt_x11_getX11InfoForWindow(xinfo,att);
+}
+
+
+static QVector<Atom> getNetWmState(QWidget *w)
+{
+ QVector<Atom> returnValue;
+
+ // Don't read anything, just get the size of the property data
+ Atom actualType;
+ int actualFormat;
+ ulong propertyLength;
+ ulong bytesLeft;
+ uchar *propertyData = 0;
+ if (XGetWindowProperty(X11->display, w->internalWinId(), ATOM(_NET_WM_STATE), 0, 0,
+ False, XA_ATOM, &actualType, &actualFormat,
+ &propertyLength, &bytesLeft, &propertyData) == Success
+ && actualType == XA_ATOM && actualFormat == 32) {
+ returnValue.resize(bytesLeft / 4);
+ XFree((char*) propertyData);
+ propertyData = 0;
+
+ // fetch all data
+ if (XGetWindowProperty(X11->display, w->internalWinId(), ATOM(_NET_WM_STATE), 0,
+ returnValue.size(), False, XA_ATOM, &actualType, &actualFormat,
+ &propertyLength, &bytesLeft, &propertyData) != Success) {
+ returnValue.clear();
+ } else if (propertyLength != (ulong)returnValue.size()) {
+ returnValue.resize(propertyLength);
+ }
+
+ // put it into netWmState
+ if (!returnValue.isEmpty()) {
+ memcpy(returnValue.data(), propertyData, returnValue.size() * sizeof(Atom));
+ }
+ if (propertyData)
+ XFree((char*) propertyData);
+ }
+
+ return returnValue;
+}
+
+void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
+{
+ Q_Q(QWidget);
+ Qt::WindowType type = q->windowType();
+ Qt::WindowFlags &flags = data.window_flags;
+ QWidget *parentWidget = q->parentWidget();
+
+ if (type == Qt::ToolTip)
+ flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint;
+ if (type == Qt::Popup)
+ flags |= Qt::X11BypassWindowManagerHint;
+
+ bool topLevel = (flags & Qt::Window);
+ bool popup = (type == Qt::Popup);
+ bool dialog = (type == Qt::Dialog
+ || type == Qt::Sheet);
+ bool desktop = (type == Qt::Desktop);
+ bool tool = (type == Qt::Tool || type == Qt::SplashScreen
+ || type == Qt::ToolTip || type == Qt::Drawer);
+
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::create_sys START:" << q << "topLevel?" << topLevel << "WId:"
+ << window << "initializeWindow:" << initializeWindow << "destroyOldWindow" << destroyOldWindow;
+#endif
+ if (topLevel) {
+ if (parentWidget) { // if our parent stays on top, so must we
+ QWidget *ptl = parentWidget->window();
+ if(ptl && (ptl->windowFlags() & Qt::WindowStaysOnTopHint))
+ flags |= Qt::WindowStaysOnTopHint;
+ }
+
+ if (type == Qt::SplashScreen) {
+ if (X11->isSupportedByWM(ATOM(_NET_WM_WINDOW_TYPE_SPLASH))) {
+ flags &= ~Qt::X11BypassWindowManagerHint;
+ } else {
+ flags |= Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint;
+ }
+ }
+ // All these buttons depend on the system menu, so we enable it
+ if (flags & (Qt::WindowMinimizeButtonHint
+ | Qt::WindowMaximizeButtonHint
+ | Qt::WindowContextHelpButtonHint))
+ flags |= Qt::WindowSystemMenuHint;
+ }
+
+
+ Window parentw, destroyw = 0;
+ WId id = 0;
+
+ // always initialize
+ if (!window)
+ initializeWindow = true;
+
+ QX11Info *parentXinfo = parentWidget ? &parentWidget->d_func()->xinfo : 0;
+
+ if (desktop &&
+ qt_x11_create_desktop_on_screen >= 0 &&
+ qt_x11_create_desktop_on_screen != xinfo.screen()) {
+ // desktop on a certain screen other than the default requested
+ QX11InfoData *xd = &X11->screens[qt_x11_create_desktop_on_screen];
+ xinfo.setX11Data(xd);
+ } else if (parentXinfo && (parentXinfo->screen() != xinfo.screen()
+ || (parentXinfo->visual() != xinfo.visual()
+ && !q->inherits("QGLWidget"))))
+ {
+ // QGLWidgets have to be excluded here as they have a
+ // specially crafted QX11Info structure which can't be swapped
+ // out with the parent widgets QX11Info. The parent visual,
+ // for instance, might not even be GL capable.
+ xinfo = *parentXinfo;
+ }
+
+ //get display, screen number, root window and desktop geometry for
+ //the current screen
+ Display *dpy = X11->display;
+ int scr = xinfo.screen();
+ Window root_win = RootWindow(dpy, scr);
+ int sw = DisplayWidth(dpy,scr);
+ int sh = DisplayHeight(dpy,scr);
+
+ if (desktop) { // desktop widget
+ dialog = popup = false; // force these flags off
+ data.crect.setRect(0, 0, sw, sh);
+ } else if (topLevel && !q->testAttribute(Qt::WA_Resized)) {
+ QDesktopWidget *desktopWidget = qApp->desktop();
+ if (desktopWidget->isVirtualDesktop()) {
+ QRect r = desktopWidget->screenGeometry();
+ sw = r.width();
+ sh = r.height();
+ }
+
+ int width = sw / 2;
+ int height = 4 * sh / 10;
+ if (extra) {
+ width = qMax(qMin(width, extra->maxw), extra->minw);
+ height = qMax(qMin(height, extra->maxh), extra->minh);
+ }
+ data.crect.setSize(QSize(width, height));
+ }
+
+ parentw = topLevel ? root_win : parentWidget->effectiveWinId();
+
+ XSetWindowAttributes wsa;
+
+ if (window) { // override the old window
+ if (destroyOldWindow) {
+ if (topLevel)
+ X11->dndEnable(q, false);
+ destroyw = data.winid;
+ }
+ id = window;
+ setWinId(window);
+ XWindowAttributes a;
+ XGetWindowAttributes(dpy, window, &a);
+ data.crect.setRect(a.x, a.y, a.width, a.height);
+
+ if (a.map_state == IsUnmapped)
+ q->setAttribute(Qt::WA_WState_Visible, false);
+ else
+ q->setAttribute(Qt::WA_WState_Visible);
+
+ qt_x11_getX11InfoForWindow(&xinfo,a);
+
+ } else if (desktop) { // desktop widget
+#ifdef QWIDGET_EXTRA_DEBUG
+ qDebug() << "create desktop";
+#endif
+ id = (WId)parentw; // id = root window
+// QWidget *otherDesktop = find(id); // is there another desktop?
+// if (otherDesktop && otherDesktop->testWFlags(Qt::WPaintDesktop)) {
+// otherDesktop->d->setWinId(0); // remove id from widget mapper
+// d->setWinId(id); // make sure otherDesktop is
+// otherDesktop->d->setWinId(id); // found first
+// } else {
+ setWinId(id);
+// }
+ } else if (topLevel || q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) {
+#ifdef QWIDGET_EXTRA_DEBUG
+ static int topLevels = 0;
+ static int children = 0;
+ if (parentw == root_win)
+ qDebug() << "create toplevel" << ++topLevels;
+ else
+ qDebug() << "create child" << ++children;
+#endif
+ QRect safeRect = data.crect; //##### must handle huge sizes as well.... i.e. wrect
+ if (safeRect.width() < 1|| safeRect.height() < 1) {
+ if (topLevel) {
+ // top-levels must be at least 1x1
+ safeRect.setSize(safeRect.size().expandedTo(QSize(1, 1)));
+ } else {
+ // create it way off screen, and rely on
+ // setWSGeometry() to do the right thing with it later
+ safeRect = QRect(-1000,-1000,1,1);
+ }
+ }
+#ifndef QT_NO_XRENDER
+ int screen = xinfo.screen();
+ if (topLevel && X11->use_xrender
+ && xinfo.depth() != 32 && X11->argbVisuals[screen]
+ && q->testAttribute(Qt::WA_TranslucentBackground))
+ {
+ QX11InfoData *xd = xinfo.getX11Data(true);
+
+ xd->screen = screen;
+ xd->visual = X11->argbVisuals[screen];
+ xd->colormap = X11->argbColormaps[screen];
+ xd->depth = 32;
+ xd->defaultVisual = false;
+ xd->defaultColormap = false;
+ xd->cells = xd->visual->map_entries;
+ xinfo.setX11Data(xd);
+ }
+#endif
+ if (xinfo.defaultVisual() && xinfo.defaultColormap()) {
+ id = (WId)qt_XCreateSimpleWindow(q, dpy, parentw,
+ safeRect.left(), safeRect.top(),
+ safeRect.width(), safeRect.height(),
+ 0,
+ BlackPixel(dpy, xinfo.screen()),
+ WhitePixel(dpy, xinfo.screen()));
+ } else {
+ wsa.background_pixel = WhitePixel(dpy, xinfo.screen());
+ wsa.border_pixel = BlackPixel(dpy, xinfo.screen());
+ wsa.colormap = xinfo.colormap();
+ id = (WId)qt_XCreateWindow(q, dpy, parentw,
+ safeRect.left(), safeRect.top(),
+ safeRect.width(), safeRect.height(),
+ 0, xinfo.depth(), InputOutput,
+ (Visual *) xinfo.visual(),
+ CWBackPixel|CWBorderPixel|CWColormap,
+ &wsa);
+ }
+
+ setWinId(id); // set widget id/handle + hd
+ }
+
+#ifndef QT_NO_XRENDER
+ if (picture) {
+ XRenderFreePicture(X11->display, picture);
+ picture = 0;
+ }
+
+ if (X11->use_xrender && !desktop && q->internalWinId()) {
+ XRenderPictFormat *format = XRenderFindVisualFormat(dpy, (Visual *) xinfo.visual());
+ if (format)
+ picture = XRenderCreatePicture(dpy, id, format, 0, 0);
+ }
+#endif // QT_NO_XRENDER
+
+ QtMWMHints mwmhints;
+ mwmhints.flags = 0L;
+ mwmhints.functions = 0L;
+ mwmhints.decorations = 0;
+ mwmhints.input_mode = 0L;
+ mwmhints.status = 0L;
+
+ if (topLevel) {
+ ulong wsa_mask = 0;
+ if (type != Qt::SplashScreen) { // && customize) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+
+ bool customize = flags & Qt::CustomizeWindowHint;
+ if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) {
+ mwmhints.decorations |= MWM_DECOR_BORDER;
+ mwmhints.decorations |= MWM_DECOR_RESIZEH;
+
+ if (flags & Qt::WindowTitleHint)
+ mwmhints.decorations |= MWM_DECOR_TITLE;
+
+ if (flags & Qt::WindowSystemMenuHint)
+ mwmhints.decorations |= MWM_DECOR_MENU;
+
+ if (flags & Qt::WindowMinimizeButtonHint) {
+ mwmhints.decorations |= MWM_DECOR_MINIMIZE;
+ mwmhints.functions |= MWM_FUNC_MINIMIZE;
+ }
+
+ if (flags & Qt::WindowMaximizeButtonHint) {
+ mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
+ mwmhints.functions |= MWM_FUNC_MAXIMIZE;
+ }
+
+ if (flags & Qt::WindowCloseButtonHint)
+ mwmhints.functions |= MWM_FUNC_CLOSE;
+ }
+ } else {
+ // if type == Qt::SplashScreen
+ mwmhints.decorations = MWM_DECOR_ALL;
+ }
+
+ if (tool) {
+ wsa.save_under = True;
+ wsa_mask |= CWSaveUnder;
+ }
+
+ if (flags & Qt::X11BypassWindowManagerHint) {
+ wsa.override_redirect = True;
+ wsa_mask |= CWOverrideRedirect;
+ }
+
+ if (wsa_mask && initializeWindow) {
+ Q_ASSERT(id);
+ XChangeWindowAttributes(dpy, id, wsa_mask, &wsa);
+ }
+
+ if (mwmhints.functions != 0) {
+ mwmhints.flags |= MWM_HINTS_FUNCTIONS;
+ mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
+ } else {
+ mwmhints.functions = MWM_FUNC_ALL;
+ }
+
+ if (!(flags & Qt::FramelessWindowHint)
+ && flags & Qt::CustomizeWindowHint
+ && flags & Qt::WindowTitleHint
+ && !(flags &
+ (Qt::WindowMinimizeButtonHint
+ | Qt::WindowMaximizeButtonHint
+ | Qt::WindowCloseButtonHint))) {
+ // a special case - only the titlebar without any button
+ mwmhints.flags = MWM_HINTS_FUNCTIONS;
+ mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
+ mwmhints.decorations = 0;
+ }
+ }
+
+ if (!initializeWindow) {
+ // do no initialization
+ } else if (popup) { // popup widget
+ // set EWMH window types
+ setNetWmWindowTypes();
+
+ wsa.override_redirect = True;
+ wsa.save_under = True;
+ Q_ASSERT(id);
+ XChangeWindowAttributes(dpy, id, CWOverrideRedirect | CWSaveUnder,
+ &wsa);
+ } else if (topLevel && !desktop) { // top-level widget
+ if (!X11->wm_client_leader)
+ create_wm_client_leader();
+
+ // note: WM_TRANSIENT_FOR is set in QWidgetPrivate::show_sys()
+
+ XSizeHints size_hints;
+ size_hints.flags = USSize | PSize | PWinGravity;
+ size_hints.x = data.crect.left();
+ size_hints.y = data.crect.top();
+ size_hints.width = data.crect.width();
+ size_hints.height = data.crect.height();
+ size_hints.win_gravity =
+ QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
+
+ XWMHints wm_hints; // window manager hints
+ memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
+ wm_hints.flags = InputHint | StateHint | WindowGroupHint;
+ wm_hints.input = q->testAttribute(Qt::WA_X11DoNotAcceptFocus) ? False : True;
+ wm_hints.initial_state = NormalState;
+ wm_hints.window_group = X11->wm_client_leader;
+
+ XClassHint class_hint;
+ QByteArray appName = qAppName().toLatin1();
+ class_hint.res_name = appName.data(); // application name
+ class_hint.res_class = const_cast<char *>(QX11Info::appClass()); // application class
+
+ XSetWMProperties(dpy, id, 0, 0,
+ qApp->d_func()->argv, qApp->d_func()->argc,
+ &size_hints, &wm_hints, &class_hint);
+
+ XResizeWindow(dpy, id,
+ qBound(1, data.crect.width(), XCOORD_MAX),
+ qBound(1, data.crect.height(), XCOORD_MAX));
+ XStoreName(dpy, id, appName.data());
+ Atom protocols[5];
+ int n = 0;
+ protocols[n++] = ATOM(WM_DELETE_WINDOW); // support del window protocol
+ protocols[n++] = ATOM(WM_TAKE_FOCUS); // support take focus window protocol
+ protocols[n++] = ATOM(_NET_WM_PING); // support _NET_WM_PING protocol
+#ifndef QT_NO_XSYNC
+ protocols[n++] = ATOM(_NET_WM_SYNC_REQUEST); // support _NET_WM_SYNC_REQUEST protocol
+#endif // QT_NO_XSYNC
+ if (flags & Qt::WindowContextHelpButtonHint)
+ protocols[n++] = ATOM(_NET_WM_CONTEXT_HELP);
+ XSetWMProtocols(dpy, id, protocols, n);
+
+ // set mwm hints
+ SetMWMHints(dpy, id, mwmhints);
+
+ // set EWMH window types
+ setNetWmWindowTypes();
+
+ // set _NET_WM_PID
+ long curr_pid = getpid();
+ XChangeProperty(dpy, id, ATOM(_NET_WM_PID), XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) &curr_pid, 1);
+
+ // when we create a toplevel widget, the frame strut should be dirty
+ data.fstrut_dirty = 1;
+
+ // declare the widget's window role
+ if (QTLWExtra *topData = maybeTopData()) {
+ if (!topData->role.isEmpty()) {
+ QByteArray windowRole = topData->role.toUtf8();
+ XChangeProperty(dpy, id,
+ ATOM(WM_WINDOW_ROLE), XA_STRING, 8, PropModeReplace,
+ (unsigned char *)windowRole.constData(), windowRole.length());
+ }
+ }
+
+ // set client leader property
+ XChangeProperty(dpy, id, ATOM(WM_CLIENT_LEADER),
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)&X11->wm_client_leader, 1);
+ } else {
+ // non-toplevel widgets don't have a frame, so no need to
+ // update the strut
+ data.fstrut_dirty = 0;
+ }
+
+ if (initializeWindow && q->internalWinId()) {
+ // don't erase when resizing
+ wsa.bit_gravity = QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
+ Q_ASSERT(id);
+ XChangeWindowAttributes(dpy, id, CWBitGravity, &wsa);
+ }
+
+ // set X11 event mask
+ if (desktop) {
+// QWidget* main_desktop = find(id);
+// if (main_desktop->testWFlags(Qt::WPaintDesktop))
+// XSelectInput(dpy, id, stdDesktopEventMask | ExposureMask);
+// else
+ XSelectInput(dpy, id, stdDesktopEventMask);
+ } else if (q->internalWinId()) {
+ XSelectInput(dpy, id, stdWidgetEventMask);
+#if !defined (QT_NO_TABLET)
+ QTabletDeviceDataList *tablet_list = qt_tablet_devices();
+ if (X11->ptrXSelectExtensionEvent) {
+ for (int i = 0; i < tablet_list->size(); ++i) {
+ QTabletDeviceData tablet = tablet_list->at(i);
+ X11->ptrXSelectExtensionEvent(dpy, id, reinterpret_cast<XEventClass*>(tablet.eventList),
+ tablet.eventCount);
+ }
+ }
+#endif
+ }
+
+ if (desktop) {
+ q->setAttribute(Qt::WA_WState_Visible);
+ } else if (topLevel) { // set X cursor
+ if (initializeWindow) {
+ qt_x11_enforce_cursor(q);
+
+ if (QTLWExtra *topData = maybeTopData())
+ if (!topData->caption.isEmpty())
+ setWindowTitle_helper(topData->caption);
+
+ //always enable dnd: it's not worth the effort to maintain the state
+ // NOTE: this always creates topData()
+ X11->dndEnable(q, true);
+
+ if (maybeTopData() && maybeTopData()->opacity != 255)
+ q->setWindowOpacity(maybeTopData()->opacity/255.);
+
+ }
+ } else if (q->internalWinId()) {
+ qt_x11_enforce_cursor(q);
+ if (QWidget *p = q->parentWidget()) // reset the cursor on the native parent
+ qt_x11_enforce_cursor(p);
+ }
+
+ if (extra && !extra->mask.isEmpty() && q->internalWinId())
+ XShapeCombineRegion(X11->display, q->internalWinId(), ShapeBounding, 0, 0,
+ extra->mask.handle(), ShapeSet);
+
+ if (q->hasFocus() && q->testAttribute(Qt::WA_InputMethodEnabled)) {
+ QInputContext *inputContext = q->inputContext();
+ if (inputContext)
+ inputContext->setFocusWidget(q);
+ }
+
+ if (destroyw) {
+ qt_XDestroyWindow(q, dpy, destroyw);
+ if (QTLWExtra *topData = maybeTopData()) {
+#ifndef QT_NO_XSYNC
+ if (topData->syncUpdateCounter)
+ XSyncDestroyCounter(dpy, topData->syncUpdateCounter);
+#endif
+ // we destroyed our old window - reset the top-level state
+ createTLSysExtra();
+ }
+ }
+
+ // newly created windows are positioned at the window system's
+ // (0,0) position. If the parent uses wrect mapping to expand the
+ // coordinate system, we must also adjust this widget's window
+ // system position
+ if (!topLevel && !parentWidget->data->wrect.topLeft().isNull())
+ setWSGeometry();
+ else if (topLevel && (data.crect.width() == 0 || data.crect.height() == 0))
+ q->setAttribute(Qt::WA_OutsideWSRange, true);
+
+ if (!topLevel && q->testAttribute(Qt::WA_NativeWindow) && q->testAttribute(Qt::WA_Mapped)) {
+ Q_ASSERT(q->internalWinId());
+ XMapWindow(X11->display, q->internalWinId());
+ // Ensure that mapped alien widgets are flushed immediately when re-created as native widgets.
+ if (QWindowSurface *surface = q->windowSurface())
+ surface->flush(q, q->rect(), q->mapTo(surface->window(), QPoint()));
+ }
+
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::create_sys END:" << q;
+#endif
+}
+
+static void qt_x11_recreateWidget(QWidget *widget)
+{
+ if (widget->inherits("QGLWidget")) {
+ // We send QGLWidgets a ParentChange event which causes them to
+ // recreate their GL context, which in turn causes them to choose
+ // their visual again. Now that WA_TranslucentBackground is set,
+ // QGLContext::chooseVisual will select an ARGB visual.
+ QEvent e(QEvent::ParentChange);
+ QApplication::sendEvent(widget, &e);
+ } else {
+ // For regular widgets, reparent them with their parent which
+ // also triggers a recreation of the native window
+ QPoint pos = widget->pos();
+ bool visible = widget->isVisible();
+ if (visible)
+ widget->hide();
+
+ widget->setParent(widget->parentWidget(), widget->windowFlags());
+ widget->move(pos);
+ if (visible)
+ widget->show();
+ }
+}
+
+static void qt_x11_recreateNativeWidgetsRecursive(QWidget *widget)
+{
+ if (widget->internalWinId())
+ qt_x11_recreateWidget(widget);
+
+ const QObjectList &children = widget->children();
+ for (int i = 0; i < children.size(); ++i) {
+ QWidget *child = qobject_cast<QWidget*>(children.at(i));
+ if (child)
+ qt_x11_recreateNativeWidgetsRecursive(child);
+ }
+}
+
+void QWidgetPrivate::x11UpdateIsOpaque()
+{
+#ifndef QT_NO_XRENDER
+ Q_Q(QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
+ return;
+
+ bool topLevel = (data.window_flags & Qt::Window);
+ int screen = xinfo.screen();
+ if (topLevel && X11->use_xrender
+ && X11->argbVisuals[screen] && xinfo.depth() != 32)
+ {
+ qt_x11_recreateNativeWidgetsRecursive(q);
+ }
+#endif
+}
+
+/*
+ Returns true if the background is inherited; otherwise returns
+ false.
+
+ Mainly used in the paintOnScreen case.
+*/
+bool QWidgetPrivate::isBackgroundInherited() const
+{
+ Q_Q(const QWidget);
+
+ // windows do not inherit their background
+ if (q->isWindow() || q->windowType() == Qt::SubWindow)
+ return false;
+
+ if (q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_OpaquePaintEvent))
+ return false;
+
+ const QPalette &pal = q->palette();
+ QPalette::ColorRole bg = q->backgroundRole();
+ QBrush brush = pal.brush(bg);
+
+ // non opaque brushes leaves us no choice, we must inherit
+ if (!q->autoFillBackground() || !brush.isOpaque())
+ return true;
+
+ if (brush.style() == Qt::SolidPattern) {
+ // the background is just a solid color. If there is no
+ // propagated contents, then we claim as performance
+ // optimization that it was not inheritet. This is the normal
+ // case in standard Windows or Motif style.
+ const QWidget *w = q->parentWidget();
+ if (!w->d_func()->isBackgroundInherited())
+ return false;
+ }
+
+ return true;
+}
+
+void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
+{
+ Q_D(QWidget);
+ d->aboutToDestroy();
+ if (!isWindow() && parentWidget())
+ parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
+ d->deactivateWidgetCleanup();
+ if (testAttribute(Qt::WA_WState_Created)) {
+ setAttribute(Qt::WA_WState_Created, false);
+ QObjectList childList = children();
+ for (int i = 0; i < childList.size(); ++i) { // destroy all widget children
+ register QObject *obj = childList.at(i);
+ if (obj->isWidgetType())
+ static_cast<QWidget*>(obj)->destroy(destroySubWindows,
+ destroySubWindows);
+ }
+ if (QWidgetPrivate::mouseGrabber == this)
+ releaseMouse();
+ if (QWidgetPrivate::keyboardGrabber == this)
+ releaseKeyboard();
+ if (isWindow())
+ X11->deferred_map.removeAll(this);
+ if (isModal()) {
+ // just be sure we leave modal
+ QApplicationPrivate::leaveModal(this);
+ }
+ else if ((windowType() == Qt::Popup))
+ qApp->d_func()->closePopup(this);
+
+#ifndef QT_NO_XRENDER
+ if (d->picture) {
+ if (destroyWindow)
+ XRenderFreePicture(X11->display, d->picture);
+ d->picture = 0;
+ }
+#endif // QT_NO_XRENDER
+
+ // delete the _NET_WM_USER_TIME_WINDOW
+ qt_net_remove_user_time(this);
+
+ if ((windowType() == Qt::Desktop)) {
+ if (acceptDrops())
+ X11->dndEnable(this, false);
+ } else {
+ if (isWindow())
+ X11->dndEnable(this, false);
+ if (destroyWindow)
+ qt_XDestroyWindow(this, X11->display, data->winid);
+ }
+ QT_TRY {
+ d->setWinId(0);
+ } QT_CATCH (const std::bad_alloc &) {
+ // swallow - destructors must not throw
+ }
+
+ extern void qPRCleanup(QWidget *widget); // from qapplication_x11.cpp
+ if (testAttribute(Qt::WA_WState_Reparented))
+ qPRCleanup(this);
+
+ if(d->ic) {
+ delete d->ic;
+ } else {
+ // release previous focus information participating with
+ // preedit preservation of qic
+ QInputContext *qic = QApplicationPrivate::inputContext;
+ if (qic)
+ qic->widgetDestroyed(this);
+ }
+ }
+}
+
+void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
+{
+ Q_Q(QWidget);
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::setParent_sys START" << q << "parent:" << parent;
+#endif
+ QX11Info old_xinfo = xinfo;
+ if (parent && parent->windowType() == Qt::Desktop) {
+ // make sure the widget is created on the same screen as the
+ // programmer specified desktop widget
+ xinfo = parent->d_func()->xinfo;
+ parent = 0;
+ }
+
+ QTLWExtra *topData = maybeTopData();
+ bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
+ if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
+ extern void qPRCreate(const QWidget *, Window);
+#ifndef QT_NO_CURSOR
+ QCursor oldcurs;
+#endif
+
+ // dnd unregister (we will register again below)
+ if (q->testAttribute(Qt::WA_DropSiteRegistered))
+ q->setAttribute(Qt::WA_DropSiteRegistered, false);
+
+ // if we are a top then remove our dnd prop for now
+ // it will get rest later
+ if (q->isWindow() && wasCreated)
+ X11->dndEnable(q, false);
+
+ if (topData)
+ qt_net_remove_user_time(q);
+
+// QWidget *oldparent = q->parentWidget();
+ WId old_winid = wasCreated ? data.winid : 0;
+ if ((q->windowType() == Qt::Desktop))
+ old_winid = 0;
+ setWinId(0);
+
+#ifndef QT_NO_XRENDER
+ if (picture) {
+ XRenderFreePicture(X11->display, picture);
+ picture = 0;
+ }
+#endif
+
+ // hide and reparent our own window away. Otherwise we might get
+ // destroyed when emitting the child remove event below. See QWorkspace.
+ if (wasCreated && old_winid) {
+ XUnmapWindow(X11->display, old_winid);
+ if (!old_xinfo.screen() != xinfo.screen())
+ XReparentWindow(X11->display, old_winid, RootWindow(X11->display, xinfo.screen()), 0, 0);
+ }
+ if (topData) {
+ topData->parentWinId = 0;
+ // zero the frame strut and mark it dirty
+ topData->frameStrut.setCoords(0, 0, 0, 0);
+
+ // reparenting from top-level, make sure show() works again
+ topData->waitingForMapNotify = 0;
+ topData->validWMState = 0;
+ }
+ data.fstrut_dirty = (!parent || (f & Qt::Window)); // toplevels get a dirty framestrut
+
+ QObjectPrivate::setParent_helper(parent);
+ bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
+
+ data.window_flags = f;
+ q->setAttribute(Qt::WA_WState_Created, false);
+ q->setAttribute(Qt::WA_WState_Visible, false);
+ q->setAttribute(Qt::WA_WState_Hidden, false);
+ adjustFlags(data.window_flags, q);
+ // keep compatibility with previous versions, we need to preserve the created state
+ // (but we recreate the winId for the widget being reparented, again for compatibility)
+ if (wasCreated)
+ createWinId();
+ if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
+ q->setAttribute(Qt::WA_WState_Hidden);
+ q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
+
+ if (wasCreated) {
+ QObjectList chlist = q->children();
+ for (int i = 0; i < chlist.size(); ++i) { // reparent children
+ QObject *obj = chlist.at(i);
+ if (obj->isWidgetType()) {
+ QWidget *w = (QWidget *)obj;
+ if (!w->testAttribute(Qt::WA_WState_Created))
+ continue;
+ if (xinfo.screen() != w->d_func()->xinfo.screen()) {
+ // ### force setParent() to not shortcut out (because
+ // ### we're setting the parent to the current parent)
+ // ### setParent will add child back to the list
+ // ### of children so we need to make sure the
+ // ### widget won't be added twice.
+ w->d_func()->parent = 0;
+ this->children.removeOne(w);
+ w->setParent(q);
+ } else if (!w->isWindow()) {
+ w->d_func()->invalidateBuffer(w->rect());
+ if (w->internalWinId()) {
+ if (w->testAttribute(Qt::WA_NativeWindow)) {
+ QWidget *nativeParentWidget = w->nativeParentWidget();
+ // Qt::WA_NativeWindow ensures that we always have a nativeParentWidget
+ Q_ASSERT(nativeParentWidget != 0);
+ QPoint p = w->mapTo(nativeParentWidget, QPoint());
+ XReparentWindow(X11->display,
+ w->internalWinId(),
+ nativeParentWidget->internalWinId(),
+ p.x(), p.y());
+ } else {
+ w->d_func()->setParent_sys(q, w->data->window_flags);
+ }
+ }
+ } else if (isTransient(w)) {
+ /*
+ when reparenting toplevel windows with toplevel-transient children,
+ we need to make sure that the window manager gets the updated
+ WM_TRANSIENT_FOR information... unfortunately, some window managers
+ don't handle changing WM_TRANSIENT_FOR before the toplevel window is
+ visible, so we unmap and remap all toplevel-transient children *after*
+ the toplevel parent has been mapped. thankfully, this is easy in Qt :)
+
+ note that the WM_TRANSIENT_FOR hint is actually updated in
+ QWidgetPrivate::show_sys()
+ */
+ if (w->internalWinId())
+ XUnmapWindow(X11->display, w->internalWinId());
+ QApplication::postEvent(w, new QEvent(QEvent::ShowWindowRequest));
+ }
+ }
+ }
+ qPRCreate(q, old_winid);
+ updateSystemBackground();
+
+ if (old_winid) {
+ Window *cmwret;
+ int count;
+ if (XGetWMColormapWindows(X11->display, old_winid, &cmwret, &count)) {
+ Window *cmw;
+ int cmw_size = sizeof(Window)*count;
+ cmw = new Window[count];
+ memcpy((char *)cmw, (char *)cmwret, cmw_size);
+ XFree((char *)cmwret);
+ int i;
+ for (i=0; i<count; i++) {
+ if (cmw[i] == old_winid) {
+ cmw[i] = q->internalWinId();
+ break;
+ }
+ }
+ int top_count;
+ if (XGetWMColormapWindows(X11->display, q->window()->internalWinId(),
+ &cmwret, &top_count))
+ {
+ Window *merged_cmw = new Window[count + top_count];
+ memcpy((char *)merged_cmw, (char *)cmw, cmw_size);
+ memcpy((char *)merged_cmw + cmw_size, (char *)cmwret, sizeof(Window)*top_count);
+ delete [] cmw;
+ XFree((char *)cmwret);
+ cmw = merged_cmw;
+ count += top_count;
+ }
+
+ XSetWMColormapWindows(X11->display, q->window()->internalWinId(), cmw, count);
+ delete [] cmw;
+ }
+
+ qt_XDestroyWindow(q, X11->display, old_winid);
+ }
+ }
+
+ // check if we need to register our dropsite
+ if (q->testAttribute(Qt::WA_AcceptDrops)
+ || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))) {
+ q->setAttribute(Qt::WA_DropSiteRegistered, true);
+ }
+#if !defined(QT_NO_IM)
+ ic = 0;
+#endif
+ invalidateBuffer(q->rect());
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::setParent_sys END" << q;
+#endif
+}
+
+QPoint QWidgetPrivate::mapToGlobal(const QPoint &pos) const
+{
+ Q_Q(const QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created) || !q->internalWinId()) {
+ QPoint p = pos + q->data->crect.topLeft();
+ //cannot trust that !isWindow() implies parentWidget() before create
+ return (q->isWindow() || !q->parentWidget()) ? p : q->parentWidget()->d_func()->mapToGlobal(p);
+ }
+ int x, y;
+ Window child;
+ QPoint p = mapToWS(pos);
+ XTranslateCoordinates(X11->display, q->internalWinId(),
+ QApplication::desktop()->screen(xinfo.screen())->internalWinId(),
+ p.x(), p.y(), &x, &y, &child);
+ return QPoint(x, y);
+}
+
+QPoint QWidgetPrivate::mapFromGlobal(const QPoint &pos) const
+{
+ Q_Q(const QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created) || !q->internalWinId()) {
+ //cannot trust that !isWindow() implies parentWidget() before create
+ QPoint p = (q->isWindow() || !q->parentWidget()) ? pos : q->parentWidget()->d_func()->mapFromGlobal(pos);
+ return p - q->data->crect.topLeft();
+ }
+ int x, y;
+ Window child;
+ XTranslateCoordinates(X11->display,
+ QApplication::desktop()->screen(xinfo.screen())->internalWinId(),
+ q->internalWinId(), pos.x(), pos.y(), &x, &y, &child);
+ return mapFromWS(QPoint(x, y));
+}
+
+QPoint QWidget::mapToGlobal(const QPoint &pos) const
+{
+ Q_D(const QWidget);
+ QPoint offset = data->crect.topLeft();
+ const QWidget *w = this;
+ const QWidget *p = w->parentWidget();
+ while (!w->isWindow() && p) {
+ w = p;
+ p = p->parentWidget();
+ offset += w->data->crect.topLeft();
+ }
+
+ const QWidgetPrivate *wd = w->d_func();
+ QTLWExtra *tlw = wd->topData();
+ if (!tlw->embedded)
+ return pos + offset;
+
+ return d->mapToGlobal(pos);
+}
+
+QPoint QWidget::mapFromGlobal(const QPoint &pos) const
+{
+ Q_D(const QWidget);
+ QPoint offset = data->crect.topLeft();
+ const QWidget *w = this;
+ const QWidget *p = w->parentWidget();
+ while (!w->isWindow() && p) {
+ w = p;
+ p = p->parentWidget();
+ offset += w->data->crect.topLeft();
+ }
+
+ const QWidgetPrivate *wd = w->d_func();
+ QTLWExtra *tlw = wd->topData();
+ if (!tlw->embedded)
+ return pos - offset;
+
+ return d->mapFromGlobal(pos);
+}
+
+void QWidgetPrivate::updateSystemBackground()
+{
+ Q_Q(QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created) || !q->internalWinId())
+ return;
+ QBrush brush = q->palette().brush(QPalette::Active, q->backgroundRole());
+ Qt::WindowType type = q->windowType();
+ if (brush.style() == Qt::NoBrush
+ || q->testAttribute(Qt::WA_NoSystemBackground)
+ || q->testAttribute(Qt::WA_UpdatesDisabled)
+ || type == Qt::Popup || type == Qt::ToolTip) {
+ if (QX11Info::isCompositingManagerRunning()
+ && q->testAttribute(Qt::WA_TranslucentBackground)
+ && !(q->parent()))
+ XSetWindowBackground(X11->display, q->internalWinId(),
+ QColormap::instance(xinfo.screen()).pixel(Qt::transparent));
+ else
+ XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), XNone);
+ }
+ else if (brush.style() == Qt::SolidPattern && brush.isOpaque())
+ XSetWindowBackground(X11->display, q->internalWinId(),
+ QColormap::instance(xinfo.screen()).pixel(brush.color()));
+ else if (isBackgroundInherited())
+ XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), ParentRelative);
+ else if (brush.style() == Qt::TexturePattern) {
+ extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap); // qpixmap_x11.cpp
+ XSetWindowBackgroundPixmap(X11->display, q->internalWinId(),
+ static_cast<QX11PixmapData*>(qt_toX11Pixmap(brush.texture()).data.data())->x11ConvertToDefaultDepth());
+ } else
+ XSetWindowBackground(X11->display, q->internalWinId(),
+ QColormap::instance(xinfo.screen()).pixel(brush.color()));
+}
+
+#ifndef QT_NO_CURSOR
+void QWidgetPrivate::setCursor_sys(const QCursor &)
+{
+ Q_Q(QWidget);
+ qt_x11_enforce_cursor(q);
+ XFlush(X11->display);
+}
+
+void QWidgetPrivate::unsetCursor_sys()
+{
+ Q_Q(QWidget);
+ qt_x11_enforce_cursor(q);
+ XFlush(X11->display);
+}
+#endif
+
+static XTextProperty*
+qstring_to_xtp(const QString& s)
+{
+ static XTextProperty tp = { 0, 0, 0, 0 };
+ static bool free_prop = true; // we can't free tp.value in case it references
+ // the data of the static QCString below.
+ if (tp.value) {
+ if (free_prop)
+ XFree(tp.value);
+ tp.value = 0;
+ free_prop = true;
+ }
+
+ static const QTextCodec* mapper = QTextCodec::codecForLocale();
+ int errCode = 0;
+ if (mapper) {
+ QByteArray mapped = mapper->fromUnicode(s);
+ char* tl[2];
+ tl[0] = mapped.data();
+ tl[1] = 0;
+ errCode = XmbTextListToTextProperty(X11->display, tl, 1, XStdICCTextStyle, &tp);
+#if defined(QT_DEBUG)
+ if (errCode < 0)
+ qDebug("qstring_to_xtp result code %d", errCode);
+#endif
+ }
+ if (!mapper || errCode < 0) {
+ static QByteArray qcs;
+ qcs = s.toAscii();
+ tp.value = (uchar*)qcs.data();
+ tp.encoding = XA_STRING;
+ tp.format = 8;
+ tp.nitems = qcs.length();
+ free_prop = false;
+ }
+
+ // ### If we knew WM could understand unicode, we could use
+ // ### a much simpler, cheaper encoding...
+ /*
+ tp.value = (XChar2b*)s.unicode();
+ tp.encoding = XA_UNICODE; // wish
+ tp.format = 16;
+ tp.nitems = s.length();
+ */
+
+ return &tp;
+}
+
+void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (!q->internalWinId())
+ return;
+ XSetWMName(X11->display, q->internalWinId(), qstring_to_xtp(caption));
+
+ QByteArray net_wm_name = caption.toUtf8();
+ XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_NAME), ATOM(UTF8_STRING), 8,
+ PropModeReplace, (unsigned char *)net_wm_name.data(), net_wm_name.size());
+}
+
+void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
+{
+ Q_Q(QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created))
+ return;
+ QTLWExtra *topData = this->topData();
+ if (topData->iconPixmap && !forceReset)
+ // already been set
+ return;
+
+ // preparing images to set the _NET_WM_ICON property
+ QIcon icon = q->windowIcon();
+ QVector<long> icon_data;
+ Qt::HANDLE pixmap_handle = 0;
+ if (!icon.isNull()) {
+ QList<QSize> availableSizes = icon.availableSizes();
+ if(availableSizes.isEmpty()) {
+ // try to use default sizes since the icon can be a scalable image like svg.
+ availableSizes.push_back(QSize(16,16));
+ availableSizes.push_back(QSize(32,32));
+ availableSizes.push_back(QSize(64,64));
+ availableSizes.push_back(QSize(128,128));
+ }
+ for(int i = 0; i < availableSizes.size(); ++i) {
+ QSize size = availableSizes.at(i);
+ QPixmap pixmap = icon.pixmap(size);
+ if (!pixmap.isNull()) {
+ QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ int pos = icon_data.size();
+ icon_data.resize(pos + 2 + image.width()*image.height());
+ icon_data[pos++] = image.width();
+ icon_data[pos++] = image.height();
+ if (sizeof(long) == sizeof(quint32)) {
+ memcpy(icon_data.data() + pos, image.scanLine(0), image.byteCount());
+ } else {
+ for (int y = 0; y < image.height(); ++y) {
+ uint *scanLine = reinterpret_cast<uint *>(image.scanLine(y));
+ for (int x = 0; x < image.width(); ++x)
+ icon_data[pos + y*image.width() + x] = scanLine[x];
+ }
+ }
+ }
+ }
+ if (!icon_data.isEmpty()) {
+ extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap);
+ /*
+ if the app is running on an unknown desktop, or it is not
+ using the default visual, convert the icon to 1bpp as stated
+ in the ICCCM section 4.1.2.4; otherwise, create the icon pixmap
+ in the default depth (even though this violates the ICCCM)
+ */
+ if (X11->desktopEnvironment == DE_UNKNOWN
+ || !QX11Info::appDefaultVisual(xinfo.screen())
+ || !QX11Info::appDefaultColormap(xinfo.screen())) {
+ // unknown DE or non-default visual/colormap, use 1bpp bitmap
+ if (!forceReset || !topData->iconPixmap)
+ topData->iconPixmap = new QPixmap(qt_toX11Pixmap(QBitmap(icon.pixmap(QSize(64,64)))));
+ pixmap_handle = topData->iconPixmap->handle();
+ } else {
+ // default depth, use a normal pixmap (even though this
+ // violates the ICCCM), since this works on all DEs known to Qt
+ if (!forceReset || !topData->iconPixmap)
+ topData->iconPixmap = new QPixmap(qt_toX11Pixmap(icon.pixmap(QSize(64,64))));
+ pixmap_handle = static_cast<QX11PixmapData*>(topData->iconPixmap->data.data())->x11ConvertToDefaultDepth();
+ }
+ }
+ }
+
+ if (!q->internalWinId())
+ return;
+
+ if (!icon_data.isEmpty()) {
+ XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON), XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) icon_data.data(),
+ icon_data.size());
+ } else {
+ XDeleteProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON));
+ }
+
+ XWMHints *h = XGetWMHints(X11->display, q->internalWinId());
+ XWMHints wm_hints;
+ if (!h) {
+ memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
+ h = &wm_hints;
+ }
+
+ if (pixmap_handle) {
+ h->icon_pixmap = pixmap_handle;
+ h->flags |= IconPixmapHint;
+ } else {
+ h->icon_pixmap = 0;
+ h->flags &= ~(IconPixmapHint | IconMaskHint);
+ }
+
+ XSetWMHints(X11->display, q->internalWinId(), h);
+ if (h != &wm_hints)
+ XFree((char *)h);
+}
+
+void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
+{
+ Q_Q(QWidget);
+ if (!q->internalWinId())
+ return;
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ XSetWMIconName(X11->display, q->internalWinId(), qstring_to_xtp(iconText));
+
+ QByteArray icon_name = iconText.toUtf8();
+ XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON_NAME), ATOM(UTF8_STRING), 8,
+ PropModeReplace, (unsigned char *) icon_name.constData(), icon_name.size());
+}
+
+
+void QWidget::grabMouse()
+{
+ if (isVisible() && !qt_nograb()) {
+ if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
+ QWidgetPrivate::mouseGrabber->releaseMouse();
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+#ifndef QT_NO_DEBUG
+ int status =
+#endif
+ XGrabPointer(X11->display, effectiveWinId(), False,
+ (uint)(ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | EnterWindowMask |
+ LeaveWindowMask),
+ GrabModeAsync, GrabModeAsync,
+ XNone, XNone, X11->time);
+#ifndef QT_NO_DEBUG
+ if (status) {
+ const char *s =
+ status == GrabNotViewable ? "\"GrabNotViewable\"" :
+ status == AlreadyGrabbed ? "\"AlreadyGrabbed\"" :
+ status == GrabFrozen ? "\"GrabFrozen\"" :
+ status == GrabInvalidTime ? "\"GrabInvalidTime\"" :
+ "<?>";
+ qWarning("QWidget::grabMouse: Failed with %s", s);
+ }
+#endif
+ QWidgetPrivate::mouseGrabber = this;
+ }
+}
+
+
+#ifndef QT_NO_CURSOR
+void QWidget::grabMouse(const QCursor &cursor)
+{
+ if (!qt_nograb()) {
+ if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
+ QWidgetPrivate::mouseGrabber->releaseMouse();
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+#ifndef QT_NO_DEBUG
+ int status =
+#endif
+ XGrabPointer(X11->display, effectiveWinId(), False,
+ (uint)(ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | EnterWindowMask | LeaveWindowMask),
+ GrabModeAsync, GrabModeAsync,
+ XNone, cursor.handle(), X11->time);
+#ifndef QT_NO_DEBUG
+ if (status) {
+ const char *s =
+ status == GrabNotViewable ? "\"GrabNotViewable\"" :
+ status == AlreadyGrabbed ? "\"AlreadyGrabbed\"" :
+ status == GrabFrozen ? "\"GrabFrozen\"" :
+ status == GrabInvalidTime ? "\"GrabInvalidTime\"" :
+ "<?>";
+ qWarning("QWidget::grabMouse: Failed with %s", s);
+ }
+#endif
+ QWidgetPrivate::mouseGrabber = this;
+ }
+}
+#endif
+
+
+void QWidget::releaseMouse()
+{
+ if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) {
+ XUngrabPointer(X11->display, X11->time);
+ XFlush(X11->display);
+ QWidgetPrivate::mouseGrabber = 0;
+ }
+}
+
+
+void QWidget::grabKeyboard()
+{
+ if (!qt_nograb()) {
+ if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this)
+ QWidgetPrivate::keyboardGrabber->releaseKeyboard();
+ XGrabKeyboard(X11->display, effectiveWinId(), False, GrabModeAsync, GrabModeAsync,
+ X11->time);
+ QWidgetPrivate::keyboardGrabber = this;
+ }
+}
+
+
+void QWidget::releaseKeyboard()
+{
+ if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) {
+ XUngrabKeyboard(X11->display, X11->time);
+ QWidgetPrivate::keyboardGrabber = 0;
+ }
+}
+
+
+QWidget *QWidget::mouseGrabber()
+{
+ return QWidgetPrivate::mouseGrabber;
+}
+
+
+QWidget *QWidget::keyboardGrabber()
+{
+ return QWidgetPrivate::keyboardGrabber;
+}
+
+void QWidget::activateWindow()
+{
+ QWidget *tlw = window();
+ if (tlw->isVisible() && !tlw->d_func()->topData()->embedded && !X11->deferred_map.contains(tlw)) {
+ if (X11->userTime == 0)
+ X11->userTime = X11->time;
+ qt_net_update_user_time(tlw, X11->userTime);
+
+ if (X11->isSupportedByWM(ATOM(_NET_ACTIVE_WINDOW))
+ && !(tlw->windowFlags() & Qt::X11BypassWindowManagerHint)) {
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = ATOM(_NET_ACTIVE_WINDOW);
+ e.xclient.display = X11->display;
+ e.xclient.window = tlw->internalWinId();
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = 1; // 1 == application
+ e.xclient.data.l[1] = X11->userTime;
+ if (QWidget *aw = QApplication::activeWindow())
+ e.xclient.data.l[2] = aw->internalWinId();
+ else
+ e.xclient.data.l[2] = XNone;
+ e.xclient.data.l[3] = 0;
+ e.xclient.data.l[4] = 0;
+ XSendEvent(X11->display, RootWindow(X11->display, tlw->x11Info().screen()),
+ false, SubstructureNotifyMask | SubstructureRedirectMask, &e);
+ } else {
+ if (!qt_widget_private(tlw)->topData()->waitingForMapNotify)
+ XSetInputFocus(X11->display, tlw->internalWinId(), XRevertToParent, X11->time);
+ }
+ }
+}
+
+void QWidget::setWindowState(Qt::WindowStates newstate)
+{
+ Q_D(QWidget);
+ bool needShow = false;
+ Qt::WindowStates oldstate = windowState();
+ if (oldstate == newstate)
+ return;
+ if (isWindow()) {
+ // Ensure the initial size is valid, since we store it as normalGeometry below.
+ if (!testAttribute(Qt::WA_Resized) && !isVisible())
+ adjustSize();
+
+ QTLWExtra *top = d->topData();
+
+ if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) {
+ if (X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ))
+ && X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT))) {
+ if ((newstate & Qt::WindowMaximized) && !(oldstate & Qt::WindowFullScreen))
+ top->normalGeometry = geometry();
+ qt_change_net_wm_state(this, (newstate & Qt::WindowMaximized),
+ ATOM(_NET_WM_STATE_MAXIMIZED_HORZ),
+ ATOM(_NET_WM_STATE_MAXIMIZED_VERT));
+ } else if (! (newstate & Qt::WindowFullScreen)) {
+ if (newstate & Qt::WindowMaximized) {
+ // save original geometry
+ const QRect normalGeometry = geometry();
+
+ if (isVisible()) {
+ data->fstrut_dirty = true;
+ const QRect maxRect = QApplication::desktop()->availableGeometry(this);
+ const QRect r = top->normalGeometry;
+ const QRect fs = d->frameStrut();
+ setGeometry(maxRect.x() + fs.left(),
+ maxRect.y() + fs.top(),
+ maxRect.width() - fs.left() - fs.right(),
+ maxRect.height() - fs.top() - fs.bottom());
+ top->normalGeometry = r;
+ }
+
+ if (top->normalGeometry.width() < 0)
+ top->normalGeometry = normalGeometry;
+ } else {
+ // restore original geometry
+ setGeometry(top->normalGeometry);
+ }
+ }
+ }
+
+ if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) {
+ if (X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN))) {
+ if (newstate & Qt::WindowFullScreen) {
+ top->normalGeometry = geometry();
+ top->fullScreenOffset = d->frameStrut().topLeft();
+ }
+ qt_change_net_wm_state(this, (newstate & Qt::WindowFullScreen),
+ ATOM(_NET_WM_STATE_FULLSCREEN));
+ } else {
+ needShow = isVisible();
+
+ if (newstate & Qt::WindowFullScreen) {
+ data->fstrut_dirty = true;
+ const QRect normalGeometry = geometry();
+ const QPoint fullScreenOffset = d->frameStrut().topLeft();
+
+ top->savedFlags = windowFlags();
+ setParent(0, Qt::Window | Qt::FramelessWindowHint);
+ const QRect r = top->normalGeometry;
+ setGeometry(qApp->desktop()->screenGeometry(this));
+ top->normalGeometry = r;
+
+ if (top->normalGeometry.width() < 0) {
+ top->normalGeometry = normalGeometry;
+ top->fullScreenOffset = fullScreenOffset;
+ }
+ } else {
+ setParent(0, top->savedFlags);
+
+ if (newstate & Qt::WindowMaximized) {
+ // from fullscreen to maximized
+ data->fstrut_dirty = true;
+ const QRect maxRect = QApplication::desktop()->availableGeometry(this);
+ const QRect r = top->normalGeometry;
+ const QRect fs = d->frameStrut();
+ setGeometry(maxRect.x() + fs.left(),
+ maxRect.y() + fs.top(),
+ maxRect.width() - fs.left() - fs.right(),
+ maxRect.height() - fs.top() - fs.bottom());
+ top->normalGeometry = r;
+ } else {
+ // restore original geometry
+ setGeometry(top->normalGeometry.adjusted(-top->fullScreenOffset.x(),
+ -top->fullScreenOffset.y(),
+ -top->fullScreenOffset.x(),
+ -top->fullScreenOffset.y()));
+ }
+ }
+ }
+ }
+
+ createWinId();
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) {
+ if (isVisible()) {
+ if (newstate & Qt::WindowMinimized) {
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = ATOM(WM_CHANGE_STATE);
+ e.xclient.display = X11->display;
+ e.xclient.window = data->winid;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = IconicState;
+ e.xclient.data.l[1] = 0;
+ e.xclient.data.l[2] = 0;
+ e.xclient.data.l[3] = 0;
+ e.xclient.data.l[4] = 0;
+ XSendEvent(X11->display,
+ RootWindow(X11->display,d->xinfo.screen()),
+ False, (SubstructureNotifyMask|SubstructureRedirectMask), &e);
+ } else {
+ setAttribute(Qt::WA_Mapped);
+ XMapWindow(X11->display, effectiveWinId());
+ }
+ }
+
+ needShow = false;
+ }
+ }
+
+ data->window_state = newstate;
+
+ if (needShow)
+ show();
+
+ if (newstate & Qt::WindowActive)
+ activateWindow();
+
+ QWindowStateChangeEvent e(oldstate);
+ QApplication::sendEvent(this, &e);
+}
+
+/*!
+ \internal
+ Platform-specific part of QWidget::show().
+*/
+
+void QWidgetPrivate::show_sys()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+
+ if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
+ invalidateBuffer(q->rect());
+ q->setAttribute(Qt::WA_Mapped);
+ if (QTLWExtra *tlwExtra = maybeTopData())
+ tlwExtra->waitingForMapNotify = 0;
+ return;
+ }
+
+ if (q->isWindow()) {
+ XWMHints *h = XGetWMHints(X11->display, q->internalWinId());
+ XWMHints wm_hints;
+ bool got_hints = h != 0;
+ if (!got_hints) {
+ memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
+ h = &wm_hints;
+ }
+ h->initial_state = q->isMinimized() ? IconicState : NormalState;
+ h->flags |= StateHint;
+ XSetWMHints(X11->display, q->internalWinId(), h);
+ if (got_hints)
+ XFree((char *)h);
+
+ // update WM_NORMAL_HINTS
+ do_size_hints(q, extra);
+
+ // udpate WM_TRANSIENT_FOR
+ if (isTransient(q)) {
+ QWidget *p = q->parentWidget();
+
+#ifndef QT_NO_MENU
+ // hackish ... try to find the main window related to this QMenu
+ if (qobject_cast<QMenu *>(q)) {
+ p = static_cast<QMenuPrivate*>(this)->causedPopup.widget;
+ if (!p)
+ p = q->parentWidget();
+ if (!p)
+ p = QApplication::widgetAt(q->pos());
+ if (!p)
+ p = qApp->activeWindow();
+ }
+#endif
+ if (p)
+ p = p->window();
+ if (p) {
+ // transient for window
+ XSetTransientForHint(X11->display, q->internalWinId(), p->internalWinId());
+ } else {
+ // transient for group
+ XSetTransientForHint(X11->display, q->internalWinId(), X11->wm_client_leader);
+ }
+ }
+
+ // update _MOTIF_WM_HINTS
+ QtMWMHints mwmhints = GetMWMHints(X11->display, q->internalWinId());
+
+ if (data.window_modality != Qt::NonModal) {
+ switch (data.window_modality) {
+ case Qt::WindowModal:
+ mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL;
+ break;
+ case Qt::ApplicationModal:
+ default:
+ mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL;
+ break;
+ }
+ mwmhints.flags |= MWM_HINTS_INPUT_MODE;
+ } else {
+ mwmhints.input_mode = MWM_INPUT_MODELESS;
+ mwmhints.flags &= ~MWM_HINTS_INPUT_MODE;
+ }
+
+ if (q->minimumSize() == q->maximumSize()) {
+ // fixed size, remove the resize handle (since mwm/dtwm
+ // isn't smart enough to do it itself)
+ mwmhints.flags |= MWM_HINTS_FUNCTIONS;
+ if (mwmhints.functions == MWM_FUNC_ALL) {
+ mwmhints.functions = MWM_FUNC_MOVE;
+ } else {
+ mwmhints.functions &= ~MWM_FUNC_RESIZE;
+ }
+
+ if (mwmhints.decorations == MWM_DECOR_ALL) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = (MWM_DECOR_BORDER
+ | MWM_DECOR_TITLE
+ | MWM_DECOR_MENU);
+ } else {
+ mwmhints.decorations &= ~MWM_DECOR_RESIZEH;
+ }
+
+ if (q->windowFlags() & Qt::WindowMinimizeButtonHint) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+ mwmhints.decorations |= MWM_DECOR_MINIMIZE;
+ mwmhints.functions |= MWM_FUNC_MINIMIZE;
+ }
+ if (q->windowFlags() & Qt::WindowMaximizeButtonHint) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+ mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
+ mwmhints.functions |= MWM_FUNC_MAXIMIZE;
+ }
+ if (q->windowFlags() & Qt::WindowCloseButtonHint)
+ mwmhints.functions |= MWM_FUNC_CLOSE;
+ }
+
+ SetMWMHints(X11->display, q->internalWinId(), mwmhints);
+
+ // update _NET_WM_STATE
+ QVector<Atom> netWmState = getNetWmState(q);
+
+ Qt::WindowFlags flags = q->windowFlags();
+ if (flags & Qt::WindowStaysOnTopHint) {
+ if (flags & Qt::WindowStaysOnBottomHint)
+ qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
+ if (!netWmState.contains(ATOM(_NET_WM_STATE_ABOVE)))
+ netWmState.append(ATOM(_NET_WM_STATE_ABOVE));
+ if (!netWmState.contains(ATOM(_NET_WM_STATE_STAYS_ON_TOP)))
+ netWmState.append(ATOM(_NET_WM_STATE_STAYS_ON_TOP));
+ } else if (flags & Qt::WindowStaysOnBottomHint) {
+ if (!netWmState.contains(ATOM(_NET_WM_STATE_BELOW)))
+ netWmState.append(ATOM(_NET_WM_STATE_BELOW));
+ }
+ if (q->isFullScreen()) {
+ if (!netWmState.contains(ATOM(_NET_WM_STATE_FULLSCREEN)))
+ netWmState.append(ATOM(_NET_WM_STATE_FULLSCREEN));
+ }
+ if (q->isMaximized()) {
+ if (!netWmState.contains(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ)))
+ netWmState.append(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ));
+ if (!netWmState.contains(ATOM(_NET_WM_STATE_MAXIMIZED_VERT)))
+ netWmState.append(ATOM(_NET_WM_STATE_MAXIMIZED_VERT));
+ }
+ if (data.window_modality != Qt::NonModal) {
+ if (!netWmState.contains(ATOM(_NET_WM_STATE_MODAL)))
+ netWmState.append(ATOM(_NET_WM_STATE_MODAL));
+ }
+
+ if (!netWmState.isEmpty()) {
+ XChangeProperty(X11->display, q->internalWinId(),
+ ATOM(_NET_WM_STATE), XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) netWmState.data(), netWmState.size());
+ } else {
+ XDeleteProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_STATE));
+ }
+
+ // set _NET_WM_USER_TIME
+ Time userTime = X11->userTime;
+ bool setUserTime = false;
+ if (q->testAttribute(Qt::WA_ShowWithoutActivating)) {
+ userTime = 0;
+ setUserTime = true;
+ } else if (userTime != CurrentTime) {
+ setUserTime = true;
+ }
+ if (setUserTime)
+ qt_net_update_user_time(q, userTime);
+
+#ifndef QT_NO_XSYNC
+ if (!topData()->syncUpdateCounter) {
+ XSyncValue value;
+ XSyncIntToValue(&value, 0);
+ topData()->syncUpdateCounter = XSyncCreateCounter(X11->display, value);
+
+ XChangeProperty(X11->display, q->internalWinId(),
+ ATOM(_NET_WM_SYNC_REQUEST_COUNTER),
+ XA_CARDINAL,
+ 32, PropModeReplace,
+ (uchar *) &topData()->syncUpdateCounter, 1);
+
+ topData()->newCounterValueHi = 0;
+ topData()->newCounterValueLo = 0;
+ }
+#endif
+
+ if (!topData()->embedded
+ && (topData()->validWMState || topData()->waitingForMapNotify)
+ && !q->isMinimized()) {
+ X11->deferred_map.append(q);
+ return;
+ }
+
+ if (q->isMaximized() && !q->isFullScreen()
+ && !(X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ))
+ && X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT)))) {
+ XMapWindow(X11->display, q->internalWinId());
+ data.fstrut_dirty = true;
+ qt_x11_wait_for_window_manager(q);
+
+ // if the wm was not smart enough to adjust our size, do that manually
+ QRect maxRect = QApplication::desktop()->availableGeometry(q);
+
+ QTLWExtra *top = topData();
+ QRect normalRect = top->normalGeometry;
+ const QRect fs = frameStrut();
+
+ q->setGeometry(maxRect.x() + fs.left(),
+ maxRect.y() + fs.top(),
+ maxRect.width() - fs.left() - fs.right(),
+ maxRect.height() - fs.top() - fs.bottom());
+
+ // restore the original normalGeometry
+ top->normalGeometry = normalRect;
+ // internalSetGeometry() clears the maximized flag... make sure we set it back
+ data.window_state = data.window_state | Qt::WindowMaximized;
+ q->setAttribute(Qt::WA_Mapped);
+ return;
+ }
+
+ if (q->isFullScreen() && !X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN))) {
+ XMapWindow(X11->display, q->internalWinId());
+ qt_x11_wait_for_window_manager(q);
+ q->setAttribute(Qt::WA_Mapped);
+ return;
+ }
+ }
+
+ invalidateBuffer(q->rect());
+
+ if (q->testAttribute(Qt::WA_OutsideWSRange))
+ return;
+ q->setAttribute(Qt::WA_Mapped);
+ if (q->isWindow())
+ topData()->waitingForMapNotify = 1;
+
+ if (!q->isWindow()
+ && (!q->autoFillBackground()
+ || q->palette().brush(q->backgroundRole()).style() == Qt::LinearGradientPattern)) {
+ if (q->internalWinId()) {
+ XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), XNone);
+ XMapWindow(X11->display, q->internalWinId());
+ updateSystemBackground();
+ }
+ return;
+ }
+
+ if (q->internalWinId())
+ XMapWindow(X11->display, q->internalWinId());
+
+ // Freedesktop.org Startup Notification
+ if (X11->startupId && q->isWindow()) {
+ QByteArray message("remove: ID=");
+ message.append(X11->startupId);
+ sendStartupMessage(message.constData());
+ X11->startupId = 0;
+ }
+}
+
+/*!
+ \internal
+ Platform-specific part of QWidget::show().
+*/
+
+void QWidgetPrivate::sendStartupMessage(const char *message) const
+{
+ Q_Q(const QWidget);
+
+ if (!message)
+ return;
+
+ XEvent xevent;
+ xevent.xclient.type = ClientMessage;
+ xevent.xclient.message_type = ATOM(_NET_STARTUP_INFO_BEGIN);
+ xevent.xclient.display = X11->display;
+ xevent.xclient.window = q->internalWinId();
+ xevent.xclient.format = 8;
+
+ Window rootWindow = RootWindow(X11->display, DefaultScreen(X11->display));
+ uint sent = 0;
+ uint length = strlen(message) + 1;
+ do {
+ if (sent == 20)
+ xevent.xclient.message_type = ATOM(_NET_STARTUP_INFO);
+
+ for (uint i = 0; i < 20 && i + sent <= length; i++)
+ xevent.xclient.data.b[i] = message[i + sent++];
+
+ XSendEvent(X11->display, rootWindow, false, PropertyChangeMask, &xevent);
+ } while (sent <= length);
+}
+
+void QWidgetPrivate::setNetWmWindowTypes()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+
+ if (!q->isWindow()) {
+ if (q->internalWinId())
+ XDeleteProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_WINDOW_TYPE));
+ return;
+ }
+
+ QVector<long> windowTypes;
+
+ // manual selection 1 (these are never set by Qt and take precedence)
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDesktop))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DESKTOP));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDock))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DOCK));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeNotification))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_NOTIFICATION));
+
+ // manual selection 2 (Qt uses these during auto selection);
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeUtility))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_UTILITY));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeSplash))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_SPLASH));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDialog))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DIALOG));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeToolTip))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_TOOLTIP));
+
+ // manual selection 3 (these can be set by Qt, but don't have a
+ // corresponding Qt::WindowType). note that order of the *MENU
+ // atoms is important
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeMenu))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_MENU));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypePopupMenu))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_POPUP_MENU));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeToolBar))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_TOOLBAR));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeCombo))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_COMBO));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDND))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DND));
+
+ // automatic selection
+ switch (q->windowType()) {
+ case Qt::Dialog:
+ case Qt::Sheet:
+ // dialog netwm type
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DIALOG));
+ break;
+
+ case Qt::Tool:
+ case Qt::Drawer:
+ // utility netwm type
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_UTILITY));
+ break;
+
+ case Qt::ToolTip:
+ // tooltip netwm type
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_TOOLTIP));
+ break;
+
+ case Qt::SplashScreen:
+ // splash netwm type
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_SPLASH));
+ break;
+
+ default:
+ break;
+ }
+
+ if (q->windowFlags() & Qt::FramelessWindowHint) {
+ // override netwm type - quick and easy for KDE noborder
+ windowTypes.append(ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
+ }
+
+ // normal netwm type - default
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_NORMAL));
+
+ if (!windowTypes.isEmpty()) {
+ XChangeProperty(X11->display, q->winId(), ATOM(_NET_WM_WINDOW_TYPE), XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) windowTypes.constData(),
+ windowTypes.count());
+ } else {
+ XDeleteProperty(X11->display, q->winId(), ATOM(_NET_WM_WINDOW_TYPE));
+ }
+}
+
+/*!
+ \internal
+ Platform-specific part of QWidget::hide().
+*/
+
+void QWidgetPrivate::hide_sys()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ deactivateWidgetCleanup();
+ if (q->isWindow()) {
+ X11->deferred_map.removeAll(q);
+ if (q->internalWinId()) // in nsplugin, may be 0
+ XWithdrawWindow(X11->display, q->internalWinId(), xinfo.screen());
+ XFlush(X11->display);
+ } else {
+ invalidateBuffer(q->rect());
+ if (q->internalWinId()) // in nsplugin, may be 0
+ XUnmapWindow(X11->display, q->internalWinId());
+ }
+ q->setAttribute(Qt::WA_Mapped, false);
+}
+
+void QWidgetPrivate::setFocus_sys()
+{
+
+}
+
+
+void QWidgetPrivate::raise_sys()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (q->internalWinId())
+ XRaiseWindow(X11->display, q->internalWinId());
+}
+
+void QWidgetPrivate::lower_sys()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (q->internalWinId())
+ XLowerWindow(X11->display, q->internalWinId());
+ if(!q->isWindow())
+ invalidateBuffer(q->rect());
+}
+
+void QWidgetPrivate::stackUnder_sys(QWidget* w)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (q->internalWinId() && w->internalWinId()) {
+ Window stack[2];
+ stack[0] = w->internalWinId();;
+ stack[1] = q->internalWinId();
+ XRestackWindows(X11->display, stack, 2);
+ }
+ if(!q->isWindow() || !w->internalWinId())
+ invalidateBuffer(q->rect());
+}
+
+
+static void do_size_hints(QWidget* widget, QWExtra *x)
+{
+ Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
+ XSizeHints s;
+ s.flags = 0;
+ if (x) {
+ QRect g = widget->geometry();
+ s.x = g.x();
+ s.y = g.y();
+ s.width = g.width();
+ s.height = g.height();
+ if (x->minw > 0 || x->minh > 0) {
+ // add minimum size hints
+ s.flags |= PMinSize;
+ s.min_width = qMin(XCOORD_MAX, x->minw);
+ s.min_height = qMin(XCOORD_MAX, x->minh);
+ }
+ if (x->maxw < QWIDGETSIZE_MAX || x->maxh < QWIDGETSIZE_MAX) {
+ // add maximum size hints
+ s.flags |= PMaxSize;
+ s.max_width = qMin(XCOORD_MAX, x->maxw);
+ s.max_height = qMin(XCOORD_MAX, x->maxh);
+ }
+ if (x->topextra &&
+ (x->topextra->incw > 0 || x->topextra->inch > 0)) {
+ // add resize increment hints
+ s.flags |= PResizeInc | PBaseSize;
+ s.width_inc = x->topextra->incw;
+ s.height_inc = x->topextra->inch;
+ s.base_width = x->topextra->basew;
+ s.base_height = x->topextra->baseh;
+ }
+ }
+ if (widget->testAttribute(Qt::WA_Moved)) {
+ // user (i.e. command-line) specified position
+ s.flags |= USPosition;
+ s.flags |= PPosition;
+ }
+ if (widget->testAttribute(Qt::WA_Resized)) {
+ // user (i.e. command-line) specified size
+ s.flags |= USSize;
+ s.flags |= PSize;
+ }
+ s.flags |= PWinGravity;
+ if (widget->testAttribute(Qt::WA_Moved) && x && x->topextra && !x->topextra->posFromMove) {
+ // position came from setGeometry(), tell the WM that we don't
+ // want our window gravity-shifted
+ s.win_gravity = StaticGravity;
+ } else {
+ // position came from move()
+ s.x = widget->x();
+ s.y = widget->y();
+ s.win_gravity = QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
+ }
+ if (widget->internalWinId())
+ XSetWMNormalHints(X11->display, widget->internalWinId(), &s);
+}
+
+
+/*
+ Helper function for non-toplevel widgets. Helps to map Qt's 32bit
+ coordinate system to X11's 16bit coordinate system.
+
+ Sets the geometry of the widget to data.crect, but clipped to sizes
+ that X can handle. Unmaps widgets that are completely outside the
+ valid range.
+
+ Maintains data.wrect, which is the geometry of the X widget,
+ measured in this widget's coordinate system.
+
+ if the parent is not clipped, parentWRect is empty, otherwise
+ parentWRect is the geometry of the parent's X rect, measured in
+ parent's coord sys
+ */
+void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+
+ /*
+ There are up to four different coordinate systems here:
+ Qt coordinate system for this widget.
+ X coordinate system for this widget (relative to wrect).
+ Qt coordinate system for parent
+ X coordinate system for parent (relative to parent's wrect).
+ */
+ Display *dpy = xinfo.display();
+ QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
+ QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
+ QRect wrect;
+ //xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys)
+ QRect xrect = data.crect;
+
+ const QWidget *const parent = q->parentWidget();
+ QRect parentWRect = parent->data->wrect;
+
+ if (parentWRect.isValid()) {
+ // parent is clipped, and we have to clip to the same limit as parent
+ if (!parentWRect.contains(xrect)) {
+ xrect &= parentWRect;
+ wrect = xrect;
+ //translate from parent's to my Qt coord sys
+ wrect.translate(-data.crect.topLeft());
+ }
+ //translate from parent's Qt coords to parent's X coords
+ xrect.translate(-parentWRect.topLeft());
+
+ } else {
+ // parent is not clipped, we may or may not have to clip
+
+ if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
+ // This is where the main optimization is: we are already
+ // clipped, and if our clip is still valid, we can just
+ // move our window, and do not need to move or clip
+ // children
+
+ QRect vrect = xrect & parent->rect();
+ vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
+ if (data.wrect.contains(vrect)) {
+ xrect = data.wrect;
+ xrect.translate(data.crect.topLeft());
+ if (data.winid)
+ XMoveWindow(dpy, data.winid, xrect.x(), xrect.y());
+ return;
+ }
+ }
+
+ if (!validRange.contains(xrect)) {
+ // we are too big, and must clip
+ xrect &=wrectRange;
+ wrect = xrect;
+ wrect.translate(-data.crect.topLeft());
+ //parent's X coord system is equal to parent's Qt coord
+ //sys, so we don't need to map xrect.
+ }
+
+ }
+
+ // unmap if we are outside the valid window system coord system
+ bool outsideRange = !xrect.isValid();
+ bool mapWindow = false;
+ if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
+ q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
+ if (outsideRange) {
+ if (data.winid)
+ XUnmapWindow(dpy, data.winid);
+ q->setAttribute(Qt::WA_Mapped, false);
+ } else if (!q->isHidden()) {
+ mapWindow = true;
+ }
+ }
+
+ if (outsideRange)
+ return;
+
+ bool jump = (data.wrect != wrect);
+ data.wrect = wrect;
+
+
+ // and now recursively for all children...
+ // ### can be optimized
+ for (int i = 0; i < children.size(); ++i) {
+ QObject *object = children.at(i);
+ if (object->isWidgetType()) {
+ QWidget *w = static_cast<QWidget *>(object);
+ if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
+ w->d_func()->setWSGeometry(jump);
+ }
+ }
+
+ if (data.winid) {
+ // move ourselves to the new position and map (if necessary) after
+ // the movement. Rationale: moving unmapped windows is much faster
+ // than moving mapped windows
+ if (jump) //avoid flicker when jumping
+ XSetWindowBackgroundPixmap(dpy, data.winid, XNone);
+ if (!parent->internalWinId())
+ xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
+ XMoveResizeWindow(dpy, data.winid, xrect.x(), xrect.y(), xrect.width(), xrect.height());
+ }
+
+ //to avoid flicker, we have to show children after the helper widget has moved
+ if (jump) {
+ for (int i = 0; i < children.size(); ++i) {
+ QObject *object = children.at(i);
+ if (object->isWidgetType()) {
+ QWidget *w = static_cast<QWidget *>(object);
+ if (!w->testAttribute(Qt::WA_OutsideWSRange) && !w->testAttribute(Qt::WA_Mapped) && !w->isHidden()) {
+ w->setAttribute(Qt::WA_Mapped);
+ if (w->internalWinId())
+ XMapWindow(dpy, w->data->winid);
+ }
+ }
+ }
+ }
+
+
+ if (jump && data.winid)
+ XClearArea(dpy, data.winid, 0, 0, wrect.width(), wrect.height(), True);
+
+ if (mapWindow && !dontShow) {
+ q->setAttribute(Qt::WA_Mapped);
+ if (data.winid)
+ XMapWindow(dpy, data.winid);
+ }
+}
+
+void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ Display *dpy = X11->display;
+
+ if ((q->windowType() == Qt::Desktop))
+ return;
+ if (q->isWindow()) {
+ if (!X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT))
+ && !X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ)))
+ data.window_state &= ~Qt::WindowMaximized;
+ if (!X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN)))
+ data.window_state &= ~Qt::WindowFullScreen;
+ if (QTLWExtra *topData = maybeTopData())
+ topData->normalGeometry = QRect(0,0,-1,-1);
+ } else {
+ uint s = data.window_state;
+ s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen);
+ data.window_state = s;
+ }
+ if (extra) { // any size restrictions?
+ w = qMin(w,extra->maxw);
+ h = qMin(h,extra->maxh);
+ w = qMax(w,extra->minw);
+ h = qMax(h,extra->minh);
+ }
+ QPoint oldPos(q->pos());
+ QSize oldSize(q->size());
+ QRect oldGeom(data.crect);
+ QRect r(x, y, w, h);
+
+ // We only care about stuff that changes the geometry, or may
+ // cause the window manager to change its state
+ if (!q->isWindow() && oldGeom == r)
+ return;
+
+ data.crect = r;
+ bool isResize = q->size() != oldSize;
+
+ if (q->isWindow()) {
+ if (w == 0 || h == 0) {
+ q->setAttribute(Qt::WA_OutsideWSRange, true);
+ if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
+ hide_sys();
+ } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
+ q->setAttribute(Qt::WA_OutsideWSRange, false);
+
+ // put the window in its place and show it
+ if (data.winid)
+ XMoveResizeWindow(dpy, data.winid, x, y, w, h);
+ topData()->posFromMove = false; // force StaticGravity
+ do_size_hints(q, extra);
+ show_sys();
+ } else {
+ q->setAttribute(Qt::WA_OutsideWSRange, false);
+ if (!q->isVisible())
+ do_size_hints(q, extra);
+ if (isMove) {
+ if ((data.window_flags & Qt::X11BypassWindowManagerHint) == Qt::X11BypassWindowManagerHint
+ // work around 4Dwm's incompliance with ICCCM 4.1.5
+ || X11->desktopEnvironment == DE_4DWM) {
+ if (data.winid)
+ XMoveResizeWindow(dpy, data.winid, x, y, w, h);
+ } else if (q->isVisible()
+ && topData()->validWMState
+ && X11->isSupportedByWM(ATOM(_NET_MOVERESIZE_WINDOW))) {
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = ATOM(_NET_MOVERESIZE_WINDOW);
+ e.xclient.display = X11->display;
+ e.xclient.window = q->internalWinId();
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = StaticGravity | 1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12;
+ e.xclient.data.l[1] = x;
+ e.xclient.data.l[2] = y;
+ e.xclient.data.l[3] = w;
+ e.xclient.data.l[4] = h;
+ XSendEvent(X11->display, RootWindow(X11->display, q->x11Info().screen()),
+ false, (SubstructureNotifyMask | SubstructureRedirectMask), &e);
+ } else if (data.winid) {
+ // pos() is right according to ICCCM 4.1.5
+ XMoveResizeWindow(dpy, data.winid, q->pos().x(), q->pos().y(), w, h);
+ }
+ } else if (isResize && data.winid) {
+ if (!q->isVisible()
+ && topData()->validWMState
+ && !q->testAttribute(Qt::WA_PendingMoveEvent)) {
+ /*
+ even though we've not visible, we could be in a
+ race w/ the window manager, and it may ignore
+ our ConfigureRequest. setting posFromMove to
+ false makes sure that doDeferredMap() in
+ qapplication_x11.cpp keeps the window in the
+ right place
+ */
+ topData()->posFromMove = false;
+ }
+ XResizeWindow(dpy, data.winid, w, h);
+ }
+ }
+ if (isResize && !q->testAttribute(Qt::WA_DontShowOnScreen)) // set config pending only on resize, see qapplication_x11.cpp, translateConfigEvent()
+ q->setAttribute(Qt::WA_WState_ConfigPending);
+
+ } else {
+ QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
+ const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
+ const bool disableInTopLevelResize = inTopLevelResize && q->internalWinId();
+ if (disableInTopLevelResize) {
+ // Top-level resize optimization does not work for native child widgets;
+ // disable it for this particular widget.
+ tlwExtra->inTopLevelResize = false;
+ }
+
+ if (!isResize && (!inTopLevelResize || disableInTopLevelResize) && q->isVisible()) {
+ moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
+ }
+ if (q->testAttribute(Qt::WA_WState_Created))
+ setWSGeometry();
+
+ if (isResize && (!inTopLevelResize || disableInTopLevelResize) && q->isVisible())
+ invalidateBuffer_resizeHelper(oldPos, oldSize);
+
+ if (disableInTopLevelResize)
+ tlwExtra->inTopLevelResize = true;
+ }
+
+ if (q->isVisible()) {
+ if (isMove && q->pos() != oldPos) {
+ if (X11->desktopEnvironment != DE_4DWM) {
+ // pos() is right according to ICCCM 4.1.5
+ QMoveEvent e(q->pos(), oldPos);
+ QApplication::sendEvent(q, &e);
+ } else {
+ // work around 4Dwm's incompliance with ICCCM 4.1.5
+ QMoveEvent e(data.crect.topLeft(), oldGeom.topLeft());
+ QApplication::sendEvent(q, &e);
+ }
+ }
+ if (isResize) {
+ static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
+ // If we have a backing store with static contents, we have to disable the top-level
+ // resize optimization in order to get invalidated regions for resized widgets.
+ // The optimization discards all invalidateBuffer() calls since we're going to
+ // repaint everything anyways, but that's not the case with static contents.
+ const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
+ && !extra->topextra->inTopLevelResize
+ && (!extra->topextra->backingStore
+ || !extra->topextra->backingStore->hasStaticContents());
+ if (setTopLevelResize)
+ extra->topextra->inTopLevelResize = true;
+ QResizeEvent e(q->size(), oldSize);
+ QApplication::sendEvent(q, &e);
+ if (setTopLevelResize)
+ extra->topextra->inTopLevelResize = false;
+ }
+ } else {
+ if (isMove && q->pos() != oldPos)
+ q->setAttribute(Qt::WA_PendingMoveEvent, true);
+ if (isResize)
+ q->setAttribute(Qt::WA_PendingResizeEvent, true);
+ }
+}
+
+void QWidgetPrivate::setConstraints_sys()
+{
+ Q_Q(QWidget);
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::setConstraints_sys START" << q;
+#endif
+ if (q->testAttribute(Qt::WA_WState_Created))
+ do_size_hints(q, extra);
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::setConstraints_sys END" << q;
+#endif
+}
+
+void QWidgetPrivate::scroll_sys(int dx, int dy)
+{
+ Q_Q(QWidget);
+
+ scrollChildren(dx, dy);
+ if (!paintOnScreen()) {
+ scrollRect(q->rect(), dx, dy);
+ } else {
+ scroll_sys(dx, dy, QRect());
+ }
+}
+
+void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
+{
+ Q_Q(QWidget);
+
+ if (!paintOnScreen()) {
+ scrollRect(r, dx, dy);
+ return;
+ }
+ bool valid_rect = r.isValid();
+ bool just_update = qAbs(dx) > q->width() || qAbs(dy) > q->height();
+ QRect sr = valid_rect ? r : clipRect();
+ if (just_update)
+ q->update();
+ else if (!valid_rect)
+ dirty.translate(dx, dy);
+
+ int x1, y1, x2, y2, w = sr.width(), h = sr.height();
+ if (dx > 0) {
+ x1 = sr.x();
+ x2 = x1+dx;
+ w -= dx;
+ } else {
+ x2 = sr.x();
+ x1 = x2-dx;
+ w += dx;
+ }
+ if (dy > 0) {
+ y1 = sr.y();
+ y2 = y1+dy;
+ h -= dy;
+ } else {
+ y2 = sr.y();
+ y1 = y2-dy;
+ h += dy;
+ }
+
+ if (dx == 0 && dy == 0)
+ return;
+
+ Display *dpy = X11->display;
+ // Want expose events
+ if (w > 0 && h > 0 && !just_update && q->internalWinId()) {
+ GC gc = XCreateGC(dpy, q->internalWinId(), 0, 0);
+ XSetGraphicsExposures(dpy, gc, True);
+ XCopyArea(dpy, q->internalWinId(), q->internalWinId(), gc, x1, y1, w, h, x2, y2);
+ XFreeGC(dpy, gc);
+ }
+
+ if (!valid_rect && !children.isEmpty()) { // scroll children
+ QPoint pd(dx, dy);
+ for (int i = 0; i < children.size(); ++i) { // move all children
+ register QObject *object = children.at(i);
+ if (object->isWidgetType()) {
+ QWidget *w = static_cast<QWidget *>(object);
+ if (!w->isWindow())
+ w->move(w->pos() + pd);
+ }
+ }
+ }
+
+ if (just_update)
+ return;
+
+ // Don't let the server be bogged-down with repaint events
+ bool repaint_immediately = (qt_sip_count(q) < 3 && !q->testAttribute(Qt::WA_WState_InPaintEvent));
+
+ if (dx) {
+ int x = x2 == sr.x() ? sr.x()+w : sr.x();
+ if (repaint_immediately)
+ q->repaint(x, sr.y(), qAbs(dx), sr.height());
+ else if (q->internalWinId())
+ XClearArea(dpy, data.winid, x, sr.y(), qAbs(dx), sr.height(), True);
+ }
+ if (dy) {
+ int y = y2 == sr.y() ? sr.y()+h : sr.y();
+ if (repaint_immediately)
+ q->repaint(sr.x(), y, sr.width(), qAbs(dy));
+ else if (q->internalWinId())
+ XClearArea(dpy, data.winid, sr.x(), y, sr.width(), qAbs(dy), True);
+ }
+
+ qt_insert_sip(q, dx, dy); // #### ignores r
+}
+
+int QWidget::metric(PaintDeviceMetric m) const
+{
+ Q_D(const QWidget);
+ int val;
+ if (m == PdmWidth) {
+ val = data->crect.width();
+ } else if (m == PdmHeight) {
+ val = data->crect.height();
+ } else {
+ Display *dpy = X11->display;
+ int scr = d->xinfo.screen();
+ switch (m) {
+ case PdmDpiX:
+ case PdmPhysicalDpiX:
+ if (d->extra && d->extra->customDpiX)
+ val = d->extra->customDpiX;
+ else if (d->parent)
+ val = static_cast<QWidget *>(d->parent)->metric(m);
+ else
+ val = QX11Info::appDpiX(scr);
+ break;
+ case PdmDpiY:
+ case PdmPhysicalDpiY:
+ if (d->extra && d->extra->customDpiY)
+ val = d->extra->customDpiY;
+ else if (d->parent)
+ val = static_cast<QWidget *>(d->parent)->metric(m);
+ else
+ val = QX11Info::appDpiY(scr);
+ break;
+ case PdmWidthMM:
+ val = (DisplayWidthMM(dpy,scr)*data->crect.width())/
+ DisplayWidth(dpy,scr);
+ break;
+ case PdmHeightMM:
+ val = (DisplayHeightMM(dpy,scr)*data->crect.height())/
+ DisplayHeight(dpy,scr);
+ break;
+ case PdmNumColors:
+ val = d->xinfo.cells();
+ break;
+ case PdmDepth:
+ val = d->xinfo.depth();
+ break;
+ default:
+ val = 0;
+ qWarning("QWidget::metric: Invalid metric command");
+ }
+ }
+ return val;
+}
+
+void QWidgetPrivate::createSysExtra()
+{
+ extra->compress_events = true;
+ extra->xDndProxy = 0;
+}
+
+void QWidgetPrivate::deleteSysExtra()
+{
+}
+
+void QWidgetPrivate::createTLSysExtra()
+{
+ extra->topextra->spont_unmapped = 0;
+ extra->topextra->dnd = 0;
+ extra->topextra->validWMState = 0;
+ extra->topextra->waitingForMapNotify = 0;
+ extra->topextra->parentWinId = 0;
+ extra->topextra->userTimeWindow = 0;
+#ifndef QT_NO_XSYNC
+ extra->topextra->syncUpdateCounter = 0;
+ extra->topextra->syncRequestTimestamp = 0;
+ extra->topextra->newCounterValueHi = 0;
+ extra->topextra->newCounterValueLo = 0;
+#endif
+}
+
+void QWidgetPrivate::deleteTLSysExtra()
+{
+ // don't destroy input context here. it will be destroyed in
+ // QWidget::destroy() destroyInputContext();
+}
+
+void QWidgetPrivate::registerDropSite(bool on)
+{
+ Q_UNUSED(on);
+}
+
+void QWidgetPrivate::setMask_sys(const QRegion &region)
+{
+ Q_Q(QWidget);
+ if (!q->internalWinId())
+ return;
+
+ if (region.isEmpty()) {
+ XShapeCombineMask(X11->display, q->internalWinId(), ShapeBounding, 0, 0,
+ XNone, ShapeSet);
+ } else {
+ XShapeCombineRegion(X11->display, q->internalWinId(), ShapeBounding, 0, 0,
+ region.handle(), ShapeSet);
+ }
+}
+
+/*!
+ \internal
+
+ Computes the frame rectangle when needed. This is an internal function, you
+ should never call this.
+*/
+
+void QWidgetPrivate::updateFrameStrut()
+{
+ Q_Q(QWidget);
+
+ QTLWExtra *top = topData();
+ if (!top->validWMState) {
+ return;
+ }
+ if (!q->isWindow() && !q->internalWinId()) {
+ data.fstrut_dirty = false;
+ return;
+ }
+
+ Atom type_ret;
+ Window l = q->effectiveWinId(), w = l, p, r; // target window, its parent, root
+ Window *c;
+ int i_unused;
+ unsigned int nc;
+ unsigned char *data_ret;
+ unsigned long l_unused;
+
+ while (XQueryTree(X11->display, w, &r, &p, &c, &nc)) {
+ if (c && nc > 0)
+ XFree(c);
+
+ if (! p) {
+ qWarning("QWidget::updateFrameStrut: No parent");
+ return;
+ }
+
+ // if the parent window is the root window, an Enlightenment virtual root or
+ // a NET WM virtual root window, stop here
+ data_ret = 0;
+ if (p == r ||
+ (XGetWindowProperty(X11->display, p,
+ ATOM(ENLIGHTENMENT_DESKTOP), 0, 1, False, XA_CARDINAL,
+ &type_ret, &i_unused, &l_unused, &l_unused,
+ &data_ret) == Success &&
+ type_ret == XA_CARDINAL)) {
+ if (data_ret)
+ XFree(data_ret);
+
+ break;
+ } else if (X11->isSupportedByWM(ATOM(_NET_VIRTUAL_ROOTS)) && X11->net_virtual_root_list) {
+ int i = 0;
+ while (X11->net_virtual_root_list[i] != 0) {
+ if (X11->net_virtual_root_list[i++] == p)
+ break;
+ }
+ }
+
+ l = w;
+ w = p;
+ }
+
+ // we have our window
+ int transx, transy;
+ XWindowAttributes wattr;
+ if (XTranslateCoordinates(X11->display, l, w,
+ 0, 0, &transx, &transy, &p) &&
+ XGetWindowAttributes(X11->display, w, &wattr)) {
+ top->frameStrut.setCoords(transx,
+ transy,
+ wattr.width - data.crect.width() - transx,
+ wattr.height - data.crect.height() - transy);
+
+ // add the border_width for the window managers frame... some window managers
+ // do not use a border_width of zero for their frames, and if we the left and
+ // top strut, we ensure that pos() is absolutely correct. frameGeometry()
+ // will still be incorrect though... perhaps i should have foffset as well, to
+ // indicate the frame offset (equal to the border_width on X).
+ // - Brad
+ top->frameStrut.adjust(wattr.border_width,
+ wattr.border_width,
+ wattr.border_width,
+ wattr.border_width);
+ }
+
+ data.fstrut_dirty = false;
+}
+
+void QWidgetPrivate::setWindowOpacity_sys(qreal opacity)
+{
+ Q_Q(QWidget);
+ ulong value = ulong(opacity * 0xffffffff);
+ XChangeProperty(QX11Info::display(), q->internalWinId(), ATOM(_NET_WM_WINDOW_OPACITY), XA_CARDINAL,
+ 32, PropModeReplace, (uchar*)&value, 1);
+}
+
+const QX11Info &QWidget::x11Info() const
+{
+ Q_D(const QWidget);
+ return d->xinfo;
+}
+
+void QWidgetPrivate::setWindowRole()
+{
+ Q_Q(QWidget);
+ if (!q->internalWinId())
+ return;
+ QByteArray windowRole = topData()->role.toUtf8();
+ XChangeProperty(X11->display, q->internalWinId(),
+ ATOM(WM_WINDOW_ROLE), XA_STRING, 8, PropModeReplace,
+ (unsigned char *)windowRole.constData(), windowRole.length());
+}
+
+Q_GLOBAL_STATIC(QX11PaintEngine, qt_widget_paintengine)
+QPaintEngine *QWidget::paintEngine() const
+{
+ Q_D(const QWidget);
+ if (qt_widget_paintengine()->isActive()) {
+ if (d->extraPaintEngine)
+ return d->extraPaintEngine;
+ QWidget *self = const_cast<QWidget *>(this);
+ self->d_func()->extraPaintEngine = new QX11PaintEngine();
+ return d->extraPaintEngine;
+ }
+ return qt_widget_paintengine();
+}
+
+QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
+{
+ return new QX11WindowSurface(q_func());
+}
+
+Qt::HANDLE QWidget::x11PictureHandle() const
+{
+#ifndef QT_NO_XRENDER
+ Q_D(const QWidget);
+ if (!internalWinId() && testAttribute(Qt::WA_WState_Created))
+ (void)winId(); // enforce native window
+ return d->picture;
+#else
+ return 0;
+#endif // QT_NO_XRENDER
+}
+
+#ifndef QT_NO_XRENDER
+XRenderColor QX11Data::preMultiply(const QColor &c)
+{
+ XRenderColor color;
+ const uint A = c.alpha(),
+ R = c.red(),
+ G = c.green(),
+ B = c.blue();
+ color.alpha = (A | A << 8);
+ color.red = (R | R << 8) * color.alpha / 0x10000;
+ color.green = (G | G << 8) * color.alpha / 0x10000;
+ color.blue = (B | B << 8) * color.alpha / 0x10000;
+ return color;
+}
+Picture QX11Data::getSolidFill(int screen, const QColor &c)
+{
+ if (!X11->use_xrender)
+ return XNone;
+
+ XRenderColor color = preMultiply(c);
+ for (int i = 0; i < X11->solid_fill_count; ++i) {
+ if (X11->solid_fills[i].screen == screen
+ && X11->solid_fills[i].color.alpha == color.alpha
+ && X11->solid_fills[i].color.red == color.red
+ && X11->solid_fills[i].color.green == color.green
+ && X11->solid_fills[i].color.blue == color.blue)
+ return X11->solid_fills[i].picture;
+ }
+ // none found, replace one
+ int i = qrand() % 16;
+
+ if (X11->solid_fills[i].screen != screen && X11->solid_fills[i].picture) {
+ XRenderFreePicture (X11->display, X11->solid_fills[i].picture);
+ X11->solid_fills[i].picture = 0;
+ }
+
+ if (!X11->solid_fills[i].picture) {
+ Pixmap pixmap = XCreatePixmap (X11->display, RootWindow (X11->display, screen), 1, 1, 32);
+ XRenderPictureAttributes attrs;
+ attrs.repeat = True;
+ X11->solid_fills[i].picture = XRenderCreatePicture (X11->display, pixmap,
+ XRenderFindStandardFormat(X11->display, PictStandardARGB32),
+ CPRepeat, &attrs);
+ XFreePixmap (X11->display, pixmap);
+ }
+
+ X11->solid_fills[i].color = color;
+ X11->solid_fills[i].screen = screen;
+ XRenderFillRectangle (X11->display, PictOpSrc, X11->solid_fills[i].picture, &color, 0, 0, 1, 1);
+ return X11->solid_fills[i].picture;
+}
+#endif
+
+void QWidgetPrivate::setModal_sys()
+{
+}
+
+void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const QX11WindowAttributes &att)
+{
+ QX11InfoData* xd = xinfo->getX11Data(true);
+ const XWindowAttributes &a = *(att.att);
+ // find which screen the window is on...
+ xd->screen = QX11Info::appScreen(); // by default, use the default :)
+ int i;
+ for (i = 0; i < ScreenCount(X11->display); i++) {
+ if (RootWindow(X11->display, i) == a.root) {
+ xd->screen = i;
+ break;
+ }
+ }
+
+ xd->depth = a.depth;
+ xd->cells = DisplayCells(X11->display, xd->screen);
+ xd->visual = a.visual;
+ xd->defaultVisual = (XVisualIDFromVisual((Visual *) a.visual) ==
+ XVisualIDFromVisual((Visual *) QX11Info::appVisual(xinfo->screen())));
+ xd->colormap = a.colormap;
+ xd->defaultColormap = (a.colormap == QX11Info::appColormap(xinfo->screen()));
+ xinfo->setX11Data(xd);
+}
+
+void QWidgetPrivate::updateX11AcceptFocus()
+{
+ Q_Q(QWidget);
+ if (!q->isWindow() || !q->internalWinId())
+ return;
+
+ XWMHints *h = XGetWMHints(X11->display, q->internalWinId());
+ XWMHints wm_hints;
+ if (!h) {
+ memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
+ h = &wm_hints;
+ }
+ h->flags |= InputHint;
+ h->input = q->testAttribute(Qt::WA_X11DoNotAcceptFocus) ? False : True;
+
+ XSetWMHints(X11->display, q->internalWinId(), h);
+ if (h != &wm_hints)
+ XFree((char *)h);
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qwidgetcreate_x11.cpp b/src/widgets/platforms/x11/qwidgetcreate_x11.cpp
new file mode 100644
index 0000000000..16bd6abf9a
--- /dev/null
+++ b/src/widgets/platforms/x11/qwidgetcreate_x11.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qwidget.h"
+#include "qt_x11_p.h"
+
+/*
+ Internal Qt functions to create X windows. We have put them in
+ separate functions to allow the programmer to reimplement them by
+ custom versions.
+*/
+
+QT_BEGIN_NAMESPACE
+
+Window qt_XCreateWindow(const QWidget *, Display *display, Window parent,
+ int x, int y, uint w, uint h,
+ int borderwidth, int depth,
+ uint windowclass, Visual *visual,
+ ulong valuemask, XSetWindowAttributes *attributes)
+{
+ return XCreateWindow(display, parent, x, y, w, h, borderwidth, depth,
+ windowclass, visual, valuemask, attributes);
+}
+
+
+Window qt_XCreateSimpleWindow(const QWidget *, Display *display, Window parent,
+ int x, int y, uint w, uint h, int borderwidth,
+ ulong border, ulong background)
+{
+ return XCreateSimpleWindow(display, parent, x, y, w, h, borderwidth,
+ border, background);
+}
+
+
+void qt_XDestroyWindow(const QWidget *, Display *display, Window window)
+{
+ if (window)
+ XDestroyWindow(display, window);
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qx11embed_x11.cpp b/src/widgets/platforms/x11/qx11embed_x11.cpp
new file mode 100644
index 0000000000..49a819469e
--- /dev/null
+++ b/src/widgets/platforms/x11/qx11embed_x11.cpp
@@ -0,0 +1,1808 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qx11embed_x11.h"
+#include <qapplication.h>
+#include <qevent.h>
+#include <qpainter.h>
+#include <qlayout.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+#include <qelapsedtimer.h>
+#include <qpointer.h>
+#include <qdebug.h>
+#include <qx11info_x11.h>
+#include <private/qt_x11_p.h>
+#include <private/qwidget_p.h>
+
+#define XK_MISCELLANY
+#define XK_LATIN1
+#define None 0
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#include <X11/keysymdef.h>
+#include <X11/X.h>
+
+#ifndef XK_ISO_Left_Tab
+#define XK_ISO_Left_Tab 0xFE20
+#endif
+
+//#define QX11EMBED_DEBUG
+#ifdef QX11EMBED_DEBUG
+#include <qdebug.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QX11EmbedWidget
+ \ingroup advanced
+
+ \brief The QX11EmbedWidget class provides an XEmbed client widget.
+
+ XEmbed is an X11 protocol that supports the embedding of a widget
+ from one application into another application.
+
+ An XEmbed \e{client widget} is a window that is embedded into a
+ \e container. A container is the graphical location that embeds
+ (or \e swallows) an external application.
+
+ QX11EmbedWidget is a widget used for writing XEmbed applets or
+ plugins. When it has been embedded and the container receives tab
+ focus, focus is passed on to the widget. When the widget reaches
+ the end of its focus chain, focus is passed back to the
+ container. Window activation, accelerator support, modality and
+ drag and drop (XDND) are also handled.
+
+ The widget and container can both initiate the embedding. If the
+ widget is the initiator, the X11 window ID of the container that
+ it wants to embed itself into must be passed to embedInto().
+
+ If the container initiates the embedding, the window ID of the
+ embedded widget must be known. The container calls embed(),
+ passing the window ID.
+
+ This example shows an application that embeds a QX11EmbedWidget
+ subclass into the window whose ID is passed as a command-line
+ argument:
+
+ \snippet doc/src/snippets/qx11embedwidget/main.cpp 0
+
+ The problem of obtaining the window IDs is often solved by the
+ container invoking the application that provides the widget as a
+ separate process (as a panel invokes a docked applet), passing
+ its window ID to the new process as a command-line argument. The
+ new process can then call embedInto() with the container's window
+ ID, as shown in the example code above. Similarly, the new
+ process can report its window ID to the container through IPC, in
+ which case the container can embed the widget.
+
+ When the widget has been embedded, it emits the signal
+ embedded(). If it is closed by the container, the widget emits
+ containerClosed(). If an error occurs when embedding, error() is
+ emitted.
+
+ There are XEmbed widgets available for KDE and GTK+. The GTK+
+ equivalent of QX11EmbedWidget is GtkPlug. The corresponding KDE 3
+ widget is called QXEmbed.
+
+ \sa QX11EmbedContainer, {XEmbed Specification}
+*/
+
+/*!
+ \class QX11EmbedContainer
+ \ingroup advanced
+
+ \brief The QX11EmbedContainer class provides an XEmbed container
+ widget.
+
+ XEmbed is an X11 protocol that supports the embedding of a widget
+ from one application into another application.
+
+ An XEmbed \e container is the graphical location that embeds an
+ external \e {client widget}. A client widget is a window that is
+ embedded into a container.
+
+ When a widget has been embedded and the container receives tab
+ focus, focus is passed on to the widget. When the widget reaches
+ the end of its focus chain, focus is passed back to the
+ container. Window activation, accelerator support, modality and
+ drag and drop (XDND) are also handled.
+
+ QX11EmbedContainer is commonly used for writing panels or
+ toolbars that hold applets, or for \e swallowing X11
+ applications. When writing a panel application, one container
+ widget is created on the toolbar, and it can then either swallow
+ another widget using embed(), or allow an XEmbed widget to be
+ embedded into itself. The container's X11 window ID, which is
+ retrieved with winId(), must then be known to the client widget.
+ After embedding, the client's window ID can be retrieved with
+ clientWinId().
+
+ In the following example, a container widget is created as the
+ main widget. It then invokes an application called "playmovie",
+ passing its window ID as a command line argument. The "playmovie"
+ program is an XEmbed client widget. The widget embeds itself into
+ the container using the container's window ID.
+
+ \snippet doc/src/snippets/qx11embedcontainer/main.cpp 0
+
+ When the client widget is embedded, the container emits the
+ signal clientIsEmbedded(). The signal clientClosed() is emitted
+ when a widget is closed.
+
+ It is possible for QX11EmbedContainer to embed XEmbed widgets
+ from toolkits other than Qt, such as GTK+. Arbitrary (non-XEmbed)
+ X11 widgets can also be embedded, but the XEmbed-specific
+ features such as window activation and focus handling are then
+ lost.
+
+ The GTK+ equivalent of QX11EmbedContainer is GtkSocket. The
+ corresponding KDE 3 widget is called QXEmbed.
+
+ \sa QX11EmbedWidget, {XEmbed Specification}
+*/
+
+/*! \fn void QX11EmbedWidget::embedded()
+
+ This signal is emitted by the widget that has been embedded by an
+ XEmbed container.
+*/
+
+/*! \fn void QX11EmbedWidget::containerClosed()
+
+ This signal is emitted by the client widget when the container
+ closes the widget. This can happen if the container itself
+ closes, or if the widget is rejected.
+
+ The container can reject a widget for any reason, but the most
+ common cause of a rejection is when an attempt is made to embed a
+ widget into a container that already has an embedded widget.
+*/
+
+/*! \fn void QX11EmbedContainer::clientIsEmbedded()
+
+ This signal is emitted by the container when a client widget has
+ been embedded.
+*/
+
+/*! \fn void QX11EmbedContainer::clientClosed()
+
+ This signal is emitted by the container when the client widget
+ closes.
+*/
+
+/*!
+ \fn void QX11EmbedWidget::error(QX11EmbedWidget::Error error)
+
+ This signal is emitted if an error occurred as a result of
+ embedding into or communicating with a container. The specified
+ \a error describes the problem that occurred.
+
+ \sa QX11EmbedWidget::Error
+*/
+
+/*!
+ \fn QX11EmbedContainer::Error QX11EmbedContainer::error() const
+
+ Returns the last error that occurred.
+*/
+
+/*! \fn void QX11EmbedContainer::error(QX11EmbedContainer::Error error)
+
+ This signal is emitted if an error occurred when embedding or
+ communicating with a client. The specified \a error describes the
+ problem that occurred.
+
+ \sa QX11EmbedContainer::Error
+*/
+
+/*!
+ \enum QX11EmbedWidget::Error
+
+ \value Unknown An unrecognized error occurred.
+
+ \value InvalidWindowID The X11 window ID of the container was
+ invalid. This error is usually triggered by passing an invalid
+ window ID to embedInto().
+
+ \omitvalue Internal
+*/
+
+/*!
+ \enum QX11EmbedContainer::Error
+
+ \value Unknown An unrecognized error occurred.
+
+ \value InvalidWindowID The X11 window ID of the container was
+ invalid. This error is usually triggered by passing an invalid
+ window ID to embed().
+
+ \omitvalue Internal
+*/
+
+const int XButtonPress = ButtonPress;
+const int XButtonRelease = ButtonRelease;
+#undef ButtonPress
+#undef ButtonRelease
+
+// This is a hack to move topData() out from QWidgetPrivate to public. We
+// need to to inspect window()'s embedded state.
+class QHackWidget : public QWidget
+{
+ Q_DECLARE_PRIVATE(QWidget)
+public:
+ QTLWExtra* topData() { return d_func()->topData(); }
+};
+
+static unsigned int XEMBED_VERSION = 0;
+
+enum QX11EmbedMessageType {
+ XEMBED_EMBEDDED_NOTIFY = 0,
+ XEMBED_WINDOW_ACTIVATE = 1,
+ XEMBED_WINDOW_DEACTIVATE = 2,
+ XEMBED_REQUEST_FOCUS = 3,
+ XEMBED_FOCUS_IN = 4,
+ XEMBED_FOCUS_OUT = 5,
+ XEMBED_FOCUS_NEXT = 6,
+ XEMBED_FOCUS_PREV = 7,
+ XEMBED_MODALITY_ON = 10,
+ XEMBED_MODALITY_OFF = 11,
+ XEMBED_REGISTER_ACCELERATOR = 12,
+ XEMBED_UNREGISTER_ACCELERATOR = 13,
+ XEMBED_ACTIVATE_ACCELERATOR = 14
+};
+
+enum QX11EmbedFocusInDetail {
+ XEMBED_FOCUS_CURRENT = 0,
+ XEMBED_FOCUS_FIRST = 1,
+ XEMBED_FOCUS_LAST = 2
+};
+
+enum QX11EmbedFocusInFlags {
+ XEMBED_FOCUS_OTHER = (0 << 0),
+ XEMBED_FOCUS_WRAPAROUND = (1 << 0)
+};
+
+enum QX11EmbedInfoFlags {
+ XEMBED_MAPPED = (1 << 0)
+};
+
+enum QX11EmbedAccelModifiers {
+ XEMBED_MODIFIER_SHIFT = (1 << 0),
+ XEMBED_MODIFIER_CONTROL = (1 << 1),
+ XEMBED_MODIFIER_ALT = (1 << 2),
+ XEMBED_MODIFIER_SUPER = (1 << 3),
+ XEMBED_MODIFIER_HYPER = (1 << 4)
+};
+
+enum QX11EmbedAccelFlags {
+ XEMBED_ACCELERATOR_OVERLOADED = (1 << 0)
+};
+
+// Silence the default X11 error handler.
+static int x11ErrorHandler(Display *, XErrorEvent *)
+{
+ return 0;
+}
+
+// Returns the X11 timestamp. Maintained mainly by qapplication
+// internals, but also updated by the XEmbed widgets.
+static Time x11Time()
+{
+ return qt_x11Data->time;
+}
+
+// Gives the version and flags of the supported XEmbed protocol.
+static unsigned int XEmbedVersion()
+{
+ return 0;
+}
+
+// Sends an XEmbed message.
+static void sendXEmbedMessage(WId window, Display *display, long message,
+ long detail = 0, long data1 = 0, long data2 = 0)
+{
+ XClientMessageEvent c;
+ memset(&c, 0, sizeof(c));
+ c.type = ClientMessage;
+ c.message_type = ATOM(_XEMBED);
+ c.format = 32;
+ c.display = display;
+ c.window = window;
+
+ c.data.l[0] = x11Time();
+ c.data.l[1] = message;
+ c.data.l[2] = detail;
+ c.data.l[3] = data1;
+ c.data.l[4] = data2;
+
+ XSendEvent(display, window, false, NoEventMask, (XEvent *) &c);
+}
+
+// From qapplication_x11.cpp
+static XKeyEvent lastKeyEvent;
+
+static QCoreApplication::EventFilter oldX11EventFilter;
+
+// The purpose of this global x11 filter is for one to capture the key
+// events in their original state, but most importantly this is the
+// only way to get the WM_TAKE_FOCUS message from WM_PROTOCOLS.
+static bool x11EventFilter(void *message, long *result)
+{
+ XEvent *event = reinterpret_cast<XEvent *>(message);
+ if (event->type == XKeyPress || event->type == XKeyRelease)
+ lastKeyEvent = event->xkey;
+
+ if (oldX11EventFilter && oldX11EventFilter != &x11EventFilter)
+ return oldX11EventFilter(message, result);
+ else
+ return false;
+}
+
+//
+struct functorData
+{
+ Window id, rootWindow;
+ bool clearedWmState;
+ bool reparentedToRoot;
+};
+
+static Bool functor(Display *display, XEvent *event, XPointer arg)
+{
+ functorData *data = (functorData *) arg;
+
+ if (!data->reparentedToRoot && event->type == ReparentNotify
+ && event->xreparent.window == data->id
+ && event->xreparent.parent == data->rootWindow) {
+ data->reparentedToRoot = true;
+ return true;
+ }
+
+ if (!data->clearedWmState
+ && event->type == PropertyNotify
+ && event->xproperty.window == data->id
+ && event->xproperty.atom == ATOM(WM_STATE)) {
+ if (event->xproperty.state == PropertyDelete) {
+ data->clearedWmState = true;
+ return true;
+ }
+
+ Atom ret;
+ int format, status;
+ unsigned char *retval;
+ unsigned long nitems, after;
+ status = XGetWindowProperty(display, data->id, ATOM(WM_STATE), 0, 2, False, ATOM(WM_STATE),
+ &ret, &format, &nitems, &after, &retval );
+ if (status == Success && ret == ATOM(WM_STATE) && format == 32 && nitems > 0) {
+ long state = *(long *)retval;
+ XFree(retval);
+ if (state == WithdrawnState) {
+ data->clearedWmState = true;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+class QX11EmbedWidgetPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QX11EmbedWidget)
+public:
+ inline QX11EmbedWidgetPrivate()
+ {
+ lastError = QX11EmbedWidget::Unknown;
+ container = 0;
+ }
+
+ void setEmbedded();
+
+ void emitError(QX11EmbedWidget::Error error) {
+ Q_Q(QX11EmbedWidget);
+
+ lastError = error;
+ emit q->error(error);
+ }
+
+ enum FocusWidgets {
+ FirstFocusWidget,
+ LastFocusWidget
+ };
+
+ int focusOriginator;
+ QWidget *getFocusWidget(FocusWidgets fw);
+ void checkActivateWindow(QObject *o);
+ QX11EmbedWidget *xEmbedWidget(QObject *o) const;
+ void clearFocus();
+
+ WId container;
+ QPointer<QWidget> currentFocus;
+
+ QX11EmbedWidget::Error lastError;
+
+};
+
+/*!
+ Constructs a QX11EmbedWidget object with the given \a parent.
+*/
+QX11EmbedWidget::QX11EmbedWidget(QWidget *parent)
+ : QWidget(*new QX11EmbedWidgetPrivate, parent, 0)
+{
+ XSetErrorHandler(x11ErrorHandler);
+
+ setAttribute(Qt::WA_NativeWindow);
+ setAttribute(Qt::WA_DontCreateNativeAncestors);
+ createWinId();
+ XSelectInput(x11Info().display(), internalWinId(),
+ KeyPressMask | KeyReleaseMask | ButtonPressMask
+ | ButtonReleaseMask
+ | KeymapStateMask | ButtonMotionMask | PointerMotionMask
+ | FocusChangeMask
+ | ExposureMask | StructureNotifyMask
+ | SubstructureNotifyMask | PropertyChangeMask);
+
+ long data[] = {XEMBED_VERSION, XEMBED_MAPPED};
+ XChangeProperty(x11Info().display(), internalWinId(), ATOM(_XEMBED_INFO),
+ ATOM(_XEMBED_INFO), 32, PropModeReplace,
+ (unsigned char*) data, 2);
+
+ setFocusPolicy(Qt::StrongFocus);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ QApplication::instance()->installEventFilter(this);
+
+#ifdef QX11EMBED_DEBUG
+ qDebug() << "QX11EmbedWidget::QX11EmbedWidget: constructed client"
+ << (void *)this << "with winId" << winId();
+#endif
+}
+
+/*!
+ Destructs the QX11EmbedWidget object. If the widget is embedded
+ when deleted, it is hidden and then detached from its container,
+ so that the container is free to embed a new widget.
+*/
+QX11EmbedWidget::~QX11EmbedWidget()
+{
+ Q_D(QX11EmbedWidget);
+ if (d->container) {
+#ifdef QX11EMBED_DEBUG
+ qDebug() << "QX11EmbedWidget::~QX11EmbedWidget: unmapping"
+ << (void *)this << "with winId" << winId()
+ << "from container with winId" << d->container;
+#endif
+ XUnmapWindow(x11Info().display(), internalWinId());
+ XReparentWindow(x11Info().display(), internalWinId(), x11Info().appRootWindow(x11Info().screen()), 0, 0);
+ }
+
+#ifdef QX11EMBED_DEBUG
+ qDebug() << "QX11EmbedWidget::~QX11EmbedWidget: destructed client"
+ << (void *)this << "with winId" << winId();
+#endif
+}
+
+/*!
+ Returns the type of error that occurred last. This is the same error code
+ that is emitted by the error() signal.
+
+ \sa Error
+*/
+QX11EmbedWidget::Error QX11EmbedWidget::error() const
+{
+ return d_func()->lastError;
+}
+
+/*!
+ When this function is called, the widget embeds itself into the
+ container whose window ID is \a id.
+
+ If \a id is \e not the window ID of a container this function will
+ behave unpredictably.
+*/
+void QX11EmbedWidget::embedInto(WId id)
+{
+ Q_D(QX11EmbedWidget);
+#ifdef QX11EMBED_DEBUG
+ qDebug() << "QX11EmbedWidget::embedInto: embedding client"
+ << (void *)this << "with winId" << winId() << "into container"
+ << id;
+#endif
+
+ d->container = id;
+ switch (XReparentWindow(x11Info().display(), internalWinId(), d->container, 0, 0)) {
+ case BadWindow:
+ d->emitError(InvalidWindowID);
+ break;
+ case BadMatch:
+ d->emitError(Internal);
+ break;
+ case Success:
+ default:
+ break;
+ }
+ QTLWExtra* x = d->extra ? d->extra->topextra : 0;
+ if (x)
+ x->frameStrut.setCoords(0, 0, 0, 0);
+ d->data.fstrut_dirty = false;
+}
+
+/*! \internal
+
+ Gets the first or last child widget that can get focus.
+*/
+QWidget *QX11EmbedWidgetPrivate::getFocusWidget(FocusWidgets fw)
+{
+ Q_Q(QX11EmbedWidget);
+ QWidget *tlw = q;
+ QWidget *w = tlw->nextInFocusChain();
+
+ QWidget *last = tlw;
+
+ extern bool qt_tab_all_widgets;
+ uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
+
+ while (w != tlw)
+ {
+ if (((w->focusPolicy() & focus_flag) == focus_flag)
+ && w->isVisibleTo(q) && w->isEnabled())
+ {
+ last = w;
+ if (fw == FirstFocusWidget)
+ break;
+ }
+ w = w->nextInFocusChain();
+ }
+
+ return last;
+}
+
+/*! \internal
+
+ Returns the xembed widget that the widget is a child of
+*/
+QX11EmbedWidget *QX11EmbedWidgetPrivate::xEmbedWidget(QObject *o) const
+{
+ QX11EmbedWidget *xec = 0;
+
+ // Check the widget itself, then its parents, and find the first
+ // QX11EmbedWidget.
+ do {
+ if ((xec = qobject_cast<QX11EmbedWidget *>(o)))
+ return xec;
+ } while ((o = o->parent()));
+ return 0;
+}
+
+/*! \internal
+
+ Checks the active window.
+*/
+void QX11EmbedWidgetPrivate::checkActivateWindow(QObject *o)
+{
+ Q_Q(QX11EmbedWidget);
+ QX11EmbedWidget *xec = xEmbedWidget(o);
+
+ // check if we are in the right xembed client
+ if (q != xec)
+ return;
+
+ QWidget *w = qobject_cast<QWidget *>(o);
+
+ // if it is no active window, then don't do the change
+ if (!(w && qApp->activeWindow()))
+ return;
+
+ // if it already is the active window, don't do anything
+ if (w->window() != qApp->activeWindow())
+ {
+ qApp->setActiveWindow(w->window());
+ currentFocus = w;
+
+ sendXEmbedMessage(xec->containerWinId(), q->x11Info().display(), XEMBED_REQUEST_FOCUS);
+ }
+}
+
+/*! \internal
+
+ Clears the focus
+*/
+void QX11EmbedWidgetPrivate::clearFocus()
+{
+ Q_Q(QX11EmbedWidget);
+ // Setting focus on the client itself removes Qt's
+ // logical focus rectangle. We can't just do a
+ // clearFocus here, because when we send the synthetic
+ // FocusIn to ourselves on activation, Qt will set
+ // focus on focusWidget() again. This way, we "hide"
+ // focus rather than clearing it.
+
+ if (!q->window()->hasFocus())
+ q->window()->setFocus(Qt::OtherFocusReason);
+
+ currentFocus = 0;
+}
+
+/*! \internal
+
+ Sets the embedded flag on the client.
+*/
+void QX11EmbedWidgetPrivate::setEmbedded()
+{
+ Q_Q(QX11EmbedWidget);
+ ((QHackWidget *)q->window())->topData()->embedded = 1;
+}
+
+/*! \internal
+
+ Handles WindowActivate and FocusIn events for the client.
+*/
+bool QX11EmbedWidget::eventFilter(QObject *o, QEvent *event)
+{
+ Q_D(QX11EmbedWidget);
+ switch (event->type()) {
+ case QEvent::FocusIn:
+ switch (((QFocusEvent *)event)->reason()) {
+ case Qt::MouseFocusReason:
+ // If the user clicks into one of the client widget's
+ // children and we didn't have focus already, we request
+ // focus from our container.
+ if (d->xEmbedWidget(o) == this) {
+ if (d->currentFocus.isNull())
+ sendXEmbedMessage(d->container, x11Info().display(), XEMBED_REQUEST_FOCUS);
+
+ d->currentFocus = qobject_cast<QWidget *>(o);
+ }
+ break;
+ case Qt::TabFocusReason:
+ // If the xembed client receives a focus event because of
+ // a Tab, then we are at the end of our focus chain and we
+ // ask the container to move to its next focus widget.
+ if (o == this) {
+ d->clearFocus();
+ sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_NEXT);
+ return true;
+ } else {
+ // We're listening on events from qApp, so in order
+ // for us to know who to set focus on if we receive an
+ // activation event, we note the widget that got the
+ // focusin last.
+ if (d->xEmbedWidget(o) == this)
+ d->currentFocus = qobject_cast<QWidget *>(o);
+ }
+ break;
+ case Qt::BacktabFocusReason:
+ // If the window receives a focus event because of
+ // a Backtab, then we are at the start of our focus chain
+ // and we ask the container to move to its previous focus
+ // widget.
+ if (o == this) {
+ // See comment for Tab.
+ // If we receive a XEMBED_FOCUS_IN
+ // XEMBED_FOCUS_CURRENT, we will set focus in
+ // currentFocus. To avoid that in this case, we reset
+ // currentFocus.
+ d->clearFocus();
+ sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_PREV);
+ return true;
+ } else {
+ if (d->xEmbedWidget(o) == this)
+ d->currentFocus = qobject_cast<QWidget *>(o);
+ }
+ break;
+ case Qt::ActiveWindowFocusReason:
+ if (isActiveWindow()) {
+ if (!d->currentFocus.isNull()) {
+ if (!d->currentFocus->hasFocus())
+ d->currentFocus->setFocus(Qt::OtherFocusReason);
+ } else {
+ d->clearFocus();
+ return true;
+ }
+ }
+
+ break;
+ case Qt::PopupFocusReason:
+ case Qt::ShortcutFocusReason:
+ case Qt::OtherFocusReason:
+ // If focus is received to any child widget because of any
+ // other reason, remember the widget so that we can give
+ // it focus again if we're activated.
+ if (d->xEmbedWidget(o) == this) {
+ d->currentFocus = qobject_cast<QWidget *>(o);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case QEvent::MouseButtonPress:
+ // If we get a mouse button press event inside a embedded widget
+ // make sure this is the active window in qapp.
+ d->checkActivateWindow(o);
+ break;
+ default:
+ break;
+ }
+
+ return QWidget::eventFilter(o, event);
+}
+
+/*! \internal
+
+ Handles some notification events and client messages. Client side
+ XEmbed message receiving is also handled here.
+*/
+bool QX11EmbedWidget::x11Event(XEvent *event)
+{
+ Q_D(QX11EmbedWidget);
+ switch (event->type) {
+ case DestroyNotify:
+#ifdef QX11EMBED_DEBUG
+ qDebug() << "QX11EmbedWidget::x11Event: client"
+ << (void *)this << "with winId" << winId()
+ << "received a DestroyNotify";
+#endif
+ // If the container window is destroyed, we signal this to the user.
+ d->container = 0;
+ emit containerClosed();
+ break;
+ case ReparentNotify:
+#ifdef QX11EMBED_DEBUG
+ qDebug() << "QX11EmbedWidget::x11Event: client"
+ << (void *)this << "with winId" << winId()
+ << "received a ReparentNotify to"
+ << ((event->xreparent.parent == x11Info().appRootWindow(x11Info().screen()))
+ ? QString::fromLatin1("root") : QString::number(event->xreparent.parent));
+#endif
+ // If the container shuts down, we will be reparented to the
+ // root window. We must also consider the case that we may be
+ // reparented from one container to another.
+ if (event->xreparent.parent == x11Info().appRootWindow(x11Info().screen())) {
+ if (((QHackWidget *)this)->topData()->embedded) {
+ d->container = 0;
+ emit containerClosed();
+ }
+ return true;
+ } else {
+ d->container = event->xreparent.parent;
+ }
+ break;
+ case UnmapNotify:
+ // Mapping and unmapping are handled by changes to the
+ // _XEMBED_INFO property. Any default map/unmap requests are
+ // ignored.
+ return true;
+ case PropertyNotify:
+ // The container sends us map/unmap messages through the
+ // _XEMBED_INFO property. We adhere to the XEMBED_MAPPED bit in
+ // data2.
+ if (event->xproperty.atom == ATOM(_XEMBED_INFO)) {
+ Atom actual_type_return;
+ int actual_format_return;
+ unsigned long nitems_return;
+ unsigned long bytes_after_return;
+ unsigned char *prop_return = 0;
+ if (XGetWindowProperty(x11Info().display(), internalWinId(), ATOM(_XEMBED_INFO), 0, 2,
+ false, ATOM(_XEMBED_INFO), &actual_type_return,
+ &actual_format_return, &nitems_return,
+ &bytes_after_return, &prop_return) == Success) {
+ if (nitems_return > 1) {
+ if (((long * )prop_return)[1] & XEMBED_MAPPED) {
+ XMapWindow(x11Info().display(), internalWinId());
+ } else {
+ XUnmapWindow(x11Info().display(), internalWinId());
+ }
+ }
+ if (prop_return)
+ XFree(prop_return);
+ }
+ }
+
+ break;
+ case ClientMessage:
+ // XEMBED messages have message_type _XEMBED
+ if (event->xclient.message_type == ATOM(_XEMBED)) {
+ // Discard XEMBED messages not to ourselves. (### dead code?)
+ if (event->xclient.window != internalWinId())
+ break;
+
+ // Update qt_x_time if necessary
+ Time msgtime = (Time) event->xclient.data.l[0];
+ if (msgtime > X11->time)
+ X11->time = msgtime;
+
+ switch (event->xclient.data.l[1]) {
+ case XEMBED_WINDOW_ACTIVATE: {
+ // When we receive an XEMBED_WINDOW_ACTIVATE, we simply send
+ // ourselves a WindowActivate event. Real activation happens
+ // when receive XEMBED_FOCUS_IN.
+ if (!isActiveWindow()) {
+ QEvent ev(QEvent::WindowActivate);
+ QApplication::sendEvent(this, &ev);
+ }
+ }
+ break;
+ case XEMBED_WINDOW_DEACTIVATE: {
+ // When we receive an XEMBED_WINDOW_DEACTIVATE, we simply send
+ // ourselves a WindowDeactivate event. Real activation happens
+ // when receive XEMBED_FOCUS_IN.
+ if (isActiveWindow()) {
+ if (!qApp->activePopupWidget())
+ QApplication::setActiveWindow(0);
+ } else {
+ QEvent ev(QEvent::WindowDeactivate);
+ QApplication::sendEvent(this, &ev);
+ }
+ }
+ break;
+ case XEMBED_EMBEDDED_NOTIFY: {
+#ifdef QX11EMBED_DEBUG
+ qDebug() << "QX11EmbedWidget::x11Event: client"
+ << (void *)this << "with winId" << winId()
+ << "received an XEMBED EMBEDDED NOTIFY message";
+#endif
+ // In this message's l[2] we have the max version
+ // supported by both the client and the
+ // container. QX11EmbedWidget does not use this field.
+
+ // We have been embedded, so we set our
+ // client's embedded flag.
+ d->setEmbedded();
+ emit embedded();
+ }
+ break;
+ case XEMBED_FOCUS_IN:
+ // don't set the focus if a modal dialog is open
+ if (qApp->activeModalWidget())
+ break;
+
+ // in case we embed more than one topLevel window inside the same
+ // host window.
+ if (window() != qApp->activeWindow())
+ qApp->setActiveWindow(this);
+
+ switch (event->xclient.data.l[2]) {
+ case XEMBED_FOCUS_CURRENT:
+ // The container sends us this message if it wants
+ // us to focus on the widget that last had focus.
+ // This is the reply when XEMBED_REQUEST_FOCUS is
+ // sent to the container.
+ if (!d->currentFocus.isNull()) {
+ if (!d->currentFocus->hasFocus())
+ d->currentFocus->setFocus(Qt::OtherFocusReason);
+ } else {
+ // No widget currently has focus. We set focus
+ // on the first widget next to the
+ // client widget. Since the setFocus will not work
+ // if the window is disabled, set the currentFocus
+ // directly so that it's set on window activate.
+ d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget);
+ d->currentFocus->setFocus(Qt::OtherFocusReason);
+ }
+ break;
+ case XEMBED_FOCUS_FIRST:
+ // The container sends this message when it wants
+ // us to focus on the first widget in our focus
+ // chain (typically because of a tab).
+ d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget);
+ d->currentFocus->setFocus(Qt::TabFocusReason);
+ break;
+ case XEMBED_FOCUS_LAST:
+ // The container sends this message when it wants
+ // us to focus on the last widget in our focus
+ // chain (typically because of a backtab).
+ d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::LastFocusWidget);
+ d->currentFocus->setFocus(Qt::BacktabFocusReason);
+ break;
+ default:
+ // Ignore any other XEMBED_FOCUS_IN details.
+ break;
+ }
+ break;
+ case XEMBED_FOCUS_OUT:
+ // The container sends us this message when it wants us
+ // to lose focus and forget about the widget that last
+ // had focus. Typically sent by the container when it
+ // loses focus because of mouse or tab activity. We do
+ // then not want to set focus on anything if we're
+ // activated.
+ if (isActiveWindow())
+ d->clearFocus();
+
+ break;
+ default:
+ // Ignore any other XEMBED messages.
+ break;
+ };
+ } else {
+ // Non-XEMBED client messages are not interesting.
+ }
+
+ break;
+ default:
+ // Ignore all other x11 events.
+ break;
+ }
+
+ // Allow default handling.
+ return QWidget::x11Event(event);
+}
+
+/*!
+ \reimp
+*/
+bool QX11EmbedWidget::event(QEvent *event)
+{
+ if (event->type() == QEvent::ParentChange) {
+ XSelectInput(x11Info().display(), internalWinId(),
+ KeyPressMask | KeyReleaseMask | ButtonPressMask
+ | ButtonReleaseMask
+ | KeymapStateMask | ButtonMotionMask | PointerMotionMask
+ | FocusChangeMask
+ | ExposureMask | StructureNotifyMask
+ | SubstructureNotifyMask | PropertyChangeMask);
+ }
+ return QWidget::event(event);
+}
+
+/*!
+ \reimp
+*/
+void QX11EmbedWidget::resizeEvent(QResizeEvent *event)
+{
+ if (layout())
+ layout()->update();
+ QWidget::resizeEvent(event);
+}
+
+/*!
+ If the widget is embedded, returns the window ID of the
+ container; otherwize returns 0.
+*/
+WId QX11EmbedWidget::containerWinId() const
+{
+ Q_D(const QX11EmbedWidget);
+ return d->container;
+}
+
+class QX11EmbedContainerPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QX11EmbedContainer)
+public:
+ inline QX11EmbedContainerPrivate()
+ {
+ lastError = QX11EmbedContainer::Unknown;
+ client = 0;
+ focusProxy = 0;
+ clientIsXEmbed = false;
+ xgrab = false;
+ }
+
+ bool isEmbedded() const;
+ void moveInputToProxy();
+
+ void acceptClient(WId window);
+ void rejectClient(WId window);
+
+ void checkGrab();
+
+ WId topLevelParentWinId() const;
+
+ void emitError(QX11EmbedContainer::Error error) {
+ Q_Q(QX11EmbedContainer);
+ lastError = error;
+ emit q->error(error);
+ }
+
+ WId client;
+ QWidget *focusProxy;
+ bool clientIsXEmbed;
+ bool xgrab;
+ QRect clientOriginalRect;
+ QSize wmMinimumSizeHint;
+
+ QX11EmbedContainer::Error lastError;
+
+ static QX11EmbedContainer *activeContainer;
+};
+
+QX11EmbedContainer *QX11EmbedContainerPrivate::activeContainer = 0;
+
+/*!
+ Creates a QX11EmbedContainer object with the given \a parent.
+*/
+QX11EmbedContainer::QX11EmbedContainer(QWidget *parent)
+ : QWidget(*new QX11EmbedContainerPrivate, parent, 0)
+{
+ Q_D(QX11EmbedContainer);
+ XSetErrorHandler(x11ErrorHandler);
+
+ setAttribute(Qt::WA_NativeWindow);
+ setAttribute(Qt::WA_DontCreateNativeAncestors);
+ createWinId();
+
+ setFocusPolicy(Qt::StrongFocus);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ // ### PORT setKeyCompression(false);
+ setAcceptDrops(true);
+ setEnabled(false);
+
+ // Everybody gets a focus proxy, but only one toplevel container's
+ // focus proxy is actually in use.
+ d->focusProxy = new QWidget(this);
+ d->focusProxy->setAttribute(Qt::WA_NativeWindow);
+ d->focusProxy->setAttribute(Qt::WA_DontCreateNativeAncestors);
+ d->focusProxy->createWinId();
+ d->focusProxy->setGeometry(-1, -1, 1, 1);
+
+ // We need events from the window (activation status) and
+ // from qApp (keypress/release).
+ qApp->installEventFilter(this);
+
+ // Install X11 event filter.
+ if (!oldX11EventFilter)
+ oldX11EventFilter = QCoreApplication::instance()->setEventFilter(x11EventFilter);
+
+ XSelectInput(x11Info().display(), internalWinId(),
+ KeyPressMask | KeyReleaseMask
+ | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
+ | KeymapStateMask
+ | PointerMotionMask
+ | EnterWindowMask | LeaveWindowMask
+ | FocusChangeMask
+ | ExposureMask
+ | StructureNotifyMask
+ | SubstructureNotifyMask);
+
+ // Make sure our new event mask takes effect as soon as possible.
+ XFlush(x11Info().display());
+
+ // Move input to our focusProxy if this widget is active, and not
+ // shaded by a modal dialog (in which case isActiveWindow() would
+ // still return true, but where we must not move input focus).
+ if (qApp->activeWindow() == window() && !d->isEmbedded())
+ d->moveInputToProxy();
+
+#ifdef QX11EMBED_DEBUG
+ qDebug() << "QX11EmbedContainer::QX11EmbedContainer: constructed container"
+ << (void *)this << "with winId" << winId();
+#endif
+}
+
+/*!
+ Destructs a QX11EmbedContainer.
+*/
+QX11EmbedContainer::~QX11EmbedContainer()
+{
+ Q_D(QX11EmbedContainer);
+ if (d->client) {
+ XUnmapWindow(x11Info().display(), d->client);
+ XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(x11Info().screen()), 0, 0);
+ }
+
+ if (d->xgrab)
+ XUngrabButton(x11Info().display(), AnyButton, AnyModifier, internalWinId());
+}
+
+
+QX11EmbedContainer::Error QX11EmbedContainer::error() const {
+ return d_func()->lastError;
+}
+
+
+/*! \reimp
+*/
+void QX11EmbedContainer::paintEvent(QPaintEvent *)
+{
+}
+
+/*! \internal
+
+ Returns whether or not the windows' embedded flag is set.
+*/
+bool QX11EmbedContainerPrivate::isEmbedded() const
+{
+ Q_Q(const QX11EmbedContainer);
+ return ((QHackWidget *)q->window())->topData()->embedded == 1;
+}
+
+/*! \internal
+
+ Returns the parentWinId of the window.
+*/
+WId QX11EmbedContainerPrivate::topLevelParentWinId() const
+{
+ Q_Q(const QX11EmbedContainer);
+ return ((QHackWidget *)q->window())->topData()->parentWinId;
+}
+
+/*!
+ If the container has an embedded widget, this function returns
+ the X11 window ID of the client; otherwise it returns 0.
+*/
+WId QX11EmbedContainer::clientWinId() const
+{
+ Q_D(const QX11EmbedContainer);
+ return d->client;
+}
+
+/*!
+ Instructs the container to embed the X11 window with window ID \a
+ id. The client widget will then move on top of the container
+ window and be resized to fit into the container.
+
+ The \a id should be the ID of a window controlled by an XEmbed
+ enabled application, but this is not mandatory. If \a id does not
+ belong to an XEmbed client widget, then focus handling,
+ activation, accelerators and other features will not work
+ properly.
+*/
+void QX11EmbedContainer::embedClient(WId id)
+{
+ Q_D(QX11EmbedContainer);
+
+ if (id == 0) {
+ d->emitError(InvalidWindowID);
+ return;
+ }
+
+ // Walk up the tree of parent windows to prevent embedding of ancestors.
+ WId thisId = internalWinId();
+ Window rootReturn;
+ Window parentReturn;
+ Window *childrenReturn = 0;
+ unsigned int nchildrenReturn;
+ do {
+ if (XQueryTree(x11Info().display(), thisId, &rootReturn,
+ &parentReturn, &childrenReturn, &nchildrenReturn) == 0) {
+ d->emitError(InvalidWindowID);
+ return;
+ }
+ if (childrenReturn) {
+ XFree(childrenReturn);
+ childrenReturn = 0;
+ }
+
+ thisId = parentReturn;
+ if (id == thisId) {
+ d->emitError(InvalidWindowID);
+ return;
+ }
+ } while (thisId != rootReturn);
+
+ // watch for property notify events (see below)
+ XGrabServer(x11Info().display());
+ XWindowAttributes attrib;
+ if (!XGetWindowAttributes(x11Info().display(), id, &attrib)) {
+ XUngrabServer(x11Info().display());
+ d->emitError(InvalidWindowID);
+ return;
+ }
+ XSelectInput(x11Info().display(), id, attrib.your_event_mask | PropertyChangeMask | StructureNotifyMask);
+ XUngrabServer(x11Info().display());
+
+ // Put the window into WithdrawnState
+ XUnmapWindow(x11Info().display(), id);
+ XSync(x11Info().display(), False); // make sure the window is hidden
+
+ /*
+ Wait for notification from the window manager that the window is
+ in withdrawn state. According to the ICCCM section 4.1.3.1,
+ we should wait for the WM_STATE property to either be deleted or
+ set to WithdrawnState.
+
+ For safety, we will not wait more than 500 ms, so that we can
+ preemptively workaround buggy window managers.
+ */
+ QElapsedTimer t;
+ t.start();
+
+ functorData data;
+ data.id = id;
+ data.rootWindow = attrib.root;
+ data.clearedWmState = false;
+ data.reparentedToRoot = false;
+
+ do {
+ if (t.elapsed() > 500) // time-out after 500 ms
+ break;
+
+ XEvent event;
+ if (!XCheckIfEvent(x11Info().display(), &event, functor, (XPointer) &data)) {
+ XSync(x11Info().display(), False);
+ usleep(50000);
+ continue;
+ }
+
+ qApp->x11ProcessEvent(&event);
+ } while (!data.clearedWmState || !data.reparentedToRoot);
+
+ // restore the event mask
+ XSelectInput(x11Info().display(), id, attrib.your_event_mask);
+
+ switch (XReparentWindow(x11Info().display(), id, internalWinId(), 0, 0)) {
+ case BadWindow:
+ case BadMatch:
+ d->emitError(InvalidWindowID);
+ break;
+ default:
+ break;
+ }
+}
+
+/*! \internal
+
+ Handles key, activation and focus events for the container.
+*/
+bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event)
+{
+ Q_D(QX11EmbedContainer);
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ // Forward any keypresses to our client.
+ if (o == this && d->client) {
+ lastKeyEvent.window = d->client;
+ XSendEvent(x11Info().display(), d->client, false, KeyPressMask, (XEvent *) &lastKeyEvent);
+ return true;
+ }
+ break;
+ case QEvent::KeyRelease:
+ // Forward any keyreleases to our client.
+ if (o == this && d->client) {
+ lastKeyEvent.window = d->client;
+ XSendEvent(x11Info().display(), d->client, false, KeyReleaseMask, (XEvent *) &lastKeyEvent);
+ return true;
+ }
+ break;
+
+ case QEvent::WindowActivate:
+ // When our container window is activated, we pass the
+ // activation message on to our client. Note that X input
+ // focus is set to our focus proxy. We want to intercept all
+ // keypresses.
+ if (o == window() && d->client) {
+ if (d->clientIsXEmbed) {
+ sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_ACTIVATE);
+ } else {
+ d->checkGrab();
+ if (hasFocus())
+ XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
+ }
+ if (!d->isEmbedded())
+ d->moveInputToProxy();
+ }
+ break;
+ case QEvent::WindowDeactivate:
+ // When our container window is deactivated, we pass the
+ // deactivation message to our client.
+ if (o == window() && d->client) {
+ if (d->clientIsXEmbed)
+ sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_DEACTIVATE);
+ else
+ d->checkGrab();
+ }
+ break;
+ case QEvent::FocusIn:
+ // When receiving FocusIn events generated by Tab or Backtab,
+ // we pass focus on to our client. Any mouse activity is sent
+ // directly to the client, and it will ask us for focus with
+ // XEMBED_REQUEST_FOCUS.
+ if (o == this && d->client) {
+ if (!d->isEmbedded())
+ d->activeContainer = this;
+
+ if (d->clientIsXEmbed) {
+ if (!d->isEmbedded())
+ d->moveInputToProxy();
+
+ QFocusEvent *fe = (QFocusEvent *)event;
+ switch (fe->reason()) {
+ case Qt::TabFocusReason:
+ sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
+ break;
+ case Qt::BacktabFocusReason:
+ sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_LAST);
+ break;
+ default:
+ sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
+ break;
+ }
+ } else {
+ d->checkGrab();
+ XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
+ }
+ }
+
+ break;
+ case QEvent::FocusOut: {
+ // When receiving a FocusOut, we ask our client to remove its
+ // focus.
+ if (o == this && d->client) {
+ if (!d->isEmbedded()) {
+ d->activeContainer = 0;
+ if (isActiveWindow())
+ d->moveInputToProxy();
+ }
+
+ if (d->clientIsXEmbed) {
+ QFocusEvent *fe = (QFocusEvent *)event;
+ if (o == this && d->client && fe->reason() != Qt::ActiveWindowFocusReason)
+ sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_OUT);
+ } else {
+ d->checkGrab();
+ }
+ }
+ }
+ break;
+
+ case QEvent::Close: {
+ if (o == this && d->client) {
+ // Unmap the client and reparent it to the root window.
+ // Wait until the messages have been processed. Then ask
+ // the window manager to delete the window.
+ XUnmapWindow(x11Info().display(), d->client);
+ XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(x11Info().screen()), 0, 0);
+ XSync(x11Info().display(), false);
+
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = d->client;
+ ev.xclient.message_type = ATOM(WM_PROTOCOLS);
+ ev.xclient.format = 32;
+ ev.xclient.data.s[0] = ATOM(WM_DELETE_WINDOW);
+ XSendEvent(x11Info().display(), d->client, false, NoEventMask, &ev);
+
+ XFlush(x11Info().display());
+ d->client = 0;
+ d->clientIsXEmbed = false;
+ d->wmMinimumSizeHint = QSize();
+ updateGeometry();
+ setEnabled(false);
+ update();
+
+ emit clientClosed();
+ }
+ }
+ default:
+ break;
+ }
+
+ return QWidget::eventFilter(o, event);
+}
+
+/*! \internal
+
+ Handles X11 events for the container.
+*/
+bool QX11EmbedContainer::x11Event(XEvent *event)
+{
+ Q_D(QX11EmbedContainer);
+
+ switch (event->type) {
+ case CreateNotify:
+ // The client created an embedded window.
+ if (d->client)
+ d->rejectClient(event->xcreatewindow.window);
+ else
+ d->acceptClient(event->xcreatewindow.window);
+ break;
+ case DestroyNotify:
+ if (event->xdestroywindow.window == d->client) {
+ // The client died.
+ d->client = 0;
+ d->clientIsXEmbed = false;
+ d->wmMinimumSizeHint = QSize();
+ updateGeometry();
+ update();
+ setEnabled(false);
+ emit clientClosed();
+ }
+ break;
+ case ReparentNotify:
+ // The client sends us this if it reparents itself out of our
+ // widget.
+ if (event->xreparent.window == d->client && event->xreparent.parent != internalWinId()) {
+ d->client = 0;
+ d->clientIsXEmbed = false;
+ d->wmMinimumSizeHint = QSize();
+ updateGeometry();
+ update();
+ setEnabled(false);
+ emit clientClosed();
+ } else if (event->xreparent.parent == internalWinId()) {
+ // The client reparented itself into this window.
+ if (d->client)
+ d->rejectClient(event->xreparent.window);
+ else
+ d->acceptClient(event->xreparent.window);
+ }
+ break;
+ case ClientMessage: {
+ if (event->xclient.message_type == ATOM(_XEMBED)) {
+ // Ignore XEMBED messages not to ourselves
+ if (event->xclient.window != internalWinId())
+ break;
+
+ // Receiving an XEmbed message means the client
+ // is an XEmbed client.
+ d->clientIsXEmbed = true;
+
+ Time msgtime = (Time) event->xclient.data.l[0];
+ if (msgtime > X11->time)
+ X11->time = msgtime;
+
+ switch (event->xclient.data.l[1]) {
+ case XEMBED_REQUEST_FOCUS: {
+ // This typically happens when the client gets focus
+ // because of a mouse click.
+ if (!hasFocus())
+ setFocus(Qt::OtherFocusReason);
+
+ // The message is passed along to the topmost container
+ // that eventually responds with a XEMBED_FOCUS_IN
+ // message. The focus in message is passed all the way
+ // back until it reaches the original focus
+ // requestor. In the end, not only the original client
+ // has focus, but also all its ancestor containers.
+ if (d->isEmbedded()) {
+ // If our window's embedded flag is set, then
+ // that suggests that we are part of a client. The
+ // parentWinId will then point to an container to whom
+ // we must pass this message.
+ sendXEmbedMessage(d->topLevelParentWinId(), x11Info().display(), XEMBED_REQUEST_FOCUS);
+ } else {
+ // Our window's embedded flag is not set,
+ // so we are the topmost container. We respond to
+ // the focus request message with a focus in
+ // message. This message will pass on from client
+ // to container to client until it reaches the
+ // originator of the XEMBED_REQUEST_FOCUS message.
+ sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
+ }
+
+ break;
+ }
+ case XEMBED_FOCUS_NEXT:
+ // Client sends this event when it received a tab
+ // forward and was at the end of its focus chain. If
+ // we are the only widget in the focus chain, we send
+ // ourselves a FocusIn event.
+ if (d->focus_next != this) {
+ focusNextPrevChild(true);
+ } else {
+ QFocusEvent event(QEvent::FocusIn, Qt::TabFocusReason);
+ qApp->sendEvent(this, &event);
+ }
+
+ break;
+ case XEMBED_FOCUS_PREV:
+ // Client sends this event when it received a backtab
+ // and was at the start of its focus chain. If we are
+ // the only widget in the focus chain, we send
+ // ourselves a FocusIn event.
+ if (d->focus_next != this) {
+ focusNextPrevChild(false);
+ } else {
+ QFocusEvent event(QEvent::FocusIn, Qt::BacktabFocusReason);
+ qApp->sendEvent(this, &event);
+ }
+
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ case XButtonPress:
+ if (!d->clientIsXEmbed) {
+ setFocus(Qt::MouseFocusReason);
+ XAllowEvents(x11Info().display(), ReplayPointer, CurrentTime);
+ return true;
+ }
+ break;
+ case XButtonRelease:
+ if (!d->clientIsXEmbed)
+ XAllowEvents(x11Info().display(), SyncPointer, CurrentTime);
+ break;
+ default:
+ break;
+ }
+
+ return QWidget::x11Event(event);
+}
+
+/*! \internal
+
+ Whenever the container is resized, we need to resize our client.
+*/
+void QX11EmbedContainer::resizeEvent(QResizeEvent *)
+{
+ Q_D(QX11EmbedContainer);
+ if (d->client)
+ XResizeWindow(x11Info().display(), d->client, width(), height());
+}
+
+/*! \internal
+
+ We use the QShowEvent to signal to our client that we want it to
+ map itself. We do this by changing its window property
+ XEMBED_INFO. The client will get an X11 PropertyNotify.
+*/
+void QX11EmbedContainer::showEvent(QShowEvent *)
+{
+ Q_D(QX11EmbedContainer);
+ if (d->client) {
+ long data[] = {XEMBED_VERSION, XEMBED_MAPPED};
+ XChangeProperty(x11Info().display(), d->client, ATOM(_XEMBED_INFO), ATOM(_XEMBED_INFO), 32,
+ PropModeReplace, (unsigned char *) data, 2);
+ }
+}
+
+/*! \internal
+
+ We use the QHideEvent to signal to our client that we want it to
+ unmap itself. We do this by changing its window property
+ XEMBED_INFO. The client will get an X11 PropertyNotify.
+*/
+void QX11EmbedContainer::hideEvent(QHideEvent *)
+{
+ Q_D(QX11EmbedContainer);
+ if (d->client) {
+ long data[] = {XEMBED_VERSION, XEMBED_MAPPED};
+ XChangeProperty(x11Info().display(), d->client, ATOM(_XEMBED_INFO), ATOM(_XEMBED_INFO), 32,
+ PropModeReplace, (unsigned char *) data, 2);
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QX11EmbedContainer::event(QEvent *event)
+{
+ if (event->type() == QEvent::ParentChange) {
+ XSelectInput(x11Info().display(), internalWinId(),
+ KeyPressMask | KeyReleaseMask
+ | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
+ | KeymapStateMask
+ | PointerMotionMask
+ | EnterWindowMask | LeaveWindowMask
+ | FocusChangeMask
+ | ExposureMask
+ | StructureNotifyMask
+ | SubstructureNotifyMask);
+ }
+ return QWidget::event(event);
+}
+
+/*! \internal
+
+ Rejects a client window by reparenting it to the root window. The
+ client will receive a reparentnotify, and will most likely assume
+ that the container has shut down. The XEmbed protocol does not
+ define any way to reject a client window, but this is a clean way
+ to do it.
+*/
+void QX11EmbedContainerPrivate::rejectClient(WId window)
+{
+ Q_Q(QX11EmbedContainer);
+ q->setEnabled(false);
+ XRemoveFromSaveSet(q->x11Info().display(), client);
+ XReparentWindow(q->x11Info().display(), window, q->x11Info().appRootWindow(q->x11Info().screen()), 0, 0);
+}
+
+/*! \internal
+
+ Accepts a client by mapping it, resizing it and optionally
+ activating and giving it logical focusing through XEMBED messages.
+*/
+void QX11EmbedContainerPrivate::acceptClient(WId window)
+{
+ Q_Q(QX11EmbedContainer);
+ client = window;
+ q->setEnabled(true);
+
+ // This tells Qt that we wish to forward DnD messages to
+ // our client.
+ if (!extra)
+ createExtra();
+ extraData()->xDndProxy = client;
+
+ unsigned int version = XEmbedVersion();
+
+ Atom actual_type_return;
+ int actual_format_return;
+ unsigned long nitems_return = 0;
+ unsigned long bytes_after_return;
+ unsigned char *prop_return = 0;
+ unsigned int clientversion = 0;
+
+ // Add this client to our saveset, so if we crash, the client window
+ // doesn't get destroyed. This is useful for containers that restart
+ // automatically after a crash, because it can simply reembed its clients
+ // without having to restart them (KDE panel).
+ XAddToSaveSet(q->x11Info().display(), client);
+
+ // XEmbed clients have an _XEMBED_INFO property in which we can
+ // fetch the version
+ if (XGetWindowProperty(q->x11Info().display(), client, ATOM(_XEMBED_INFO), 0, 2, false,
+ ATOM(_XEMBED_INFO), &actual_type_return, &actual_format_return,
+ &nitems_return, &bytes_after_return, &prop_return) == Success) {
+
+ if (actual_type_return != None && actual_format_return != 0) {
+ // Clients with the _XEMBED_INFO property are XEMBED clients.
+ clientIsXEmbed = true;
+
+ long *p = (long *)prop_return;
+ if (nitems_return >= 2)
+ clientversion = (unsigned int)p[0];
+ }
+
+ XFree(prop_return);
+ }
+
+ // Store client window's original size and placement.
+ Window root;
+ int x_return, y_return;
+ unsigned int width_return, height_return, border_width_return, depth_return;
+ XGetGeometry(q->x11Info().display(), client, &root, &x_return, &y_return,
+ &width_return, &height_return, &border_width_return, &depth_return);
+ clientOriginalRect.setCoords(x_return, y_return,
+ x_return + width_return - 1,
+ y_return + height_return - 1);
+
+ // Ask the client for its minimum size.
+ XSizeHints size;
+ long msize;
+ if (XGetWMNormalHints(q->x11Info().display(), client, &size, &msize) && (size.flags & PMinSize)) {
+ wmMinimumSizeHint = QSize(size.min_width, size.min_height);
+ q->updateGeometry();
+ }
+
+ // The container should set the data2 field to the lowest of its
+ // supported version number and that of the client (from
+ // _XEMBED_INFO property).
+ unsigned int minversion = version > clientversion ? clientversion : version;
+ sendXEmbedMessage(client, q->x11Info().display(), XEMBED_EMBEDDED_NOTIFY, q->internalWinId(), minversion);
+ XMapWindow(q->x11Info().display(), client);
+
+ // Resize it, but no smaller than its minimum size hint.
+ XResizeWindow(q->x11Info().display(),
+ client,
+ qMax(q->width(), wmMinimumSizeHint.width()),
+ qMax(q->height(), wmMinimumSizeHint.height()));
+ q->update();
+
+ // Not mentioned in the protocol is that if the container
+ // is already active, the client must be activated to work
+ // properly.
+ if (q->window()->isActiveWindow())
+ sendXEmbedMessage(client, q->x11Info().display(), XEMBED_WINDOW_ACTIVATE);
+
+ // Also, if the container already has focus, then it must
+ // send a focus in message to its new client; otherwise we ask
+ // it to remove focus.
+ if (q->focusWidget() == q && q->hasFocus())
+ sendXEmbedMessage(client, q->x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
+ else
+ sendXEmbedMessage(client, q->x11Info().display(), XEMBED_FOCUS_OUT);
+
+ if (!clientIsXEmbed) {
+ checkGrab();
+ if (q->hasFocus()) {
+ XSetInputFocus(q->x11Info().display(), client, XRevertToParent, x11Time());
+ }
+ } else {
+ if (!isEmbedded())
+ moveInputToProxy();
+ }
+
+ emit q->clientIsEmbedded();
+}
+
+/*! \internal
+
+ Moves X11 keyboard input focus to the focusProxy, unless the focus
+ is there already. When X11 keyboard input focus is on the
+ focusProxy, which is a child of the container and a sibling of the
+ client, X11 keypresses and keyreleases will always go to the proxy
+ and not to the client.
+*/
+void QX11EmbedContainerPrivate::moveInputToProxy()
+{
+ Q_Q(QX11EmbedContainer);
+ // Following Owen Taylor's advice from the XEmbed specification to
+ // always use CurrentTime when no explicit user action is involved.
+ XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, CurrentTime);
+}
+
+/*! \internal
+
+ Ask the window manager to give us a default minimum size.
+*/
+QSize QX11EmbedContainer::minimumSizeHint() const
+{
+ Q_D(const QX11EmbedContainer);
+ if (!d->client || !d->wmMinimumSizeHint.isValid())
+ return QWidget::minimumSizeHint();
+ return d->wmMinimumSizeHint;
+}
+
+/*! \internal
+
+*/
+void QX11EmbedContainerPrivate::checkGrab()
+{
+ Q_Q(QX11EmbedContainer);
+ if (!clientIsXEmbed && q->isActiveWindow() && !q->hasFocus()) {
+ if (!xgrab) {
+ XGrabButton(q->x11Info().display(), AnyButton, AnyModifier, q->internalWinId(),
+ true, ButtonPressMask, GrabModeSync, GrabModeAsync,
+ None, None);
+ }
+ xgrab = true;
+ } else {
+ if (xgrab)
+ XUngrabButton(q->x11Info().display(), AnyButton, AnyModifier, q->internalWinId());
+ xgrab = false;
+ }
+}
+
+/*!
+ Detaches the client from the embedder. The client will appear as a
+ standalone window on the desktop.
+*/
+void QX11EmbedContainer::discardClient()
+{
+ Q_D(QX11EmbedContainer);
+ if (d->client) {
+ XResizeWindow(x11Info().display(), d->client, d->clientOriginalRect.width(),
+ d->clientOriginalRect.height());
+
+ d->rejectClient(d->client);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qx11embed_x11.h b/src/widgets/platforms/x11/qx11embed_x11.h
new file mode 100644
index 0000000000..30929f7ba9
--- /dev/null
+++ b/src/widgets/platforms/x11/qx11embed_x11.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QX11EMBED_X11_H
+#define QX11EMBED_X11_H
+
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QX11EmbedWidgetPrivate;
+class Q_GUI_EXPORT QX11EmbedWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QX11EmbedWidget(QWidget *parent = 0);
+ ~QX11EmbedWidget();
+
+ void embedInto(WId id);
+ WId containerWinId() const;
+
+ enum Error {
+ Unknown,
+ Internal,
+ InvalidWindowID
+ };
+ Error error() const;
+
+Q_SIGNALS:
+ void embedded();
+ void containerClosed();
+ void error(QX11EmbedWidget::Error error);
+
+protected:
+ bool x11Event(XEvent *);
+ bool eventFilter(QObject *, QEvent *);
+ bool event(QEvent *);
+ void resizeEvent(QResizeEvent *);
+
+private:
+ Q_DECLARE_PRIVATE(QX11EmbedWidget)
+ Q_DISABLE_COPY(QX11EmbedWidget)
+};
+
+class QX11EmbedContainerPrivate;
+class Q_GUI_EXPORT QX11EmbedContainer : public QWidget
+{
+ Q_OBJECT
+public:
+ QX11EmbedContainer(QWidget *parent = 0);
+ ~QX11EmbedContainer();
+
+ void embedClient(WId id);
+ void discardClient();
+
+ WId clientWinId() const;
+
+ QSize minimumSizeHint() const;
+
+ enum Error {
+ Unknown,
+ Internal,
+ InvalidWindowID
+ };
+ Error error() const;
+
+Q_SIGNALS:
+ void clientIsEmbedded();
+ void clientClosed();
+ void error(QX11EmbedContainer::Error);
+
+protected:
+ bool x11Event(XEvent *);
+ bool eventFilter(QObject *, QEvent *);
+ void paintEvent(QPaintEvent *e);
+ void resizeEvent(QResizeEvent *);
+ void showEvent(QShowEvent *);
+ void hideEvent(QHideEvent *);
+ bool event(QEvent *);
+
+private:
+ Q_DECLARE_PRIVATE(QX11EmbedContainer)
+ Q_DISABLE_COPY(QX11EmbedContainer)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QX11EMBED_X11_H
diff --git a/src/widgets/platforms/x11/qx11info_x11.cpp b/src/widgets/platforms/x11/qx11info_x11.cpp
new file mode 100644
index 0000000000..f52443befc
--- /dev/null
+++ b/src/widgets/platforms/x11/qx11info_x11.cpp
@@ -0,0 +1,543 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qwidget.h"
+#include "qpixmap.h"
+#include "qx11info_x11.h"
+#include "qt_x11_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QX11Info
+ \brief The QX11Info class provides information about the X display
+ configuration.
+
+ \ingroup shared
+
+ The class provides two APIs: a set of non-static functions that
+ provide information about a specific widget or pixmap, and a set
+ of static functions that provide the default information for the
+ application.
+
+ \warning This class is only available on X11. For querying
+ per-screen information in a portable way, use QDesktopWidget.
+
+ \sa QWidget::x11Info(), QPixmap::x11Info(), QDesktopWidget
+*/
+
+/*!
+ Constructs an empty QX11Info object.
+*/
+QX11Info::QX11Info()
+ : x11data(0)
+{
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+QX11Info::QX11Info(const QX11Info &other)
+{
+ x11data = other.x11data;
+ if (x11data)
+ ++x11data->ref;
+}
+
+/*!
+ Assigns \a other to this object and returns a reference to this
+ object.
+*/
+QX11Info &QX11Info::operator=(const QX11Info &other)
+{
+ if (other.x11data)
+ ++other.x11data->ref;
+ if (x11data && !--x11data->ref)
+ delete x11data;
+ x11data = other.x11data;
+ return *this;
+}
+
+/*!
+ Destroys the QX11Info object.
+*/
+QX11Info::~QX11Info()
+{
+ if (x11data && !--x11data->ref)
+ delete x11data;
+}
+
+/*!
+ \internal
+ Makes a shallow copy of the X11-specific data of \a fromDevice, if it is not
+ null. Otherwise this function sets it to null.
+*/
+
+void QX11Info::copyX11Data(const QPaintDevice *fromDevice)
+{
+ QX11InfoData *xd = 0;
+ if (fromDevice) {
+ if (fromDevice->devType() == QInternal::Widget)
+ xd = static_cast<const QWidget *>(fromDevice)->x11Info().x11data;
+ else if (fromDevice->devType() == QInternal::Pixmap)
+ xd = static_cast<const QPixmap *>(fromDevice)->x11Info().x11data;
+ }
+ setX11Data(xd);
+}
+
+/*!
+ \internal
+ Makes a deep copy of the X11-specific data of \a fromDevice, if it is not
+ null. Otherwise this function sets it to null.
+*/
+
+void QX11Info::cloneX11Data(const QPaintDevice *fromDevice)
+{
+ QX11InfoData *d = 0;
+ if (fromDevice) {
+ QX11InfoData *xd;
+ if (fromDevice->devType() == QInternal::Widget) {
+ xd = static_cast<const QWidget *>(fromDevice)->x11Info().x11data;
+ } else {
+ Q_ASSERT(fromDevice->devType() == QInternal::Pixmap);
+ xd = static_cast<const QPixmap *>(fromDevice)->x11Info().x11data;
+ }
+ d = new QX11InfoData(*xd);
+ d->ref = 0;
+ }
+ setX11Data(d);
+}
+
+/*!
+ \internal
+ Makes a shallow copy of the X11-specific data \a d and assigns it to this
+ class. This function increments the reference code of \a d.
+*/
+
+void QX11Info::setX11Data(const QX11InfoData* d)
+{
+ if (x11data && !--x11data->ref)
+ delete x11data;
+ x11data = (QX11InfoData *)d;
+ if (x11data)
+ ++x11data->ref;
+}
+
+
+/*!
+ \internal
+ If \a def is false, returns a deep copy of the x11Data, or 0 if x11Data is 0.
+ If \a def is true, makes a QX11Data struct filled with the default
+ values.
+
+ In either case the caller is responsible for deleting the returned
+ struct. But notice that the struct is a shared class, so other
+ classes might also have a reference to it. The reference count of
+ the returned QX11Data* is 0.
+*/
+
+QX11InfoData* QX11Info::getX11Data(bool def) const
+{
+ QX11InfoData* res = 0;
+ if (def) {
+ res = new QX11InfoData;
+ res->ref = 0;
+ res->screen = appScreen();
+ res->depth = appDepth();
+ res->cells = appCells();
+ res->colormap = colormap();
+ res->defaultColormap = appDefaultColormap();
+ res->visual = (Visual*) appVisual();
+ res->defaultVisual = appDefaultVisual();
+ } else if (x11data) {
+ res = new QX11InfoData;
+ *res = *x11data;
+ res->ref = 0;
+ }
+ return res;
+}
+
+/*!
+ Returns the horizontal resolution of the given \a screen in terms of the
+ number of dots per inch.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+
+ \sa setAppDpiX(), appDpiY()
+*/
+int QX11Info::appDpiX(int screen)
+{
+ if (!X11)
+ return 75;
+ if (screen < 0)
+ screen = X11->defaultScreen;
+ if (screen > X11->screenCount)
+ return 0;
+ return X11->screens[screen].dpiX;
+}
+
+/*!
+ Sets the horizontal resolution of the given \a screen to the number of
+ dots per inch specified by \a xdpi.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+
+ \sa appDpiX(), setAppDpiY()
+*/
+
+void QX11Info::setAppDpiX(int screen, int xdpi)
+{
+ if (!X11)
+ return;
+ if (screen < 0)
+ screen = X11->defaultScreen;
+ if (screen > X11->screenCount)
+ return;
+ X11->screens[screen].dpiX = xdpi;
+}
+
+/*!
+ Returns the vertical resolution of the given \a screen in terms of the
+ number of dots per inch.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+
+ \sa setAppDpiY(), appDpiX()
+*/
+
+int QX11Info::appDpiY(int screen)
+{
+ if (!X11)
+ return 75;
+ if (screen < 0)
+ screen = X11->defaultScreen;
+ if (screen > X11->screenCount)
+ return 0;
+ return X11->screens[screen].dpiY;
+}
+
+/*!
+ Sets the vertical resolution of the given \a screen to the number of
+ dots per inch specified by \a ydpi.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+
+ \sa appDpiY(), setAppDpiX()
+*/
+void QX11Info::setAppDpiY(int screen, int ydpi)
+{
+ if (!X11)
+ return;
+ if (screen < 0)
+ screen = X11->defaultScreen;
+ if (screen > X11->screenCount)
+ return;
+ X11->screens[screen].dpiY = ydpi;
+}
+
+/*!
+ Returns the X11 time.
+
+ \sa setAppTime(), appUserTime()
+*/
+unsigned long QX11Info::appTime()
+{
+ return X11 ? X11->time : 0;
+}
+
+/*!
+ Sets the X11 time to the value specified by \a time.
+
+ \sa appTime(), setAppUserTime()
+*/
+void QX11Info::setAppTime(unsigned long time)
+{
+ if (X11) {
+ X11->time = time;
+ }
+}
+
+/*!
+ Returns the X11 user time.
+
+ \sa setAppUserTime(), appTime()
+*/
+unsigned long QX11Info::appUserTime()
+{
+ return X11 ? X11->userTime : 0;
+}
+
+/*!
+ Sets the X11 user time as specified by \a time.
+
+ \sa appUserTime(), setAppTime()
+*/
+void QX11Info::setAppUserTime(unsigned long time)
+{
+ if (X11) {
+ X11->userTime = time;
+ }
+}
+
+
+/*!
+ \fn const char *QX11Info::appClass()
+
+ Returns the X11 application class.
+
+ \sa display()
+*/
+
+/*!
+ Returns the default display for the application.
+
+ \sa appScreen()
+*/
+
+Display *QX11Info::display()
+{
+ return X11 ? X11->display : 0;
+}
+
+/*!
+ Returns the number of the screen where the application is being
+ displayed.
+
+ \sa display(), screen()
+*/
+int QX11Info::appScreen()
+{
+ return X11 ? X11->defaultScreen : 0;
+}
+
+/*!
+ Returns a handle for the application's color map on the given \a screen.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+
+ \sa colormap(), defaultColormap()
+*/
+Qt::HANDLE QX11Info::appColormap(int screen)
+{
+ return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].colormap : 0;
+}
+
+/*!
+ Returns the current visual used by the application on the given
+ \a screen.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+
+ \sa visual(), defaultVisual()
+*/
+
+void *QX11Info::appVisual(int screen)
+{
+ return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].visual : 0;
+}
+
+/*!
+ Returns a handle for the applications root window on the given \a screen.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+
+ \sa QApplication::desktop()
+*/
+Qt::HANDLE QX11Info::appRootWindow(int screen)
+{
+ return X11 ? RootWindow(X11->display, screen == -1 ? X11->defaultScreen : screen) : 0;
+}
+
+/*!
+ Returns the color depth (bits per pixel) used by the application on the
+ given \a screen.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+
+ \sa depth()
+*/
+
+int QX11Info::appDepth(int screen)
+{
+ return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].depth : 32;
+}
+
+/*!
+ Returns the number of cells used by the application on the given \a screen.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+
+ \sa cells()
+*/
+
+int QX11Info::appCells(int screen)
+{ return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].cells : 0; }
+
+/*!
+ Returns true if the application has a default color map on the given
+ \a screen; otherwise returns false.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+*/
+bool QX11Info::appDefaultColormap(int screen)
+{ return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].defaultColormap : true; }
+
+/*!
+ Returns true if the application has a default visual on the given \a screen;
+ otherwise returns false.
+
+ The \a screen argument is an X screen number. Be aware that if
+ the user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+*/
+bool QX11Info::appDefaultVisual(int screen)
+{ return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].defaultVisual : true; }
+
+/*!
+ Returns the number of the screen currently in use.
+
+ The return value is an X screen number. Be aware that if the
+ user's system uses Xinerama (as opposed to traditional X11
+ multiscreen), there is only one X screen. Use QDesktopWidget to
+ query for information about Xinerama screens.
+
+ \sa appScreen()
+*/
+int QX11Info::screen() const
+{ return x11data ? x11data->screen : QX11Info::appScreen(); }
+
+/*!
+ Returns the color depth (bits per pixel) of the X display.
+
+ \sa appDepth()
+*/
+
+int QX11Info::depth() const
+{ return x11data ? x11data->depth : QX11Info::appDepth(); }
+
+/*!
+ Returns the number of cells.
+
+ \sa appCells()
+*/
+
+int QX11Info::cells() const
+{ return x11data ? x11data->cells : QX11Info::appCells(); }
+
+/*!
+ Returns a handle for the color map.
+
+ \sa defaultColormap()
+*/
+
+Qt::HANDLE QX11Info::colormap() const
+{ return x11data ? x11data->colormap : QX11Info::appColormap(); }
+
+/*!
+ Returns true if there is a default color map; otherwise returns false.
+
+ \sa colormap()
+*/
+
+bool QX11Info::defaultColormap() const
+{ return x11data ? x11data->defaultColormap : QX11Info::appDefaultColormap(); }
+
+/*!
+ Returns the current visual.
+
+ \sa appVisual(), defaultVisual()
+*/
+
+void *QX11Info::visual() const
+{ return x11data ? x11data->visual : QX11Info::appVisual(); }
+
+/*!
+ Returns true if there is a default visual; otherwise returns false.
+
+ \sa visual(), appVisual()
+*/
+
+bool QX11Info::defaultVisual() const
+{ return x11data ? x11data->defaultVisual : QX11Info::appDefaultVisual(); }
+
+
+/*!
+ \since 4.4
+
+ Returns true if there is a compositing manager running.
+*/
+bool QX11Info::isCompositingManagerRunning()
+{
+ return X11 ? X11->compositingManagerRunning : false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/platforms/x11/qx11info_x11.h b/src/widgets/platforms/x11/qx11info_x11.h
new file mode 100644
index 0000000000..ece85740d2
--- /dev/null
+++ b/src/widgets/platforms/x11/qx11info_x11.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QX11INFO_X11_H
+#define QX11INFO_X11_H
+
+#include <QtCore/qnamespace.h>
+
+typedef struct _XDisplay Display;
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+struct QX11InfoData;
+class QX11Info;
+class QPaintDevice;
+class QApplicationPrivate;
+class QX11InfoPrivate;
+struct QX11WindowAttributes;
+
+void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const QX11WindowAttributes &a);
+class Q_GUI_EXPORT QX11Info
+{
+public:
+ QX11Info();
+ ~QX11Info();
+ QX11Info(const QX11Info &other);
+ QX11Info &operator=(const QX11Info &other);
+
+ static Display *display();
+ static const char *appClass();
+ int screen() const;
+ int depth() const;
+ int cells() const;
+ Qt::HANDLE colormap() const;
+ bool defaultColormap() const;
+ void *visual() const;
+ bool defaultVisual() const;
+
+ static int appScreen();
+ static int appDepth(int screen = -1);
+ static int appCells(int screen = -1);
+ static Qt::HANDLE appColormap(int screen = -1);
+ static void *appVisual(int screen = -1);
+ static Qt::HANDLE appRootWindow(int screen = -1);
+ static bool appDefaultColormap(int screen = -1);
+ static bool appDefaultVisual(int screen = -1);
+ static int appDpiX(int screen = -1);
+ static int appDpiY(int screen = -1);
+ static void setAppDpiX(int screen, int dpi);
+ static void setAppDpiY(int screen, int dpi);
+ static unsigned long appTime();
+ static unsigned long appUserTime();
+ static void setAppTime(unsigned long time);
+ static void setAppUserTime(unsigned long time);
+ static bool isCompositingManagerRunning();
+
+protected:
+ void copyX11Data(const QPaintDevice *);
+ void cloneX11Data(const QPaintDevice *);
+ void setX11Data(const QX11InfoData *);
+ QX11InfoData* getX11Data(bool def = false) const;
+
+ QX11InfoData *x11data;
+
+ friend class QX11PaintEngine;
+ friend class QPixmap;
+ friend class QX11PixmapData;
+ friend class QWidget;
+ friend class QWidgetPrivate;
+ friend class QGLWidget;
+ friend void qt_init(QApplicationPrivate *priv, int, Display *display, Qt::HANDLE visual,
+ Qt::HANDLE colormap);
+ friend void qt_cleanup();
+ friend void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const QX11WindowAttributes &a);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QX11INFO_X11_H