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