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 *) ×tamp, 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] = ∝
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