source: branches/4.5.1/src/gui/kernel/qapplication_x11.cpp

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

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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