source: trunk/src/gui/kernel/qapplication_x11.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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