1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42// ### 4.0: examine Q_EXPORT's below. The respective symbols had all
43// been in use (e.g. in the KDE wm) before the introduction of a version
44// map. One might want to turn some of them into proper public API and
45// provide a proper alternative for others. See also the exports in
46// qapplication_win.cpp, which suggest a unification.
47
48#include "qplatformdefs.h"
49
50#include "qcolormap.h"
51#include "qdesktopwidget.h"
52#include "qapplication.h"
53#include "qapplication_p.h"
54#include "qcursor.h"
55#include "qwidget.h"
56#include "qbitarray.h"
57#include "qpainter.h"
58#include "qfile.h"
59#include "qpixmapcache.h"
60#include "qdatetime.h"
61#include "qtextcodec.h"
62#include "qdatastream.h"
63#include "qbuffer.h"
64#include "qsocketnotifier.h"
65#include "qsessionmanager.h"
66#include "qclipboard.h"
67#include "qwhatsthis.h"
68#include "qsettings.h"
69#include "qstylefactory.h"
70#include "qfileinfo.h"
71#include "qdir.h"
72#include "qhash.h"
73#include "qevent.h"
74#include "qevent_p.h"
75#include "qvarlengtharray.h"
76#include "qdebug.h"
77#include <private/qcrashhandler_p.h>
78#include <private/qcolor_p.h>
79#include <private/qcursor_p.h>
80#include <private/qiconloader_p.h>
81#include <qgtkstyle.h>
82#include "qstyle.h"
83#include "qmetaobject.h"
84#include "qtimer.h"
85#include "qlibrary.h"
86#include <private/qgraphicssystemfactory_p.h>
87#include "qguiplatformplugin_p.h"
88#include "qkde_p.h"
89
90#if !defined (QT_NO_TABLET)
91extern "C" {
92# define class c_class //XIproto.h has a name member named 'class' which the c++ compiler doesn't like
93# include <wacomcfg.h>
94# undef class
95}
96#endif
97
98#ifndef QT_GUI_DOUBLE_CLICK_RADIUS
99#define QT_GUI_DOUBLE_CLICK_RADIUS 5
100#endif
101
102
103//#define ALIEN_DEBUG
104
105#if !defined(QT_NO_GLIB)
106# include "qguieventdispatcher_glib_p.h"
107#endif
108#include "qeventdispatcher_x11_p.h"
109#include <private/qpaintengine_x11_p.h>
110
111#include <private/qkeymapper_p.h>
112
113// Input method stuff
114#ifndef QT_NO_IM
115#include "qinputcontext.h"
116#include "qinputcontextfactory.h"
117#endif // QT_NO_IM
118
119#ifndef QT_NO_XFIXES
120#include <X11/extensions/Xfixes.h>
121#endif // QT_NO_XFIXES
122
123#include "qt_x11_p.h"
124#include "qx11info_x11.h"
125
126#define XK_MISCELLANY
127#include <X11/keysymdef.h>
128#if !defined(QT_NO_XINPUT)
129#include <X11/extensions/XI.h>
130#endif
131
132#include <stdlib.h>
133#include <string.h>
134#include <ctype.h>
135#include <locale.h>
136
137#include "qwidget_p.h"
138
139#include <private/qbackingstore_p.h>
140
141#ifdef QT_RX71_MULTITOUCH
142# include <qsocketnotifier.h>
143# include <linux/input.h>
144# include <errno.h>
145#endif
146
147#if _POSIX_VERSION+0 < 200112L && !defined(Q_OS_BSD4)
148# define QT_NO_UNSETENV
149#endif
150
151QT_BEGIN_NAMESPACE
152
153//#define X_NOT_BROKEN
154#ifdef X_NOT_BROKEN
155// Some X libraries are built with setlocale #defined to _Xsetlocale,
156// even though library users are then built WITHOUT such a definition.
157// This creates a problem - Qt might setlocale() one value, but then
158// X looks and doesn't see the value Qt set. The solution here is to
159// implement _Xsetlocale just in case X calls it - redirecting it to
160// the real libC version.
161//
162# ifndef setlocale
163extern "C" char *_Xsetlocale(int category, const char *locale);
164char *_Xsetlocale(int category, const char *locale)
165{
166 //qDebug("_Xsetlocale(%d,%s),category,locale");
167 return setlocale(category,locale);
168}
169# endif // setlocale
170#endif // X_NOT_BROKEN
171
172/* Warning: if you modify this string, modify the list of atoms in qt_x11_p.h as well! */
173static const char * x11_atomnames = {
174 // window-manager <-> client protocols
175 "WM_PROTOCOLS\0"
176 "WM_DELETE_WINDOW\0"
177 "WM_TAKE_FOCUS\0"
178 "_NET_WM_PING\0"
179 "_NET_WM_CONTEXT_HELP\0"
180 "_NET_WM_SYNC_REQUEST\0"
181 "_NET_WM_SYNC_REQUEST_COUNTER\0"
182
183 // ICCCM window state
184 "WM_STATE\0"
185 "WM_CHANGE_STATE\0"
186
187 // Session management
188 "WM_CLIENT_LEADER\0"
189 "WM_WINDOW_ROLE\0"
190 "SM_CLIENT_ID\0"
191
192 // Clipboard
193 "CLIPBOARD\0"
194 "INCR\0"
195 "TARGETS\0"
196 "MULTIPLE\0"
197 "TIMESTAMP\0"
198 "SAVE_TARGETS\0"
199 "CLIP_TEMPORARY\0"
200 "_QT_SELECTION\0"
201 "_QT_CLIPBOARD_SENTINEL\0"
202 "_QT_SELECTION_SENTINEL\0"
203 "CLIPBOARD_MANAGER\0"
204
205 "RESOURCE_MANAGER\0"
206
207 "_XSETROOT_ID\0"
208
209 "_QT_SCROLL_DONE\0"
210 "_QT_INPUT_ENCODING\0"
211
212 "_MOTIF_WM_HINTS\0"
213
214 "DTWM_IS_RUNNING\0"
215 "ENLIGHTENMENT_DESKTOP\0"
216 "_DT_SAVE_MODE\0"
217 "_SGI_DESKS_MANAGER\0"
218
219 // EWMH (aka NETWM)
220 "_NET_SUPPORTED\0"
221 "_NET_VIRTUAL_ROOTS\0"
222 "_NET_WORKAREA\0"
223
224 "_NET_MOVERESIZE_WINDOW\0"
225 "_NET_WM_MOVERESIZE\0"
226
227 "_NET_WM_NAME\0"
228 "_NET_WM_ICON_NAME\0"
229 "_NET_WM_ICON\0"
230
231 "_NET_WM_PID\0"
232
233 "_NET_WM_WINDOW_OPACITY\0"
234
235 "_NET_WM_STATE\0"
236 "_NET_WM_STATE_ABOVE\0"
237 "_NET_WM_STATE_BELOW\0"
238 "_NET_WM_STATE_FULLSCREEN\0"
239 "_NET_WM_STATE_MAXIMIZED_HORZ\0"
240 "_NET_WM_STATE_MAXIMIZED_VERT\0"
241 "_NET_WM_STATE_MODAL\0"
242 "_NET_WM_STATE_STAYS_ON_TOP\0"
243 "_NET_WM_STATE_DEMANDS_ATTENTION\0"
244
245 "_NET_WM_USER_TIME\0"
246 "_NET_WM_USER_TIME_WINDOW\0"
247 "_NET_WM_FULL_PLACEMENT\0"
248
249 "_NET_WM_WINDOW_TYPE\0"
250 "_NET_WM_WINDOW_TYPE_DESKTOP\0"
251 "_NET_WM_WINDOW_TYPE_DOCK\0"
252 "_NET_WM_WINDOW_TYPE_TOOLBAR\0"
253 "_NET_WM_WINDOW_TYPE_MENU\0"
254 "_NET_WM_WINDOW_TYPE_UTILITY\0"
255 "_NET_WM_WINDOW_TYPE_SPLASH\0"
256 "_NET_WM_WINDOW_TYPE_DIALOG\0"
257 "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0"
258 "_NET_WM_WINDOW_TYPE_POPUP_MENU\0"
259 "_NET_WM_WINDOW_TYPE_TOOLTIP\0"
260 "_NET_WM_WINDOW_TYPE_NOTIFICATION\0"
261 "_NET_WM_WINDOW_TYPE_COMBO\0"
262 "_NET_WM_WINDOW_TYPE_DND\0"
263 "_NET_WM_WINDOW_TYPE_NORMAL\0"
264 "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0"
265
266 "_KDE_NET_WM_FRAME_STRUT\0"
267
268 "_NET_STARTUP_INFO\0"
269 "_NET_STARTUP_INFO_BEGIN\0"
270
271 "_NET_SUPPORTING_WM_CHECK\0"
272
273 "_NET_WM_CM_S0\0"
274
275 "_NET_SYSTEM_TRAY_VISUAL\0"
276
277 "_NET_ACTIVE_WINDOW\0"
278
279 // Property formats
280 "COMPOUND_TEXT\0"
281 "TEXT\0"
282 "UTF8_STRING\0"
283
284 // xdnd
285 "XdndEnter\0"
286 "XdndPosition\0"
287 "XdndStatus\0"
288 "XdndLeave\0"
289 "XdndDrop\0"
290 "XdndFinished\0"
291 "XdndTypeList\0"
292 "XdndActionList\0"
293
294 "XdndSelection\0"
295
296 "XdndAware\0"
297 "XdndProxy\0"
298
299 "XdndActionCopy\0"
300 "XdndActionLink\0"
301 "XdndActionMove\0"
302 "XdndActionPrivate\0"
303
304 // Motif DND
305 "_MOTIF_DRAG_AND_DROP_MESSAGE\0"
306 "_MOTIF_DRAG_INITIATOR_INFO\0"
307 "_MOTIF_DRAG_RECEIVER_INFO\0"
308 "_MOTIF_DRAG_WINDOW\0"
309 "_MOTIF_DRAG_TARGETS\0"
310
311 "XmTRANSFER_SUCCESS\0"
312 "XmTRANSFER_FAILURE\0"
313
314 // Xkb
315 "_XKB_RULES_NAMES\0"
316
317 // XEMBED
318 "_XEMBED\0"
319 "_XEMBED_INFO\0"
320
321 // Wacom old. (before version 0.10)
322 "Wacom Stylus\0"
323 "Wacom Cursor\0"
324 "Wacom Eraser\0"
325
326 // Tablet
327 "STYLUS\0"
328 "ERASER\0"
329 "TABLET\0"
330};
331
332Q_GUI_EXPORT QX11Data *qt_x11Data = 0;
333
334/*****************************************************************************
335 Internal variables and functions
336 *****************************************************************************/
337static const char *appName = 0; // application name
338static const char *appClass = 0; // application class
339static const char *appFont = 0; // application font
340static const char *appBGCol = 0; // application bg color
341static const char *appFGCol = 0; // application fg color
342static const char *appBTNCol = 0; // application btn color
343static const char *mwGeometry = 0; // main widget geometry
344static const char *mwTitle = 0; // main widget title
345char *qt_ximServer = 0; // XIM Server will connect to
346static bool appSync = false; // X11 synchronization
347#if defined(QT_DEBUG)
348static bool appNoGrab = false; // X11 grabbing enabled
349static bool appDoGrab = false; // X11 grabbing override (gdb)
350#endif
351static bool app_save_rootinfo = false; // save root info
352static bool app_do_modal = false; // modal mode
353static Window curWin = 0; // current window
354
355
356// function to update the workarea of the screen - in qdesktopwidget_x11.cpp
357extern void qt_desktopwidget_update_workarea();
358
359// Function to change the window manager state (from qwidget_x11.cpp)
360extern void qt_change_net_wm_state(const QWidget *w, bool set, Atom one, Atom two = 0);
361
362// modifier masks for alt, meta, super, hyper, and mode_switch - detected when the application starts
363// and/or keyboard layout changes
364uchar qt_alt_mask = 0;
365uchar qt_meta_mask = 0;
366uchar qt_super_mask = 0;
367uchar qt_hyper_mask = 0;
368uchar qt_mode_switch_mask = 0;
369
370// flags for extensions for special Languages, currently only for RTL languages
371bool qt_use_rtl_extensions = false;
372
373static Window mouseActWindow = 0; // window where mouse is
374static Qt::MouseButton mouseButtonPressed = Qt::NoButton; // last mouse button pressed
375static Qt::MouseButtons mouseButtonState = Qt::NoButton; // mouse button state
376static Time mouseButtonPressTime = 0; // when was a button pressed
377static short mouseXPos, mouseYPos; // mouse pres position in act window
378static short mouseGlobalXPos, mouseGlobalYPos; // global mouse press position
379
380extern QWidgetList *qt_modal_stack; // stack of modal widgets
381
382// window where mouse buttons have been pressed
383static Window pressed_window = XNone;
384
385// popup control
386static bool replayPopupMouseEvent = false;
387static bool popupGrabOk;
388
389bool qt_sm_blockUserInput = false; // session management
390
391Q_GUI_EXPORT int qt_xfocusout_grab_counter = 0;
392
393#if !defined (QT_NO_TABLET)
394Q_GLOBAL_STATIC(QTabletDeviceDataList, tablet_devices)
395QTabletDeviceDataList *qt_tablet_devices()
396{
397 return tablet_devices();
398}
399
400extern bool qt_tabletChokeMouse;
401#endif
402
403typedef bool(*QX11FilterFunction)(XEvent *event);
404
405Q_GLOBAL_STATIC(QList<QX11FilterFunction>, x11Filters)
406
407Q_GUI_EXPORT void qt_installX11EventFilter(QX11FilterFunction func)
408{
409 Q_ASSERT(func);
410
411 if (QList<QX11FilterFunction> *list = x11Filters())
412 list->append(func);
413}
414
415Q_GUI_EXPORT void qt_removeX11EventFilter(QX11FilterFunction func)
416{
417 Q_ASSERT(func);
418
419 if (QList<QX11FilterFunction> *list = x11Filters())
420 list->removeOne(func);
421}
422
423
424static bool qt_x11EventFilter(XEvent* ev)
425{
426 long unused;
427 if (qApp->filterEvent(ev, &unused))
428 return true;
429 if (const QList<QX11FilterFunction> *list = x11Filters()) {
430 for (QList<QX11FilterFunction>::const_iterator it = list->constBegin(); it != list->constEnd(); ++it) {
431 if ((*it)(ev))
432 return true;
433 }
434 }
435
436 return qApp->x11EventFilter(ev);
437}
438
439#if !defined(QT_NO_XIM)
440XIMStyle qt_xim_preferred_style = 0;
441#endif
442int qt_ximComposingKeycode=0;
443QTextCodec * qt_input_mapper = 0;
444
445extern bool qt_check_clipboard_sentinel(); //def in qclipboard_x11.cpp
446extern bool qt_check_selection_sentinel(); //def in qclipboard_x11.cpp
447extern bool qt_xfixes_clipboard_changed(Window clipboardOwner, Time timestamp); //def in qclipboard_x11.cpp
448extern bool qt_xfixes_selection_changed(Window selectionOwner, Time timestamp); //def in qclipboard_x11.cpp
449
450static void qt_save_rootinfo();
451Q_GUI_EXPORT bool qt_try_modal(QWidget *, XEvent *);
452
453QWidget *qt_button_down = 0; // last widget to be pressed with the mouse
454QPointer<QWidget> qt_last_mouse_receiver = 0;
455static QWidget *qt_popup_down = 0; // popup that contains the pressed widget
456
457extern bool qt_xdnd_dragging;
458
459// gui or non-gui from qapplication.cpp
460extern bool qt_is_gui_used;
461
462/*!
463 \internal
464 Try to resolve a \a symbol from \a library with the version specified
465 by \a vernum.
466
467 Note that, in the case of the Xfixes library, \a vernum is not the same as
468 \c XFIXES_MAJOR - it is a part of soname and may differ from the Xfixes
469 version.
470*/
471static void* qt_load_library_runtime(const char *library, int vernum,
472 int highestVernum, const char *symbol)
473{
474 QList<int> versions;
475 // we try to load in the following order:
476 // explicit version -> the default one -> (from the highest (highestVernum) to the lowest (vernum) )
477 if (vernum != -1)
478 versions << vernum;
479 versions << -1;
480 if (vernum != -1) {
481 for(int i = highestVernum; i > vernum; --i)
482 versions << i;
483 }
484 Q_FOREACH(int version, versions) {
485 QLatin1String libName(library);
486 QLibrary xfixesLib(libName, version);
487 xfixesLib.setLoadHints(QLibrary::ImprovedSearchHeuristics);
488 void *ptr = xfixesLib.resolve(symbol);
489 if (ptr)
490 return ptr;
491 }
492 return 0;
493}
494
495#ifndef QT_NO_XINPUT
496# ifdef QT_RUNTIME_XINPUT
497# define XINPUT_LOAD_RUNTIME(vernum, symbol, symbol_type) \
498 (symbol_type)qt_load_library_runtime("libXi", vernum, 6, #symbol);
499# define XINPUT_LOAD(symbol) \
500 XINPUT_LOAD_RUNTIME(1, symbol, Ptr##symbol)
501# else // not runtime XInput
502# define XINPUT_LOAD(symbol) symbol
503# endif // QT_RUNTIME_XINPUT
504#else // not using Xinput at all
505# define XINPUT_LOAD(symbol) 0
506#endif // QT_NO_XINPUT
507
508#ifndef QT_NO_XFIXES
509# ifdef QT_RUNTIME_XFIXES
510# define XFIXES_LOAD_RUNTIME(vernum, symbol, symbol_type) \
511 (symbol_type)qt_load_library_runtime("libXfixes", vernum, 4, #symbol);
512# define XFIXES_LOAD_V1(symbol) \
513 XFIXES_LOAD_RUNTIME(1, symbol, Ptr##symbol)
514# define XFIXES_LOAD_V2(symbol) \
515 XFIXES_LOAD_RUNTIME(2, symbol, Ptr##symbol)
516
517# else // not runtime Xfixes
518
519# if XFIXES_MAJOR >= 2
520# define XFIXES_LOAD_V1(symbol) symbol
521# define XFIXES_LOAD_V2(symbol) symbol
522# elif XFIXES_MAJOR >= 1
523# define XFIXES_LOAD_V1(symbol) symbol
524# define XFIXES_LOAD_V2(symbol) 0
525# else
526# error Unsupported version of Xfixes
527# endif
528# endif // QT_RUNTIME_XFIXES
529#else // not using Xfixes at all
530# define XFIXES_LOAD_V1(symbol) 0
531# define XFIXES_LOAD_V2(symbol) 0
532#endif // QT_NO_XFIXES
533
534#ifndef QT_NO_XFIXES
535
536struct qt_xfixes_selection_event_data
537{
538 // which selection to filter out.
539 Atom selection;
540};
541
542#if defined(Q_C_CALLBACKS)
543extern "C" {
544#endif
545
546static Bool qt_xfixes_scanner(Display*, XEvent *event, XPointer arg)
547{
548 qt_xfixes_selection_event_data *data =
549 reinterpret_cast<qt_xfixes_selection_event_data*>(arg);
550 if (event->type == X11->xfixes_eventbase + XFixesSelectionNotify) {
551 XFixesSelectionNotifyEvent *xfixes_event = reinterpret_cast<XFixesSelectionNotifyEvent*>(event);
552 if (xfixes_event->selection == data->selection)
553 return true;
554 }
555 return false;
556}
557
558#if defined(Q_C_CALLBACKS)
559}
560#endif
561
562#endif // QT_NO_XFIXES
563
564class QETWidget : public QWidget // event translator widget
565{
566public:
567 QWidgetPrivate* d_func() { return QWidget::d_func(); }
568 bool translateMouseEvent(const XEvent *);
569 void translatePaintEvent(const XEvent *);
570 bool translateConfigEvent(const XEvent *);
571 bool translateCloseEvent(const XEvent *);
572 bool translateScrollDoneEvent(const XEvent *);
573 bool translateWheelEvent(int global_x, int global_y, int delta, Qt::MouseButtons buttons,
574 Qt::KeyboardModifiers modifiers, Qt::Orientation orient);
575#if !defined (QT_NO_TABLET)
576 bool translateXinputEvent(const XEvent*, QTabletDeviceData *tablet);
577#endif
578 bool translatePropertyEvent(const XEvent *);
579
580 void doDeferredMap()
581 {
582 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
583 if (!testAttribute(Qt::WA_Resized)) {
584 adjustSize();
585 setAttribute(Qt::WA_Resized, false);
586 }
587
588 /*
589 workaround for WM's that throw away ConfigureRequests from the following:
590
591 window->hide();
592 window->move(x, y); // could also be resize(), move()+resize(), or setGeometry()
593 window->show();
594 */
595 QRect r = geometry();
596
597 XMoveResizeWindow(X11->display,
598 internalWinId(),
599 r.x(),
600 r.y(),
601 r.width(),
602 r.height());
603
604 // static gravity!
605 XSizeHints sh;
606 memset(&sh, 0, sizeof(sh));
607 long unused;
608 XGetWMNormalHints(X11->display, internalWinId(), &sh, &unused);
609 sh.flags |= USPosition | PPosition | USSize | PSize | PWinGravity;
610 sh.x = r.x();
611 sh.y = r.y();
612 sh.width = r.width();
613 sh.height = r.height();
614 sh.win_gravity = StaticGravity;
615 XSetWMNormalHints(X11->display, internalWinId(), &sh);
616
617 setAttribute(Qt::WA_Mapped);
618 if (testAttribute(Qt::WA_DontShowOnScreen))
619 return;
620 d_func()->topData()->waitingForMapNotify = 1;
621 XMapWindow(X11->display, internalWinId());
622 }
623};
624
625
626void QApplicationPrivate::createEventDispatcher()
627{
628 Q_Q(QApplication);
629#if !defined(QT_NO_GLIB)
630 if (qgetenv("QT_NO_GLIB").isEmpty() && QEventDispatcherGlib::versionSupported())
631 eventDispatcher = (q->type() != QApplication::Tty
632 ? new QGuiEventDispatcherGlib(q)
633 : new QEventDispatcherGlib(q));
634 else
635#endif
636 eventDispatcher = (q->type() != QApplication::Tty
637 ? new QEventDispatcherX11(q)
638 : new QEventDispatcherUNIX(q));
639}
640
641/*****************************************************************************
642 Default X error handlers
643 *****************************************************************************/
644
645#if defined(Q_C_CALLBACKS)
646extern "C" {
647#endif
648
649static int (*original_x_errhandler)(Display *dpy, XErrorEvent *);
650static int (*original_xio_errhandler)(Display *dpy);
651
652static int qt_x_errhandler(Display *dpy, XErrorEvent *err)
653{
654 if (X11->display != dpy) {
655 // only handle X errors for our display
656 return 0;
657 }
658
659 switch (err->error_code) {
660 case BadAtom:
661 if (err->request_code == 20 /* X_GetProperty */
662 && (err->resourceid == XA_RESOURCE_MANAGER
663 || err->resourceid == XA_RGB_DEFAULT_MAP
664 || err->resourceid == ATOM(_NET_SUPPORTED)
665 || err->resourceid == ATOM(_NET_SUPPORTING_WM_CHECK)
666 || err->resourceid == ATOM(XdndProxy)
667 || err->resourceid == ATOM(XdndAware))) {
668 // Perhaps we're running under SECURITY reduction? :/
669 return 0;
670 }
671 break;
672
673 case BadWindow:
674 if (err->request_code == 2 /* X_ChangeWindowAttributes */
675 || err->request_code == 38 /* X_QueryPointer */) {
676 for (int i = 0; i < ScreenCount(dpy); ++i) {
677 if (err->resourceid == RootWindow(dpy, i)) {
678 // Perhaps we're running under SECURITY reduction? :/
679 return 0;
680 }
681 }
682 }
683 X11->seen_badwindow = true;
684 if (err->request_code == 25 /* X_SendEvent */) {
685 for (int i = 0; i < ScreenCount(dpy); ++i) {
686 if (err->resourceid == RootWindow(dpy, i)) {
687 // Perhaps we're running under SECURITY reduction? :/
688 return 0;
689 }
690 }
691 if (X11->xdndHandleBadwindow()) {
692 qDebug("xdndHandleBadwindow returned true");
693 return 0;
694 }
695 }
696 if (X11->ignore_badwindow)
697 return 0;
698 break;
699
700 default:
701#if !defined(QT_NO_XINPUT)
702 if (err->request_code == X11->xinput_major
703 && err->error_code == (X11->xinput_errorbase + XI_BadDevice)
704 && err->minor_code == 3 /* X_OpenDevice */) {
705 return 0;
706 }
707#endif
708 break;
709 }
710
711 char errstr[256];
712 XGetErrorText( dpy, err->error_code, errstr, 256 );
713 char buffer[256];
714 char request_str[256];
715 qsnprintf(buffer, 256, "%d", err->request_code);
716 XGetErrorDatabaseText(dpy, "XRequest", buffer, "", request_str, 256);
717 if (err->request_code < 128) {
718 // X error for a normal protocol request
719 qWarning( "X Error: %s %d\n"
720 " Major opcode: %d (%s)\n"
721 " Resource id: 0x%lx",
722 errstr, err->error_code,
723 err->request_code,
724 request_str,
725 err->resourceid );
726 } else {
727 // X error for an extension request
728 const char *extensionName = 0;
729 if (err->request_code == X11->xrender_major)
730 extensionName = "RENDER";
731 else if (err->request_code == X11->xrandr_major)
732 extensionName = "RANDR";
733 else if (err->request_code == X11->xinput_major)
734 extensionName = "XInputExtension";
735 else if (err->request_code == X11->mitshm_major)
736 extensionName = "MIT-SHM";
737#ifndef QT_NO_XKB
738 else if(err->request_code == X11->xkb_major)
739 extensionName = "XKEYBOARD";
740#endif
741
742 char minor_str[256];
743 if (extensionName) {
744 qsnprintf(buffer, 256, "%s.%d", extensionName, err->minor_code);
745 XGetErrorDatabaseText(dpy, "XRequest", buffer, "", minor_str, 256);
746 } else {
747 extensionName = "Uknown extension";
748 qsnprintf(minor_str, 256, "Unknown request");
749 }
750 qWarning( "X Error: %s %d\n"
751 " Extension: %d (%s)\n"
752 " Minor opcode: %d (%s)\n"
753 " Resource id: 0x%lx",
754 errstr, err->error_code,
755 err->request_code,
756 extensionName,
757 err->minor_code,
758 minor_str,
759 err->resourceid );
760 }
761
762 // ### we really should distinguish between severe, non-severe and
763 // ### application specific errors
764
765 return 0;
766}
767
768
769static int qt_xio_errhandler(Display *)
770{
771 qWarning("%s: Fatal IO error: client killed", appName);
772 QApplicationPrivate::reset_instance_pointer();
773 exit(1);
774 //### give the application a chance for a proper shutdown instead,
775 //### exit(1) doesn't help.
776 return 0;
777}
778
779#if defined(Q_C_CALLBACKS)
780}
781#endif
782
783#ifndef QT_NO_XSYNC
784struct qt_sync_request_event_data
785{
786 WId window;
787};
788
789#if defined(Q_C_CALLBACKS)
790extern "C" {
791#endif
792
793static Bool qt_sync_request_scanner(Display*, XEvent *event, XPointer arg)
794{
795 qt_sync_request_event_data *data =
796 reinterpret_cast<qt_sync_request_event_data*>(arg);
797 if (event->type == ClientMessage &&
798 event->xany.window == data->window &&
799 event->xclient.message_type == ATOM(WM_PROTOCOLS) &&
800 (Atom)event->xclient.data.l[0] == ATOM(_NET_WM_SYNC_REQUEST)) {
801 QWidget *w = QWidget::find(event->xany.window);
802 if (QTLWExtra *tlw = ((QETWidget*)w)->d_func()->maybeTopData()) {
803 const ulong timestamp = (const ulong) event->xclient.data.l[1];
804 if (timestamp > X11->time)
805 X11->time = timestamp;
806 if (timestamp == CurrentTime || timestamp > tlw->syncRequestTimestamp) {
807 tlw->syncRequestTimestamp = timestamp;
808 tlw->newCounterValueLo = event->xclient.data.l[2];
809 tlw->newCounterValueHi = event->xclient.data.l[3];
810 }
811 }
812 return true;
813 }
814 return false;
815}
816
817#if defined(Q_C_CALLBACKS)
818}
819#endif
820#endif // QT_NO_XSYNC
821
822static void qt_x11_create_intern_atoms()
823{
824 const char *names[QX11Data::NAtoms];
825 const char *ptr = x11_atomnames;
826
827 int i = 0;
828 while (*ptr) {
829 names[i++] = ptr;
830 while (*ptr)
831 ++ptr;
832 ++ptr;
833 }
834
835 Q_ASSERT(i == QX11Data::NPredefinedAtoms);
836
837 QByteArray settings_atom_name("_QT_SETTINGS_TIMESTAMP_");
838 settings_atom_name += XDisplayName(X11->displayName);
839 names[i++] = settings_atom_name;
840
841 Q_ASSERT(i == QX11Data::NAtoms);
842#if defined(XlibSpecificationRelease) && (XlibSpecificationRelease >= 6)
843 XInternAtoms(X11->display, (char **)names, i, False, X11->atoms);
844#else
845 for (i = 0; i < QX11Data::NAtoms; ++i)
846 X11->atoms[i] = XInternAtom(X11->display, (char *)names[i], False);
847#endif
848}
849
850Q_GUI_EXPORT void qt_x11_apply_settings_in_all_apps()
851{
852 QByteArray stamp;
853 QDataStream s(&stamp, QIODevice::WriteOnly);
854 s << QDateTime::currentDateTime();
855
856 XChangeProperty(QX11Info::display(), QX11Info::appRootWindow(0),
857 ATOM(_QT_SETTINGS_TIMESTAMP), ATOM(_QT_SETTINGS_TIMESTAMP), 8,
858 PropModeReplace, (unsigned char *)stamp.data(), stamp.size());
859}
860
861/*! \internal
862 apply the settings to the application
863*/
864bool QApplicationPrivate::x11_apply_settings()
865{
866 QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
867
868 settings.beginGroup(QLatin1String("Qt"));
869
870 /*
871 Qt settings. This is now they are written into the datastream.
872
873 Palette / * - QPalette
874 font - QFont
875 libraryPath - QStringList
876 style - QString
877 doubleClickInterval - int
878 keyboardInputInterval - int
879 cursorFlashTime - int
880 wheelScrollLines - int
881 colorSpec - QString
882 defaultCodec - QString
883 globalStrut/width - int
884 globalStrut/height - int
885 GUIEffects - QStringList
886 Font Substitutions/ * - QStringList
887 Font Substitutions/... - QStringList
888 */
889
890 QStringList strlist;
891 int i;
892 QPalette pal(Qt::black);
893 int groupCount = 0;
894 strlist = settings.value(QLatin1String("Palette/active")).toStringList();
895 if (!strlist.isEmpty()) {
896 ++groupCount;
897 for (i = 0; i < qMin(strlist.count(), int(QPalette::NColorRoles)); i++)
898 pal.setColor(QPalette::Active, (QPalette::ColorRole) i,
899 QColor(strlist[i]));
900 }
901 strlist = settings.value(QLatin1String("Palette/inactive")).toStringList();
902 if (!strlist.isEmpty()) {
903 ++groupCount;
904 for (i = 0; i < qMin(strlist.count(), int(QPalette::NColorRoles)); i++)
905 pal.setColor(QPalette::Inactive, (QPalette::ColorRole) i,
906 QColor(strlist[i]));
907 }
908 strlist = settings.value(QLatin1String("Palette/disabled")).toStringList();
909 if (!strlist.isEmpty()) {
910 ++groupCount;
911 for (i = 0; i < qMin(strlist.count(), int(QPalette::NColorRoles)); i++)
912 pal.setColor(QPalette::Disabled, (QPalette::ColorRole) i,
913 QColor(strlist[i]));
914 }
915
916 // ### Fix properly for 4.6
917 bool usingGtkSettings = QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle");
918 if (!usingGtkSettings) {
919 if (groupCount == QPalette::NColorGroups)
920 QApplicationPrivate::setSystemPalette(pal);
921 }
922
923 if (!appFont) {
924 // ### Fix properly for 4.6
925 if (!usingGtkSettings) {
926 QFont font(QApplication::font());
927 QString fontDescription;
928 // Override Qt font if KDE4 settings can be used
929 if (X11->desktopVersion == 4) {
930 QSettings kdeSettings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat);
931 fontDescription = kdeSettings.value(QLatin1String("font")).toString();
932 if (fontDescription.isEmpty()) {
933 // KDE stores fonts without quotes
934 fontDescription = kdeSettings.value(QLatin1String("font")).toStringList().join(QLatin1String(","));
935 }
936 }
937 if (fontDescription.isEmpty())
938 fontDescription = settings.value(QLatin1String("font")).toString();
939 if (!fontDescription .isEmpty()) {
940 font.fromString(fontDescription );
941 QApplicationPrivate::setSystemFont(font);
942 }
943 }
944 }
945
946 // read library (ie. plugin) path list
947 QString libpathkey =
948 QString::fromLatin1("%1.%2/libraryPath")
949 .arg(QT_VERSION >> 16)
950 .arg((QT_VERSION & 0xff00) >> 8);
951 QStringList pathlist = settings.value(libpathkey).toString().split(QLatin1Char(':'));
952 if (! pathlist.isEmpty()) {
953 QStringList::ConstIterator it = pathlist.constBegin();
954 while (it != pathlist.constEnd())
955 QApplication::addLibraryPath(*it++);
956 }
957
958 // read new QStyle
959 QString stylename = settings.value(QLatin1String("style")).toString();
960
961 if (stylename.isEmpty() && QApplicationPrivate::styleOverride.isNull() && X11->use_xrender) {
962 stylename = qt_guiPlatformPlugin()->styleName();
963 }
964
965 static QString currentStyleName = stylename;
966 if (QCoreApplication::startingUp()) {
967 if (!stylename.isEmpty() && QApplicationPrivate::styleOverride.isNull())
968 QApplicationPrivate::styleOverride = stylename;
969 } else {
970 if (currentStyleName != stylename) {
971 currentStyleName = stylename;
972 QApplication::setStyle(stylename);
973 }
974 }
975
976 int num =
977 settings.value(QLatin1String("doubleClickInterval"),
978 QApplication::doubleClickInterval()).toInt();
979 QApplication::setDoubleClickInterval(num);
980
981 num =
982 settings.value(QLatin1String("cursorFlashTime"),
983 QApplication::cursorFlashTime()).toInt();
984 QApplication::setCursorFlashTime(num);
985
986#ifndef QT_NO_WHEELEVENT
987 num =
988 settings.value(QLatin1String("wheelScrollLines"),
989 QApplication::wheelScrollLines()).toInt();
990 QApplication::setWheelScrollLines(num);
991#endif
992
993 QString colorspec = settings.value(QLatin1String("colorSpec"),
994 QVariant(QLatin1String("default"))).toString();
995 if (colorspec == QLatin1String("normal"))
996 QApplication::setColorSpec(QApplication::NormalColor);
997 else if (colorspec == QLatin1String("custom"))
998 QApplication::setColorSpec(QApplication::CustomColor);
999 else if (colorspec == QLatin1String("many"))
1000 QApplication::setColorSpec(QApplication::ManyColor);
1001 else if (colorspec != QLatin1String("default"))
1002 colorspec = QLatin1String("default");
1003
1004 QString defaultcodec = settings.value(QLatin1String("defaultCodec"),
1005 QVariant(QLatin1String("none"))).toString();
1006 if (defaultcodec != QLatin1String("none")) {
1007 QTextCodec *codec = QTextCodec::codecForName(defaultcodec.toLatin1());
1008 if (codec)
1009 QTextCodec::setCodecForTr(codec);
1010 }
1011
1012 int w = settings.value(QLatin1String("globalStrut/width")).toInt();
1013 int h = settings.value(QLatin1String("globalStrut/height")).toInt();
1014 QSize strut(w, h);
1015 if (strut.isValid())
1016 QApplication::setGlobalStrut(strut);
1017
1018 QStringList effects = settings.value(QLatin1String("GUIEffects")).toStringList();
1019 QApplication::setEffectEnabled(Qt::UI_General,
1020 effects.contains(QLatin1String("general")));
1021 QApplication::setEffectEnabled(Qt::UI_AnimateMenu,
1022 effects.contains(QLatin1String("animatemenu")));
1023 QApplication::setEffectEnabled(Qt::UI_FadeMenu,
1024 effects.contains(QLatin1String("fademenu")));
1025 QApplication::setEffectEnabled(Qt::UI_AnimateCombo,
1026 effects.contains(QLatin1String("animatecombo")));
1027 QApplication::setEffectEnabled(Qt::UI_AnimateTooltip,
1028 effects.contains(QLatin1String("animatetooltip")));
1029 QApplication::setEffectEnabled(Qt::UI_FadeTooltip,
1030 effects.contains(QLatin1String("fadetooltip")));
1031 QApplication::setEffectEnabled(Qt::UI_AnimateToolBox,
1032 effects.contains(QLatin1String("animatetoolbox")));
1033
1034 if (!X11->has_fontconfig) {
1035 settings.beginGroup(QLatin1String("Font Substitutions"));
1036 QStringList fontsubs = settings.childKeys();
1037 if (!fontsubs.isEmpty()) {
1038 QStringList::Iterator it = fontsubs.begin();
1039 for (; it != fontsubs.end(); ++it) {
1040 QString fam = *it;
1041 QStringList subs = settings.value(fam).toStringList();
1042 QFont::insertSubstitutions(fam, subs);
1043 }
1044 }
1045 settings.endGroup();
1046 }
1047
1048 qt_use_rtl_extensions =
1049 settings.value(QLatin1String("useRtlExtensions"), false).toBool();
1050
1051#ifndef QT_NO_IM
1052#ifndef QT_NO_XIM
1053 if (qt_xim_preferred_style == 0) {
1054 QString ximInputStyle = settings.value(QLatin1String("XIMInputStyle"),
1055 QVariant(QLatin1String("on the spot"))).toString().toLower();
1056 if (ximInputStyle == QLatin1String("on the spot"))
1057 qt_xim_preferred_style = XIMPreeditCallbacks | XIMStatusNothing;
1058 else if (ximInputStyle == QLatin1String("over the spot"))
1059 qt_xim_preferred_style = XIMPreeditPosition | XIMStatusNothing;
1060 else if (ximInputStyle == QLatin1String("off the spot"))
1061 qt_xim_preferred_style = XIMPreeditArea | XIMStatusArea;
1062 else if (ximInputStyle == QLatin1String("root"))
1063 qt_xim_preferred_style = XIMPreeditNothing | XIMStatusNothing;
1064 }
1065#endif // QT_NO_XIM
1066 QStringList inputMethods = QInputContextFactory::keys();
1067 if (inputMethods.size() > 2 && inputMethods.contains(QLatin1String("imsw-multi"))) {
1068 X11->default_im = QLatin1String("imsw-multi");
1069 } else {
1070 X11->default_im = settings.value(QLatin1String("DefaultInputMethod"),
1071 QLatin1String("xim")).toString();
1072 }
1073#endif //QT_NO_IM
1074 settings.endGroup(); // Qt
1075
1076 return true;
1077}
1078
1079
1080/*! \internal
1081 Resets the QApplication::instance() pointer to zero
1082*/
1083void QApplicationPrivate::reset_instance_pointer()
1084{ QApplication::self = 0; }
1085
1086
1087// read the _QT_INPUT_ENCODING property and apply the settings to
1088// the application
1089static void qt_set_input_encoding()
1090{
1091 Atom type;
1092 int format;
1093 ulong nitems, after = 1;
1094 unsigned char *data = 0;
1095
1096 int e = XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
1097 ATOM(_QT_INPUT_ENCODING), 0, 1024,
1098 False, XA_STRING, &type, &format, &nitems,
1099 &after, &data);
1100 if (e != Success || !nitems || type == XNone) {
1101 // Always use the locale codec, since we have no examples of non-local
1102 // XIMs, and since we cannot get a sensible answer about the encoding
1103 // from the XIM.
1104 qt_input_mapper = QTextCodec::codecForLocale();
1105
1106 } else {
1107 if (!qstricmp((char *)data, "locale"))
1108 qt_input_mapper = QTextCodec::codecForLocale();
1109 else
1110 qt_input_mapper = QTextCodec::codecForName((char *)data);
1111 // make sure we have an input codec
1112 if(!qt_input_mapper)
1113 qt_input_mapper = QTextCodec::codecForName("ISO 8859-1");
1114 }
1115 if (qt_input_mapper && qt_input_mapper->mibEnum() == 11) // 8859-8
1116 qt_input_mapper = QTextCodec::codecForName("ISO 8859-8-I");
1117 if(data)
1118 XFree((char *)data);
1119}
1120
1121// set font, foreground and background from x11 resources. The
1122// arguments may override the resource settings.
1123static void qt_set_x11_resources(const char* font = 0, const char* fg = 0,
1124 const char* bg = 0, const char* button = 0)
1125{
1126
1127 QString resFont, resFG, resBG, resButton, resEF, sysFont, selectBackground, selectForeground;
1128
1129 QApplication::setEffectEnabled(Qt::UI_General, false);
1130 QApplication::setEffectEnabled(Qt::UI_AnimateMenu, false);
1131 QApplication::setEffectEnabled(Qt::UI_FadeMenu, false);
1132 QApplication::setEffectEnabled(Qt::UI_AnimateCombo, false);
1133 QApplication::setEffectEnabled(Qt::UI_AnimateTooltip, false);
1134 QApplication::setEffectEnabled(Qt::UI_FadeTooltip, false);
1135 QApplication::setEffectEnabled(Qt::UI_AnimateToolBox, false);
1136
1137 bool paletteAlreadySet = false;
1138 if (QApplication::desktopSettingsAware()) {
1139 // first, read from settings
1140 QApplicationPrivate::x11_apply_settings();
1141 // the call to QApplication::style() below creates the system
1142 // palette, which breaks the logic after the RESOURCE_MANAGER
1143 // loop... so I have to save this value to be able to use it later
1144 paletteAlreadySet = (QApplicationPrivate::sys_pal != 0);
1145
1146 // second, parse the RESOURCE_MANAGER property
1147 int format;
1148 ulong nitems, after = 1;
1149 QString res;
1150 long offset = 0;
1151 Atom type = XNone;
1152
1153 while (after > 0) {
1154 uchar *data = 0;
1155 if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(0),
1156 ATOM(RESOURCE_MANAGER),
1157 offset, 8192, False, AnyPropertyType,
1158 &type, &format, &nitems, &after,
1159 &data) != Success) {
1160 res = QString();
1161 break;
1162 }
1163 if (type == XA_STRING)
1164 res += QString::fromLatin1((char*)data);
1165 else
1166 res += QString::fromLocal8Bit((char*)data);
1167 offset += 2048; // offset is in 32bit quantities... 8192/4 == 2048
1168 if (data)
1169 XFree((char *)data);
1170 }
1171
1172 QString key, value;
1173 int l = 0, r;
1174 QString apn = QString::fromLocal8Bit(appName);
1175 QString apc = QString::fromLocal8Bit(appClass);
1176 int apnl = apn.length();
1177 int apcl = apc.length();
1178 int resl = res.length();
1179
1180 while (l < resl) {
1181 r = res.indexOf(QLatin1Char('\n'), l);
1182 if (r < 0)
1183 r = resl;
1184 while (res.at(l).isSpace())
1185 l++;
1186 bool mine = false;
1187 QChar sc = res.at(l + 1);
1188 if (res.at(l) == QLatin1Char('*') &&
1189 (sc == QLatin1Char('f') || sc == QLatin1Char('b') || sc == QLatin1Char('g') ||
1190 sc == QLatin1Char('F') || sc == QLatin1Char('B') || sc == QLatin1Char('G') ||
1191 sc == QLatin1Char('s') || sc == QLatin1Char('S')
1192 // capital T only, since we're looking for "Text.selectSomething"
1193 || sc == QLatin1Char('T'))) {
1194 // OPTIMIZED, since we only want "*[fbgsT].."
1195 QString item = res.mid(l, r - l).simplified();
1196 int i = item.indexOf(QLatin1Char(':'));
1197 key = item.left(i).trimmed().mid(1).toLower();
1198 value = item.right(item.length() - i - 1).trimmed();
1199 mine = true;
1200 } else if ((apnl && res.at(l) == apn.at(0)) || (appClass && apcl && res.at(l) == apc.at(0))) {
1201 if (res.mid(l,apnl) == apn && (res.at(l+apnl) == QLatin1Char('.')
1202 || res.at(l+apnl) == QLatin1Char('*'))) {
1203 QString item = res.mid(l, r - l).simplified();
1204 int i = item.indexOf(QLatin1Char(':'));
1205 key = item.left(i).trimmed().mid(apnl+1).toLower();
1206 value = item.right(item.length() - i - 1).trimmed();
1207 mine = true;
1208 } else if (res.mid(l,apcl) == apc && (res.at(l+apcl) == QLatin1Char('.')
1209 || res.at(l+apcl) == QLatin1Char('*'))) {
1210 QString item = res.mid(l, r - l).simplified();
1211 int i = item.indexOf(QLatin1Char(':'));
1212 key = item.left(i).trimmed().mid(apcl+1).toLower();
1213 value = item.right(item.length() - i - 1).trimmed();
1214 mine = true;
1215 }
1216 }
1217
1218 if (mine) {
1219 if (!font && key == QLatin1String("systemfont"))
1220 sysFont = value.left(value.lastIndexOf(QLatin1Char(':')));
1221 if (!font && key == QLatin1String("font"))
1222 resFont = value;
1223 else if (!fg && !paletteAlreadySet) {
1224 if (key == QLatin1String("foreground"))
1225 resFG = value;
1226 else if (!bg && key == QLatin1String("background"))
1227 resBG = value;
1228 else if (!bg && !button && key == QLatin1String("button.background"))
1229 resButton = value;
1230 else if (key == QLatin1String("text.selectbackground")) {
1231 selectBackground = value;
1232 } else if (key == QLatin1String("text.selectforeground")) {
1233 selectForeground = value;
1234 }
1235 } else if (key == QLatin1String("guieffects"))
1236 resEF = value;
1237 // NOTE: if you add more, change the [fbg] stuff above
1238 }
1239
1240 l = r + 1;
1241 }
1242 }
1243 if (!sysFont.isEmpty())
1244 resFont = sysFont;
1245 if (resFont.isEmpty())
1246 resFont = QString::fromLocal8Bit(font);
1247 if (resFG.isEmpty())
1248 resFG = QString::fromLocal8Bit(fg);
1249 if (resBG.isEmpty())
1250 resBG = QString::fromLocal8Bit(bg);
1251 if (resButton.isEmpty())
1252 resButton = QString::fromLocal8Bit(button);
1253 if (!resFont.isEmpty()
1254 && !X11->has_fontconfig
1255 && !QApplicationPrivate::sys_font) {
1256 // set application font
1257 QFont fnt;
1258 fnt.setRawName(resFont);
1259
1260 // the font we get may actually be an alias for another font,
1261 // so we reset the application font to the real font info.
1262 if (! fnt.exactMatch()) {
1263 QFontInfo fontinfo(fnt);
1264 fnt.setFamily(fontinfo.family());
1265 fnt.setRawMode(fontinfo.rawMode());
1266
1267 if (! fnt.rawMode()) {
1268 fnt.setItalic(fontinfo.italic());
1269 fnt.setWeight(fontinfo.weight());
1270 fnt.setUnderline(fontinfo.underline());
1271 fnt.setStrikeOut(fontinfo.strikeOut());
1272 fnt.setStyleHint(fontinfo.styleHint());
1273
1274 if (fnt.pointSize() <= 0 && fnt.pixelSize() <= 0) {
1275 // size is all wrong... fix it
1276 qreal pointSize = fontinfo.pixelSize() * 72. / (float) QX11Info::appDpiY();
1277 if (pointSize <= 0)
1278 pointSize = 12;
1279 fnt.setPointSize(qRound(pointSize));
1280 }
1281 }
1282 }
1283
1284 QApplicationPrivate::setSystemFont(fnt);
1285 }
1286 // QGtkStyle sets it's own system palette
1287 bool gtkStyle = QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle");
1288 bool kdeColors = (QApplication::desktopSettingsAware() && X11->desktopEnvironment == DE_KDE);
1289 if (!gtkStyle && (kdeColors || (button || !resBG.isEmpty() || !resFG.isEmpty()))) {// set app colors
1290 bool allowX11ColorNames = QColor::allowX11ColorNames();
1291 QColor::setAllowX11ColorNames(true);
1292
1293 (void) QApplication::style(); // trigger creation of application style and system palettes
1294 QColor btn;
1295 QColor bg;
1296 QColor fg;
1297 QColor bfg;
1298 QColor wfg;
1299 if (!resBG.isEmpty())
1300 bg = QColor(resBG);
1301 if (!bg.isValid())
1302 bg = QApplicationPrivate::sys_pal->color(QPalette::Active, QPalette::Window);
1303
1304 if (!resFG.isEmpty())
1305 fg = QColor(resFG);
1306 if (!fg.isValid())
1307 fg = QApplicationPrivate::sys_pal->color(QPalette::Active, QPalette::WindowText);
1308
1309 if (!resButton.isEmpty())
1310 btn = QColor(resButton);
1311 else if (!resBG.isEmpty())
1312 btn = bg;
1313 if (!btn.isValid())
1314 btn = QApplicationPrivate::sys_pal->color(QPalette::Active, QPalette::Button);
1315
1316 int h,s,v;
1317 fg.getHsv(&h,&s,&v);
1318 QColor base = Qt::white;
1319 bool bright_mode = false;
1320 if (v >= 255 - 50) {
1321 base = btn.darker(150);
1322 bright_mode = true;
1323 }
1324
1325 QPalette pal(fg, btn, btn.lighter(125), btn.darker(130), btn.darker(120), wfg.isValid() ? wfg : fg, Qt::white, base, bg);
1326 QColor disabled((fg.red() + btn.red()) / 2,
1327 (fg.green() + btn.green())/ 2,
1328 (fg.blue() + btn.blue()) / 2);
1329 pal.setColorGroup(QPalette::Disabled, disabled, btn, btn.lighter(125),
1330 btn.darker(130), btn.darker(150), disabled, Qt::white, Qt::white, bg);
1331
1332 QColor highlight, highlightText;
1333 if (!selectBackground.isEmpty() && !selectForeground.isEmpty()) {
1334 highlight = QColor(selectBackground);
1335 highlightText = QColor(selectForeground);
1336 }
1337
1338 if (highlight.isValid() && highlightText.isValid()) {
1339 pal.setColor(QPalette::Highlight, highlight);
1340 pal.setColor(QPalette::HighlightedText, highlightText);
1341
1342 // calculate disabled colors by removing saturation
1343 highlight.setHsv(highlight.hue(), 0, highlight.value(), highlight.alpha());
1344 highlightText.setHsv(highlightText.hue(), 0, highlightText.value(), highlightText.alpha());
1345 pal.setColor(QPalette::Disabled, QPalette::Highlight, highlight);
1346 pal.setColor(QPalette::Disabled, QPalette::HighlightedText, highlightText);
1347 } else if (bright_mode) {
1348 pal.setColor(QPalette::HighlightedText, base);
1349 pal.setColor(QPalette::Highlight, Qt::white);
1350 pal.setColor(QPalette::Disabled, QPalette::HighlightedText, base);
1351 pal.setColor(QPalette::Disabled, QPalette::Highlight, Qt::white);
1352 } else {
1353 pal.setColor(QPalette::HighlightedText, Qt::white);
1354 pal.setColor(QPalette::Highlight, Qt::darkBlue);
1355 pal.setColor(QPalette::Disabled, QPalette::HighlightedText, Qt::white);
1356 pal.setColor(QPalette::Disabled, QPalette::Highlight, Qt::darkBlue);
1357 }
1358
1359 pal = qt_guiPlatformPlugin()->palette().resolve(pal);
1360 QApplicationPrivate::setSystemPalette(pal);
1361 QColor::setAllowX11ColorNames(allowX11ColorNames);
1362 }
1363
1364 if (!resEF.isEmpty()) {
1365 QStringList effects = resEF.split(QLatin1Char(' '));
1366 QApplication::setEffectEnabled(Qt::UI_General, effects.contains(QLatin1String("general")));
1367 QApplication::setEffectEnabled(Qt::UI_AnimateMenu,
1368 effects.contains(QLatin1String("animatemenu")));
1369 QApplication::setEffectEnabled(Qt::UI_FadeMenu,
1370 effects.contains(QLatin1String("fademenu")));
1371 QApplication::setEffectEnabled(Qt::UI_AnimateCombo,
1372 effects.contains(QLatin1String("animatecombo")));
1373 QApplication::setEffectEnabled(Qt::UI_AnimateTooltip,
1374 effects.contains(QLatin1String("animatetooltip")));
1375 QApplication::setEffectEnabled(Qt::UI_FadeTooltip,
1376 effects.contains(QLatin1String("fadetooltip")));
1377 QApplication::setEffectEnabled(Qt::UI_AnimateToolBox,
1378 effects.contains(QLatin1String("animatetoolbox")));
1379 }
1380
1381 QIconLoader::instance()->updateSystemTheme();
1382}
1383
1384
1385// update the supported array
1386static void qt_get_net_supported()
1387{
1388 Atom type;
1389 int format;
1390 long offset = 0;
1391 unsigned long nitems, after;
1392 unsigned char *data = 0;
1393
1394 int e = XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
1395 ATOM(_NET_SUPPORTED), 0, 0,
1396 False, XA_ATOM, &type, &format, &nitems, &after, &data);
1397 if (data)
1398 XFree(data);
1399
1400 if (X11->net_supported_list)
1401 delete [] X11->net_supported_list;
1402 X11->net_supported_list = 0;
1403
1404 if (e == Success && type == XA_ATOM && format == 32) {
1405 QBuffer ts;
1406 ts.open(QIODevice::WriteOnly);
1407
1408 while (after > 0) {
1409 XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
1410 ATOM(_NET_SUPPORTED), offset, 1024,
1411 False, XA_ATOM, &type, &format, &nitems, &after, &data);
1412
1413 if (type == XA_ATOM && format == 32) {
1414 ts.write(reinterpret_cast<char *>(data), nitems * sizeof(long));
1415 offset += nitems;
1416 } else
1417 after = 0;
1418 if (data)
1419 XFree(data);
1420 }
1421
1422 // compute nitems
1423 QByteArray buffer(ts.buffer());
1424 nitems = buffer.size() / sizeof(Atom);
1425 X11->net_supported_list = new Atom[nitems + 1];
1426 Atom *a = (Atom *) buffer.data();
1427 uint i;
1428 for (i = 0; i < nitems; i++)
1429 X11->net_supported_list[i] = a[i];
1430 X11->net_supported_list[nitems] = 0;
1431 }
1432}
1433
1434
1435bool QX11Data::isSupportedByWM(Atom atom)
1436{
1437 if (!X11->net_supported_list)
1438 return false;
1439
1440 bool supported = false;
1441 int i = 0;
1442 while (X11->net_supported_list[i] != 0) {
1443 if (X11->net_supported_list[i++] == atom) {
1444 supported = true;
1445 break;
1446 }
1447 }
1448
1449 return supported;
1450}
1451
1452
1453// update the virtual roots array
1454static void qt_get_net_virtual_roots()
1455{
1456 if (X11->net_virtual_root_list)
1457 delete [] X11->net_virtual_root_list;
1458 X11->net_virtual_root_list = 0;
1459
1460 if (!X11->isSupportedByWM(ATOM(_NET_VIRTUAL_ROOTS)))
1461 return;
1462
1463 Atom type;
1464 int format;
1465 long offset = 0;
1466 unsigned long nitems, after;
1467 unsigned char *data;
1468
1469 int e = XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
1470 ATOM(_NET_VIRTUAL_ROOTS), 0, 0,
1471 False, XA_ATOM, &type, &format, &nitems, &after, &data);
1472 if (data)
1473 XFree(data);
1474
1475 if (e == Success && type == XA_ATOM && format == 32) {
1476 QBuffer ts;
1477 ts.open(QIODevice::WriteOnly);
1478
1479 while (after > 0) {
1480 XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
1481 ATOM(_NET_VIRTUAL_ROOTS), offset, 1024,
1482 False, XA_ATOM, &type, &format, &nitems, &after, &data);
1483
1484 if (type == XA_ATOM && format == 32) {
1485 ts.write(reinterpret_cast<char *>(data), nitems * 4);
1486 offset += nitems;
1487 } else
1488 after = 0;
1489 if (data)
1490 XFree(data);
1491 }
1492
1493 // compute nitems
1494 QByteArray buffer(ts.buffer());
1495 nitems = buffer.size() / sizeof(Window);
1496 X11->net_virtual_root_list = new Window[nitems + 1];
1497 Window *a = (Window *) buffer.data();
1498 uint i;
1499 for (i = 0; i < nitems; i++)
1500 X11->net_virtual_root_list[i] = a[i];
1501 X11->net_virtual_root_list[nitems] = 0;
1502 }
1503}
1504
1505void qt_net_remove_user_time(QWidget *tlw)
1506{
1507 Q_ASSERT(tlw);
1508 QTLWExtra *extra = tlw->d_func()->maybeTopData();
1509 if (extra && extra->userTimeWindow) {
1510 Q_ASSERT(tlw->internalWinId());
1511 XDeleteProperty(X11->display, tlw->internalWinId(), ATOM(_NET_WM_USER_TIME_WINDOW));
1512 XDestroyWindow(X11->display, extra->userTimeWindow);
1513 extra->userTimeWindow = 0;
1514 }
1515}
1516
1517void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp)
1518{
1519 Q_ASSERT(tlw);
1520 Q_ASSERT(tlw->isWindow());
1521 Q_ASSERT(tlw->testAttribute(Qt::WA_WState_Created));
1522 QTLWExtra *extra = tlw->d_func()->topData();
1523 WId wid = tlw->internalWinId();
1524 const bool isSupportedByWM = X11->isSupportedByWM(ATOM(_NET_WM_USER_TIME_WINDOW));
1525 if (extra->userTimeWindow || isSupportedByWM) {
1526 if (!extra->userTimeWindow) {
1527 extra->userTimeWindow = XCreateSimpleWindow(X11->display,
1528 tlw->internalWinId(),
1529 -1, -1, 1, 1, 0, 0, 0);
1530 wid = extra->userTimeWindow;
1531 XChangeProperty(X11->display, tlw->internalWinId(), ATOM(_NET_WM_USER_TIME_WINDOW),
1532 XA_WINDOW, 32, PropModeReplace,
1533 (unsigned char *)&wid, 1);
1534 XDeleteProperty(X11->display, tlw->internalWinId(), ATOM(_NET_WM_USER_TIME));
1535 } else if (!isSupportedByWM) {
1536 // WM no longer supports it, then we should remove the
1537 // _NET_WM_USER_TIME_WINDOW atom.
1538 qt_net_remove_user_time(tlw);
1539 } else {
1540 wid = extra->userTimeWindow;
1541 }
1542 }
1543 XChangeProperty(X11->display, wid, ATOM(_NET_WM_USER_TIME),
1544 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &timestamp, 1);
1545}
1546
1547static void qt_check_focus_model()
1548{
1549 Window fw = XNone;
1550 int unused;
1551 XGetInputFocus(X11->display, &fw, &unused);
1552 if (fw == PointerRoot)
1553 X11->focus_model = QX11Data::FM_PointerRoot;
1554 else
1555 X11->focus_model = QX11Data::FM_Other;
1556}
1557
1558#ifndef QT_NO_TABLET
1559
1560#if !defined (Q_OS_IRIX)
1561// from include/Xwacom.h
1562# define XWACOM_PARAM_TOOLID 322
1563# define XWACOM_PARAM_TOOLSERIAL 323
1564
1565typedef WACOMCONFIG * (*PtrWacomConfigInit) (Display*, WACOMERRORFUNC);
1566typedef WACOMDEVICE * (*PtrWacomConfigOpenDevice) (WACOMCONFIG*, const char*);
1567typedef int *(*PtrWacomConfigGetRawParam) (WACOMDEVICE*, int, int*, int, unsigned*);
1568typedef int (*PtrWacomConfigCloseDevice) (WACOMDEVICE *);
1569typedef void (*PtrWacomConfigTerm) (WACOMCONFIG *);
1570
1571static PtrWacomConfigInit ptrWacomConfigInit = 0;
1572static PtrWacomConfigOpenDevice ptrWacomConfigOpenDevice = 0;
1573static PtrWacomConfigGetRawParam ptrWacomConfigGetRawParam = 0;
1574static PtrWacomConfigCloseDevice ptrWacomConfigCloseDevice = 0;
1575static PtrWacomConfigTerm ptrWacomConfigTerm = 0;
1576Q_GLOBAL_STATIC(QByteArray, wacomDeviceName)
1577#endif
1578
1579#endif
1580
1581/*****************************************************************************
1582 qt_init() - initializes Qt for X11
1583 *****************************************************************************/
1584
1585#if !defined(QT_NO_FONTCONFIG)
1586static void getXDefault(const char *group, const char *key, int *val)
1587{
1588 char *str = XGetDefault(X11->display, group, key);
1589 if (str) {
1590 char *end = 0;
1591 int v = strtol(str, &end, 0);
1592 if (str != end)
1593 *val = v;
1594 // otherwise use fontconfig to convert the string to integer
1595 else
1596 FcNameConstant((FcChar8 *) str, val);
1597 }
1598}
1599
1600static void getXDefault(const char *group, const char *key, double *val)
1601{
1602 char *str = XGetDefault(X11->display, group, key);
1603 if (str) {
1604 bool ok;
1605 double v = QByteArray(str).toDouble(&ok);
1606 if (ok)
1607 *val = v;
1608 }
1609}
1610
1611static void getXDefault(const char *group, const char *key, bool *val)
1612{
1613 char *str = XGetDefault(X11->display, group, key);
1614 if (str) {
1615 char c = str[0];
1616 if (isupper((int)c))
1617 c = tolower(c);
1618 if (c == 't' || c == 'y' || c == '1')
1619 *val = true;
1620 else if (c == 'f' || c == 'n' || c == '0')
1621 *val = false;
1622 if (c == 'o') {
1623 c = str[1];
1624 if (isupper((int)c))
1625 c = tolower(c);
1626 if (c == 'n')
1627 *val = true;
1628 if (c == 'f')
1629 *val = false;
1630 }
1631 }
1632}
1633#endif
1634
1635#if defined(QT_DEBUG) && defined(Q_OS_LINUX)
1636// Find out if our parent process is gdb by looking at the 'exe' symlink under /proc,.
1637// or, for older Linuxes, read out 'cmdline'.
1638bool runningUnderDebugger()
1639{
1640 const QString parentProc = QLatin1String("/proc/") + QString::number(getppid());
1641 const QFileInfo parentProcExe(parentProc + QLatin1String("/exe"));
1642 if (parentProcExe.isSymLink())
1643 return parentProcExe.symLinkTarget().endsWith(QLatin1String("/gdb"));
1644 QFile f(parentProc + QLatin1String("/cmdline"));
1645 if (!f.open(QIODevice::ReadOnly))
1646 return false;
1647 QByteArray s;
1648 char c;
1649 while (f.getChar(&c) && c) {
1650 if (c == '/')
1651 s.clear();
1652 else
1653 s += c;
1654 }
1655 return s == "gdb";
1656}
1657#endif
1658
1659// ### This should be static but it isn't because of the friend declaration
1660// ### in qpaintdevice.h which then should have a static too but can't have
1661// ### it because "storage class specifiers invalid in friend function
1662// ### declarations" :-) Ideas anyone?
1663void qt_init(QApplicationPrivate *priv, int,
1664 Display *display, Qt::HANDLE visual, Qt::HANDLE colormap)
1665{
1666 X11 = new QX11Data;
1667 X11->display = display;
1668 X11->displayName = 0;
1669 X11->foreignDisplay = (display != 0);
1670 X11->focus_model = -1;
1671
1672 // RANDR
1673 X11->use_xrandr = false;
1674 X11->xrandr_major = 0;
1675 X11->xrandr_eventbase = 0;
1676 X11->xrandr_errorbase = 0;
1677
1678 // RENDER
1679 X11->use_xrender = false;
1680 X11->xrender_major = 0;
1681 X11->xrender_version = 0;
1682
1683 // XFIXES
1684 X11->use_xfixes = false;
1685 X11->xfixes_major = 0;
1686 X11->xfixes_eventbase = 0;
1687 X11->xfixes_errorbase = 0;
1688
1689 // XInputExtension
1690 X11->use_xinput = false;
1691 X11->xinput_major = 0;
1692 X11->xinput_eventbase = 0;
1693 X11->xinput_errorbase = 0;
1694
1695 X11->use_xkb = false;
1696 X11->xkb_major = 0;
1697 X11->xkb_eventbase = 0;
1698 X11->xkb_errorbase = 0;
1699
1700 // MIT-SHM
1701 X11->use_mitshm = false;
1702 X11->use_mitshm_pixmaps = false;
1703 X11->mitshm_major = 0;
1704
1705 X11->sip_serial = 0;
1706 X11->net_supported_list = 0;
1707 X11->net_virtual_root_list = 0;
1708 X11->wm_client_leader = 0;
1709 X11->screens = 0;
1710 X11->argbVisuals = 0;
1711 X11->argbColormaps = 0;
1712 X11->screenCount = 0;
1713 X11->time = CurrentTime;
1714 X11->userTime = CurrentTime;
1715 X11->ignore_badwindow = false;
1716 X11->seen_badwindow = false;
1717
1718 X11->motifdnd_active = false;
1719
1720 X11->default_im = QLatin1String("imsw-multi");
1721 priv->inputContext = 0;
1722
1723 // colormap control
1724 X11->visual_class = -1;
1725 X11->visual_id = -1;
1726 X11->color_count = 0;
1727 X11->custom_cmap = false;
1728
1729 // outside visual/colormap
1730 X11->visual = reinterpret_cast<Visual *>(visual);
1731 X11->colormap = colormap;
1732
1733 // Fontconfig
1734 X11->has_fontconfig = false;
1735#if !defined(QT_NO_FONTCONFIG)
1736 if (qgetenv("QT_X11_NO_FONTCONFIG").isNull())
1737 X11->has_fontconfig = FcInit();
1738 X11->fc_antialias = true;
1739#endif
1740
1741#ifndef QT_NO_XRENDER
1742 memset(X11->solid_fills, 0, sizeof(X11->solid_fills));
1743 for (int i = 0; i < X11->solid_fill_count; ++i)
1744 X11->solid_fills[i].screen = -1;
1745 memset(X11->pattern_fills, 0, sizeof(X11->pattern_fills));
1746 for (int i = 0; i < X11->pattern_fill_count; ++i)
1747 X11->pattern_fills[i].screen = -1;
1748#endif
1749
1750 X11->startupId = 0;
1751
1752 int argc = priv->argc;
1753 char **argv = priv->argv;
1754
1755 if (X11->display) {
1756 // Qt part of other application
1757
1758 // Set application name and class
1759 appName = qstrdup("Qt-subapplication");
1760 char *app_class = 0;
1761 if (argv) {
1762 const char* p = strrchr(argv[0], '/');
1763 app_class = qstrdup(p ? p + 1 : argv[0]);
1764 if (app_class[0])
1765 app_class[0] = toupper(app_class[0]);
1766 }
1767 appClass = app_class;
1768 } else {
1769 // Qt controls everything (default)
1770
1771 if (QApplication::testAttribute(Qt::AA_X11InitThreads))
1772 XInitThreads();
1773
1774 // Set application name and class
1775 char *app_class = 0;
1776 if (argv && argv[0]) {
1777 const char *p = strrchr(argv[0], '/');
1778 appName = p ? p + 1 : argv[0];
1779 app_class = qstrdup(appName);
1780 if (app_class[0])
1781 app_class[0] = toupper(app_class[0]);
1782 }
1783 appClass = app_class;
1784 }
1785
1786 // Install default error handlers
1787 original_x_errhandler = XSetErrorHandler(qt_x_errhandler);
1788 original_xio_errhandler = XSetIOErrorHandler(qt_xio_errhandler);
1789
1790 // Get command line params
1791 int j = argc ? 1 : 0;
1792 for (int i=1; i<argc; i++) {
1793 if (argv[i] && *argv[i] != '-') {
1794 argv[j++] = argv[i];
1795 continue;
1796 }
1797 QByteArray arg(argv[i]);
1798 if (arg == "-display") {
1799 if (++i < argc && !X11->display)
1800 X11->displayName = argv[i];
1801 } else if (arg == "-fn" || arg == "-font") {
1802 if (++i < argc)
1803 appFont = argv[i];
1804 } else if (arg == "-bg" || arg == "-background") {
1805 if (++i < argc)
1806 appBGCol = argv[i];
1807 } else if (arg == "-btn" || arg == "-button") {
1808 if (++i < argc)
1809 appBTNCol = argv[i];
1810 } else if (arg == "-fg" || arg == "-foreground") {
1811 if (++i < argc)
1812 appFGCol = argv[i];
1813 } else if (arg == "-name") {
1814 if (++i < argc)
1815 appName = argv[i];
1816 } else if (arg == "-title") {
1817 if (++i < argc)
1818 mwTitle = argv[i];
1819 } else if (arg == "-geometry") {
1820 if (++i < argc)
1821 mwGeometry = argv[i];
1822 } else if (arg == "-im") {
1823 if (++i < argc)
1824 qt_ximServer = argv[i];
1825 } else if (arg == "-ncols") { // xv and netscape use this name
1826 if (++i < argc)
1827 X11->color_count = qMax(0,atoi(argv[i]));
1828 } else if (arg == "-visual") { // xv and netscape use this name
1829 if (++i < argc && !X11->visual) {
1830 QString s = QString::fromLocal8Bit(argv[i]).toLower();
1831 if (s == QLatin1String("staticgray"))
1832 X11->visual_class = StaticGray;
1833 else if (s == QLatin1String("grayscale"))
1834 X11->visual_class = XGrayScale;
1835 else if (s == QLatin1String("staticcolor"))
1836 X11->visual_class = StaticColor;
1837 else if (s == QLatin1String("pseudocolor"))
1838 X11->visual_class = PseudoColor;
1839 else if (s == QLatin1String("truecolor"))
1840 X11->visual_class = TrueColor;
1841 else if (s == QLatin1String("directcolor"))
1842 X11->visual_class = DirectColor;
1843 else
1844 X11->visual_id = static_cast<int>(strtol(argv[i], 0, 0));
1845 }
1846#ifndef QT_NO_XIM
1847 } else if (arg == "-inputstyle") {
1848 if (++i < argc) {
1849 QString s = QString::fromLocal8Bit(argv[i]).toLower();
1850 if (s == QLatin1String("onthespot"))
1851 qt_xim_preferred_style = XIMPreeditCallbacks |
1852 XIMStatusNothing;
1853 else if (s == QLatin1String("overthespot"))
1854 qt_xim_preferred_style = XIMPreeditPosition |
1855 XIMStatusNothing;
1856 else if (s == QLatin1String("offthespot"))
1857 qt_xim_preferred_style = XIMPreeditArea |
1858 XIMStatusArea;
1859 else if (s == QLatin1String("root"))
1860 qt_xim_preferred_style = XIMPreeditNothing |
1861 XIMStatusNothing;
1862 }
1863#endif
1864 } else if (arg == "-cmap") { // xv uses this name
1865 if (!X11->colormap)
1866 X11->custom_cmap = true;
1867 }
1868 else if (arg == "-sync")
1869 appSync = !appSync;
1870#if defined(QT_DEBUG)
1871 else if (arg == "-nograb")
1872 appNoGrab = !appNoGrab;
1873 else if (arg == "-dograb")
1874 appDoGrab = !appDoGrab;
1875#endif
1876 else
1877 argv[j++] = argv[i];
1878 }
1879
1880 priv->argc = j;
1881
1882#if defined(QT_DEBUG) && defined(Q_OS_LINUX)
1883 if (!appNoGrab && !appDoGrab && runningUnderDebugger()) {
1884 appNoGrab = true;
1885 qDebug("Qt: gdb: -nograb added to command-line options.\n"
1886 "\t Use the -dograb option to enforce grabbing.");
1887 }
1888#endif
1889
1890 // Connect to X server
1891 if (qt_is_gui_used && !X11->display) {
1892 if ((X11->display = XOpenDisplay(X11->displayName)) == 0) {
1893 qWarning("%s: cannot connect to X server %s", appName,
1894 XDisplayName(X11->displayName));
1895 QApplicationPrivate::reset_instance_pointer();
1896 exit(1);
1897 }
1898
1899 if (appSync) // if "-sync" argument
1900 XSynchronize(X11->display, true);
1901 }
1902
1903 // Common code, regardless of whether display is foreign.
1904
1905 // Get X parameters
1906
1907 if (qt_is_gui_used) {
1908 X11->defaultScreen = DefaultScreen(X11->display);
1909 X11->screenCount = ScreenCount(X11->display);
1910
1911 int formatCount = 0;
1912 XPixmapFormatValues *values = XListPixmapFormats(X11->display, &formatCount);
1913 for (int i = 0; i < formatCount; ++i)
1914 X11->bppForDepth[values[i].depth] = values[i].bits_per_pixel;
1915 XFree(values);
1916
1917 X11->screens = new QX11InfoData[X11->screenCount];
1918 X11->argbVisuals = new Visual *[X11->screenCount];
1919 X11->argbColormaps = new Colormap[X11->screenCount];
1920
1921 for (int s = 0; s < X11->screenCount; s++) {
1922 QX11InfoData *screen = X11->screens + s;
1923 screen->ref = 1; // ensures it doesn't get deleted
1924 screen->screen = s;
1925
1926 int widthMM = DisplayWidthMM(X11->display, s);
1927 if (widthMM != 0) {
1928 screen->dpiX = (DisplayWidth(X11->display, s) * 254 + widthMM * 5) / (widthMM * 10);
1929 } else {
1930 screen->dpiX = 72;
1931 }
1932
1933 int heightMM = DisplayHeightMM(X11->display, s);
1934 if (heightMM != 0) {
1935 screen->dpiY = (DisplayHeight(X11->display, s) * 254 + heightMM * 5) / (heightMM * 10);
1936 } else {
1937 screen->dpiY = 72;
1938 }
1939
1940 X11->argbVisuals[s] = 0;
1941 X11->argbColormaps[s] = 0;
1942 }
1943
1944
1945#ifndef QT_NO_XRENDER
1946 int xrender_eventbase, xrender_errorbase;
1947 // See if XRender is supported on the connected display
1948 if (XQueryExtension(X11->display, "RENDER", &X11->xrender_major,
1949 &xrender_eventbase, &xrender_errorbase)
1950 && XRenderQueryExtension(X11->display, &xrender_eventbase,
1951 &xrender_errorbase)) {
1952 // Check the version as well - we need v0.4 or higher
1953 int major = 0;
1954 int minor = 0;
1955 XRenderQueryVersion(X11->display, &major, &minor);
1956 if (qgetenv("QT_X11_NO_XRENDER").isNull()) {
1957 X11->use_xrender = (major >= 0 && minor >= 5);
1958 X11->xrender_version = major*100+minor;
1959 // workaround for broken XServer on Ubuntu Breezy (6.8 compiled with 7.0
1960 // protocol headers)
1961 if (X11->xrender_version == 10
1962 && VendorRelease(X11->display) < 60900000
1963 && QByteArray(ServerVendor(X11->display)).contains("X.Org"))
1964 X11->xrender_version = 9;
1965 }
1966 }
1967#endif // QT_NO_XRENDER
1968
1969#ifndef QT_NO_MITSHM
1970 int mitshm_minor;
1971 int mitshm_major;
1972 int mitshm_eventbase;
1973 int mitshm_errorbase;
1974 int mitshm_pixmaps;
1975 if (XQueryExtension(X11->display, "MIT-SHM", &X11->mitshm_major,
1976 &mitshm_eventbase, &mitshm_errorbase)
1977 && XShmQueryVersion(X11->display, &mitshm_major, &mitshm_minor,
1978 &mitshm_pixmaps))
1979 {
1980 QString displayName = QLatin1String(XDisplayName(NULL));
1981
1982 // MITSHM only works for local displays, so do a quick check here
1983 // to determine whether the display is local or not (not 100 % accurate).
1984 // BGR server layouts are not supported either, since it requires the raster
1985 // engine to work on a QImage with BGR layout.
1986 bool local = displayName.isEmpty() || displayName.lastIndexOf(QLatin1Char(':')) == 0;
1987 if (local && (qgetenv("QT_X11_NO_MITSHM").toInt() == 0)) {
1988 Visual *defaultVisual = DefaultVisual(X11->display, DefaultScreen(X11->display));
1989 X11->use_mitshm = ((defaultVisual->red_mask == 0xff0000
1990 || defaultVisual->red_mask == 0xf800)
1991 && (defaultVisual->green_mask == 0xff00
1992 || defaultVisual->green_mask == 0x7e0)
1993 && (defaultVisual->blue_mask == 0xff
1994 || defaultVisual->blue_mask == 0x1f));
1995 X11->use_mitshm_pixmaps = X11->use_mitshm && mitshm_pixmaps;
1996 }
1997 }
1998#endif // QT_NO_MITSHM
1999
2000 // initialize the graphics system - order is imporant here - it must be done before
2001 // the QColormap::initialize() call
2002 QApplicationPrivate::graphics_system = QGraphicsSystemFactory::create(QApplicationPrivate::graphics_system_name);
2003 QColormap::initialize();
2004
2005 // Support protocols
2006 X11->xdndSetup();
2007
2008 // Finally create all atoms
2009 qt_x11_create_intern_atoms();
2010
2011 // initialize NET lists
2012 qt_get_net_supported();
2013 qt_get_net_virtual_roots();
2014
2015#ifndef QT_NO_XRANDR
2016 // See if XRandR is supported on the connected display
2017 if (XQueryExtension(X11->display, "RANDR", &X11->xrandr_major,
2018 &X11->xrandr_eventbase, &X11->xrandr_errorbase)) {
2019
2020# ifdef QT_RUNTIME_XRANDR
2021 X11->ptrXRRSelectInput = 0;
2022 X11->ptrXRRUpdateConfiguration = 0;
2023 X11->ptrXRRRootToScreen = 0;
2024 X11->ptrXRRQueryExtension = 0;
2025 QLibrary xrandrLib(QLatin1String("Xrandr"), 2);
2026 xrandrLib.setLoadHints(QLibrary::ImprovedSearchHeuristics);
2027 if (!xrandrLib.load()) { // try without the version number
2028 xrandrLib.setFileName(QLatin1String("Xrandr"));
2029 xrandrLib.load();
2030 }
2031 if (xrandrLib.isLoaded()) {
2032 X11->ptrXRRSelectInput =
2033 (PtrXRRSelectInput) xrandrLib.resolve("XRRSelectInput");
2034 X11->ptrXRRUpdateConfiguration =
2035 (PtrXRRUpdateConfiguration) xrandrLib.resolve("XRRUpdateConfiguration");
2036 X11->ptrXRRRootToScreen =
2037 (PtrXRRRootToScreen) xrandrLib.resolve("XRRRootToScreen");
2038 X11->ptrXRRQueryExtension =
2039 (PtrXRRQueryExtension) xrandrLib.resolve("XRRQueryExtension");
2040 }
2041# else
2042 X11->ptrXRRSelectInput = XRRSelectInput;
2043 X11->ptrXRRUpdateConfiguration = XRRUpdateConfiguration;
2044 X11->ptrXRRRootToScreen = XRRRootToScreen;
2045 X11->ptrXRRQueryExtension = XRRQueryExtension;
2046# endif
2047
2048 if (X11->ptrXRRQueryExtension
2049 && X11->ptrXRRQueryExtension(X11->display, &X11->xrandr_eventbase, &X11->xrandr_errorbase)) {
2050 // XRandR is supported
2051 X11->use_xrandr = true;
2052 }
2053 }
2054#endif // QT_NO_XRANDR
2055
2056#ifndef QT_NO_XRENDER
2057 if (X11->use_xrender) {
2058 // XRender is supported, let's see if we have a PictFormat for the
2059 // default visual
2060 XRenderPictFormat *format =
2061 XRenderFindVisualFormat(X11->display,
2062 (Visual *) QX11Info::appVisual(X11->defaultScreen));
2063
2064 if (!format) {
2065 X11->use_xrender = false;
2066 }
2067 }
2068#endif // QT_NO_XRENDER
2069
2070#ifndef QT_NO_XFIXES
2071 // See if Xfixes is supported on the connected display
2072 if (XQueryExtension(X11->display, "XFIXES", &X11->xfixes_major,
2073 &X11->xfixes_eventbase, &X11->xfixes_errorbase)) {
2074 X11->ptrXFixesQueryExtension = XFIXES_LOAD_V1(XFixesQueryExtension);
2075 X11->ptrXFixesQueryVersion = XFIXES_LOAD_V1(XFixesQueryVersion);
2076 X11->ptrXFixesSetCursorName = XFIXES_LOAD_V2(XFixesSetCursorName);
2077 X11->ptrXFixesSelectSelectionInput = XFIXES_LOAD_V2(XFixesSelectSelectionInput);
2078
2079 if(X11->ptrXFixesQueryExtension && X11->ptrXFixesQueryVersion
2080 && X11->ptrXFixesQueryExtension(X11->display, &X11->xfixes_eventbase,
2081 &X11->xfixes_errorbase)) {
2082 // Xfixes is supported.
2083 // Note: the XFixes protocol version is negotiated using QueryVersion.
2084 // We supply the highest version we support, the X server replies with
2085 // the highest version it supports, but no higher than the version we
2086 // asked for. The version sent back is the protocol version the X server
2087 // will use to talk us. If this call is removed, the behavior of the
2088 // X server when it receives an XFixes request is undefined.
2089 int major = 3;
2090 int minor = 0;
2091 X11->ptrXFixesQueryVersion(X11->display, &major, &minor);
2092 X11->use_xfixes = (major >= 1);
2093 X11->xfixes_major = major;
2094 }
2095 } else {
2096 X11->ptrXFixesQueryExtension = 0;
2097 X11->ptrXFixesQueryVersion = 0;
2098 X11->ptrXFixesSetCursorName = 0;
2099 X11->ptrXFixesSelectSelectionInput = 0;
2100 }
2101#endif // QT_NO_XFIXES
2102
2103#ifndef QT_NO_XCURSOR
2104#ifdef QT_RUNTIME_XCURSOR
2105 X11->ptrXcursorLibraryLoadCursor = 0;
2106 QLibrary xcursorLib(QLatin1String("Xcursor"), 1);
2107 xcursorLib.setLoadHints(QLibrary::ImprovedSearchHeuristics);
2108 bool xcursorFound = xcursorLib.load();
2109 if (!xcursorFound) { //try without the version number
2110 xcursorLib.setFileName(QLatin1String("Xcursor"));
2111 xcursorFound = xcursorLib.load();
2112 }
2113 if (xcursorFound) {
2114 X11->ptrXcursorLibraryLoadCursor =
2115 (PtrXcursorLibraryLoadCursor) xcursorLib.resolve("XcursorLibraryLoadCursor");
2116 }
2117#else
2118 X11->ptrXcursorLibraryLoadCursor = XcursorLibraryLoadCursor;
2119#endif // QT_RUNTIME_XCURSOR
2120#endif // QT_NO_XCURSOR
2121
2122#ifndef QT_NO_XSYNC
2123 int xsync_evbase, xsync_errbase;
2124 int major, minor;
2125 if (XSyncQueryExtension(X11->display, &xsync_evbase, &xsync_errbase))
2126 XSyncInitialize(X11->display, &major, &minor);
2127#endif // QT_NO_XSYNC
2128
2129#ifndef QT_NO_XINERAMA
2130#ifdef QT_RUNTIME_XINERAMA
2131 X11->ptrXineramaQueryExtension = 0;
2132 X11->ptrXineramaIsActive = 0;
2133 X11->ptrXineramaQueryScreens = 0;
2134 QLibrary xineramaLib(QLatin1String("Xinerama"), 1);
2135 xineramaLib.setLoadHints(QLibrary::ImprovedSearchHeuristics);
2136 bool xineramaFound = xineramaLib.load();
2137 if (!xineramaFound) { //try without the version number
2138 xineramaLib.setFileName(QLatin1String("Xinerama"));
2139 xineramaFound = xineramaLib.load();
2140 }
2141 if (xineramaFound) {
2142 X11->ptrXineramaQueryExtension =
2143 (PtrXineramaQueryExtension) xineramaLib.resolve("XineramaQueryExtension");
2144 X11->ptrXineramaIsActive =
2145 (PtrXineramaIsActive) xineramaLib.resolve("XineramaIsActive");
2146 X11->ptrXineramaQueryScreens =
2147 (PtrXineramaQueryScreens) xineramaLib.resolve("XineramaQueryScreens");
2148 }
2149#else
2150 X11->ptrXineramaQueryScreens = XineramaQueryScreens;
2151 X11->ptrXineramaIsActive = XineramaIsActive;
2152 X11->ptrXineramaQueryExtension = XineramaQueryExtension;
2153#endif // QT_RUNTIME_XINERAMA
2154#endif // QT_NO_XINERAMA
2155
2156#ifndef QT_NO_XINPUT
2157 // See if Xinput is supported on the connected display
2158 X11->ptrXCloseDevice = 0;
2159 X11->ptrXListInputDevices = 0;
2160 X11->ptrXOpenDevice = 0;
2161 X11->ptrXFreeDeviceList = 0;
2162 X11->ptrXSelectExtensionEvent = 0;
2163 X11->use_xinput = XQueryExtension(X11->display, "XInputExtension", &X11->xinput_major,
2164 &X11->xinput_eventbase, &X11->xinput_errorbase);
2165 if (X11->use_xinput) {
2166 X11->ptrXCloseDevice = XINPUT_LOAD(XCloseDevice);
2167 X11->ptrXListInputDevices = XINPUT_LOAD(XListInputDevices);
2168 X11->ptrXOpenDevice = XINPUT_LOAD(XOpenDevice);
2169 X11->ptrXFreeDeviceList = XINPUT_LOAD(XFreeDeviceList);
2170 X11->ptrXSelectExtensionEvent = XINPUT_LOAD(XSelectExtensionEvent);
2171 }
2172#endif // QT_NO_XINPUT
2173
2174#ifndef QT_NO_XKB
2175 int xkblibMajor = XkbMajorVersion;
2176 int xkblibMinor = XkbMinorVersion;
2177 X11->use_xkb = XkbQueryExtension(X11->display,
2178 &X11->xkb_major,
2179 &X11->xkb_eventbase,
2180 &X11->xkb_errorbase,
2181 &xkblibMajor,
2182 &xkblibMinor);
2183 if (X11->use_xkb) {
2184 // If XKB is detected, set the GrabsUseXKBState option so input method
2185 // compositions continue to work (ie. deadkeys)
2186 unsigned int state = XkbPCF_GrabsUseXKBStateMask;
2187 (void) XkbSetPerClientControls(X11->display, state, &state);
2188
2189 // select for group change events
2190 XkbSelectEventDetails(X11->display,
2191 XkbUseCoreKbd,
2192 XkbStateNotify,
2193 XkbAllStateComponentsMask,
2194 XkbGroupStateMask);
2195
2196 // current group state is queried when creating the keymapper, no need to do it here
2197 }
2198#endif
2199
2200
2201#if !defined(QT_NO_FONTCONFIG)
2202 int dpi = 0;
2203 getXDefault("Xft", FC_DPI, &dpi);
2204 if (dpi) {
2205 for (int s = 0; s < ScreenCount(X11->display); ++s) {
2206 QX11Info::setAppDpiX(s, dpi);
2207 QX11Info::setAppDpiY(s, dpi);
2208 }
2209 }
2210 double fc_scale = 1.;
2211 getXDefault("Xft", FC_SCALE, &fc_scale);
2212 X11->fc_scale = fc_scale;
2213 for (int s = 0; s < ScreenCount(X11->display); ++s) {
2214 int subpixel = FC_RGBA_UNKNOWN;
2215#if !defined(QT_NO_XRENDER) && (RENDER_MAJOR > 0 || RENDER_MINOR >= 6)
2216 if (X11->use_xrender) {
2217 int rsp = XRenderQuerySubpixelOrder(X11->display, s);
2218 switch (rsp) {
2219 default:
2220 case SubPixelUnknown:
2221 subpixel = FC_RGBA_UNKNOWN;
2222 break;
2223 case SubPixelHorizontalRGB:
2224 subpixel = FC_RGBA_RGB;
2225 break;
2226 case SubPixelHorizontalBGR:
2227 subpixel = FC_RGBA_BGR;
2228 break;
2229 case SubPixelVerticalRGB:
2230 subpixel = FC_RGBA_VRGB;
2231 break;
2232 case SubPixelVerticalBGR:
2233 subpixel = FC_RGBA_VBGR;
2234 break;
2235 case SubPixelNone:
2236 subpixel = FC_RGBA_NONE;
2237 break;
2238 }
2239 }
2240#endif
2241
2242 char *rgba = XGetDefault(X11->display, "Xft", FC_RGBA);
2243 if (rgba) {
2244 char *end = 0;
2245 int v = strtol(rgba, &end, 0);
2246 if (rgba != end) {
2247 subpixel = v;
2248 } else if (qstrncmp(rgba, "unknown", 7) == 0) {
2249 subpixel = FC_RGBA_UNKNOWN;
2250 } else if (qstrncmp(rgba, "rgb", 3) == 0) {
2251 subpixel = FC_RGBA_RGB;
2252 } else if (qstrncmp(rgba, "bgr", 3) == 0) {
2253 subpixel = FC_RGBA_BGR;
2254 } else if (qstrncmp(rgba, "vrgb", 4) == 0) {
2255 subpixel = FC_RGBA_VRGB;
2256 } else if (qstrncmp(rgba, "vbgr", 4) == 0) {
2257 subpixel = FC_RGBA_VBGR;
2258 } else if (qstrncmp(rgba, "none", 4) == 0) {
2259 subpixel = FC_RGBA_NONE;
2260 }
2261 }
2262 X11->screens[s].subpixel = subpixel;
2263 }
2264 getXDefault("Xft", FC_ANTIALIAS, &X11->fc_antialias);
2265#ifdef FC_HINT_STYLE
2266 X11->fc_hint_style = -1;
2267 getXDefault("Xft", FC_HINT_STYLE, &X11->fc_hint_style);
2268#endif
2269#if 0
2270 // ###### these are implemented by Xft, not sure we need them
2271 getXDefault("Xft", FC_AUTOHINT, &X11->fc_autohint);
2272 getXDefault("Xft", FC_HINTING, &X11->fc_autohint);
2273 getXDefault("Xft", FC_MINSPACE, &X11->fc_autohint);
2274#endif
2275#endif // QT_NO_XRENDER
2276
2277 // initialize key mapper
2278 QKeyMapper::changeKeyboard();
2279
2280 // Misc. initialization
2281#if 0 //disabled for now..
2282 QSegfaultHandler::initialize(priv->argv, priv->argc);
2283#endif
2284 QCursorData::initialize();
2285 }
2286 QFont::initialize();
2287
2288 if(qt_is_gui_used) {
2289 qApp->setObjectName(QString::fromLocal8Bit(appName));
2290
2291 int screen;
2292 for (screen = 0; screen < X11->screenCount; ++screen) {
2293 XSelectInput(X11->display, QX11Info::appRootWindow(screen),
2294 KeymapStateMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask);
2295
2296#ifndef QT_NO_XRANDR
2297 if (X11->use_xrandr)
2298 X11->ptrXRRSelectInput(X11->display, QX11Info::appRootWindow(screen), True);
2299#endif // QT_NO_XRANDR
2300 }
2301 }
2302
2303 if (qt_is_gui_used) {
2304 // Attempt to determine the current running X11 Desktop Enviornment
2305 // Use dbus if/when we can, but fall back to using windowManagerName() for now
2306
2307#ifndef QT_NO_XFIXES
2308 if (X11->ptrXFixesSelectSelectionInput)
2309 X11->ptrXFixesSelectSelectionInput(X11->display, QX11Info::appRootWindow(), ATOM(_NET_WM_CM_S0),
2310 XFixesSetSelectionOwnerNotifyMask
2311 | XFixesSelectionWindowDestroyNotifyMask
2312 | XFixesSelectionClientCloseNotifyMask);
2313#endif // QT_NO_XFIXES
2314 X11->compositingManagerRunning = XGetSelectionOwner(X11->display,
2315 ATOM(_NET_WM_CM_S0));
2316 X11->desktopEnvironment = DE_UNKNOWN;
2317 X11->desktopVersion = 0;
2318
2319 Atom type;
2320 int format;
2321 unsigned long length, after;
2322 uchar *data = 0;
2323 int rc;
2324
2325 do {
2326 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
2327 X11->desktopEnvironment = DE_KDE;
2328 X11->desktopVersion = qgetenv("KDE_SESSION_VERSION").toInt();
2329 break;
2330 }
2331
2332 if (qgetenv("DESKTOP_SESSION") == "gnome") {
2333 X11->desktopEnvironment = DE_GNOME;
2334 break;
2335 }
2336
2337 // GNOME_DESKTOP_SESSION_ID is deprecated for some reason, but still check it
2338 if (!qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty()) {
2339 X11->desktopEnvironment = DE_GNOME;
2340 break;
2341 }
2342
2343 rc = XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(_DT_SAVE_MODE),
2344 0, 2, False, XA_STRING, &type, &format, &length,
2345 &after, &data);
2346 if (rc == Success && length) {
2347 if (!strcmp(reinterpret_cast<char *>(data), "xfce4")) {
2348 // Pretend that xfce4 is gnome, as it uses the same libraries.
2349 // The detection above is stolen from xdg-open.
2350 X11->desktopEnvironment = DE_GNOME;
2351 break;
2352 }
2353
2354 // We got the property but it wasn't xfce4. Free data before it gets overwritten.
2355 XFree(data);
2356 data = 0;
2357 }
2358
2359 rc = XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(DTWM_IS_RUNNING),
2360 0, 1, False, AnyPropertyType, &type, &format, &length,
2361 &after, &data);
2362 if (rc == Success && length) {
2363 // DTWM is running, meaning most likely CDE is running...
2364 X11->desktopEnvironment = DE_CDE;
2365 break;
2366 }
2367
2368 rc = XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
2369 ATOM(_SGI_DESKS_MANAGER), 0, 1, False, XA_WINDOW,
2370 &type, &format, &length, &after, &data);
2371 if (rc == Success && length) {
2372 X11->desktopEnvironment = DE_4DWM;
2373 break;
2374 }
2375
2376 if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
2377 ATOM(_NET_SUPPORTING_WM_CHECK),
2378 0, 1024, False, XA_WINDOW, &type,
2379 &format, &length, &after, &data) == Success) {
2380 if (type == XA_WINDOW && format == 32) {
2381 Window windowManagerWindow = *((Window*) data);
2382 XFree(data);
2383 data = 0;
2384
2385 if (windowManagerWindow != XNone) {
2386 Atom utf8atom = ATOM(UTF8_STRING);
2387 if (XGetWindowProperty(QX11Info::display(), windowManagerWindow, ATOM(_NET_WM_NAME),
2388 0, 1024, False, utf8atom, &type,
2389 &format, &length, &after, &data) == Success) {
2390 if (type == utf8atom && format == 8) {
2391 if (qstrcmp((const char *)data, "MCompositor") == 0)
2392 X11->desktopEnvironment = DE_MEEGO_COMPOSITOR;
2393 }
2394 }
2395 }
2396 }
2397 }
2398
2399 } while(0);
2400
2401 if (data)
2402 XFree((char *)data);
2403
2404#if !defined(QT_NO_STYLE_GTK)
2405 if (X11->desktopEnvironment == DE_GNOME) {
2406 static bool menusHaveIcons = QGtkStyle::getGConfBool(QLatin1String("/desktop/gnome/interface/menus_have_icons"), true);
2407 QApplication::setAttribute(Qt::AA_DontShowIconsInMenus, !menusHaveIcons);
2408 }
2409#endif
2410 qt_set_input_encoding();
2411
2412 qt_set_x11_resources(appFont, appFGCol, appBGCol, appBTNCol);
2413
2414 // be smart about the size of the default font. most X servers have helvetica
2415 // 12 point available at 2 resolutions:
2416 // 75dpi (12 pixels) and 100dpi (17 pixels).
2417 // At 95 DPI, a 12 point font should be 16 pixels tall - in which case a 17
2418 // pixel font is a closer match than a 12 pixel font
2419 int ptsz = (X11->use_xrender
2420 ? 9
2421 : (int) (((QX11Info::appDpiY() >= 95 ? 17. : 12.) *
2422 72. / (float) QX11Info::appDpiY()) + 0.5));
2423
2424 if (!QApplicationPrivate::sys_font) {
2425 // no font from settings or RESOURCE_MANAGER, provide a fallback
2426 QFont f(X11->has_fontconfig ? QLatin1String("Sans Serif") : QLatin1String("Helvetica"),
2427 ptsz);
2428 QApplicationPrivate::setSystemFont(f);
2429 }
2430
2431#if !defined (QT_NO_TABLET)
2432 if (X11->use_xinput) {
2433 int ndev,
2434 i,
2435 j;
2436 bool gotStylus,
2437 gotEraser;
2438 XDeviceInfo *devices = 0, *devs;
2439 XInputClassInfo *ip;
2440 XAnyClassPtr any;
2441 XValuatorInfoPtr v;
2442 XAxisInfoPtr a;
2443 XDevice *dev = 0;
2444
2445 if (X11->ptrXListInputDevices) {
2446 devices = X11->ptrXListInputDevices(X11->display, &ndev);
2447 if (!devices)
2448 qWarning("QApplication: Failed to get list of tablet devices");
2449 }
2450 if (!devices)
2451 ndev = -1;
2452 QTabletEvent::TabletDevice deviceType;
2453 for (devs = devices, i = 0; i < ndev && devs; i++, devs++) {
2454 dev = 0;
2455 deviceType = QTabletEvent::NoDevice;
2456 gotStylus = false;
2457 gotEraser = false;
2458
2459#if defined(Q_OS_IRIX)
2460 QString devName = QString::fromLocal8Bit(devs->name).toLower();
2461 if (devName == QLatin1String(WACOM_NAME)) {
2462 deviceType = QTabletEvent::Stylus;
2463 gotStylus = true;
2464 }
2465#else
2466 // qDebug() << "found input device" << devs->name << "type" << devs->type << XGetAtomName(X11->display, devs->type);
2467 if (devs->type == ATOM(XWacomStylus) || devs->type == ATOM(XTabletStylus) || devs->type == ATOM(XTablet)) {
2468 deviceType = QTabletEvent::Stylus;
2469 if (wacomDeviceName()->isEmpty())
2470 wacomDeviceName()->append(devs->name);
2471 gotStylus = true;
2472 } else if (devs->type == ATOM(XWacomEraser) || devs->type == ATOM(XTabletEraser)) {
2473 deviceType = QTabletEvent::XFreeEraser;
2474 gotEraser = true;
2475 }
2476#endif
2477 if (deviceType == QTabletEvent::NoDevice)
2478 continue;
2479
2480 if (gotStylus || gotEraser) {
2481 if (X11->ptrXOpenDevice)
2482 dev = X11->ptrXOpenDevice(X11->display, devs->id);
2483
2484 if (!dev)
2485 continue;
2486
2487 QTabletDeviceData device_data;
2488 device_data.deviceType = deviceType;
2489 device_data.eventCount = 0;
2490 device_data.device = dev;
2491 device_data.xinput_motion = -1;
2492 device_data.xinput_key_press = -1;
2493 device_data.xinput_key_release = -1;
2494 device_data.xinput_button_press = -1;
2495 device_data.xinput_button_release = -1;
2496 device_data.xinput_proximity_in = -1;
2497 device_data.xinput_proximity_out = -1;
2498 device_data.widgetToGetPress = 0;
2499
2500 if (dev->num_classes > 0) {
2501 for (ip = dev->classes, j = 0; j < dev->num_classes;
2502 ip++, j++) {
2503 switch (ip->input_class) {
2504 case KeyClass:
2505 DeviceKeyPress(dev, device_data.xinput_key_press,
2506 device_data.eventList[device_data.eventCount]);
2507 if (device_data.eventList[device_data.eventCount])
2508 ++device_data.eventCount;
2509 DeviceKeyRelease(dev, device_data.xinput_key_release,
2510 device_data.eventList[device_data.eventCount]);
2511 if (device_data.eventList[device_data.eventCount])
2512 ++device_data.eventCount;
2513 break;
2514 case ButtonClass:
2515 DeviceButtonPress(dev, device_data.xinput_button_press,
2516 device_data.eventList[device_data.eventCount]);
2517 if (device_data.eventList[device_data.eventCount])
2518 ++device_data.eventCount;
2519 DeviceButtonRelease(dev, device_data.xinput_button_release,
2520 device_data.eventList[device_data.eventCount]);
2521 if (device_data.eventList[device_data.eventCount])
2522 ++device_data.eventCount;
2523 break;
2524 case ValuatorClass:
2525 // I'm only going to be interested in motion when the
2526 // stylus is already down anyway!
2527 DeviceMotionNotify(dev, device_data.xinput_motion,
2528 device_data.eventList[device_data.eventCount]);
2529 if (device_data.eventList[device_data.eventCount])
2530 ++device_data.eventCount;
2531 ProximityIn(dev, device_data.xinput_proximity_in, device_data.eventList[device_data.eventCount]);
2532 if (device_data.eventList[device_data.eventCount])
2533 ++device_data.eventCount;
2534 ProximityOut(dev, device_data.xinput_proximity_out, device_data.eventList[device_data.eventCount]);
2535 if (device_data.eventList[device_data.eventCount])
2536 ++device_data.eventCount;
2537 default:
2538 break;
2539 }
2540 }
2541 }
2542
2543 // get the min/max value for pressure!
2544 any = (XAnyClassPtr) (devs->inputclassinfo);
2545 for (j = 0; j < devs->num_classes; j++) {
2546 if (any->c_class == ValuatorClass) {
2547 v = (XValuatorInfoPtr) any;
2548 a = (XAxisInfoPtr) ((char *) v +
2549 sizeof (XValuatorInfo));
2550#if defined (Q_OS_IRIX)
2551 // I'm not exaclty wild about this, but the
2552 // dimensions of the tablet are more relevant here
2553 // than the min and max values from the axis
2554 // (actually it seems to be 2/3 or what is in the
2555 // axis. So we'll try to parse it from this
2556 // string. --tws
2557 char returnString[SGIDeviceRtrnLen];
2558 int tmp;
2559 if (XSGIMiscQueryExtension(X11->display, &tmp, &tmp)
2560 && XSGIDeviceQuery(X11->display, devs->id,
2561 "dimensions", returnString)) {
2562 QString str = QLatin1String(returnString);
2563 int comma = str.indexOf(',');
2564 device_data.minX = 0;
2565 device_data.minY = 0;
2566 device_data.maxX = str.left(comma).toInt();
2567 device_data.maxY = str.mid(comma + 1).toInt();
2568 } else {
2569 device_data.minX = a[WAC_XCOORD_I].min_value;
2570 device_data.maxX = a[WAC_XCOORD_I].max_value;
2571 device_data.minY = a[WAC_YCOORD_I].min_value;
2572 device_data.maxY = a[WAC_YCOORD_I].max_value;
2573 }
2574 device_data.minPressure = a[WAC_PRESSURE_I].min_value;
2575 device_data.maxPressure = a[WAC_PRESSURE_I].max_value;
2576 device_data.minTanPressure = a[WAC_TAN_PRESSURE_I].min_value;
2577 device_data.maxTanPressure = a[WAC_TAN_PRESSURE_I].max_value;
2578 device_data.minZ = a[WAC_ZCOORD_I].min_value;
2579 device_data.maxZ = a[WAC_ZCOORD_I].max_value;
2580#else
2581 device_data.minX = a[0].min_value;
2582 device_data.maxX = a[0].max_value;
2583 device_data.minY = a[1].min_value;
2584 device_data.maxY = a[1].max_value;
2585 device_data.minPressure = a[2].min_value;
2586 device_data.maxPressure = a[2].max_value;
2587 device_data.minTanPressure = 0;
2588 device_data.maxTanPressure = 0;
2589 device_data.minZ = 0;
2590 device_data.maxZ = 0;
2591#endif
2592
2593 // got the max pressure no need to go further...
2594 break;
2595 }
2596 any = (XAnyClassPtr) ((char *) any + any->length);
2597 } // end of for loop
2598
2599 tablet_devices()->append(device_data);
2600 } // if (gotStylus || gotEraser)
2601 }
2602 if (X11->ptrXFreeDeviceList)
2603 X11->ptrXFreeDeviceList(devices);
2604 }
2605#endif // QT_NO_TABLET
2606
2607 X11->startupId = getenv("DESKTOP_STARTUP_ID");
2608 if (X11->startupId) {
2609#ifndef QT_NO_UNSETENV
2610 unsetenv("DESKTOP_STARTUP_ID");
2611#else
2612 // it's a small memory leak, however we won't crash if Qt is
2613 // unloaded and someones tries to use the envoriment.
2614 putenv(strdup("DESKTOP_STARTUP_ID="));
2615#endif
2616 }
2617 } else {
2618 // read some non-GUI settings when not using the X server...
2619
2620 if (QApplication::desktopSettingsAware()) {
2621 QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
2622 settings.beginGroup(QLatin1String("Qt"));
2623
2624 // read library (ie. plugin) path list
2625 QString libpathkey = QString::fromLatin1("%1.%2/libraryPath")
2626 .arg(QT_VERSION >> 16)
2627 .arg((QT_VERSION & 0xff00) >> 8);
2628 QStringList pathlist =
2629 settings.value(libpathkey).toString().split(QLatin1Char(':'));
2630 if (! pathlist.isEmpty()) {
2631 QStringList::ConstIterator it = pathlist.constBegin();
2632 while (it != pathlist.constEnd())
2633 QApplication::addLibraryPath(*it++);
2634 }
2635
2636 QString defaultcodec = settings.value(QLatin1String("defaultCodec"),
2637 QVariant(QLatin1String("none"))).toString();
2638 if (defaultcodec != QLatin1String("none")) {
2639 QTextCodec *codec = QTextCodec::codecForName(defaultcodec.toLatin1());
2640 if (codec)
2641 QTextCodec::setCodecForTr(codec);
2642 }
2643
2644 settings.endGroup(); // Qt
2645 }
2646 }
2647
2648#if !defined (Q_OS_IRIX) && !defined (QT_NO_TABLET)
2649 QLibrary wacom(QString::fromLatin1("wacomcfg"), 0); // version 0 is the latest release at time of writing this.
2650 wacom.setLoadHints(QLibrary::ImprovedSearchHeuristics);
2651 // NOTE: C casts instead of reinterpret_cast for GCC 3.3.x
2652 ptrWacomConfigInit = (PtrWacomConfigInit)wacom.resolve("WacomConfigInit");
2653 ptrWacomConfigOpenDevice = (PtrWacomConfigOpenDevice)wacom.resolve("WacomConfigOpenDevice");
2654 ptrWacomConfigGetRawParam = (PtrWacomConfigGetRawParam)wacom.resolve("WacomConfigGetRawParam");
2655 ptrWacomConfigCloseDevice = (PtrWacomConfigCloseDevice)wacom.resolve("WacomConfigCloseDevice");
2656 ptrWacomConfigTerm = (PtrWacomConfigTerm)wacom.resolve("WacomConfigTerm");
2657
2658 if (ptrWacomConfigInit == 0 || ptrWacomConfigOpenDevice == 0 || ptrWacomConfigGetRawParam == 0
2659 || ptrWacomConfigCloseDevice == 0 || ptrWacomConfigTerm == 0) { // either we have all, or we have none.
2660 ptrWacomConfigInit = 0;
2661 ptrWacomConfigOpenDevice = 0;
2662 ptrWacomConfigGetRawParam = 0;
2663 ptrWacomConfigCloseDevice = 0;
2664 ptrWacomConfigTerm = 0;
2665 }
2666#endif
2667}
2668
2669void QApplicationPrivate::initializeWidgetPaletteHash()
2670{
2671}
2672
2673/*****************************************************************************
2674 qt_cleanup() - cleans up when the application is finished
2675 *****************************************************************************/
2676
2677void qt_cleanup()
2678{
2679 if (app_save_rootinfo) // root window must keep state
2680 qt_save_rootinfo();
2681
2682 if (qt_is_gui_used) {
2683 QPixmapCache::clear();
2684 QCursorData::cleanup();
2685 QFont::cleanup();
2686 QColormap::cleanup();
2687
2688#if !defined (QT_NO_TABLET)
2689 QTabletDeviceDataList *devices = qt_tablet_devices();
2690 if (X11->ptrXCloseDevice)
2691 for (int i = 0; i < devices->size(); ++i)
2692 X11->ptrXCloseDevice(X11->display, (XDevice*)devices->at(i).device);
2693 devices->clear();
2694#endif
2695 }
2696
2697#ifndef QT_NO_XRENDER
2698 for (int i = 0; i < X11->solid_fill_count; ++i) {
2699 if (X11->solid_fills[i].picture)
2700 XRenderFreePicture(X11->display, X11->solid_fills[i].picture);
2701 }
2702 for (int i = 0; i < X11->pattern_fill_count; ++i) {
2703 if (X11->pattern_fills[i].picture)
2704 XRenderFreePicture(X11->display, X11->pattern_fills[i].picture);
2705 }
2706#endif
2707
2708#if !defined(QT_NO_IM)
2709 delete QApplicationPrivate::inputContext;
2710 QApplicationPrivate::inputContext = 0;
2711#endif
2712
2713 // Reset the error handlers
2714 if (qt_is_gui_used)
2715 XSync(X11->display, False); // sync first to process all possible errors
2716 XSetErrorHandler(original_x_errhandler);
2717 XSetIOErrorHandler(original_xio_errhandler);
2718
2719 if (X11->argbColormaps) {
2720 for (int s = 0; s < X11->screenCount; s++) {
2721 if (X11->argbColormaps[s])
2722 XFreeColormap(X11->display, X11->argbColormaps[s]);
2723 }
2724 }
2725
2726 if (qt_is_gui_used && !X11->foreignDisplay)
2727 XCloseDisplay(X11->display); // close X display
2728 X11->display = 0;
2729
2730 delete [] X11->screens;
2731 delete [] X11->argbVisuals;
2732 delete [] X11->argbColormaps;
2733
2734 if (X11->foreignDisplay) {
2735 delete [] (char *)appName;
2736 appName = 0;
2737 }
2738
2739 delete [] (char *)appClass;
2740 appClass = 0;
2741
2742 if (X11->net_supported_list)
2743 delete [] X11->net_supported_list;
2744 X11->net_supported_list = 0;
2745
2746 if (X11->net_virtual_root_list)
2747 delete [] X11->net_virtual_root_list;
2748 X11->net_virtual_root_list = 0;
2749
2750 delete X11;
2751 X11 = 0;
2752}
2753
2754
2755/*****************************************************************************
2756 Platform specific global and internal functions
2757 *****************************************************************************/
2758
2759void qt_save_rootinfo() // save new root info
2760{
2761 Atom type;
2762 int format;
2763 unsigned long length, after;
2764 uchar *data = 0;
2765
2766 if (ATOM(_XSETROOT_ID)) { // kill old pixmap
2767 if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(),
2768 ATOM(_XSETROOT_ID), 0, 1,
2769 True, AnyPropertyType, &type, &format,
2770 &length, &after, &data) == Success) {
2771 if (type == XA_PIXMAP && format == 32 && length == 1 &&
2772 after == 0 && data) {
2773 XKillClient(X11->display, *((Pixmap*)data));
2774 }
2775 Pixmap dummy = XCreatePixmap(X11->display, QX11Info::appRootWindow(),
2776 1, 1, 1);
2777 XChangeProperty(X11->display, QX11Info::appRootWindow(),
2778 ATOM(_XSETROOT_ID), XA_PIXMAP, 32,
2779 PropModeReplace, (uchar *)&dummy, 1);
2780 XSetCloseDownMode(X11->display, RetainPermanent);
2781 }
2782 }
2783 if (data)
2784 XFree((char *)data);
2785}
2786
2787void qt_updated_rootinfo()
2788{
2789 app_save_rootinfo = true;
2790}
2791
2792// ### Cleanup, this function is not in use!
2793bool qt_wstate_iconified(WId winid)
2794{
2795 Atom type;
2796 int format;
2797 unsigned long length, after;
2798 uchar *data = 0;
2799 int r = XGetWindowProperty(X11->display, winid, ATOM(WM_STATE), 0, 2,
2800 False, AnyPropertyType, &type, &format,
2801 &length, &after, &data);
2802 bool iconic = false;
2803 if (r == Success && data && format == 32) {
2804 // quint32 *wstate = (quint32*)data;
2805 unsigned long *wstate = (unsigned long *) data;
2806 iconic = (*wstate == IconicState);
2807 XFree((char *)data);
2808 }
2809 return iconic;
2810}
2811
2812QString QApplicationPrivate::appName() const
2813{
2814 return QString::fromLocal8Bit(QT_PREPEND_NAMESPACE(appName));
2815}
2816
2817const char *QX11Info::appClass() // get application class
2818{
2819 return QT_PREPEND_NAMESPACE(appClass);
2820}
2821
2822bool qt_nograb() // application no-grab option
2823{
2824#if defined(QT_DEBUG)
2825 return appNoGrab;
2826#else
2827 return false;
2828#endif
2829}
2830
2831
2832/*****************************************************************************
2833 Platform specific QApplication members
2834 *****************************************************************************/
2835
2836#ifdef QT3_SUPPORT
2837void QApplication::setMainWidget(QWidget *mainWidget)
2838{
2839#ifndef QT_NO_DEBUG
2840 if (mainWidget && mainWidget->parentWidget() && mainWidget->isWindow())
2841 qWarning("QApplication::setMainWidget: New main widget (%s/%s) "
2842 "has a parent",
2843 mainWidget->metaObject()->className(), mainWidget->objectName().toLocal8Bit().constData());
2844#endif
2845 if (mainWidget)
2846 mainWidget->d_func()->createWinId();
2847 QApplicationPrivate::main_widget = mainWidget;
2848 if (QApplicationPrivate::main_widget) // give WM command line
2849 QApplicationPrivate::applyX11SpecificCommandLineArguments(QApplicationPrivate::main_widget);
2850}
2851#endif
2852
2853void QApplicationPrivate::applyX11SpecificCommandLineArguments(QWidget *main_widget)
2854{
2855 static bool beenHereDoneThat = false;
2856 if (beenHereDoneThat)
2857 return;
2858 beenHereDoneThat = true;
2859 Q_ASSERT(main_widget->testAttribute(Qt::WA_WState_Created));
2860 if (mwTitle) {
2861 XStoreName(X11->display, main_widget->effectiveWinId(), (char*)mwTitle);
2862 QByteArray net_wm_name = QString::fromLocal8Bit(mwTitle).toUtf8();
2863 XChangeProperty(X11->display, main_widget->effectiveWinId(), ATOM(_NET_WM_NAME), ATOM(UTF8_STRING), 8,
2864 PropModeReplace, (unsigned char *)net_wm_name.data(), net_wm_name.size());
2865 }
2866 if (mwGeometry) { // parse geometry
2867 int x, y;
2868 int w, h;
2869 int m = XParseGeometry((char*)mwGeometry, &x, &y, (uint*)&w, (uint*)&h);
2870 QSize minSize = main_widget->minimumSize();
2871 QSize maxSize = main_widget->maximumSize();
2872 if ((m & XValue) == 0)
2873 x = main_widget->geometry().x();
2874 if ((m & YValue) == 0)
2875 y = main_widget->geometry().y();
2876 if ((m & WidthValue) == 0)
2877 w = main_widget->width();
2878 if ((m & HeightValue) == 0)
2879 h = main_widget->height();
2880 w = qMin(w,maxSize.width());
2881 h = qMin(h,maxSize.height());
2882 w = qMax(w,minSize.width());
2883 h = qMax(h,minSize.height());
2884 if ((m & XNegative)) {
2885 x = QApplication::desktop()->width() + x - w;
2886 }
2887 if ((m & YNegative)) {
2888 y = QApplication::desktop()->height() + y - h;
2889 }
2890 main_widget->setGeometry(x, y, w, h);
2891 }
2892}
2893
2894#ifndef QT_NO_CURSOR
2895
2896/*****************************************************************************
2897 QApplication cursor stack
2898 *****************************************************************************/
2899
2900void QApplication::setOverrideCursor(const QCursor &cursor)
2901{
2902 qApp->d_func()->cursor_list.prepend(cursor);
2903
2904 QWidgetList all = allWidgets();
2905 for (QWidgetList::ConstIterator it = all.constBegin(); it != all.constEnd(); ++it) {
2906 register QWidget *w = *it;
2907 if ((w->testAttribute(Qt::WA_SetCursor) || w->isWindow()) && (w->windowType() != Qt::Desktop))
2908 qt_x11_enforce_cursor(w);
2909 }
2910 XFlush(X11->display); // make X execute it NOW
2911}
2912
2913void QApplication::restoreOverrideCursor()
2914{
2915 if (qApp->d_func()->cursor_list.isEmpty())
2916 return;
2917 qApp->d_func()->cursor_list.removeFirst();
2918
2919 if (QWidgetPrivate::mapper != 0 && !closingDown()) {
2920 QWidgetList all = allWidgets();
2921 for (QWidgetList::ConstIterator it = all.constBegin(); it != all.constEnd(); ++it) {
2922 register QWidget *w = *it;
2923 if ((w->testAttribute(Qt::WA_SetCursor) || w->isWindow()) && (w->windowType() != Qt::Desktop))
2924 qt_x11_enforce_cursor(w);
2925 }
2926 XFlush(X11->display);
2927 }
2928}
2929
2930#endif
2931
2932
2933/*****************************************************************************
2934 Routines to find a Qt widget from a screen position
2935 *****************************************************************************/
2936
2937Window QX11Data::findClientWindow(Window win, Atom property, bool leaf)
2938{
2939 Atom type = XNone;
2940 int format, i;
2941 ulong nitems, after;
2942 uchar *data = 0;
2943 Window root, parent, target=0, *children=0;
2944 uint nchildren;
2945 if (XGetWindowProperty(X11->display, win, property, 0, 0, false, AnyPropertyType,
2946 &type, &format, &nitems, &after, &data) == Success) {
2947 if (data)
2948 XFree((char *)data);
2949 if (type)
2950 return win;
2951 }
2952 if (!XQueryTree(X11->display,win,&root,&parent,&children,&nchildren)) {
2953 if (children)
2954 XFree((char *)children);
2955 return 0;
2956 }
2957 for (i=nchildren-1; !target && i >= 0; i--)
2958 target = X11->findClientWindow(children[i], property, leaf);
2959 if (children)
2960 XFree((char *)children);
2961 return target;
2962}
2963
2964QWidget *QApplication::topLevelAt(const QPoint &p)
2965{
2966#ifdef QT_NO_CURSOR
2967 Q_UNUSED(p);
2968 return 0;
2969#else
2970 int screen = QCursor::x11Screen();
2971 int unused;
2972
2973 int x = p.x();
2974 int y = p.y();
2975 Window target;
2976 if (!XTranslateCoordinates(X11->display,
2977 QX11Info::appRootWindow(screen),
2978 QX11Info::appRootWindow(screen),
2979 x, y, &unused, &unused, &target)) {
2980 return 0;
2981 }
2982 if (!target || target == QX11Info::appRootWindow(screen))
2983 return 0;
2984 QWidget *w;
2985 w = QWidget::find((WId)target);
2986
2987 if (!w) {
2988 X11->ignoreBadwindow();
2989 target = X11->findClientWindow(target, ATOM(WM_STATE), true);
2990 if (X11->badwindow())
2991 return 0;
2992 w = QWidget::find((WId)target);
2993 if (!w) {
2994 // Perhaps the widget at (x,y) is inside a foreign application?
2995 // Search all toplevel widgets to see if one is within target
2996 QWidgetList list = QApplication::topLevelWidgets();
2997 for (int i = 0; i < list.count(); ++i) {
2998 QWidget *widget = list.at(i);
2999 Window ctarget = target;
3000 if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) {
3001 Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
3002 Window wid = widget->internalWinId();
3003 while (ctarget && !w) {
3004 X11->ignoreBadwindow();
3005 if (!XTranslateCoordinates(X11->display,
3006 QX11Info::appRootWindow(screen),
3007 ctarget, x, y, &unused, &unused, &ctarget)
3008 || X11->badwindow())
3009 break;
3010 if (ctarget == wid) {
3011 // Found!
3012 w = widget;
3013 break;
3014 }
3015 }
3016 }
3017 if (w)
3018 break;
3019 }
3020 }
3021 }
3022 return w ? w->window() : 0;
3023#endif
3024}
3025
3026void QApplication::syncX()
3027{
3028 if (X11->display)
3029 XSync(X11->display, False); // don't discard events
3030}
3031
3032
3033void QApplication::beep()
3034{
3035 if (X11->display)
3036 XBell(X11->display, 0);
3037 else
3038 printf("\7");
3039}
3040
3041void QApplication::alert(QWidget *widget, int msec)
3042{
3043 if (!QApplicationPrivate::checkInstance("alert"))
3044 return;
3045
3046 QWidgetList windowsToMark;
3047 if (!widget) {
3048 windowsToMark += topLevelWidgets();
3049 } else {
3050 windowsToMark.append(widget->window());
3051 }
3052
3053 for (int i = 0; i < windowsToMark.size(); ++i) {
3054 QWidget *window = windowsToMark.at(i);
3055 if (!window->isActiveWindow()) {
3056 qt_change_net_wm_state(window, true, ATOM(_NET_WM_STATE_DEMANDS_ATTENTION));
3057 if (msec != 0) {
3058 QTimer *timer = new QTimer(qApp);
3059 timer->setSingleShot(true);
3060 connect(timer, SIGNAL(timeout()), qApp, SLOT(_q_alertTimeOut()));
3061 if (QTimer *oldTimer = qApp->d_func()->alertTimerHash.value(window)) {
3062 qApp->d_func()->alertTimerHash.remove(window);
3063 delete oldTimer;
3064 }
3065 qApp->d_func()->alertTimerHash.insert(window, timer);
3066 timer->start(msec);
3067 }
3068 }
3069 }
3070}
3071
3072void QApplicationPrivate::_q_alertTimeOut()
3073{
3074 if (QTimer *timer = qobject_cast<QTimer *>(q_func()->sender())) {
3075 QHash<QWidget *, QTimer *>::iterator it = alertTimerHash.begin();
3076 while (it != alertTimerHash.end()) {
3077 if (it.value() == timer) {
3078 QWidget *window = it.key();
3079 qt_change_net_wm_state(window, false, ATOM(_NET_WM_STATE_DEMANDS_ATTENTION));
3080 alertTimerHash.erase(it);
3081 timer->deleteLater();
3082 break;
3083 }
3084 ++it;
3085 }
3086 }
3087}
3088
3089Qt::KeyboardModifiers QApplication::queryKeyboardModifiers()
3090{
3091 Window root;
3092 Window child;
3093 int root_x, root_y, win_x, win_y;
3094 uint keybstate;
3095 for (int i = 0; i < ScreenCount(X11->display); ++i) {
3096 if (XQueryPointer(X11->display, QX11Info::appRootWindow(i), &root, &child,
3097 &root_x, &root_y, &win_x, &win_y, &keybstate))
3098 return X11->translateModifiers(keybstate & 0x00ff);
3099 }
3100 return 0;
3101
3102}
3103
3104/*****************************************************************************
3105 Special lookup functions for windows that have been reparented recently
3106 *****************************************************************************/
3107
3108static QWidgetMapper *wPRmapper = 0; // alternative widget mapper
3109
3110void qPRCreate(const QWidget *widget, Window oldwin)
3111{ // QWidget::reparent mechanism
3112 if (!wPRmapper)
3113 wPRmapper = new QWidgetMapper;
3114
3115 QETWidget *w = static_cast<QETWidget *>(const_cast<QWidget *>(widget));
3116 wPRmapper->insert((int)oldwin, w); // add old window to mapper
3117 w->setAttribute(Qt::WA_WState_Reparented); // set reparented flag
3118}
3119
3120void qPRCleanup(QWidget *widget)
3121{
3122 QETWidget *etw = static_cast<QETWidget *>(const_cast<QWidget *>(widget));
3123 if (!(wPRmapper && widget->testAttribute(Qt::WA_WState_Reparented)))
3124 return; // not a reparented widget
3125 QWidgetMapper::Iterator it = wPRmapper->begin();
3126 while (it != wPRmapper->constEnd()) {
3127 QWidget *w = *it;
3128 if (w == etw) { // found widget
3129 etw->setAttribute(Qt::WA_WState_Reparented, false); // clear flag
3130 it = wPRmapper->erase(it);// old window no longer needed
3131 } else {
3132 ++it;
3133 }
3134 }
3135 if (wPRmapper->size() == 0) { // became empty
3136 delete wPRmapper; // then reset alt mapper
3137 wPRmapper = 0;
3138 }
3139}
3140
3141static QETWidget *qPRFindWidget(Window oldwin)
3142{
3143 return wPRmapper ? (QETWidget*)wPRmapper->value((int)oldwin, 0) : 0;
3144}
3145
3146int QApplication::x11ClientMessage(QWidget* w, XEvent* event, bool passive_only)
3147{
3148 if (w && !w->internalWinId())
3149 return 0;
3150 QETWidget *widget = (QETWidget*)w;
3151 if (event->xclient.format == 32 && event->xclient.message_type) {
3152 if (event->xclient.message_type == ATOM(WM_PROTOCOLS)) {
3153 Atom a = event->xclient.data.l[0];
3154 if (a == ATOM(WM_DELETE_WINDOW)) {
3155 if (passive_only) return 0;
3156 widget->translateCloseEvent(event);
3157 }
3158 else if (a == ATOM(WM_TAKE_FOCUS)) {
3159 if ((ulong) event->xclient.data.l[1] > X11->time)
3160 X11->time = event->xclient.data.l[1];
3161 QWidget *amw = activeModalWidget();
3162 if (amw && amw->testAttribute(Qt::WA_X11DoNotAcceptFocus))
3163 amw = 0;
3164 if (amw && !QApplicationPrivate::tryModalHelper(widget, 0)) {
3165 QWidget *p = amw->parentWidget();
3166 while (p && p != widget)
3167 p = p->parentWidget();
3168 if (!p || !X11->net_supported_list)
3169 amw->raise(); // help broken window managers
3170 amw->activateWindow();
3171 }
3172#ifndef QT_NO_WHATSTHIS
3173 } else if (a == ATOM(_NET_WM_CONTEXT_HELP)) {
3174 QWhatsThis::enterWhatsThisMode();
3175#endif // QT_NO_WHATSTHIS
3176 } else if (a == ATOM(_NET_WM_PING)) {
3177 // avoid send/reply loops
3178 Window root = RootWindow(X11->display, w->x11Info().screen());
3179 if (event->xclient.window != root) {
3180 event->xclient.window = root;
3181 XSendEvent(event->xclient.display, event->xclient.window,
3182 False, SubstructureNotifyMask|SubstructureRedirectMask, event);
3183 }
3184#ifndef QT_NO_XSYNC
3185 } else if (a == ATOM(_NET_WM_SYNC_REQUEST)) {
3186 const ulong timestamp = (const ulong) event->xclient.data.l[1];
3187 if (timestamp > X11->time)
3188 X11->time = timestamp;
3189 if (QTLWExtra *tlw = w->d_func()->maybeTopData()) {
3190 if (timestamp == CurrentTime || timestamp > tlw->syncRequestTimestamp) {
3191 tlw->syncRequestTimestamp = timestamp;
3192 tlw->newCounterValueLo = event->xclient.data.l[2];
3193 tlw->newCounterValueHi = event->xclient.data.l[3];
3194 }
3195 }
3196#endif
3197 }
3198 } else if (event->xclient.message_type == ATOM(_QT_SCROLL_DONE)) {
3199 widget->translateScrollDoneEvent(event);
3200 } else if (event->xclient.message_type == ATOM(XdndPosition)) {
3201 X11->xdndHandlePosition(widget, event, passive_only);
3202 } else if (event->xclient.message_type == ATOM(XdndEnter)) {
3203 X11->xdndHandleEnter(widget, event, passive_only);
3204 } else if (event->xclient.message_type == ATOM(XdndStatus)) {
3205 X11->xdndHandleStatus(widget, event, passive_only);
3206 } else if (event->xclient.message_type == ATOM(XdndLeave)) {
3207 X11->xdndHandleLeave(widget, event, passive_only);
3208 } else if (event->xclient.message_type == ATOM(XdndDrop)) {
3209 X11->xdndHandleDrop(widget, event, passive_only);
3210 } else if (event->xclient.message_type == ATOM(XdndFinished)) {
3211 X11->xdndHandleFinished(widget, event, passive_only);
3212 } else {
3213 if (passive_only) return 0;
3214 // All other are interactions
3215 }
3216 } else {
3217 X11->motifdndHandle(widget, event, passive_only);
3218 }
3219
3220 return 0;
3221}
3222
3223int QApplication::x11ProcessEvent(XEvent* event)
3224{
3225 Q_D(QApplication);
3226 QScopedLoopLevelCounter loopLevelCounter(d->threadData);
3227
3228#ifdef ALIEN_DEBUG
3229 //qDebug() << "QApplication::x11ProcessEvent:" << event->type;
3230#endif
3231 switch (event->type) {
3232 case ButtonPress:
3233 pressed_window = event->xbutton.window;
3234 X11->userTime = event->xbutton.time;
3235 // fallthrough intended
3236 case ButtonRelease:
3237 X11->time = event->xbutton.time;
3238 break;
3239 case MotionNotify:
3240 X11->time = event->xmotion.time;
3241 break;
3242 case XKeyPress:
3243 X11->userTime = event->xkey.time;
3244 // fallthrough intended
3245 case XKeyRelease:
3246 X11->time = event->xkey.time;
3247 break;
3248 case PropertyNotify:
3249 X11->time = event->xproperty.time;
3250 break;
3251 case EnterNotify:
3252 case LeaveNotify:
3253 X11->time = event->xcrossing.time;
3254 break;
3255 case SelectionClear:
3256 X11->time = event->xselectionclear.time;
3257 break;
3258 default:
3259 break;
3260 }
3261#ifndef QT_NO_XFIXES
3262 if (X11->use_xfixes && event->type == (X11->xfixes_eventbase + XFixesSelectionNotify)) {
3263 XFixesSelectionNotifyEvent *req =
3264 reinterpret_cast<XFixesSelectionNotifyEvent *>(event);
3265 X11->time = req->selection_timestamp;
3266 if (req->selection == ATOM(_NET_WM_CM_S0))
3267 X11->compositingManagerRunning = req->owner;
3268 }
3269#endif
3270
3271 QETWidget *widget = (QETWidget*)QWidget::find((WId)event->xany.window);
3272
3273 if (wPRmapper) { // just did a widget reparent?
3274 if (widget == 0) { // not in std widget mapper
3275 switch (event->type) { // only for mouse/key events
3276 case ButtonPress:
3277 case ButtonRelease:
3278 case MotionNotify:
3279 case XKeyPress:
3280 case XKeyRelease:
3281 widget = qPRFindWidget(event->xany.window);
3282 break;
3283 }
3284 }
3285 else if (widget->testAttribute(Qt::WA_WState_Reparented))
3286 qPRCleanup(widget); // remove from alt mapper
3287 }
3288
3289 QETWidget *keywidget=0;
3290 bool grabbed=false;
3291 if (event->type==XKeyPress || event->type==XKeyRelease) {
3292 keywidget = (QETWidget*)QWidget::keyboardGrabber();
3293 if (keywidget) {
3294 grabbed = true;
3295 } else if (!keywidget) {
3296 if (d->inPopupMode()) // no focus widget, see if we have a popup
3297 keywidget = (QETWidget*) (activePopupWidget()->focusWidget() ? activePopupWidget()->focusWidget() : activePopupWidget());
3298 else if (QApplicationPrivate::focus_widget)
3299 keywidget = (QETWidget*)QApplicationPrivate::focus_widget;
3300 else if (widget)
3301 keywidget = (QETWidget*)widget->window();
3302 }
3303 }
3304
3305#ifndef QT_NO_IM
3306 // Filtering input events by the input context. It has to be taken
3307 // place before any other key event consumers such as eventfilters
3308 // and accelerators because some input methods require quite
3309 // various key combination and sequences. It often conflicts with
3310 // accelerators and so on, so we must give the input context the
3311 // filtering opportunity first to ensure all input methods work
3312 // properly regardless of application design.
3313
3314 if(keywidget && keywidget->isEnabled() && keywidget->testAttribute(Qt::WA_InputMethodEnabled)) {
3315 // block user interaction during session management
3316 if((event->type==XKeyPress || event->type==XKeyRelease) && qt_sm_blockUserInput)
3317 return true;
3318
3319 // for XIM handling
3320 QInputContext *qic = keywidget->inputContext();
3321 if(qic && qic->x11FilterEvent(keywidget, event))
3322 return true;
3323
3324 // filterEvent() accepts QEvent *event rather than preexpanded
3325 // key event attribute values. This is intended to pass other
3326 // QInputEvent in future. Other non IM-related events should
3327 // not be forwarded to input contexts to prevent weird event
3328 // handling.
3329 if ((event->type == XKeyPress || event->type == XKeyRelease)) {
3330 int code = -1;
3331 int count = 0;
3332 Qt::KeyboardModifiers modifiers;
3333 QEvent::Type type;
3334 QString text;
3335 KeySym keySym;
3336
3337 qt_keymapper_private()->translateKeyEventInternal(keywidget, event, keySym, count,
3338 text, modifiers, code, type, false);
3339
3340 // both key press/release is required for some complex
3341 // input methods. don't eliminate anything.
3342 QKeyEventEx keyevent(type, code, modifiers, text, false, qMax(qMax(count, 1), text.length()),
3343 event->xkey.keycode, keySym, event->xkey.state);
3344 if(qic && qic->filterEvent(&keyevent))
3345 return true;
3346 }
3347 } else
3348#endif // QT_NO_IM
3349 {
3350 if (XFilterEvent(event, XNone))
3351 return true;
3352 }
3353
3354 if (qt_x11EventFilter(event)) // send through app filter
3355 return 1;
3356
3357 if (event->type == MappingNotify) {
3358 // keyboard mapping changed
3359 XRefreshKeyboardMapping(&event->xmapping);
3360
3361 QKeyMapper::changeKeyboard();
3362 return 0;
3363 }
3364#ifndef QT_NO_XKB
3365 else if (X11->use_xkb && event->type == X11->xkb_eventbase) {
3366 XkbAnyEvent *xkbevent = (XkbAnyEvent *) event;
3367 switch (xkbevent->xkb_type) {
3368 case XkbStateNotify:
3369 {
3370 XkbStateNotifyEvent *xkbstateevent = (XkbStateNotifyEvent *) xkbevent;
3371 if ((xkbstateevent->changed & XkbGroupStateMask) != 0) {
3372 qt_keymapper_private()->xkb_currentGroup = xkbstateevent->group;
3373 QKeyMapper::changeKeyboard();
3374 }
3375 break;
3376 }
3377 default:
3378 break;
3379 }
3380 }
3381#endif
3382
3383 if (!widget) { // don't know this windows
3384 QWidget* popup = QApplication::activePopupWidget();
3385 if (popup) {
3386
3387 /*
3388 That is more than suboptimal. The real solution should
3389 do some keyevent and buttonevent translation, so that
3390 the popup still continues to work as the user expects.
3391 Unfortunately this translation is currently only
3392 possible with a known widget. I'll change that soon
3393 (Matthias).
3394 */
3395
3396 // Danger - make sure we don't lock the server
3397 switch (event->type) {
3398 case ButtonPress:
3399 case ButtonRelease:
3400 case XKeyPress:
3401 case XKeyRelease:
3402 do {
3403 popup->close();
3404 } while ((popup = qApp->activePopupWidget()));
3405 return 1;
3406 }
3407 }
3408 return -1;
3409 }
3410
3411 if (event->type == XKeyPress || event->type == XKeyRelease)
3412 widget = keywidget; // send XKeyEvents through keywidget->x11Event()
3413
3414 if (app_do_modal) // modal event handling
3415 if (!qt_try_modal(widget, event)) {
3416 if (event->type == ClientMessage && !widget->x11Event(event))
3417 x11ClientMessage(widget, event, true);
3418 return 1;
3419 }
3420
3421
3422 if (widget->x11Event(event)) // send through widget filter
3423 return 1;
3424#if !defined (QT_NO_TABLET)
3425 if (!qt_xdnd_dragging) {
3426 QTabletDeviceDataList *tablets = qt_tablet_devices();
3427 for (int i = 0; i < tablets->size(); ++i) {
3428 QTabletDeviceData &tab = tablets->operator [](i);
3429 if (event->type == tab.xinput_motion
3430 || event->type == tab.xinput_button_release
3431 || event->type == tab.xinput_button_press
3432 || event->type == tab.xinput_proximity_in
3433 || event->type == tab.xinput_proximity_out) {
3434 widget->translateXinputEvent(event, &tab);
3435 return 0;
3436 }
3437 }
3438 }
3439#endif
3440
3441#ifndef QT_NO_XRANDR
3442 if (X11->use_xrandr && event->type == (X11->xrandr_eventbase + RRScreenChangeNotify)) {
3443 // update Xlib internals with the latest screen configuration
3444 X11->ptrXRRUpdateConfiguration(event);
3445
3446 // update the size for desktop widget
3447 int scr = X11->ptrXRRRootToScreen(X11->display, event->xany.window);
3448 QDesktopWidget *desktop = QApplication::desktop();
3449 QWidget *w = desktop->screen(scr);
3450 QSize oldSize(w->size());
3451 w->data->crect.setWidth(DisplayWidth(X11->display, scr));
3452 w->data->crect.setHeight(DisplayHeight(X11->display, scr));
3453 QResizeEvent e(w->size(), oldSize);
3454 QApplication::sendEvent(w, &e);
3455 if (w != desktop)
3456 QApplication::sendEvent(desktop, &e);
3457 }
3458#endif // QT_NO_XRANDR
3459
3460#ifndef QT_NO_XFIXES
3461 if (X11->use_xfixes && event->type == (X11->xfixes_eventbase + XFixesSelectionNotify)) {
3462 XFixesSelectionNotifyEvent *req = reinterpret_cast<XFixesSelectionNotifyEvent *>(event);
3463
3464 // compress all XFixes events related to this selection
3465 // we don't want to handle old SelectionNotify events.
3466 qt_xfixes_selection_event_data xfixes_event;
3467 xfixes_event.selection = req->selection;
3468 for (XEvent ev;;) {
3469 if (!XCheckIfEvent(X11->display, &ev, &qt_xfixes_scanner, (XPointer)&xfixes_event))
3470 break;
3471 }
3472
3473 if (req->selection == ATOM(CLIPBOARD)) {
3474 if (qt_xfixes_clipboard_changed(req->owner, req->selection_timestamp)) {
3475 emit clipboard()->changed(QClipboard::Clipboard);
3476 emit clipboard()->dataChanged();
3477 }
3478 } else if (req->selection == XA_PRIMARY) {
3479 if (qt_xfixes_selection_changed(req->owner, req->selection_timestamp)) {
3480 emit clipboard()->changed(QClipboard::Selection);
3481 emit clipboard()->selectionChanged();
3482 }
3483 }
3484 }
3485#endif // QT_NO_XFIXES
3486
3487 switch (event->type) {
3488
3489 case ButtonRelease: // mouse event
3490 if (!d->inPopupMode() && !QWidget::mouseGrabber() && pressed_window != widget->internalWinId()
3491 && (widget = (QETWidget*) QWidget::find((WId)pressed_window)) == 0)
3492 break;
3493 // fall through intended
3494 case ButtonPress:
3495 if (event->xbutton.root != RootWindow(X11->display, widget->x11Info().screen())
3496 && ! qt_xdnd_dragging) {
3497 while (activePopupWidget())
3498 activePopupWidget()->close();
3499 return 1;
3500 }
3501 if (event->type == ButtonPress)
3502 qt_net_update_user_time(widget->window(), X11->userTime);
3503 // fall through intended
3504 case MotionNotify:
3505#if !defined(QT_NO_TABLET)
3506 if (!qt_tabletChokeMouse) {
3507#endif
3508 if (widget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
3509 QPoint pos(event->xbutton.x, event->xbutton.y);
3510 pos = widget->d_func()->mapFromWS(pos);
3511 QWidget *window = widget->window();
3512 pos = widget->mapTo(window, pos);
3513 if (QWidget *child = window->childAt(pos)) {
3514 widget = static_cast<QETWidget *>(child);
3515 pos = child->mapFrom(window, pos);
3516 event->xbutton.x = pos.x();
3517 event->xbutton.y = pos.y();
3518 }
3519 }
3520 widget->translateMouseEvent(event);
3521#if !defined(QT_NO_TABLET)
3522 } else {
3523 qt_tabletChokeMouse = false;
3524 }
3525#endif
3526 break;
3527
3528 case XKeyPress: // keyboard event
3529 qt_net_update_user_time(widget->window(), X11->userTime);
3530 // fallthrough intended
3531 case XKeyRelease:
3532 {
3533 if (keywidget && keywidget->isEnabled()) { // should always exist
3534 // qDebug("sending key event");
3535 qt_keymapper_private()->translateKeyEvent(keywidget, event, grabbed);
3536 }
3537 break;
3538 }
3539
3540 case GraphicsExpose:
3541 case Expose: // paint event
3542 widget->translatePaintEvent(event);
3543 break;
3544
3545 case ConfigureNotify: // window move/resize event
3546 if (event->xconfigure.event == event->xconfigure.window)
3547 widget->translateConfigEvent(event);
3548 break;
3549
3550 case XFocusIn: { // got focus
3551 if ((widget->windowType() == Qt::Desktop))
3552 break;
3553 if (d->inPopupMode()) // some delayed focus event to ignore
3554 break;
3555 if (!widget->isWindow())
3556 break;
3557 if (event->xfocus.detail != NotifyAncestor &&
3558 event->xfocus.detail != NotifyInferior &&
3559 event->xfocus.detail != NotifyNonlinear)
3560 break;
3561 setActiveWindow(widget);
3562 if (X11->focus_model == QX11Data::FM_PointerRoot) {
3563 // We got real input focus from somewhere, but we were in PointerRoot
3564 // mode, so we don't trust this event. Check the focus model to make
3565 // sure we know what focus mode we are using...
3566 qt_check_focus_model();
3567 }
3568 }
3569 break;
3570
3571 case XFocusOut: // lost focus
3572 if ((widget->windowType() == Qt::Desktop))
3573 break;
3574 if (!widget->isWindow())
3575 break;
3576 if (event->xfocus.mode == NotifyGrab) {
3577 qt_xfocusout_grab_counter++;
3578 break;
3579 }
3580 if (event->xfocus.detail != NotifyAncestor &&
3581 event->xfocus.detail != NotifyNonlinearVirtual &&
3582 event->xfocus.detail != NotifyNonlinear)
3583 break;
3584 if (!d->inPopupMode() && widget == QApplicationPrivate::active_window) {
3585 XEvent ev;
3586 bool focus_will_change = false;
3587 if (XCheckTypedEvent(X11->display, XFocusIn, &ev)) {
3588 // we're about to get an XFocusIn, if we know we will
3589 // get a new active window, we don't want to set the
3590 // active window to 0 now
3591 QWidget *w2 = QWidget::find(ev.xany.window);
3592 if (w2
3593 && w2->windowType() != Qt::Desktop
3594 && !d->inPopupMode() // some delayed focus event to ignore
3595 && w2->isWindow()
3596 && (ev.xfocus.detail == NotifyAncestor
3597 || ev.xfocus.detail == NotifyInferior
3598 || ev.xfocus.detail == NotifyNonlinear))
3599 focus_will_change = true;
3600
3601 XPutBackEvent(X11->display, &ev);
3602 }
3603 if (!focus_will_change)
3604 setActiveWindow(0);
3605 }
3606 break;
3607
3608 case EnterNotify: { // enter window
3609 if (QWidget::mouseGrabber() && (!d->inPopupMode() || widget->window() != activePopupWidget()))
3610 break;
3611 if ((event->xcrossing.mode != NotifyNormal
3612 && event->xcrossing.mode != NotifyUngrab)
3613 || event->xcrossing.detail == NotifyVirtual
3614 || event->xcrossing.detail == NotifyNonlinearVirtual)
3615 break;
3616 if (event->xcrossing.focus &&
3617 !(widget->windowType() == Qt::Desktop) && !widget->isActiveWindow()) {
3618 if (X11->focus_model == QX11Data::FM_Unknown) // check focus model
3619 qt_check_focus_model();
3620 if (X11->focus_model == QX11Data::FM_PointerRoot) // PointerRoot mode
3621 setActiveWindow(widget);
3622 }
3623
3624 if (qt_button_down && !d->inPopupMode())
3625 break;
3626
3627 QWidget *alien = widget->childAt(widget->d_func()->mapFromWS(QPoint(event->xcrossing.x,
3628 event->xcrossing.y)));
3629 QWidget *enter = alien ? alien : widget;
3630 QWidget *leave = 0;
3631 if (qt_last_mouse_receiver && !qt_last_mouse_receiver->internalWinId())
3632 leave = qt_last_mouse_receiver;
3633 else
3634 leave = QWidget::find(curWin);
3635
3636 // ### Alien: enter/leave might be wrong here with overlapping siblings
3637 // if the enter widget is native and stacked under a non-native widget.
3638 QApplicationPrivate::dispatchEnterLeave(enter, leave);
3639 curWin = widget->internalWinId();
3640 qt_last_mouse_receiver = enter;
3641 if (!d->inPopupMode() || widget->window() == activePopupWidget())
3642 widget->translateMouseEvent(event); //we don't get MotionNotify, emulate it
3643 }
3644 break;
3645 case LeaveNotify: { // leave window
3646 QWidget *mouseGrabber = QWidget::mouseGrabber();
3647 if (mouseGrabber && !d->inPopupMode())
3648 break;
3649 if (curWin && widget->internalWinId() != curWin)
3650 break;
3651 if ((event->xcrossing.mode != NotifyNormal
3652 && event->xcrossing.mode != NotifyUngrab)
3653 || event->xcrossing.detail == NotifyInferior)
3654 break;
3655 if (!(widget->windowType() == Qt::Desktop))
3656 widget->translateMouseEvent(event); //we don't get MotionNotify, emulate it
3657
3658 QWidget* enter = 0;
3659 QPoint enterPoint;
3660 XEvent ev;
3661 while (XCheckMaskEvent(X11->display, EnterWindowMask | LeaveWindowMask , &ev)
3662 && !qt_x11EventFilter(&ev)) {
3663 QWidget* event_widget = QWidget::find(ev.xcrossing.window);
3664 if(event_widget && event_widget->x11Event(&ev))
3665 break;
3666 if (ev.type == LeaveNotify
3667 || (ev.xcrossing.mode != NotifyNormal
3668 && ev.xcrossing.mode != NotifyUngrab)
3669 || ev.xcrossing.detail == NotifyVirtual
3670 || ev.xcrossing.detail == NotifyNonlinearVirtual)
3671 continue;
3672 enter = event_widget;
3673 if (enter)
3674 enterPoint = enter->d_func()->mapFromWS(QPoint(ev.xcrossing.x, ev.xcrossing.y));
3675 if (ev.xcrossing.focus &&
3676 enter && !(enter->windowType() == Qt::Desktop) && !enter->isActiveWindow()) {
3677 if (X11->focus_model == QX11Data::FM_Unknown) // check focus model
3678 qt_check_focus_model();
3679 if (X11->focus_model == QX11Data::FM_PointerRoot) // PointerRoot mode
3680 setActiveWindow(enter);
3681 }
3682 break;
3683 }
3684
3685 if ((! enter || (enter->windowType() == Qt::Desktop)) &&
3686 event->xcrossing.focus && widget == QApplicationPrivate::active_window &&
3687 X11->focus_model == QX11Data::FM_PointerRoot // PointerRoot mode
3688 ) {
3689 setActiveWindow(0);
3690 }
3691
3692 if (qt_button_down && !d->inPopupMode())
3693 break;
3694
3695 if (!curWin)
3696 QApplicationPrivate::dispatchEnterLeave(widget, 0);
3697
3698 if (enter) {
3699 QWidget *alienEnter = enter->childAt(enterPoint);
3700 if (alienEnter)
3701 enter = alienEnter;
3702 }
3703
3704 QWidget *leave = qt_last_mouse_receiver ? qt_last_mouse_receiver : widget;
3705 QWidget *activePopupWidget = qApp->activePopupWidget();
3706
3707 if (mouseGrabber && activePopupWidget && leave == activePopupWidget)
3708 enter = mouseGrabber;
3709 else if (enter != widget && mouseGrabber) {
3710 if (!widget->rect().contains(widget->d_func()->mapFromWS(QPoint(event->xcrossing.x,
3711 event->xcrossing.y))))
3712 break;
3713 }
3714
3715 QApplicationPrivate::dispatchEnterLeave(enter, leave);
3716 qt_last_mouse_receiver = enter;
3717
3718 if (enter && QApplicationPrivate::tryModalHelper(enter, 0)) {
3719 QWidget *nativeEnter = enter->internalWinId() ? enter : enter->nativeParentWidget();
3720 curWin = nativeEnter->internalWinId();
3721 static_cast<QETWidget *>(nativeEnter)->translateMouseEvent(&ev); //we don't get MotionNotify, emulate it
3722 } else {
3723 curWin = 0;
3724 qt_last_mouse_receiver = 0;
3725 }
3726 }
3727 break;
3728
3729 case UnmapNotify: // window hidden
3730 if (widget->isWindow()) {
3731 Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
3732 widget->d_func()->topData()->waitingForMapNotify = 0;
3733
3734 if (widget->windowType() != Qt::Popup && !widget->testAttribute(Qt::WA_DontShowOnScreen)) {
3735 widget->setAttribute(Qt::WA_Mapped, false);
3736 if (widget->isVisible()) {
3737 widget->d_func()->topData()->spont_unmapped = 1;
3738 QHideEvent e;
3739 QApplication::sendSpontaneousEvent(widget, &e);
3740 widget->d_func()->hideChildren(true);
3741 }
3742 }
3743
3744 if (!widget->d_func()->topData()->validWMState && X11->deferred_map.removeAll(widget))
3745 widget->doDeferredMap();
3746 }
3747 break;
3748
3749 case MapNotify: // window shown
3750 if (widget->isWindow()) {
3751 // if we got a MapNotify when we were not waiting for it, it most
3752 // likely means the user has already asked to hide the window before
3753 // it ever being shown, so we try to withdraw a window after sending
3754 // the QShowEvent.
3755 bool pendingHide = widget->testAttribute(Qt::WA_WState_ExplicitShowHide) && widget->testAttribute(Qt::WA_WState_Hidden);
3756 widget->d_func()->topData()->waitingForMapNotify = 0;
3757
3758 if (widget->windowType() != Qt::Popup) {
3759 widget->setAttribute(Qt::WA_Mapped);
3760 if (widget->d_func()->topData()->spont_unmapped) {
3761 widget->d_func()->topData()->spont_unmapped = 0;
3762 widget->d_func()->showChildren(true);
3763 QShowEvent e;
3764 QApplication::sendSpontaneousEvent(widget, &e);
3765
3766 // show() must have been called on this widget in
3767 // order to reach this point, but we could have
3768 // cleared these 2 attributes in case something
3769 // previously forced us into WithdrawnState
3770 // (e.g. kdocker)
3771 widget->setAttribute(Qt::WA_WState_ExplicitShowHide, true);
3772 widget->setAttribute(Qt::WA_WState_Visible, true);
3773 }
3774 }
3775 if (pendingHide) // hide the window
3776 XWithdrawWindow(X11->display, widget->internalWinId(), widget->x11Info().screen());
3777 }
3778 break;
3779
3780 case ClientMessage: // client message
3781 return x11ClientMessage(widget,event,False);
3782
3783 case ReparentNotify: { // window manager reparents
3784 // compress old reparent events to self
3785 XEvent ev;
3786 while (XCheckTypedWindowEvent(X11->display,
3787 widget->effectiveWinId(),
3788 ReparentNotify,
3789 &ev)) {
3790 if (ev.xreparent.window != ev.xreparent.event) {
3791 XPutBackEvent(X11->display, &ev);
3792 break;
3793 }
3794 }
3795 if (widget->isWindow()) {
3796 QTLWExtra *topData = widget->d_func()->topData();
3797
3798 // store the parent. Useful for many things, embedding for instance.
3799 topData->parentWinId = event->xreparent.parent;
3800
3801 // the widget frame strut should also be invalidated
3802 widget->data->fstrut_dirty = 1;
3803
3804 // work around broken window managers... if we get a
3805 // ReparentNotify before the MapNotify, we assume that
3806 // we're being managed by a reparenting window
3807 // manager.
3808 //
3809 // however, the WM_STATE property may not have been set
3810 // yet, but we are going to assume that it will
3811 // be... otherwise we could try to map again after getting
3812 // an UnmapNotify... which could then, in turn, trigger a
3813 // race in the window manager which causes the window to
3814 // disappear when it really should be hidden.
3815 if (topData->waitingForMapNotify && !topData->validWMState) {
3816 topData->waitingForMapNotify = 0;
3817 topData->validWMState = 1;
3818 }
3819
3820 if (X11->focus_model != QX11Data::FM_Unknown) {
3821 // toplevel reparented...
3822 QWidget *newparent = QWidget::find(event->xreparent.parent);
3823 if (! newparent || (newparent->windowType() == Qt::Desktop)) {
3824 // we don't know about the new parent (or we've been
3825 // reparented to root), perhaps a window manager
3826 // has been (re)started? reset the focus model to unknown
3827 X11->focus_model = QX11Data::FM_Unknown;
3828 }
3829 }
3830 }
3831 break;
3832 }
3833 case SelectionRequest: {
3834 XSelectionRequestEvent *req = &event->xselectionrequest;
3835 if (! req)
3836 break;
3837
3838 if (ATOM(XdndSelection) && req->selection == ATOM(XdndSelection)) {
3839 X11->xdndHandleSelectionRequest(req);
3840
3841 } else if (qt_clipboard) {
3842 QClipboardEvent e(reinterpret_cast<QEventPrivate*>(event));
3843 QApplication::sendSpontaneousEvent(qt_clipboard, &e);
3844 }
3845 break;
3846 }
3847 case SelectionClear: {
3848 XSelectionClearEvent *req = &event->xselectionclear;
3849 // don't deliver dnd events to the clipboard, it gets confused
3850 if (! req || (ATOM(XdndSelection) && req->selection == ATOM(XdndSelection)))
3851 break;
3852
3853 if (qt_clipboard && !X11->use_xfixes) {
3854 QClipboardEvent e(reinterpret_cast<QEventPrivate*>(event));
3855 QApplication::sendSpontaneousEvent(qt_clipboard, &e);
3856 }
3857 break;
3858 }
3859
3860 case SelectionNotify: {
3861 XSelectionEvent *req = &event->xselection;
3862 // don't deliver dnd events to the clipboard, it gets confused
3863 if (! req || (ATOM(XdndSelection) && req->selection == ATOM(XdndSelection)))
3864 break;
3865
3866 if (qt_clipboard) {
3867 QClipboardEvent e(reinterpret_cast<QEventPrivate*>(event));
3868 QApplication::sendSpontaneousEvent(qt_clipboard, &e);
3869 }
3870 break;
3871 }
3872 case PropertyNotify:
3873 // some properties changed
3874 if (event->xproperty.window == QX11Info::appRootWindow(0)) {
3875 // root properties for the first screen
3876 if (!X11->use_xfixes && event->xproperty.atom == ATOM(_QT_CLIPBOARD_SENTINEL)) {
3877 if (qt_check_clipboard_sentinel()) {
3878 emit clipboard()->changed(QClipboard::Clipboard);
3879 emit clipboard()->dataChanged();
3880 }
3881 } else if (!X11->use_xfixes && event->xproperty.atom == ATOM(_QT_SELECTION_SENTINEL)) {
3882 if (qt_check_selection_sentinel()) {
3883 emit clipboard()->changed(QClipboard::Selection);
3884 emit clipboard()->selectionChanged();
3885 }
3886 } else if (QApplicationPrivate::obey_desktop_settings) {
3887 if (event->xproperty.atom == ATOM(RESOURCE_MANAGER))
3888 qt_set_x11_resources();
3889 else if (event->xproperty.atom == ATOM(_QT_SETTINGS_TIMESTAMP))
3890 qt_set_x11_resources();
3891 }
3892 }
3893 if (event->xproperty.window == QX11Info::appRootWindow()) {
3894 // root properties for the default screen
3895 if (event->xproperty.atom == ATOM(_QT_INPUT_ENCODING)) {
3896 qt_set_input_encoding();
3897 } else if (event->xproperty.atom == ATOM(_NET_SUPPORTED)) {
3898 qt_get_net_supported();
3899 } else if (event->xproperty.atom == ATOM(_NET_VIRTUAL_ROOTS)) {
3900 qt_get_net_virtual_roots();
3901 } else if (event->xproperty.atom == ATOM(_NET_WORKAREA)) {
3902 qt_desktopwidget_update_workarea();
3903
3904 // emit the workAreaResized() signal
3905 QDesktopWidget *desktop = QApplication::desktop();
3906 int numScreens = desktop->numScreens();
3907 for (int i = 0; i < numScreens; ++i)
3908 emit desktop->workAreaResized(i);
3909 }
3910 } else if (widget) {
3911 widget->translatePropertyEvent(event);
3912 } else {
3913 return -1; // don't know this window
3914 }
3915 break;
3916
3917 default:
3918 break;
3919 }
3920
3921 return 0;
3922}
3923
3924bool QApplication::x11EventFilter(XEvent *)
3925{
3926 return false;
3927}
3928
3929
3930
3931/*****************************************************************************
3932 Modal widgets; Since Xlib has little support for this we roll our own
3933 modal widget mechanism.
3934 A modal widget without a parent becomes application-modal.
3935 A modal widget with a parent becomes modal to its parent and grandparents..
3936
3937 QApplicationPrivate::enterModal()
3938 Enters modal state
3939 Arguments:
3940 QWidget *widget A modal widget
3941
3942 QApplicationPrivate::leaveModal()
3943 Leaves modal state for a widget
3944 Arguments:
3945 QWidget *widget A modal widget
3946 *****************************************************************************/
3947
3948bool QApplicationPrivate::modalState()
3949{
3950 return app_do_modal;
3951}
3952
3953void QApplicationPrivate::enterModal_sys(QWidget *widget)
3954{
3955 if (!qt_modal_stack)
3956 qt_modal_stack = new QWidgetList;
3957
3958 QWidget *leave = qt_last_mouse_receiver;
3959 if (!leave)
3960 leave = QWidget::find((WId)curWin);
3961 QApplicationPrivate::dispatchEnterLeave(0, leave);
3962 qt_modal_stack->insert(0, widget);
3963 app_do_modal = true;
3964 curWin = 0;
3965 qt_last_mouse_receiver = 0;
3966}
3967
3968void QApplicationPrivate::leaveModal_sys(QWidget *widget)
3969{
3970 if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
3971 if (qt_modal_stack->isEmpty()) {
3972 delete qt_modal_stack;
3973 qt_modal_stack = 0;
3974 QPoint p(QCursor::pos());
3975 QWidget* w = QApplication::widgetAt(p.x(), p.y());
3976 QWidget *leave = qt_last_mouse_receiver;
3977 if (!leave)
3978 leave = QWidget::find((WId)curWin);
3979 if (QWidget *grabber = QWidget::mouseGrabber()) {
3980 w = grabber;
3981 if (leave == w)
3982 leave = 0;
3983 }
3984 QApplicationPrivate::dispatchEnterLeave(w, leave); // send synthetic enter event
3985 curWin = w ? w->effectiveWinId() : 0;
3986 qt_last_mouse_receiver = w;
3987 }
3988 }
3989 app_do_modal = qt_modal_stack != 0;
3990}
3991
3992bool qt_try_modal(QWidget *widget, XEvent *event)
3993{
3994 if (qt_xdnd_dragging) {
3995 // allow mouse events while DnD is active
3996 switch (event->type) {
3997 case ButtonPress:
3998 case ButtonRelease:
3999 case MotionNotify:
4000 return true;
4001 default:
4002 break;
4003 }
4004 }
4005
4006 // allow mouse release events to be sent to widgets that have been pressed
4007 if (event->type == ButtonRelease) {
4008 QWidget *alienWidget = widget->childAt(widget->mapFromGlobal(QPoint(event->xbutton.x_root,
4009 event->xbutton.y_root)));
4010 if (widget == qt_button_down || (alienWidget && alienWidget == qt_button_down))
4011 return true;
4012 }
4013
4014 if (QApplicationPrivate::tryModalHelper(widget))
4015 return true;
4016
4017 // disallow mouse/key events
4018 switch (event->type) {
4019 case ButtonPress:
4020 case ButtonRelease:
4021 case MotionNotify:
4022 case XKeyPress:
4023 case XKeyRelease:
4024 case EnterNotify:
4025 case LeaveNotify:
4026 case ClientMessage:
4027 return false;
4028 default:
4029 break;
4030 }
4031
4032 return true;
4033}
4034
4035
4036/*****************************************************************************
4037 Popup widget mechanism
4038
4039 openPopup()
4040 Adds a widget to the list of popup widgets
4041 Arguments:
4042 QWidget *widget The popup widget to be added
4043
4044 closePopup()
4045 Removes a widget from the list of popup widgets
4046 Arguments:
4047 QWidget *widget The popup widget to be removed
4048 *****************************************************************************/
4049
4050
4051static int openPopupCount = 0;
4052void QApplicationPrivate::openPopup(QWidget *popup)
4053{
4054 Q_Q(QApplication);
4055 openPopupCount++;
4056 if (!QApplicationPrivate::popupWidgets) { // create list
4057 QApplicationPrivate::popupWidgets = new QWidgetList;
4058 }
4059 QApplicationPrivate::popupWidgets->append(popup); // add to end of list
4060 Display *dpy = X11->display;
4061 if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()){ // grab mouse/keyboard
4062 Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
4063 int r = XGrabKeyboard(dpy, popup->effectiveWinId(), false,
4064 GrabModeAsync, GrabModeAsync, X11->time);
4065 if ((popupGrabOk = (r == GrabSuccess))) {
4066 r = XGrabPointer(dpy, popup->effectiveWinId(), true,
4067 (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
4068 | EnterWindowMask | LeaveWindowMask | PointerMotionMask),
4069 GrabModeAsync, GrabModeAsync, XNone, XNone, X11->time);
4070 if (!(popupGrabOk = (r == GrabSuccess))) {
4071 // transfer grab back to the keyboard grabber if any
4072 if (QWidgetPrivate::keyboardGrabber != 0)
4073 QWidgetPrivate::keyboardGrabber->grabKeyboard();
4074 else
4075 XUngrabKeyboard(dpy, X11->time);
4076 }
4077 }
4078 }
4079
4080 // popups are not focus-handled by the window system (the first
4081 // popup grabbed the keyboard), so we have to do that manually: A
4082 // new popup gets the focus
4083 if (popup->focusWidget()) {
4084 popup->focusWidget()->setFocus(Qt::PopupFocusReason);
4085 } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
4086 if (QWidget *fw = QApplication::focusWidget()) {
4087 QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
4088 q->sendEvent(fw, &e);
4089 }
4090 }
4091}
4092
4093void QApplicationPrivate::closePopup(QWidget *popup)
4094{
4095 Q_Q(QApplication);
4096 if (!QApplicationPrivate::popupWidgets)
4097 return;
4098 QApplicationPrivate::popupWidgets->removeAll(popup);
4099 if (popup == qt_popup_down) {
4100 qt_button_down = 0;
4101 qt_popup_down = 0;
4102 }
4103 if (QApplicationPrivate::popupWidgets->count() == 0) { // this was the last popup
4104 delete QApplicationPrivate::popupWidgets;
4105 QApplicationPrivate::popupWidgets = 0;
4106 if (!qt_nograb() && popupGrabOk) { // grabbing not disabled
4107 Display *dpy = X11->display;
4108 if (popup->geometry().contains(QPoint(mouseGlobalXPos, mouseGlobalYPos))
4109 || popup->testAttribute(Qt::WA_NoMouseReplay)) {
4110 // mouse release event or inside
4111 replayPopupMouseEvent = false;
4112 } else { // mouse press event
4113 mouseButtonPressTime -= 10000; // avoid double click
4114 replayPopupMouseEvent = true;
4115 }
4116 // transfer grab back to mouse grabber if any, otherwise release the grab
4117 if (QWidgetPrivate::mouseGrabber != 0)
4118 QWidgetPrivate::mouseGrabber->grabMouse();
4119 else
4120 XUngrabPointer(dpy, X11->time);
4121
4122 // transfer grab back to keyboard grabber if any, otherwise release the grab
4123 if (QWidgetPrivate::keyboardGrabber != 0)
4124 QWidgetPrivate::keyboardGrabber->grabKeyboard();
4125 else
4126 XUngrabKeyboard(dpy, X11->time);
4127
4128 XFlush(dpy);
4129 }
4130 if (QApplicationPrivate::active_window) {
4131 if (QWidget *fw = QApplicationPrivate::active_window->focusWidget()) {
4132 if (fw != QApplication::focusWidget()) {
4133 fw->setFocus(Qt::PopupFocusReason);
4134 } else {
4135 QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
4136 q->sendEvent(fw, &e);
4137 }
4138 }
4139 }
4140 } else {
4141 // popups are not focus-handled by the window system (the
4142 // first popup grabbed the keyboard), so we have to do that
4143 // manually: A popup was closed, so the previous popup gets
4144 // the focus.
4145 QWidget* aw = QApplicationPrivate::popupWidgets->last();
4146 if (QWidget *fw = aw->focusWidget())
4147 fw->setFocus(Qt::PopupFocusReason);
4148
4149 // regrab the keyboard and mouse in case 'popup' lost the grab
4150 if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()){ // grab mouse/keyboard
4151 Display *dpy = X11->display;
4152 Q_ASSERT(aw->testAttribute(Qt::WA_WState_Created));
4153 int r = XGrabKeyboard(dpy, aw->effectiveWinId(), false,
4154 GrabModeAsync, GrabModeAsync, X11->time);
4155 if ((popupGrabOk = (r == GrabSuccess))) {
4156 r = XGrabPointer(dpy, aw->effectiveWinId(), true,
4157 (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
4158 | EnterWindowMask | LeaveWindowMask | PointerMotionMask),
4159 GrabModeAsync, GrabModeAsync, XNone, XNone, X11->time);
4160 if (!(popupGrabOk = (r == GrabSuccess))) {
4161 // transfer grab back to keyboard grabber
4162 if (QWidgetPrivate::keyboardGrabber != 0)
4163 QWidgetPrivate::keyboardGrabber->grabKeyboard();
4164 else
4165 XUngrabKeyboard(dpy, X11->time);
4166 }
4167 }
4168 }
4169 }
4170}
4171
4172/*****************************************************************************
4173 Event translation; translates X11 events to Qt events
4174 *****************************************************************************/
4175
4176//
4177// Mouse event translation
4178//
4179// Xlib doesn't give mouse double click events, so we generate them by
4180// comparing window, time and position between two mouse press events.
4181//
4182
4183static Qt::MouseButtons translateMouseButtons(int s)
4184{
4185 Qt::MouseButtons ret = 0;
4186 if (s & Button1Mask)
4187 ret |= Qt::LeftButton;
4188 if (s & Button2Mask)
4189 ret |= Qt::MidButton;
4190 if (s & Button3Mask)
4191 ret |= Qt::RightButton;
4192 return ret;
4193}
4194
4195Qt::KeyboardModifiers QX11Data::translateModifiers(int s)
4196{
4197 Qt::KeyboardModifiers ret = 0;
4198 if (s & ShiftMask)
4199 ret |= Qt::ShiftModifier;
4200 if (s & ControlMask)
4201 ret |= Qt::ControlModifier;
4202 if (s & qt_alt_mask)
4203 ret |= Qt::AltModifier;
4204 if (s & qt_meta_mask)
4205 ret |= Qt::MetaModifier;
4206 if (s & qt_mode_switch_mask)
4207 ret |= Qt::GroupSwitchModifier;
4208 return ret;
4209}
4210
4211bool QETWidget::translateMouseEvent(const XEvent *event)
4212{
4213 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
4214 Q_ASSERT(internalWinId());
4215
4216 Q_D(QWidget);
4217 QEvent::Type type; // event parameters
4218 QPoint pos;
4219 QPoint globalPos;
4220 Qt::MouseButton button = Qt::NoButton;
4221 Qt::MouseButtons buttons;
4222 Qt::KeyboardModifiers modifiers;
4223 XEvent nextEvent;
4224
4225 if (qt_sm_blockUserInput) // block user interaction during session management
4226 return true;
4227
4228 if (event->type == MotionNotify) { // mouse move
4229 if (event->xmotion.root != RootWindow(X11->display, x11Info().screen()) &&
4230 ! qt_xdnd_dragging)
4231 return false;
4232
4233 XMotionEvent lastMotion = event->xmotion;
4234 while(XPending(X11->display)) { // compress mouse moves
4235 XNextEvent(X11->display, &nextEvent);
4236 if (nextEvent.type == ConfigureNotify
4237 || nextEvent.type == PropertyNotify
4238 || nextEvent.type == Expose
4239 || nextEvent.type == GraphicsExpose
4240 || nextEvent.type == NoExpose
4241 || nextEvent.type == KeymapNotify
4242 || ((nextEvent.type == EnterNotify || nextEvent.type == LeaveNotify)
4243 && qt_button_down == this)
4244 || (nextEvent.type == ClientMessage
4245 && (nextEvent.xclient.message_type == ATOM(_QT_SCROLL_DONE) ||
4246 (nextEvent.xclient.message_type == ATOM(WM_PROTOCOLS) &&
4247 (Atom)nextEvent.xclient.data.l[0] == ATOM(_NET_WM_SYNC_REQUEST))))) {
4248 // Pass the event through the event dispatcher filter so that applications
4249 // which install an event filter on the dispatcher get to handle it first.
4250 if (!QAbstractEventDispatcher::instance()->filterEvent(&nextEvent))
4251 qApp->x11ProcessEvent(&nextEvent);
4252 continue;
4253 } else if (nextEvent.type != MotionNotify ||
4254 nextEvent.xmotion.window != event->xmotion.window ||
4255 nextEvent.xmotion.state != event->xmotion.state) {
4256 XPutBackEvent(X11->display, &nextEvent);
4257 break;
4258 }
4259 if (!qt_x11EventFilter(&nextEvent)
4260 && !x11Event(&nextEvent)) // send event through filter
4261 lastMotion = nextEvent.xmotion;
4262 else
4263 break;
4264 }
4265 type = QEvent::MouseMove;
4266 pos.rx() = lastMotion.x;
4267 pos.ry() = lastMotion.y;
4268 pos = d->mapFromWS(pos);
4269 globalPos.rx() = lastMotion.x_root;
4270 globalPos.ry() = lastMotion.y_root;
4271 buttons = translateMouseButtons(lastMotion.state);
4272 modifiers = X11->translateModifiers(lastMotion.state);
4273 if (qt_button_down && !buttons)
4274 qt_button_down = 0;
4275 } else if (event->type == EnterNotify || event->type == LeaveNotify) {
4276 XEvent *xevent = (XEvent *)event;
4277 //unsigned int xstate = event->xcrossing.state;
4278 type = QEvent::MouseMove;
4279 pos.rx() = xevent->xcrossing.x;
4280 pos.ry() = xevent->xcrossing.y;
4281 pos = d->mapFromWS(pos);
4282 globalPos.rx() = xevent->xcrossing.x_root;
4283 globalPos.ry() = xevent->xcrossing.y_root;
4284 buttons = translateMouseButtons(xevent->xcrossing.state);
4285 modifiers = X11->translateModifiers(xevent->xcrossing.state);
4286 if (qt_button_down && !buttons)
4287 qt_button_down = 0;
4288 if (qt_button_down)
4289 return true;
4290 } else { // button press or release
4291 pos.rx() = event->xbutton.x;
4292 pos.ry() = event->xbutton.y;
4293 pos = d->mapFromWS(pos);
4294 globalPos.rx() = event->xbutton.x_root;
4295 globalPos.ry() = event->xbutton.y_root;
4296 buttons = translateMouseButtons(event->xbutton.state);
4297 modifiers = X11->translateModifiers(event->xbutton.state);
4298 switch (event->xbutton.button) {
4299 case Button1: button = Qt::LeftButton; break;
4300 case Button2: button = Qt::MidButton; break;
4301 case Button3: button = Qt::RightButton; break;
4302 case Button4:
4303 case Button5:
4304 case 6:
4305 case 7:
4306 // the fancy mouse wheel.
4307
4308 // We are only interested in ButtonPress.
4309 if (event->type == ButtonPress){
4310 // compress wheel events (the X Server will simply
4311 // send a button press for each single notch,
4312 // regardless whether the application can catch up
4313 // or not)
4314 int delta = 1;
4315 XEvent xevent;
4316 while (XCheckTypedWindowEvent(X11->display, effectiveWinId(), ButtonPress, &xevent)){
4317 if (xevent.xbutton.button != event->xbutton.button){
4318 XPutBackEvent(X11->display, &xevent);
4319 break;
4320 }
4321 delta++;
4322 }
4323
4324 // the delta is defined as multiples of
4325 // WHEEL_DELTA, which is set to 120. Future wheels
4326 // may offer a finer-resolution. A positive delta
4327 // indicates forward rotation, a negative one
4328 // backward rotation respectively.
4329 int btn = event->xbutton.button;
4330 delta *= 120 * ((btn == Button4 || btn == 6) ? 1 : -1);
4331 bool hor = (((btn == Button4 || btn == Button5) && (modifiers & Qt::AltModifier)) ||
4332 (btn == 6 || btn == 7));
4333 translateWheelEvent(globalPos.x(), globalPos.y(), delta, buttons,
4334 modifiers, (hor) ? Qt::Horizontal: Qt::Vertical);
4335 }
4336 return true;
4337 case 8: button = Qt::XButton1; break;
4338 case 9: button = Qt::XButton2; break;
4339 }
4340 if (event->type == ButtonPress) { // mouse button pressed
4341 buttons |= button;
4342#if defined(Q_OS_IRIX) && !defined(QT_NO_TABLET)
4343 QTabletDeviceDataList *tablets = qt_tablet_devices();
4344 for (int i = 0; i < tablets->size(); ++i) {
4345 QTabletDeviceData &tab = tablets->operator[](i);
4346 XEvent myEv;
4347 if (XCheckTypedEvent(X11->display, tab.xinput_button_press, &myEv)) {
4348 if (translateXinputEvent(&myEv, &tab)) {
4349 //Spontaneous event sent. Check if we need to continue.
4350 if (qt_tabletChokeMouse) {
4351 qt_tabletChokeMouse = false;
4352 return false;
4353 }
4354 }
4355 }
4356 }
4357#endif
4358 if (!qt_button_down) {
4359 qt_button_down = childAt(pos); //magic for masked widgets
4360 if (!qt_button_down)
4361 qt_button_down = this;
4362 }
4363 if (mouseActWindow == event->xbutton.window &&
4364 mouseButtonPressed == button &&
4365 (long)event->xbutton.time -(long)mouseButtonPressTime
4366 < QApplication::doubleClickInterval() &&
4367 qAbs(event->xbutton.x - mouseXPos) < QT_GUI_DOUBLE_CLICK_RADIUS &&
4368 qAbs(event->xbutton.y - mouseYPos) < QT_GUI_DOUBLE_CLICK_RADIUS) {
4369 type = QEvent::MouseButtonDblClick;
4370 mouseButtonPressTime -= 2000; // no double-click next time
4371 } else {
4372 type = QEvent::MouseButtonPress;
4373 mouseButtonPressTime = event->xbutton.time;
4374 }
4375 mouseButtonPressed = button; // save event params for
4376 mouseXPos = event->xbutton.x; // future double click tests
4377 mouseYPos = event->xbutton.y;
4378 mouseGlobalXPos = globalPos.x();
4379 mouseGlobalYPos = globalPos.y();
4380 } else { // mouse button released
4381 buttons &= ~button;
4382#if defined(Q_OS_IRIX) && !defined(QT_NO_TABLET)
4383 QTabletDeviceDataList *tablets = qt_tablet_devices();
4384 for (int i = 0; i < tablets->size(); ++i) {
4385 QTabletDeviceData &tab = tablets->operator[](i);
4386 XEvent myEv;
4387 if (XCheckTypedEvent(X11->display, tab.xinput_button_press, &myEv)) {
4388 if (translateXinputEvent(&myEv, &tab)) {
4389 //Spontaneous event sent. Check if we need to continue.
4390 if (qt_tabletChokeMouse) {
4391 qt_tabletChokeMouse = false;
4392 return false;
4393 }
4394 }
4395 }
4396 }
4397#endif
4398 type = QEvent::MouseButtonRelease;
4399 }
4400 }
4401 mouseActWindow = effectiveWinId(); // save some event params
4402 mouseButtonState = buttons;
4403 if (type == 0) // don't send event
4404 return false;
4405
4406 if (qApp->d_func()->inPopupMode()) { // in popup mode
4407 QWidget *activePopupWidget = qApp->activePopupWidget();
4408 QWidget *popup = qApp->activePopupWidget();
4409 if (popup != this) {
4410 if (event->type == LeaveNotify)
4411 return false;
4412 if ((windowType() == Qt::Popup) && rect().contains(pos) && 0)
4413 popup = this;
4414 else // send to last popup
4415 pos = popup->mapFromGlobal(globalPos);
4416 }
4417 bool releaseAfter = false;
4418 QWidget *popupChild = popup->childAt(pos);
4419
4420 if (popup != qt_popup_down){
4421 qt_button_down = 0;
4422 qt_popup_down = 0;
4423 }
4424
4425 switch (type) {
4426 case QEvent::MouseButtonPress:
4427 case QEvent::MouseButtonDblClick:
4428 qt_button_down = popupChild;
4429 qt_popup_down = popup;
4430 break;
4431 case QEvent::MouseButtonRelease:
4432 releaseAfter = true;
4433 break;
4434 default:
4435 break; // nothing for mouse move
4436 }
4437
4438 int oldOpenPopupCount = openPopupCount;
4439
4440 if (popup->isEnabled()) {
4441 // deliver event
4442 replayPopupMouseEvent = false;
4443 QWidget *receiver = popup;
4444 QPoint widgetPos = pos;
4445 if (qt_button_down)
4446 receiver = qt_button_down;
4447 else if (popupChild)
4448 receiver = popupChild;
4449 if (receiver != popup)
4450 widgetPos = receiver->mapFromGlobal(globalPos);
4451 QWidget *alien = childAt(mapFromGlobal(globalPos));
4452 QMouseEvent e(type, widgetPos, globalPos, button, buttons, modifiers);
4453 QApplicationPrivate::sendMouseEvent(receiver, &e, alien, this, &qt_button_down, qt_last_mouse_receiver);
4454 } else {
4455 // close disabled popups when a mouse button is pressed or released
4456 switch (type) {
4457 case QEvent::MouseButtonPress:
4458 case QEvent::MouseButtonDblClick:
4459 case QEvent::MouseButtonRelease:
4460 popup->close();
4461 break;
4462 default:
4463 break;
4464 }
4465 }
4466
4467 if (qApp->activePopupWidget() != activePopupWidget
4468 && replayPopupMouseEvent) {
4469 // the active popup was closed, replay the mouse event
4470 if (!(windowType() == Qt::Popup)) {
4471#if 1
4472 qt_button_down = 0;
4473#else
4474 if (buttons == button)
4475 qt_button_down = this;
4476 QMouseEvent e(type, mapFromGlobal(globalPos), globalPos, button,
4477 buttons, modifiers);
4478 QApplication::sendSpontaneousEvent(this, &e);
4479
4480 if (type == QEvent::MouseButtonPress
4481 && button == Qt::RightButton
4482 && (openPopupCount == oldOpenPopupCount)) {
4483 QContextMenuEvent e(QContextMenuEvent::Mouse, mapFromGlobal(globalPos),
4484 globalPos, modifiers);
4485 QApplication::sendSpontaneousEvent(this, &e);
4486 }
4487#endif
4488 }
4489 replayPopupMouseEvent = false;
4490 } else if (type == QEvent::MouseButtonPress
4491 && button == Qt::RightButton
4492 && (openPopupCount == oldOpenPopupCount)) {
4493 QWidget *popupEvent = popup;
4494 if (qt_button_down)
4495 popupEvent = qt_button_down;
4496 else if(popupChild)
4497 popupEvent = popupChild;
4498 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos, modifiers);
4499 QApplication::sendSpontaneousEvent(popupEvent, &e);
4500 }
4501
4502 if (releaseAfter) {
4503 qt_button_down = 0;
4504 qt_popup_down = 0;
4505 }
4506 } else {
4507 QWidget *alienWidget = childAt(pos);
4508 QWidget *widget = QApplicationPrivate::pickMouseReceiver(this, globalPos, pos, type, buttons,
4509 qt_button_down, alienWidget);
4510 if (!widget) {
4511 if (type == QEvent::MouseButtonRelease)
4512 QApplicationPrivate::mouse_buttons &= ~button;
4513 return false; // don't send event
4514 }
4515
4516 int oldOpenPopupCount = openPopupCount;
4517 QMouseEvent e(type, pos, globalPos, button, buttons, modifiers);
4518 QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down,
4519 qt_last_mouse_receiver);
4520 if (type == QEvent::MouseButtonPress
4521 && button == Qt::RightButton
4522 && (openPopupCount == oldOpenPopupCount)) {
4523 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos, modifiers);
4524 QApplication::sendSpontaneousEvent(widget, &e);
4525 }
4526 }
4527 return true;
4528}
4529
4530
4531//
4532// Wheel event translation
4533//
4534bool QETWidget::translateWheelEvent(int global_x, int global_y, int delta,
4535 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers,
4536 Qt::Orientation orient)
4537{
4538 const QPoint globalPos = QPoint(global_x, global_y);
4539 QPoint pos = mapFromGlobal(globalPos);
4540 QWidget *widget = childAt(pos);
4541 if (!widget)
4542 widget = this;
4543 else if (!widget->internalWinId())
4544 pos = widget->mapFromGlobal(globalPos);
4545
4546#ifdef ALIEN_DEBUG
4547 qDebug() << "QETWidget::translateWheelEvent: receiver:" << widget << "pos:" << pos;
4548#endif
4549
4550 // send the event to the widget or its ancestors
4551 {
4552 QWidget* popup = qApp->activePopupWidget();
4553 if (popup && window() != popup)
4554 popup->close();
4555#ifndef QT_NO_WHEELEVENT
4556 QWheelEvent e(pos, globalPos, delta, buttons, modifiers, orient);
4557 if (QApplication::sendSpontaneousEvent(widget, &e))
4558#endif
4559 return true;
4560 }
4561
4562 // send the event to the widget that has the focus or its ancestors, if different
4563 if (widget != qApp->focusWidget() && (widget = qApp->focusWidget())) {
4564 if (widget && !widget->internalWinId())
4565 pos = widget->mapFromGlobal(globalPos);
4566 QWidget* popup = qApp->activePopupWidget();
4567 if (popup && widget != popup)
4568 popup->hide();
4569#ifndef QT_NO_WHEELEVENT
4570 QWheelEvent e(pos, globalPos, delta, buttons, modifiers, orient);
4571 if (QApplication::sendSpontaneousEvent(widget, &e))
4572#endif
4573 return true;
4574 }
4575 return false;
4576}
4577
4578
4579//
4580// XInput Translation Event
4581//
4582#if !defined (QT_NO_TABLET)
4583
4584#if !defined (Q_OS_IRIX)
4585void fetchWacomToolId(int &deviceType, qint64 &serialId)
4586{
4587 if (ptrWacomConfigInit == 0) // we actually have the lib
4588 return;
4589 WACOMCONFIG *config = ptrWacomConfigInit(X11->display, 0);
4590 if (config == 0)
4591 return;
4592 WACOMDEVICE *device = ptrWacomConfigOpenDevice (config, wacomDeviceName()->constData());
4593 if (device == 0)
4594 return;
4595 unsigned keys[1];
4596 int serialInt;
4597 ptrWacomConfigGetRawParam (device, XWACOM_PARAM_TOOLSERIAL, &serialInt, 1, keys);
4598 serialId = serialInt;
4599 int toolId;
4600 ptrWacomConfigGetRawParam (device, XWACOM_PARAM_TOOLID, &toolId, 1, keys);
4601 switch(toolId) {
4602 case 0x007: /* Mouse 4D and 2D */
4603 case 0x017: /* Intuos3 2D Mouse */
4604 case 0x094:
4605 case 0x09c:
4606 deviceType = QTabletEvent::FourDMouse;
4607 break;
4608 case 0x096: /* Lens cursor */
4609 case 0x097: /* Intuos3 Lens cursor */
4610 deviceType = QTabletEvent::Puck;
4611 break;
4612 case 0x0fa:
4613 case 0x81b: /* Intuos3 Classic Pen Eraser */
4614 case 0x82a: /* Eraser */
4615 case 0x82b: /* Intuos3 Grip Pen Eraser */
4616 case 0x85a:
4617 case 0x91a:
4618 case 0x91b: /* Intuos3 Airbrush Eraser */
4619 case 0xd1a:
4620 deviceType = QTabletEvent::XFreeEraser;
4621 break;
4622 case 0x112:
4623 case 0x912:
4624 case 0x913: /* Intuos3 Airbrush */
4625 case 0xd12:
4626 deviceType = QTabletEvent::Airbrush;
4627 break;
4628 case 0x012:
4629 case 0x022:
4630 case 0x032:
4631 case 0x801: /* Intuos3 Inking pen */
4632 case 0x812: /* Inking pen */
4633 case 0x813: /* Intuos3 Classic Pen */
4634 case 0x822: /* Pen */
4635 case 0x823: /* Intuos3 Grip Pen */
4636 case 0x832: /* Stroke pen */
4637 case 0x842:
4638 case 0x852:
4639 case 0x885: /* Intuos3 Marker Pen */
4640 default: /* Unknown tool */
4641 deviceType = QTabletEvent::Stylus;
4642 }
4643
4644 /* Close device and return */
4645 ptrWacomConfigCloseDevice (device);
4646 ptrWacomConfigTerm(config);
4647}
4648#endif
4649
4650struct qt_tablet_motion_data
4651{
4652 bool filterByWidget;
4653 const QWidget *widget;
4654 const QWidget *etWidget;
4655 int tabletMotionType;
4656 bool error; // found a reason to stop searching
4657};
4658
4659static Bool qt_mouseMotion_scanner(Display *, XEvent *event, XPointer arg)
4660{
4661 qt_tablet_motion_data *data = (qt_tablet_motion_data *) arg;
4662 if (data->error)
4663 return false;
4664
4665 if (event->type == MotionNotify)
4666 return true;
4667
4668 data->error = event->type != data->tabletMotionType; // we stop compression when another event gets in between.
4669 return false;
4670}
4671
4672static Bool qt_tabletMotion_scanner(Display *, XEvent *event, XPointer arg)
4673{
4674 qt_tablet_motion_data *data = (qt_tablet_motion_data *) arg;
4675 if (data->error)
4676 return false;
4677 if (event->type == data->tabletMotionType) {
4678 const XDeviceMotionEvent *const motion = reinterpret_cast<const XDeviceMotionEvent*>(event);
4679 if (data->filterByWidget) {
4680 const QPoint curr(motion->x, motion->y);
4681 const QWidget *w = data->etWidget;
4682 const QWidget *const child = w->childAt(curr);
4683 if (child) {
4684 w = child;
4685 }
4686 if (w == data->widget)
4687 return true;
4688 } else {
4689 return true;
4690 }
4691 }
4692
4693 data->error = event->type != MotionNotify; // we stop compression when another event gets in between.
4694 return false;
4695}
4696
4697bool QETWidget::translateXinputEvent(const XEvent *ev, QTabletDeviceData *tablet)
4698{
4699#if defined (Q_OS_IRIX)
4700 // Wacom has put defines in their wacom.h file so it would be quite wise
4701 // to use them, need to think of a decent way of not using
4702 // it when it doesn't exist...
4703 XDeviceState *s;
4704 XInputClass *iClass;
4705 XValuatorState *vs;
4706 int j;
4707#endif
4708
4709 Q_ASSERT(tablet != 0);
4710
4711 QWidget *w = this;
4712 QPoint global,
4713 curr;
4714 QPointF hiRes;
4715 qreal pressure = 0;
4716 int xTilt = 0,
4717 yTilt = 0,
4718 z = 0;
4719 qreal tangentialPressure = 0;
4720 qreal rotation = 0;
4721 int deviceType = QTabletEvent::NoDevice;
4722 int pointerType = QTabletEvent::UnknownPointer;
4723 const XDeviceMotionEvent *motion = 0;
4724 XDeviceButtonEvent *button = 0;
4725 const XProximityNotifyEvent *proximity = 0;
4726 QEvent::Type t;
4727 Qt::KeyboardModifiers modifiers = 0;
4728#if !defined (Q_OS_IRIX)
4729 XID device_id;
4730#endif
4731
4732 if (ev->type == tablet->xinput_motion) {
4733 motion = reinterpret_cast<const XDeviceMotionEvent*>(ev);
4734 t = QEvent::TabletMove;
4735 global = QPoint(motion->x_root, motion->y_root);
4736 curr = QPoint(motion->x, motion->y);
4737#if !defined (Q_OS_IRIX)
4738 device_id = motion->deviceid;
4739#endif
4740 } else if (ev->type == tablet->xinput_button_press || ev->type == tablet->xinput_button_release) {
4741 if (ev->type == tablet->xinput_button_press) {
4742 t = QEvent::TabletPress;
4743 } else {
4744 t = QEvent::TabletRelease;
4745 }
4746 button = (XDeviceButtonEvent*)ev;
4747
4748 global = QPoint(button->x_root, button->y_root);
4749 curr = QPoint(button->x, button->y);
4750#if !defined (Q_OS_IRIX)
4751 device_id = button->deviceid;
4752#endif
4753 } else { // Proximity
4754 if (ev->type == tablet->xinput_proximity_in)
4755 t = QEvent::TabletEnterProximity;
4756 else
4757 t = QEvent::TabletLeaveProximity;
4758 proximity = (const XProximityNotifyEvent*)ev;
4759#if !defined (Q_OS_IRIX)
4760 device_id = proximity->deviceid;
4761#endif
4762 }
4763
4764 qint64 uid = 0;
4765#if defined (Q_OS_IRIX)
4766 QRect screenArea = qApp->desktop()->screenGeometry(this);
4767 s = XQueryDeviceState(X11->display, static_cast<XDevice *>(tablet->device));
4768 if (!s)
4769 return false;
4770 iClass = s->data;
4771 for (j = 0; j < s->num_classes; j++) {
4772 if (iClass->c_class == ValuatorClass) {
4773 vs = reinterpret_cast<XValuatorState *>(iClass);
4774 // figure out what device we have, based on bitmasking...
4775 if (vs->valuators[WAC_TRANSDUCER_I]
4776 & WAC_TRANSDUCER_PROX_MSK) {
4777 switch (vs->valuators[WAC_TRANSDUCER_I]
4778 & WAC_TRANSDUCER_MSK) {
4779 case WAC_PUCK_ID:
4780 pointerType = QTabletEvent::Puck;
4781 break;
4782 case WAC_STYLUS_ID:
4783 pointerType = QTabletEvent::Pen;
4784 break;
4785 case WAC_ERASER_ID:
4786 pointerType = QTabletEvent::Eraser;
4787 break;
4788 }
4789 // Get a Unique Id for the device, Wacom gives us this ability
4790 uid = vs->valuators[WAC_TRANSDUCER_I] & WAC_TRANSDUCER_ID_MSK;
4791 uid = (uid << 24) | vs->valuators[WAC_SERIAL_NUM_I];
4792 switch (WAC_TRANSDUCER_I & 0x0F0600) {
4793 case 0x080200:
4794 deviceType = QTabletEvent::Stylus;
4795 break;
4796 case 0x090200:
4797 deviceType = QTabletEvent::Airbrush;
4798 break;
4799 case 0x000400:
4800 deviceType = QTabletEvent::FourDMouse;
4801 break;
4802 case 0x000600:
4803 deviceType = QTabletEvent::Puck;
4804 break;
4805 case 0x080400:
4806 deviceType = QTabletEvent::RotationStylus;
4807 break;
4808 }
4809 } else {
4810 pointerType = QTabletEvent::UnknownPointer;
4811 deviceType = QTabletEvent::NoDevice;
4812 uid = 0;
4813 }
4814
4815 if (!proximity) {
4816 // apparently Wacom needs a cast for the +/- values to make sense
4817 xTilt = short(vs->valuators[WAC_XTILT_I]);
4818 yTilt = short(vs->valuators[WAC_YTILT_I]);
4819 pressure = vs->valuators[WAC_PRESSURE_I];
4820 if (deviceType == QTabletEvent::FourDMouse
4821 || deviceType == QTabletEvent::RotationStylus) {
4822 rotation = vs->valuators[WAC_ROTATION_I] / 64.0;
4823 if (deviceType == QTabletEvent::FourDMouse)
4824 z = vs->valuators[WAC_ZCOORD_I];
4825 } else if (deviceType == QTabletEvent::Airbrush) {
4826 tangentialPressure = vs->valuators[WAC_TAN_PRESSURE_I]
4827 / qreal(tablet->maxTanPressure - tablet->minTanPressure);
4828 }
4829
4830 hiRes = tablet->scaleCoord(vs->valuators[WAC_XCOORD_I], vs->valuators[WAC_YCOORD_I],
4831 screenArea.x(), screenArea.width(),
4832 screenArea.y(), screenArea.height());
4833 }
4834 break;
4835 }
4836 iClass = reinterpret_cast<XInputClass*>(reinterpret_cast<char*>(iClass) + iClass->length);
4837 }
4838 XFreeDeviceState(s);
4839#else
4840 // We've been passed in data for a tablet device that handles this type
4841 // of event, but it isn't necessarily the tablet device that originated
4842 // the event. Use the device id to find the originating device if we
4843 // have it.
4844 QTabletDeviceDataList *tablet_list = qt_tablet_devices();
4845 for (int i = 0; i < tablet_list->size(); ++i) {
4846 QTabletDeviceData &tab = tablet_list->operator[](i);
4847 if (device_id == static_cast<XDevice *>(tab.device)->device_id) {
4848 // Replace the tablet passed in with this one.
4849 tablet = &tab;
4850 deviceType = tab.deviceType;
4851 if (tab.deviceType == QTabletEvent::XFreeEraser) {
4852 deviceType = QTabletEvent::Stylus;
4853 pointerType = QTabletEvent::Eraser;
4854 } else if (tab.deviceType == QTabletEvent::Stylus) {
4855 pointerType = QTabletEvent::Pen;
4856 }
4857 break;
4858 }
4859 }
4860
4861 fetchWacomToolId(deviceType, uid);
4862
4863 QRect screenArea = qApp->desktop()->rect();
4864 if (motion) {
4865 xTilt = (short) motion->axis_data[3];
4866 yTilt = (short) motion->axis_data[4];
4867 rotation = ((short) motion->axis_data[5]) / 64.0;
4868 pressure = (short) motion->axis_data[2];
4869 modifiers = X11->translateModifiers(motion->state);
4870 hiRes = tablet->scaleCoord(motion->axis_data[0], motion->axis_data[1],
4871 screenArea.x(), screenArea.width(),
4872 screenArea.y(), screenArea.height());
4873 } else if (button) {
4874 xTilt = (short) button->axis_data[3];
4875 yTilt = (short) button->axis_data[4];
4876 rotation = ((short) button->axis_data[5]) / 64.0;
4877 pressure = (short) button->axis_data[2];
4878 modifiers = X11->translateModifiers(button->state);
4879 hiRes = tablet->scaleCoord(button->axis_data[0], button->axis_data[1],
4880 screenArea.x(), screenArea.width(),
4881 screenArea.y(), screenArea.height());
4882 } else if (proximity) {
4883 pressure = 0;
4884 modifiers = 0;
4885 }
4886 if (deviceType == QTabletEvent::Airbrush) {
4887 tangentialPressure = rotation;
4888 rotation = 0.;
4889 }
4890#endif
4891
4892 if (tablet->widgetToGetPress) {
4893 w = tablet->widgetToGetPress;
4894 } else {
4895 QWidget *child = w->childAt(curr);
4896 if (child)
4897 w = child;
4898 }
4899 curr = w->mapFromGlobal(global);
4900
4901 if (t == QEvent::TabletPress) {
4902 tablet->widgetToGetPress = w;
4903 } else if (t == QEvent::TabletRelease && tablet->widgetToGetPress) {
4904 w = tablet->widgetToGetPress;
4905 curr = w->mapFromGlobal(global);
4906 tablet->widgetToGetPress = 0;
4907 }
4908
4909 QTabletEvent e(t, curr, global, hiRes,
4910 deviceType, pointerType,
4911 qreal(pressure / qreal(tablet->maxPressure - tablet->minPressure)),
4912 xTilt, yTilt, tangentialPressure, rotation, z, modifiers, uid);
4913 if (proximity) {
4914 QApplication::sendSpontaneousEvent(qApp, &e);
4915 } else {
4916 QApplication::sendSpontaneousEvent(w, &e);
4917 const bool accepted = e.isAccepted();
4918 if (!accepted && ev->type == tablet->xinput_motion) {
4919 // If the widget does not accept tablet events, we drop the next ones from the event queue
4920 // for this widget so it is not overloaded with the numerous tablet events.
4921 qt_tablet_motion_data tabletMotionData;
4922 tabletMotionData.tabletMotionType = tablet->xinput_motion;
4923 tabletMotionData.widget = w;
4924 tabletMotionData.etWidget = this;
4925 // if nothing is pressed, the events are filtered by position
4926 tabletMotionData.filterByWidget = (tablet->widgetToGetPress == 0);
4927
4928 bool reinsertMouseEvent = false;
4929 XEvent mouseMotionEvent;
4930 while (true) {
4931 // Find first mouse event since we expect them in pairs inside Qt
4932 tabletMotionData.error =false;
4933 if (XCheckIfEvent(X11->display, &mouseMotionEvent, &qt_mouseMotion_scanner, (XPointer) &tabletMotionData)) {
4934 reinsertMouseEvent = true;
4935 } else {
4936 break;
4937 }
4938
4939 // Now discard any duplicate tablet events.
4940 tabletMotionData.error = false;
4941 XEvent dummy;
4942 while (XCheckIfEvent(X11->display, &dummy, &qt_tabletMotion_scanner, (XPointer) &tabletMotionData)) {
4943 // just discard the event
4944 }
4945 }
4946
4947 if (reinsertMouseEvent) {
4948 XPutBackEvent(X11->display, &mouseMotionEvent);
4949 }
4950 }
4951 }
4952 return true;
4953}
4954#endif
4955
4956bool QETWidget::translatePropertyEvent(const XEvent *event)
4957{
4958 Q_D(QWidget);
4959 if (!isWindow()) return true;
4960
4961 Atom ret;
4962 int format, e;
4963 unsigned char *data = 0;
4964 unsigned long nitems, after;
4965
4966 if (event->xproperty.atom == ATOM(_KDE_NET_WM_FRAME_STRUT)) {
4967 this->data->fstrut_dirty = 1;
4968
4969 if (event->xproperty.state == PropertyNewValue) {
4970 e = XGetWindowProperty(X11->display, event->xproperty.window, ATOM(_KDE_NET_WM_FRAME_STRUT),
4971 0, 4, // struts are 4 longs
4972 False, XA_CARDINAL, &ret, &format, &nitems, &after, &data);
4973
4974 if (e == Success && ret == XA_CARDINAL &&
4975 format == 32 && nitems == 4) {
4976 long *strut = (long *) data;
4977 d->topData()->frameStrut.setCoords(strut[0], strut[2], strut[1], strut[3]);
4978 this->data->fstrut_dirty = 0;
4979 }
4980 }
4981 } else if (event->xproperty.atom == ATOM(_NET_WM_STATE)) {
4982 bool max = false;
4983 bool full = false;
4984 Qt::WindowStates oldState = Qt::WindowStates(this->data->window_state);
4985
4986 if (event->xproperty.state == PropertyNewValue) {
4987 // using length of 1024 should be safe for all current and
4988 // possible NET states...
4989 e = XGetWindowProperty(X11->display, event->xproperty.window, ATOM(_NET_WM_STATE), 0, 1024,
4990 False, XA_ATOM, &ret, &format, &nitems, &after, &data);
4991
4992 if (e == Success && ret == XA_ATOM && format == 32 && nitems > 0) {
4993 Atom *states = (Atom *) data;
4994
4995 unsigned long i;
4996 uint maximized = 0;
4997 for (i = 0; i < nitems; i++) {
4998 if (states[i] == ATOM(_NET_WM_STATE_MAXIMIZED_VERT))
4999 maximized |= 1;
5000 else if (states[i] == ATOM(_NET_WM_STATE_MAXIMIZED_HORZ))
5001 maximized |= 2;
5002 else if (states[i] == ATOM(_NET_WM_STATE_FULLSCREEN))
5003 full = true;
5004 }
5005 if (maximized == 3) {
5006 // only set maximized if both horizontal and vertical properties are set
5007 max = true;
5008 }
5009 }
5010 }
5011
5012 bool send_event = false;
5013
5014 if (X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT))
5015 && X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ))) {
5016 if (max && !isMaximized()) {
5017 this->data->window_state = this->data->window_state | Qt::WindowMaximized;
5018 send_event = true;
5019 } else if (!max && isMaximized()) {
5020 this->data->window_state &= ~Qt::WindowMaximized;
5021 send_event = true;
5022 }
5023 }
5024
5025 if (X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN))) {
5026 if (full && !isFullScreen()) {
5027 this->data->window_state = this->data->window_state | Qt::WindowFullScreen;
5028 send_event = true;
5029 } else if (!full && isFullScreen()) {
5030 this->data->window_state &= ~Qt::WindowFullScreen;
5031 send_event = true;
5032 }
5033 }
5034
5035 if (send_event) {
5036 QWindowStateChangeEvent e(oldState);
5037 QApplication::sendSpontaneousEvent(this, &e);
5038 }
5039 } else if (event->xproperty.atom == ATOM(WM_STATE)) {
5040 // the widget frame strut should also be invalidated
5041 this->data->fstrut_dirty = 1;
5042
5043 if (event->xproperty.state == PropertyDelete) {
5044 // the window manager has removed the WM State property,
5045 // so it is now in the withdrawn state (ICCCM 4.1.3.1) and
5046 // we are free to reuse this window
5047 d->topData()->parentWinId = 0;
5048 d->topData()->validWMState = 0;
5049 // map the window if we were waiting for a transition to
5050 // withdrawn
5051 if (X11->deferred_map.removeAll(this)) {
5052 doDeferredMap();
5053 } else if (isVisible()
5054 && !testAttribute(Qt::WA_Mapped)
5055 && !testAttribute(Qt::WA_OutsideWSRange)) {
5056 // so that show() will work again. As stated in the
5057 // ICCCM section 4.1.4: "Only the client can effect a
5058 // transition into or out of the Withdrawn state.",
5059 // but apparently this particular window manager
5060 // doesn't seem to care
5061 setAttribute(Qt::WA_WState_ExplicitShowHide, false);
5062 setAttribute(Qt::WA_WState_Visible, false);
5063 }
5064 } else {
5065 // the window manager has changed the WM State property...
5066 // we are wanting to see if we are withdrawn so that we
5067 // can reuse this window...
5068 e = XGetWindowProperty(X11->display, internalWinId(), ATOM(WM_STATE), 0, 2, False,
5069 ATOM(WM_STATE), &ret, &format, &nitems, &after, &data);
5070
5071 if (e == Success && ret == ATOM(WM_STATE) && format == 32 && nitems > 0) {
5072 long *state = (long *) data;
5073 switch (state[0]) {
5074 case WithdrawnState:
5075 // if we are in the withdrawn state, we are free
5076 // to reuse this window provided we remove the
5077 // WM_STATE property (ICCCM 4.1.3.1)
5078 XDeleteProperty(X11->display, internalWinId(), ATOM(WM_STATE));
5079
5080 // set the parent id to zero, so that show() will
5081 // work again
5082 d->topData()->parentWinId = 0;
5083 d->topData()->validWMState = 0;
5084 // map the window if we were waiting for a
5085 // transition to withdrawn
5086 if (X11->deferred_map.removeAll(this)) {
5087 doDeferredMap();
5088 } else if (isVisible()
5089 && !testAttribute(Qt::WA_Mapped)
5090 && !testAttribute(Qt::WA_OutsideWSRange)) {
5091 // so that show() will work again. As stated
5092 // in the ICCCM section 4.1.4: "Only the
5093 // client can effect a transition into or out
5094 // of the Withdrawn state.", but apparently
5095 // this particular window manager doesn't seem
5096 // to care
5097 setAttribute(Qt::WA_WState_ExplicitShowHide, false);
5098 setAttribute(Qt::WA_WState_Visible, false);
5099 }
5100 break;
5101
5102 case IconicState:
5103 d->topData()->validWMState = 1;
5104 if (!isMinimized()) {
5105 // window was minimized
5106 this->data->window_state = this->data->window_state | Qt::WindowMinimized;
5107 QWindowStateChangeEvent e(Qt::WindowStates(this->data->window_state & ~Qt::WindowMinimized));
5108 QApplication::sendSpontaneousEvent(this, &e);
5109 }
5110 break;
5111
5112 default:
5113 d->topData()->validWMState = 1;
5114 if (isMinimized()) {
5115 // window was un-minimized
5116 this->data->window_state &= ~Qt::WindowMinimized;
5117 QWindowStateChangeEvent e(Qt::WindowStates(this->data->window_state | Qt::WindowMinimized));
5118 QApplication::sendSpontaneousEvent(this, &e);
5119 }
5120 break;
5121 }
5122 }
5123 }
5124 } else if (event->xproperty.atom == ATOM(_NET_WM_WINDOW_OPACITY)) {
5125 // the window opacity was changed
5126 if (event->xproperty.state == PropertyNewValue) {
5127 e = XGetWindowProperty(event->xclient.display,
5128 event->xclient.window,
5129 ATOM(_NET_WM_WINDOW_OPACITY),
5130 0, 1, False, XA_CARDINAL,
5131 &ret, &format, &nitems, &after, &data);
5132
5133 if (e == Success && ret == XA_CARDINAL && format == 32 && nitems == 1
5134 && after == 0 && data) {
5135 ulong value = *(ulong*)(data);
5136 d->topData()->opacity = uint(value >> 24);
5137 }
5138 } else
5139 d->topData()->opacity = 255;
5140 }
5141
5142 if (data)
5143 XFree(data);
5144
5145 return true;
5146}
5147
5148
5149//
5150// Paint event translation
5151//
5152// When receiving many expose events, we compress them (union of all expose
5153// rectangles) into one event which is sent to the widget.
5154
5155struct PaintEventInfo {
5156 Window window;
5157};
5158
5159#if defined(Q_C_CALLBACKS)
5160extern "C" {
5161#endif
5162
5163static Bool isPaintOrScrollDoneEvent(Display *, XEvent *ev, XPointer a)
5164{
5165 PaintEventInfo *info = (PaintEventInfo *)a;
5166 if (ev->type == Expose || ev->type == GraphicsExpose
5167 || (ev->type == ClientMessage && ev->xclient.message_type == ATOM(_QT_SCROLL_DONE)))
5168 {
5169 if (ev->xexpose.window == info->window)
5170 return True;
5171 }
5172 return False;
5173}
5174
5175#if defined(Q_C_CALLBACKS)
5176}
5177#endif
5178
5179
5180
5181static
5182bool translateBySips(QWidget* that, QRect& paintRect)
5183{
5184 int dx=0, dy=0;
5185 int sips=0;
5186 for (int i = 0; i < X11->sip_list.size(); ++i) {
5187 const QX11Data::ScrollInProgress &sip = X11->sip_list.at(i);
5188 if (sip.scrolled_widget == that) {
5189 if (sips) {
5190 dx += sip.dx;
5191 dy += sip.dy;
5192 }
5193 sips++;
5194 }
5195 }
5196 if (sips > 1) {
5197 paintRect.translate(dx, dy);
5198 return true;
5199 }
5200 return false;
5201}
5202
5203void QETWidget::translatePaintEvent(const XEvent *event)
5204{
5205 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
5206 Q_ASSERT(internalWinId());
5207
5208 Q_D(QWidget);
5209 QRect paintRect(event->xexpose.x, event->xexpose.y,
5210 event->xexpose.width, event->xexpose.height);
5211 XEvent xevent;
5212 PaintEventInfo info;
5213 info.window = internalWinId();
5214 translateBySips(this, paintRect);
5215 paintRect = d->mapFromWS(paintRect);
5216
5217 QRegion paintRegion = paintRect;
5218
5219 // WARNING: this is O(number_of_events * number_of_matching_events)
5220 while (XCheckIfEvent(X11->display,&xevent,isPaintOrScrollDoneEvent,
5221 (XPointer)&info) &&
5222 !qt_x11EventFilter(&xevent) &&
5223 !x11Event(&xevent)) // send event through filter
5224 {
5225 if (xevent.type == Expose || xevent.type == GraphicsExpose) {
5226 QRect exposure(xevent.xexpose.x,
5227 xevent.xexpose.y,
5228 xevent.xexpose.width,
5229 xevent.xexpose.height);
5230 translateBySips(this, exposure);
5231 exposure = d->mapFromWS(exposure);
5232 paintRegion |= exposure;
5233 } else {
5234 translateScrollDoneEvent(&xevent);
5235 }
5236 }
5237
5238 if (!paintRegion.isEmpty() && !testAttribute(Qt::WA_WState_ConfigPending))
5239 d->syncBackingStore(paintRegion);
5240}
5241
5242//
5243// Scroll-done event translation.
5244//
5245
5246bool QETWidget::translateScrollDoneEvent(const XEvent *event)
5247{
5248 long id = event->xclient.data.l[0];
5249
5250 // Remove any scroll-in-progress record for the given id.
5251 for (int i = 0; i < X11->sip_list.size(); ++i) {
5252 const QX11Data::ScrollInProgress &sip = X11->sip_list.at(i);
5253 if (sip.id == id) {
5254 X11->sip_list.removeAt(i);
5255 return true;
5256 }
5257 }
5258
5259 return false;
5260}
5261
5262//
5263// ConfigureNotify (window move and resize) event translation
5264
5265bool QETWidget::translateConfigEvent(const XEvent *event)
5266{
5267 Q_ASSERT((!isWindow() && !testAttribute(Qt::WA_NativeWindow)) ? internalWinId() : true);
5268
5269 Q_D(QWidget);
5270 bool wasResize = testAttribute(Qt::WA_WState_ConfigPending); // set in QWidget::setGeometry_sys()
5271 setAttribute(Qt::WA_WState_ConfigPending, false);
5272
5273 if (testAttribute(Qt::WA_OutsideWSRange)) {
5274 // discard events for windows that have a geometry X can't handle
5275 XEvent xevent;
5276 while (XCheckTypedWindowEvent(X11->display,internalWinId(), ConfigureNotify,&xevent) &&
5277 !qt_x11EventFilter(&xevent) &&
5278 !x11Event(&xevent)) // send event through filter
5279 ;
5280 return true;
5281 }
5282
5283 const QSize oldSize = size();
5284
5285 if (isWindow()) {
5286 QPoint newCPos(geometry().topLeft());
5287 QSize newSize(event->xconfigure.width, event->xconfigure.height);
5288
5289 bool trust = isVisible()
5290 && (d->topData()->parentWinId == XNone ||
5291 d->topData()->parentWinId == QX11Info::appRootWindow());
5292 bool isCPos = false;
5293
5294 if (event->xconfigure.send_event || trust) {
5295 // if a ConfigureNotify comes from a real sendevent request, we can
5296 // trust its values.
5297 newCPos.rx() = event->xconfigure.x + event->xconfigure.border_width;
5298 newCPos.ry() = event->xconfigure.y + event->xconfigure.border_width;
5299 isCPos = true;
5300 }
5301 if (isVisible())
5302 QApplication::syncX();
5303
5304 if (d->extra->compress_events) {
5305 // ConfigureNotify compression for faster opaque resizing
5306 XEvent otherEvent;
5307 while (XCheckTypedWindowEvent(X11->display, internalWinId(), ConfigureNotify,
5308 &otherEvent)) {
5309 if (qt_x11EventFilter(&otherEvent))
5310 continue;
5311
5312 if (x11Event(&otherEvent))
5313 continue;
5314
5315 if (otherEvent.xconfigure.event != otherEvent.xconfigure.window)
5316 continue;
5317
5318 newSize.setWidth(otherEvent.xconfigure.width);
5319 newSize.setHeight(otherEvent.xconfigure.height);
5320
5321 if (otherEvent.xconfigure.send_event || trust) {
5322 newCPos.rx() = otherEvent.xconfigure.x +
5323 otherEvent.xconfigure.border_width;
5324 newCPos.ry() = otherEvent.xconfigure.y +
5325 otherEvent.xconfigure.border_width;
5326 isCPos = true;
5327 }
5328 }
5329#ifndef QT_NO_XSYNC
5330 qt_sync_request_event_data sync_event;
5331 sync_event.window = internalWinId();
5332 for (XEvent ev;;) {
5333 if (!XCheckIfEvent(X11->display, &ev, &qt_sync_request_scanner, (XPointer)&sync_event))
5334 break;
5335 }
5336#endif // QT_NO_XSYNC
5337 }
5338
5339 if (!isCPos) {
5340 // we didn't get an updated position of the toplevel.
5341 // either we haven't moved or there is a bug in the window manager.
5342 // anyway, let's query the position to be certain.
5343 int x, y;
5344 Window child;
5345 XTranslateCoordinates(X11->display, internalWinId(),
5346 QApplication::desktop()->screen(d->xinfo.screen())->internalWinId(),
5347 0, 0, &x, &y, &child);
5348 newCPos.rx() = x;
5349 newCPos.ry() = y;
5350 }
5351
5352 QRect cr (geometry());
5353 if (newCPos != cr.topLeft()) { // compare with cpos (exluding frame)
5354 QPoint oldPos = geometry().topLeft();
5355 cr.moveTopLeft(newCPos);
5356 data->crect = cr;
5357 if (isVisible()) {
5358 QMoveEvent e(newCPos, oldPos); // pos (including frame), not cpos
5359 QApplication::sendSpontaneousEvent(this, &e);
5360 } else {
5361 setAttribute(Qt::WA_PendingMoveEvent, true);
5362 }
5363 }
5364 if (newSize != cr.size()) { // size changed
5365 cr.setSize(newSize);
5366 data->crect = cr;
5367
5368 uint old_state = data->window_state;
5369 if (!X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT))
5370 && !X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ)))
5371 data->window_state &= ~Qt::WindowMaximized;
5372 if (!X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN)))
5373 data->window_state &= ~Qt::WindowFullScreen;
5374
5375 if (old_state != data->window_state) {
5376 QWindowStateChangeEvent e((Qt::WindowStates) old_state);
5377 QApplication::sendEvent(this, &e);
5378 }
5379
5380 if (!isVisible())
5381 setAttribute(Qt::WA_PendingResizeEvent, true);
5382 wasResize = true;
5383 }
5384
5385 } else {
5386 XEvent xevent;
5387 while (XCheckTypedWindowEvent(X11->display,internalWinId(), ConfigureNotify,&xevent) &&
5388 !qt_x11EventFilter(&xevent) &&
5389 !x11Event(&xevent)) // send event through filter
5390 ;
5391 }
5392
5393 if (wasResize) {
5394 if (isVisible() && data->crect.size() != oldSize) {
5395 Q_ASSERT(d->extra->topextra);
5396 QWidgetBackingStore *bs = d->extra->topextra->backingStore.data();
5397 const bool hasStaticContents = bs && bs->hasStaticContents();
5398 // If we have a backing store with static contents, we have to disable the top-level
5399 // resize optimization in order to get invalidated regions for resized widgets.
5400 // The optimization discards all invalidateBuffer() calls since we're going to
5401 // repaint everything anyways, but that's not the case with static contents.
5402 if (!hasStaticContents)
5403 d->extra->topextra->inTopLevelResize = true;
5404 QResizeEvent e(data->crect.size(), oldSize);
5405 QApplication::sendSpontaneousEvent(this, &e);
5406 }
5407
5408 const bool waitingForMapNotify = d->extra->topextra && d->extra->topextra->waitingForMapNotify;
5409 if (!waitingForMapNotify) {
5410 if (d->paintOnScreen()) {
5411 QRegion updateRegion(rect());
5412 if (testAttribute(Qt::WA_StaticContents))
5413 updateRegion -= QRect(0, 0, oldSize.width(), oldSize.height());
5414 d->syncBackingStore(updateRegion);
5415 } else {
5416 d->syncBackingStore();
5417 }
5418 }
5419
5420 if (d->extra && d->extra->topextra)
5421 d->extra->topextra->inTopLevelResize = false;
5422 }
5423#ifndef QT_NO_XSYNC
5424 if (QTLWExtra *tlwExtra = d->maybeTopData()) {
5425 if (tlwExtra->newCounterValueLo != 0 || tlwExtra->newCounterValueHi != 0) {
5426 XSyncValue value;
5427 XSyncIntsToValue(&value,
5428 tlwExtra->newCounterValueLo,
5429 tlwExtra->newCounterValueHi);
5430
5431 XSyncSetCounter(X11->display, tlwExtra->syncUpdateCounter, value);
5432 tlwExtra->newCounterValueHi = 0;
5433 tlwExtra->newCounterValueLo = 0;
5434 }
5435 }
5436#endif
5437 return true;
5438}
5439
5440//
5441// Close window event translation.
5442//
5443bool QETWidget::translateCloseEvent(const XEvent *)
5444{
5445 Q_D(QWidget);
5446 return d->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
5447}
5448
5449
5450void QApplication::setCursorFlashTime(int msecs)
5451{
5452 QApplicationPrivate::cursor_flash_time = msecs;
5453}
5454
5455int QApplication::cursorFlashTime()
5456{
5457 return QApplicationPrivate::cursor_flash_time;
5458}
5459
5460void QApplication::setDoubleClickInterval(int ms)
5461{
5462 QApplicationPrivate::mouse_double_click_time = ms;
5463}
5464
5465int QApplication::doubleClickInterval()
5466{
5467 return QApplicationPrivate::mouse_double_click_time;
5468}
5469
5470void QApplication::setKeyboardInputInterval(int ms)
5471{
5472 QApplicationPrivate::keyboard_input_time = ms;
5473}
5474
5475int QApplication::keyboardInputInterval()
5476{
5477 return QApplicationPrivate::keyboard_input_time;
5478}
5479
5480#ifndef QT_NO_WHEELEVENT
5481void QApplication::setWheelScrollLines(int n)
5482{
5483 QApplicationPrivate::wheel_scroll_lines = n;
5484}
5485
5486int QApplication::wheelScrollLines()
5487{
5488 return QApplicationPrivate::wheel_scroll_lines;
5489}
5490#endif
5491
5492void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
5493{
5494 switch (effect) {
5495 case Qt::UI_AnimateMenu:
5496 if (enable) QApplicationPrivate::fade_menu = false;
5497 QApplicationPrivate::animate_menu = enable;
5498 break;
5499 case Qt::UI_FadeMenu:
5500 if (enable)
5501 QApplicationPrivate::animate_menu = true;
5502 QApplicationPrivate::fade_menu = enable;
5503 break;
5504 case Qt::UI_AnimateCombo:
5505 QApplicationPrivate::animate_combo = enable;
5506 break;
5507 case Qt::UI_AnimateTooltip:
5508 if (enable) QApplicationPrivate::fade_tooltip = false;
5509 QApplicationPrivate::animate_tooltip = enable;
5510 break;
5511 case Qt::UI_FadeTooltip:
5512 if (enable)
5513 QApplicationPrivate::animate_tooltip = true;
5514 QApplicationPrivate::fade_tooltip = enable;
5515 break;
5516 case Qt::UI_AnimateToolBox:
5517 QApplicationPrivate::animate_toolbox = enable;
5518 break;
5519 default:
5520 QApplicationPrivate::animate_ui = enable;
5521 break;
5522 }
5523}
5524
5525bool QApplication::isEffectEnabled(Qt::UIEffect effect)
5526{
5527 if (QColormap::instance().depth() < 16 || !QApplicationPrivate::animate_ui)
5528 return false;
5529
5530 switch(effect) {
5531 case Qt::UI_AnimateMenu:
5532 return QApplicationPrivate::animate_menu;
5533 case Qt::UI_FadeMenu:
5534 return QApplicationPrivate::fade_menu;
5535 case Qt::UI_AnimateCombo:
5536 return QApplicationPrivate::animate_combo;
5537 case Qt::UI_AnimateTooltip:
5538 return QApplicationPrivate::animate_tooltip;
5539 case Qt::UI_FadeTooltip:
5540 return QApplicationPrivate::fade_tooltip;
5541 case Qt::UI_AnimateToolBox:
5542 return QApplicationPrivate::animate_toolbox;
5543 default:
5544 return QApplicationPrivate::animate_ui;
5545 }
5546}
5547
5548/*****************************************************************************
5549 Session management support
5550 *****************************************************************************/
5551
5552#ifndef QT_NO_SESSIONMANAGER
5553
5554QT_BEGIN_INCLUDE_NAMESPACE
5555#include <X11/SM/SMlib.h>
5556QT_END_INCLUDE_NAMESPACE
5557
5558class QSessionManagerPrivate : public QObjectPrivate
5559{
5560public:
5561 QSessionManagerPrivate(QSessionManager* mgr, QString& id, QString& key)
5562 : QObjectPrivate(), sm(mgr), sessionId(id), sessionKey(key),
5563 restartHint(QSessionManager::RestartIfRunning), eventLoop(0) {}
5564 QSessionManager* sm;
5565 QStringList restartCommand;
5566 QStringList discardCommand;
5567 QString& sessionId;
5568 QString& sessionKey;
5569 QSessionManager::RestartHint restartHint;
5570 QEventLoop *eventLoop;
5571};
5572
5573class QSmSocketReceiver : public QObject
5574{
5575 Q_OBJECT
5576public:
5577 QSmSocketReceiver(int socket)
5578 {
5579 QSocketNotifier* sn = new QSocketNotifier(socket, QSocketNotifier::Read, this);
5580 connect(sn, SIGNAL(activated(int)), this, SLOT(socketActivated(int)));
5581 }
5582
5583public slots:
5584 void socketActivated(int);
5585};
5586
5587
5588static SmcConn smcConnection = 0;
5589static bool sm_interactionActive;
5590static bool sm_smActive;
5591static int sm_interactStyle;
5592static int sm_saveType;
5593static bool sm_cancel;
5594// static bool sm_waitingForPhase2; ### never used?!?
5595static bool sm_waitingForInteraction;
5596static bool sm_isshutdown;
5597// static bool sm_shouldbefast; ### never used?!?
5598static bool sm_phase2;
5599static bool sm_in_phase2;
5600
5601static QSmSocketReceiver* sm_receiver = 0;
5602
5603static void resetSmState();
5604static void sm_setProperty(const char* name, const char* type,
5605 int num_vals, SmPropValue* vals);
5606static void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
5607 int saveType, Bool shutdown , int interactStyle, Bool fast);
5608static void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData) ;
5609static void sm_dieCallback(SmcConn smcConn, SmPointer clientData) ;
5610static void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData);
5611static void sm_saveCompleteCallback(SmcConn smcConn, SmPointer clientData);
5612static void sm_interactCallback(SmcConn smcConn, SmPointer clientData);
5613static void sm_performSaveYourself(QSessionManagerPrivate*);
5614
5615static void resetSmState()
5616{
5617// sm_waitingForPhase2 = false; ### never used?!?
5618 sm_waitingForInteraction = false;
5619 sm_interactionActive = false;
5620 sm_interactStyle = SmInteractStyleNone;
5621 sm_smActive = false;
5622 qt_sm_blockUserInput = false;
5623 sm_isshutdown = false;
5624// sm_shouldbefast = false; ### never used?!?
5625 sm_phase2 = false;
5626 sm_in_phase2 = false;
5627}
5628
5629
5630// theoretically it's possible to set several properties at once. For
5631// simplicity, however, we do just one property at a time
5632static void sm_setProperty(const char* name, const char* type,
5633 int num_vals, SmPropValue* vals)
5634{
5635 if (num_vals) {
5636 SmProp prop;
5637 prop.name = (char*)name;
5638 prop.type = (char*)type;
5639 prop.num_vals = num_vals;
5640 prop.vals = vals;
5641
5642 SmProp* props[1];
5643 props[0] = &prop;
5644 SmcSetProperties(smcConnection, 1, props);
5645 }
5646 else {
5647 char* names[1];
5648 names[0] = (char*) name;
5649 SmcDeleteProperties(smcConnection, 1, names);
5650 }
5651}
5652
5653static void sm_setProperty(const QString& name, const QString& value)
5654{
5655 QByteArray v = value.toUtf8();
5656 SmPropValue prop;
5657 prop.length = v.length();
5658 prop.value = (SmPointer) v.constData();
5659 sm_setProperty(name.toLatin1().data(), SmARRAY8, 1, &prop);
5660}
5661
5662static void sm_setProperty(const QString& name, const QStringList& value)
5663{
5664 SmPropValue *prop = new SmPropValue[value.count()];
5665 int count = 0;
5666 QList<QByteArray> vl;
5667 for (QStringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
5668 prop[count].length = (*it).length();
5669 vl.append((*it).toUtf8());
5670 prop[count].value = (char*)vl.last().data();
5671 ++count;
5672 }
5673 sm_setProperty(name.toLatin1().data(), SmLISTofARRAY8, count, prop);
5674 delete [] prop;
5675}
5676
5677
5678// workaround for broken libsm, see below
5679struct QT_smcConn {
5680 unsigned int save_yourself_in_progress : 1;
5681 unsigned int shutdown_in_progress : 1;
5682};
5683
5684static void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
5685 int saveType, Bool shutdown , int interactStyle, Bool /*fast*/)
5686{
5687 if (smcConn != smcConnection)
5688 return;
5689 sm_cancel = false;
5690 sm_smActive = true;
5691 sm_isshutdown = shutdown;
5692 sm_saveType = saveType;
5693 sm_interactStyle = interactStyle;
5694// sm_shouldbefast = fast; ### never used?!?
5695
5696 // ugly workaround for broken libSM. libSM should do that _before_
5697 // actually invoking the callback in sm_process.c
5698 ((QT_smcConn*)smcConn)->save_yourself_in_progress = true;
5699 if (sm_isshutdown)
5700 ((QT_smcConn*)smcConn)->shutdown_in_progress = true;
5701
5702 sm_performSaveYourself((QSessionManagerPrivate*) clientData);
5703 if (!sm_isshutdown) // we cannot expect a confirmation message in that case
5704 resetSmState();
5705}
5706
5707static void sm_performSaveYourself(QSessionManagerPrivate* smd)
5708{
5709 if (sm_isshutdown)
5710 qt_sm_blockUserInput = true;
5711
5712 QSessionManager* sm = smd->sm;
5713
5714 // generate a new session key
5715 timeval tv;
5716 gettimeofday(&tv, 0);
5717 smd->sessionKey = QString::number(qulonglong(tv.tv_sec)) + QLatin1Char('_') + QString::number(qulonglong(tv.tv_usec));
5718
5719 QStringList arguments = qApp->arguments();
5720 QString argument0 = arguments.isEmpty() ? qApp->applicationFilePath() : arguments.at(0);
5721
5722 // tell the session manager about our program in best POSIX style
5723 sm_setProperty(QString::fromLatin1(SmProgram), argument0);
5724 // tell the session manager about our user as well.
5725 struct passwd *entryPtr = 0;
5726#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
5727 QVarLengthArray<char, 1024> buf(qMax<long>(sysconf(_SC_GETPW_R_SIZE_MAX), 1024L));
5728 struct passwd entry;
5729 while (getpwuid_r(geteuid(), &entry, buf.data(), buf.size(), &entryPtr) == ERANGE) {
5730 if (buf.size() >= 32768) {
5731 // too big already, fail
5732 static char badusername[] = "";
5733 entryPtr = &entry;
5734 entry.pw_name = badusername;
5735 break;
5736 }
5737
5738 // retry with a bigger buffer
5739 buf.resize(buf.size() * 2);
5740 }
5741#else
5742 entryPtr = getpwuid(geteuid());
5743#endif
5744 if (entryPtr)
5745 sm_setProperty(QString::fromLatin1(SmUserID), QString::fromLatin1(entryPtr->pw_name));
5746
5747 // generate a restart and discard command that makes sense
5748 QStringList restart;
5749 restart << argument0 << QLatin1String("-session")
5750 << smd->sessionId + QLatin1Char('_') + smd->sessionKey;
5751 if (qstricmp(appName, QX11Info::appClass()) != 0)
5752 restart << QLatin1String("-name") << qAppName();
5753 sm->setRestartCommand(restart);
5754 QStringList discard;
5755 sm->setDiscardCommand(discard);
5756
5757 switch (sm_saveType) {
5758 case SmSaveBoth:
5759 qApp->commitData(*sm);
5760 if (sm_isshutdown && sm_cancel)
5761 break; // we cancelled the shutdown, no need to save state
5762 // fall through
5763 case SmSaveLocal:
5764 qApp->saveState(*sm);
5765 break;
5766 case SmSaveGlobal:
5767 qApp->commitData(*sm);
5768 break;
5769 default:
5770 break;
5771 }
5772
5773 if (sm_phase2 && !sm_in_phase2) {
5774 SmcRequestSaveYourselfPhase2(smcConnection, sm_saveYourselfPhase2Callback, (SmPointer*) smd);
5775 qt_sm_blockUserInput = false;
5776 }
5777 else {
5778 // close eventual interaction monitors and cancel the
5779 // shutdown, if required. Note that we can only cancel when
5780 // performing a shutdown, it does not work for checkpoints
5781 if (sm_interactionActive) {
5782 SmcInteractDone(smcConnection, sm_isshutdown && sm_cancel);
5783 sm_interactionActive = false;
5784 }
5785 else if (sm_cancel && sm_isshutdown) {
5786 if (sm->allowsErrorInteraction()) {
5787 SmcInteractDone(smcConnection, True);
5788 sm_interactionActive = false;
5789 }
5790 }
5791
5792 // set restart and discard command in session manager
5793 sm_setProperty(QString::fromLatin1(SmRestartCommand), sm->restartCommand());
5794 sm_setProperty(QString::fromLatin1(SmDiscardCommand), sm->discardCommand());
5795
5796 // set the restart hint
5797 SmPropValue prop;
5798 prop.length = sizeof(int);
5799 int value = sm->restartHint();
5800 prop.value = (SmPointer) &value;
5801 sm_setProperty(SmRestartStyleHint, SmCARD8, 1, &prop);
5802
5803 // we are done
5804 SmcSaveYourselfDone(smcConnection, !sm_cancel);
5805 }
5806}
5807
5808static void sm_dieCallback(SmcConn smcConn, SmPointer /* clientData */)
5809{
5810 if (smcConn != smcConnection)
5811 return;
5812 resetSmState();
5813 QEvent quitEvent(QEvent::Quit);
5814 QApplication::sendEvent(qApp, &quitEvent);
5815}
5816
5817static void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData)
5818{
5819 if (smcConn != smcConnection)
5820 return;
5821 if (sm_waitingForInteraction)
5822 ((QSessionManagerPrivate *) clientData)->eventLoop->exit();
5823 resetSmState();
5824}
5825
5826static void sm_saveCompleteCallback(SmcConn smcConn, SmPointer /*clientData */)
5827{
5828 if (smcConn != smcConnection)
5829 return;
5830 resetSmState();
5831}
5832
5833static void sm_interactCallback(SmcConn smcConn, SmPointer clientData)
5834{
5835 if (smcConn != smcConnection)
5836 return;
5837 if (sm_waitingForInteraction)
5838 ((QSessionManagerPrivate *) clientData)->eventLoop->exit();
5839}
5840
5841static void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData)
5842{
5843 if (smcConn != smcConnection)
5844 return;
5845 sm_in_phase2 = true;
5846 sm_performSaveYourself((QSessionManagerPrivate*) clientData);
5847}
5848
5849
5850void QSmSocketReceiver::socketActivated(int)
5851{
5852 IceProcessMessages(SmcGetIceConnection(smcConnection), 0, 0);
5853}
5854
5855
5856#undef Bool
5857QT_BEGIN_INCLUDE_NAMESPACE
5858#include "qapplication_x11.moc"
5859QT_END_INCLUDE_NAMESPACE
5860
5861QSessionManager::QSessionManager(QApplication * app, QString &id, QString& key)
5862 : QObject(*new QSessionManagerPrivate(this, id, key), app)
5863{
5864 Q_D(QSessionManager);
5865 d->restartHint = RestartIfRunning;
5866
5867 resetSmState();
5868 char cerror[256];
5869 char* myId = 0;
5870 QByteArray b_id = id.toLatin1();
5871 char* prevId = b_id.data();
5872
5873 SmcCallbacks cb;
5874 cb.save_yourself.callback = sm_saveYourselfCallback;
5875 cb.save_yourself.client_data = (SmPointer) d;
5876 cb.die.callback = sm_dieCallback;
5877 cb.die.client_data = (SmPointer) d;
5878 cb.save_complete.callback = sm_saveCompleteCallback;
5879 cb.save_complete.client_data = (SmPointer) d;
5880 cb.shutdown_cancelled.callback = sm_shutdownCancelledCallback;
5881 cb.shutdown_cancelled.client_data = (SmPointer) d;
5882
5883 // avoid showing a warning message below
5884 if (qgetenv("SESSION_MANAGER").isEmpty())
5885 return;
5886
5887 smcConnection = SmcOpenConnection(0, 0, 1, 0,
5888 SmcSaveYourselfProcMask |
5889 SmcDieProcMask |
5890 SmcSaveCompleteProcMask |
5891 SmcShutdownCancelledProcMask,
5892 &cb,
5893 prevId,
5894 &myId,
5895 256, cerror);
5896
5897 id = QString::fromLatin1(myId);
5898 ::free(myId); // it was allocated by C
5899
5900 QString error = QString::fromLocal8Bit(cerror);
5901 if (!smcConnection) {
5902 qWarning("Qt: Session management error: %s", qPrintable(error));
5903 }
5904 else {
5905 sm_receiver = new QSmSocketReceiver(IceConnectionNumber(SmcGetIceConnection(smcConnection)));
5906 }
5907}
5908
5909QSessionManager::~QSessionManager()
5910{
5911 if (smcConnection)
5912 SmcCloseConnection(smcConnection, 0, 0);
5913 smcConnection = 0;
5914 delete sm_receiver;
5915}
5916
5917QString QSessionManager::sessionId() const
5918{
5919 Q_D(const QSessionManager);
5920 return d->sessionId;
5921}
5922
5923QString QSessionManager::sessionKey() const
5924{
5925 Q_D(const QSessionManager);
5926 return d->sessionKey;
5927}
5928
5929
5930void* QSessionManager::handle() const
5931{
5932 return (void*) smcConnection;
5933}
5934
5935
5936bool QSessionManager::allowsInteraction()
5937{
5938 Q_D(QSessionManager);
5939 if (sm_interactionActive)
5940 return true;
5941
5942 if (sm_waitingForInteraction)
5943 return false;
5944
5945 if (sm_interactStyle == SmInteractStyleAny) {
5946 sm_waitingForInteraction = SmcInteractRequest(smcConnection, SmDialogNormal,
5947 sm_interactCallback, (SmPointer*) d);
5948 }
5949 if (sm_waitingForInteraction) {
5950 QEventLoop eventLoop;
5951 d->eventLoop = &eventLoop;
5952 (void) eventLoop.exec();
5953 d->eventLoop = 0;
5954
5955 sm_waitingForInteraction = false;
5956 if (sm_smActive) { // not cancelled
5957 sm_interactionActive = true;
5958 qt_sm_blockUserInput = false;
5959 return true;
5960 }
5961 }
5962 return false;
5963}
5964
5965bool QSessionManager::allowsErrorInteraction()
5966{
5967 Q_D(QSessionManager);
5968 if (sm_interactionActive)
5969 return true;
5970
5971 if (sm_waitingForInteraction)
5972 return false;
5973
5974 if (sm_interactStyle == SmInteractStyleAny || sm_interactStyle == SmInteractStyleErrors) {
5975 sm_waitingForInteraction = SmcInteractRequest(smcConnection, SmDialogError,
5976 sm_interactCallback, (SmPointer*) d);
5977 }
5978 if (sm_waitingForInteraction) {
5979 QEventLoop eventLoop;
5980 d->eventLoop = &eventLoop;
5981 (void) eventLoop.exec();
5982 d->eventLoop = 0;
5983
5984 sm_waitingForInteraction = false;
5985 if (sm_smActive) { // not cancelled
5986 sm_interactionActive = true;
5987 qt_sm_blockUserInput = false;
5988 return true;
5989 }
5990 }
5991 return false;
5992}
5993
5994void QSessionManager::release()
5995{
5996 if (sm_interactionActive) {
5997 SmcInteractDone(smcConnection, False);
5998 sm_interactionActive = false;
5999 if (sm_smActive && sm_isshutdown)
6000 qt_sm_blockUserInput = true;
6001 }
6002}
6003
6004void QSessionManager::cancel()
6005{
6006 sm_cancel = true;
6007}
6008
6009void QSessionManager::setRestartHint(QSessionManager::RestartHint hint)
6010{
6011 Q_D(QSessionManager);
6012 d->restartHint = hint;
6013}
6014
6015QSessionManager::RestartHint QSessionManager::restartHint() const
6016{
6017 Q_D(const QSessionManager);
6018 return d->restartHint;
6019}
6020
6021void QSessionManager::setRestartCommand(const QStringList& command)
6022{
6023 Q_D(QSessionManager);
6024 d->restartCommand = command;
6025}
6026
6027QStringList QSessionManager::restartCommand() const
6028{
6029 Q_D(const QSessionManager);
6030 return d->restartCommand;
6031}
6032
6033void QSessionManager::setDiscardCommand(const QStringList& command)
6034{
6035 Q_D(QSessionManager);
6036 d->discardCommand = command;
6037}
6038
6039QStringList QSessionManager::discardCommand() const
6040{
6041 Q_D(const QSessionManager);
6042 return d->discardCommand;
6043}
6044
6045void QSessionManager::setManagerProperty(const QString& name, const QString& value)
6046{
6047 sm_setProperty(name, value);
6048}
6049
6050void QSessionManager::setManagerProperty(const QString& name, const QStringList& value)
6051{
6052 sm_setProperty(name, value);
6053}
6054
6055bool QSessionManager::isPhase2() const
6056{
6057 return sm_in_phase2;
6058}
6059
6060void QSessionManager::requestPhase2()
6061{
6062 sm_phase2 = true;
6063}
6064
6065#endif // QT_NO_SESSIONMANAGER
6066
6067#if defined(QT_RX71_MULTITOUCH)
6068
6069static inline int testBit(const char *array, int bit)
6070{
6071 return (array[bit/8] & (1<<(bit%8)));
6072}
6073
6074static int openRX71Device(const QByteArray &deviceName)
6075{
6076 int fd = open(deviceName, O_RDONLY | O_NONBLOCK);
6077 if (fd == -1) {
6078 fd = -errno;
6079 return fd;
6080 }
6081
6082 // fetch the event type mask and check that the device reports absolute coordinates
6083 char eventTypeMask[(EV_MAX + sizeof(char) - 1) * sizeof(char) + 1];
6084 memset(eventTypeMask, 0, sizeof(eventTypeMask));
6085 if (ioctl(fd, EVIOCGBIT(0, sizeof(eventTypeMask)), eventTypeMask) < 0) {
6086 close(fd);
6087 return -1;
6088 }
6089 if (!testBit(eventTypeMask, EV_ABS)) {
6090 close(fd);
6091 return -1;
6092 }
6093
6094 // make sure that we can get the absolute X and Y positions from the device
6095 char absMask[(ABS_MAX + sizeof(char) - 1) * sizeof(char) + 1];
6096 memset(absMask, 0, sizeof(absMask));
6097 if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absMask)), absMask) < 0) {
6098 close(fd);
6099 return -1;
6100 }
6101 if (!testBit(absMask, ABS_X) || !testBit(absMask, ABS_Y)) {
6102 close(fd);
6103 return -1;
6104 }
6105
6106 return fd;
6107}
6108
6109void QApplicationPrivate::initializeMultitouch_sys()
6110{
6111 Q_Q(QApplication);
6112
6113 QByteArray deviceName = QByteArray("/dev/input/event");
6114 int currentDeviceNumber = 0;
6115 for (;;) {
6116 int fd = openRX71Device(QByteArray(deviceName + QByteArray::number(currentDeviceNumber++)));
6117 if (fd == -ENOENT) {
6118 // no more devices
6119 break;
6120 }
6121 if (fd < 0) {
6122 // not a touch device
6123 continue;
6124 }
6125
6126 struct input_absinfo abs_x, abs_y, abs_z;
6127 ioctl(fd, EVIOCGABS(ABS_X), &abs_x);
6128 ioctl(fd, EVIOCGABS(ABS_Y), &abs_y);
6129 ioctl(fd, EVIOCGABS(ABS_Z), &abs_z);
6130
6131 int deviceNumber = allRX71TouchPoints.count();
6132
6133 QSocketNotifier *socketNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, q);
6134 QObject::connect(socketNotifier, SIGNAL(activated(int)), q, SLOT(_q_readRX71MultiTouchEvents()));
6135
6136 RX71TouchPointState touchPointState = {
6137 socketNotifier,
6138 QTouchEvent::TouchPoint(deviceNumber),
6139
6140 abs_x.minimum, abs_x.maximum, q->desktop()->screenGeometry().width(),
6141 abs_y.minimum, abs_y.maximum, q->desktop()->screenGeometry().height(),
6142 abs_z.minimum, abs_z.maximum
6143 };
6144 allRX71TouchPoints.append(touchPointState);
6145 }
6146
6147 hasRX71MultiTouch = allRX71TouchPoints.count() > 1;
6148 if (!hasRX71MultiTouch) {
6149 for (int i = 0; i < allRX71TouchPoints.count(); ++i) {
6150 QSocketNotifier *socketNotifier = allRX71TouchPoints.at(i).socketNotifier;
6151 close(socketNotifier->socket());
6152 delete socketNotifier;
6153 }
6154 allRX71TouchPoints.clear();
6155 }
6156}
6157
6158void QApplicationPrivate::cleanupMultitouch_sys()
6159{
6160 hasRX71MultiTouch = false;
6161 for (int i = 0; i < allRX71TouchPoints.count(); ++i) {
6162 QSocketNotifier *socketNotifier = allRX71TouchPoints.at(i).socketNotifier;
6163 close(socketNotifier->socket());
6164 delete socketNotifier;
6165 }
6166 allRX71TouchPoints.clear();
6167}
6168
6169bool QApplicationPrivate::readRX71MultiTouchEvents(int deviceNumber)
6170{
6171 RX71TouchPointState &touchPointState = allRX71TouchPoints[deviceNumber];
6172 QSocketNotifier *socketNotifier = touchPointState.socketNotifier;
6173 int fd = socketNotifier->socket();
6174
6175 QTouchEvent::TouchPoint &touchPoint = touchPointState.touchPoint;
6176
6177 bool down = touchPoint.state() != Qt::TouchPointReleased;
6178 if (down)
6179 touchPoint.setState(Qt::TouchPointStationary);
6180
6181 bool changed = false;
6182 for (;;) {
6183 struct input_event inputEvent;
6184 int bytesRead = read(fd, &inputEvent, sizeof(inputEvent));
6185 if (bytesRead <= 0)
6186 break;
6187 if (bytesRead != sizeof(inputEvent)) {
6188 qWarning("Qt: INTERNAL ERROR: short read in readRX71MultiTouchEvents()");
6189 return false;
6190 }
6191
6192 switch (inputEvent.type) {
6193 case EV_SYN:
6194 changed = true;
6195 switch (touchPoint.state()) {
6196 case Qt::TouchPointPressed:
6197 case Qt::TouchPointReleased:
6198 // make sure we don't compress pressed and releases with any other events
6199 return changed;
6200 default:
6201 break;
6202 }
6203 continue;
6204 case EV_KEY:
6205 case EV_ABS:
6206 break;
6207 default:
6208 qWarning("Qt: WARNING: unknown event type %d on multitouch device", inputEvent.type);
6209 continue;
6210 }
6211
6212 QPointF screenPos = touchPoint.screenPos();
6213 switch (inputEvent.code) {
6214 case BTN_TOUCH:
6215 if (!down && inputEvent.value != 0)
6216 touchPoint.setState(Qt::TouchPointPressed);
6217 else if (down && inputEvent.value == 0)
6218 touchPoint.setState(Qt::TouchPointReleased);
6219 break;
6220 case ABS_TOOL_WIDTH:
6221 case ABS_VOLUME:
6222 case ABS_PRESSURE:
6223 // ignore for now
6224 break;
6225 case ABS_X:
6226 {
6227 qreal newValue = ((qreal(inputEvent.value - touchPointState.minX)
6228 / qreal(touchPointState.maxX - touchPointState.minX))
6229 * touchPointState.scaleX);
6230 screenPos.rx() = newValue;
6231 touchPoint.setScreenPos(screenPos);
6232 break;
6233 }
6234 case ABS_Y:
6235 {
6236 qreal newValue = ((qreal(inputEvent.value - touchPointState.minY)
6237 / qreal(touchPointState.maxY - touchPointState.minY))
6238 * touchPointState.scaleY);
6239 screenPos.ry() = newValue;
6240 touchPoint.setScreenPos(screenPos);
6241 break;
6242 }
6243 case ABS_Z:
6244 {
6245 // map Z (signal strength) to pressure for now
6246 qreal newValue = (qreal(inputEvent.value - touchPointState.minZ)
6247 / qreal(touchPointState.maxZ - touchPointState.minZ));
6248 touchPoint.setPressure(newValue);
6249 break;
6250 }
6251 default:
6252 qWarning("Qt: WARNING: unknown event code %d on multitouch device", inputEvent.code);
6253 continue;
6254 }
6255 }
6256
6257 if (down && touchPoint.state() != Qt::TouchPointReleased)
6258 touchPoint.setState(changed ? Qt::TouchPointMoved : Qt::TouchPointStationary);
6259
6260 return changed;
6261}
6262
6263void QApplicationPrivate::_q_readRX71MultiTouchEvents()
6264{
6265 // read touch events from all devices
6266 bool changed = false;
6267 for (int i = 0; i < allRX71TouchPoints.count(); ++i)
6268 changed = readRX71MultiTouchEvents(i) || changed;
6269 if (!changed)
6270 return;
6271
6272 QList<QTouchEvent::TouchPoint> touchPoints;
6273 for (int i = 0; i < allRX71TouchPoints.count(); ++i)
6274 touchPoints.append(allRX71TouchPoints.at(i).touchPoint);
6275
6276 translateRawTouchEvent(0, QTouchEvent::TouchScreen, touchPoints);
6277}
6278
6279#else // !QT_RX71_MULTITOUCH
6280
6281void QApplicationPrivate::initializeMultitouch_sys()
6282{ }
6283void QApplicationPrivate::cleanupMultitouch_sys()
6284{ }
6285
6286#endif // QT_RX71_MULTITOUCH
6287
6288QT_END_NAMESPACE
6289