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