source: trunk/src/gui/kernel/qwidget_x11.cpp@ 1027

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

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

File size: 109.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qevent.h"
43#include "qwidget.h"
44#include "qdesktopwidget.h"
45#include "qapplication.h"
46#include "qapplication_p.h"
47#include "qnamespace.h"
48#include "qpainter.h"
49#include "qbitmap.h"
50#include "qlayout.h"
51#include "qtextcodec.h"
52#include "qelapsedtimer.h"
53#include "qcursor.h"
54#include "qstack.h"
55#include "qcolormap.h"
56#include "qdebug.h"
57#include "qmenu.h"
58#include "private/qmenu_p.h"
59#include "private/qbackingstore_p.h"
60#include "private/qwindowsurface_x11_p.h"
61
62//extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); //qapplication_x11.cpp
63
64#include <private/qpixmap_x11_p.h>
65#include <private/qpaintengine_x11_p.h>
66#include "qt_x11_p.h"
67#include "qx11info_x11.h"
68
69#include <stdlib.h>
70
71//#define ALIEN_DEBUG
72
73// defined in qapplication_x11.cpp
74//bool qt_wstate_iconified(WId);
75//void qt_updated_rootinfo();
76
77
78#if !defined(QT_NO_IM)
79#include "qinputcontext.h"
80#include "qinputcontextfactory.h"
81#endif
82
83#include "qwidget_p.h"
84
85#define XCOORD_MAX 16383
86#define WRECT_MAX 8191
87
88QT_BEGIN_NAMESPACE
89
90extern bool qt_nograb();
91
92QWidget *QWidgetPrivate::mouseGrabber = 0;
93QWidget *QWidgetPrivate::keyboardGrabber = 0;
94
95void qt_net_remove_user_time(QWidget *tlw);
96void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp);
97
98int qt_x11_create_desktop_on_screen = -1;
99
100extern void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp);
101
102// MWM support
103struct QtMWMHints {
104 ulong flags, functions, decorations;
105 long input_mode;
106 ulong status;
107};
108
109enum {
110 MWM_HINTS_FUNCTIONS = (1L << 0),
111
112 MWM_FUNC_ALL = (1L << 0),
113 MWM_FUNC_RESIZE = (1L << 1),
114 MWM_FUNC_MOVE = (1L << 2),
115 MWM_FUNC_MINIMIZE = (1L << 3),
116 MWM_FUNC_MAXIMIZE = (1L << 4),
117 MWM_FUNC_CLOSE = (1L << 5),
118
119 MWM_HINTS_DECORATIONS = (1L << 1),
120
121 MWM_DECOR_ALL = (1L << 0),
122 MWM_DECOR_BORDER = (1L << 1),
123 MWM_DECOR_RESIZEH = (1L << 2),
124 MWM_DECOR_TITLE = (1L << 3),
125 MWM_DECOR_MENU = (1L << 4),
126 MWM_DECOR_MINIMIZE = (1L << 5),
127 MWM_DECOR_MAXIMIZE = (1L << 6),
128
129 MWM_HINTS_INPUT_MODE = (1L << 2),
130
131 MWM_INPUT_MODELESS = 0L,
132 MWM_INPUT_PRIMARY_APPLICATION_MODAL = 1L,
133 MWM_INPUT_FULL_APPLICATION_MODAL = 3L
134};
135
136
137static QtMWMHints GetMWMHints(Display *display, Window window)
138{
139 QtMWMHints mwmhints;
140
141 Atom type;
142 int format;
143 ulong nitems, bytesLeft;
144 uchar *data = 0;
145 if ((XGetWindowProperty(display, window, ATOM(_MOTIF_WM_HINTS), 0, 5, false,
146 ATOM(_MOTIF_WM_HINTS), &type, &format, &nitems, &bytesLeft,
147 &data) == Success)
148 && (type == ATOM(_MOTIF_WM_HINTS)
149 && format == 32
150 && nitems >= 5)) {
151 mwmhints = *(reinterpret_cast<QtMWMHints *>(data));
152 } else {
153 mwmhints.flags = 0L;
154 mwmhints.functions = MWM_FUNC_ALL;
155 mwmhints.decorations = MWM_DECOR_ALL;
156 mwmhints.input_mode = 0L;
157 mwmhints.status = 0L;
158 }
159
160 if (data)
161 XFree(data);
162
163 return mwmhints;
164}
165
166static void SetMWMHints(Display *display, Window window, const QtMWMHints &mwmhints)
167{
168 if (mwmhints.flags != 0l) {
169 XChangeProperty(display, window, ATOM(_MOTIF_WM_HINTS), ATOM(_MOTIF_WM_HINTS), 32,
170 PropModeReplace, (unsigned char *) &mwmhints, 5);
171 } else {
172 XDeleteProperty(display, window, ATOM(_MOTIF_WM_HINTS));
173 }
174}
175
176// Returns true if we should set WM_TRANSIENT_FOR on \a w
177static inline bool isTransient(const QWidget *w)
178{
179 return ((w->windowType() == Qt::Dialog
180 || w->windowType() == Qt::Sheet
181 || w->windowType() == Qt::Tool
182 || w->windowType() == Qt::SplashScreen
183 || w->windowType() == Qt::ToolTip
184 || w->windowType() == Qt::Drawer
185 || w->windowType() == Qt::Popup)
186 && !w->testAttribute(Qt::WA_X11BypassTransientForHint));
187}
188
189static void do_size_hints(QWidget* widget, QWExtra *x);
190
191/*****************************************************************************
192 QWidget member functions
193 *****************************************************************************/
194
195const uint stdWidgetEventMask = // X event mask
196 (uint)(
197 KeyPressMask | KeyReleaseMask |
198 ButtonPressMask | ButtonReleaseMask |
199 KeymapStateMask |
200 ButtonMotionMask | PointerMotionMask |
201 EnterWindowMask | LeaveWindowMask |
202 FocusChangeMask |
203 ExposureMask |
204 PropertyChangeMask |
205 StructureNotifyMask
206 );
207
208const uint stdDesktopEventMask = // X event mask
209 (uint)(
210 KeymapStateMask |
211 EnterWindowMask | LeaveWindowMask |
212 PropertyChangeMask
213 );
214
215
216/*
217 The qt_ functions below are implemented in qwidgetcreate_x11.cpp.
218*/
219
220Window qt_XCreateWindow(const QWidget *creator,
221 Display *display, Window parent,
222 int x, int y, uint w, uint h,
223 int borderwidth, int depth,
224 uint windowclass, Visual *visual,
225 ulong valuemask, XSetWindowAttributes *attributes);
226Window qt_XCreateSimpleWindow(const QWidget *creator,
227 Display *display, Window parent,
228 int x, int y, uint w, uint h, int borderwidth,
229 ulong border, ulong background);
230void qt_XDestroyWindow(const QWidget *destroyer,
231 Display *display, Window window);
232
233
234static void qt_insert_sip(QWidget* scrolled_widget, int dx, int dy)
235{
236 if (!scrolled_widget->isWindow() && !scrolled_widget->internalWinId())
237 return;
238 QX11Data::ScrollInProgress sip = { X11->sip_serial++, scrolled_widget, dx, dy };
239 X11->sip_list.append(sip);
240
241 XClientMessageEvent client_message;
242 client_message.type = ClientMessage;
243 client_message.window = scrolled_widget->internalWinId();
244 client_message.format = 32;
245 client_message.message_type = ATOM(_QT_SCROLL_DONE);
246 client_message.data.l[0] = sip.id;
247
248 XSendEvent(X11->display, scrolled_widget->internalWinId(), False, NoEventMask,
249 (XEvent*)&client_message);
250}
251
252static int qt_sip_count(QWidget* scrolled_widget)
253{
254 int sips=0;
255
256 for (int i = 0; i < X11->sip_list.size(); ++i) {
257 const QX11Data::ScrollInProgress &sip = X11->sip_list.at(i);
258 if (sip.scrolled_widget == scrolled_widget)
259 sips++;
260 }
261
262 return sips;
263}
264
265static void create_wm_client_leader()
266{
267 if (X11->wm_client_leader) return;
268
269 X11->wm_client_leader =
270 XCreateSimpleWindow(X11->display,
271 QX11Info::appRootWindow(),
272 0, 0, 1, 1, 0, 0, 0);
273
274 // set client leader property to itself
275 XChangeProperty(X11->display,
276 X11->wm_client_leader, ATOM(WM_CLIENT_LEADER),
277 XA_WINDOW, 32, PropModeReplace,
278 (unsigned char *)&X11->wm_client_leader, 1);
279
280#ifndef QT_NO_SESSIONMANAGER
281 // If we are session managed, inform the window manager about it
282 QByteArray session = qApp->sessionId().toLatin1();
283 if (!session.isEmpty()) {
284 XChangeProperty(X11->display,
285 X11->wm_client_leader, ATOM(SM_CLIENT_ID),
286 XA_STRING, 8, PropModeReplace,
287 (unsigned char *)session.data(), session.size());
288 }
289#endif
290}
291
292/*!
293 \internal
294 Update the X11 cursor of the widget w.
295 \a force is true if this function is called from dispatchEnterLeave, it means that the
296 mouse is actually directly under this widget.
297 */
298void qt_x11_enforce_cursor(QWidget * w, bool force)
299{
300 if (!w->testAttribute(Qt::WA_WState_Created))
301 return;
302
303 static QPointer<QWidget> lastUnderMouse = 0;
304 if (force) {
305 lastUnderMouse = w;
306 } else if (lastUnderMouse && lastUnderMouse->effectiveWinId() == w->effectiveWinId()) {
307 w = lastUnderMouse;
308 } else if (!w->internalWinId()) {
309 return; //the mouse is not under this widget, and it's not native, so don't change it
310 }
311
312 while (!w->internalWinId() && w->parentWidget() && !w->isWindow() && !w->testAttribute(Qt::WA_SetCursor))
313 w = w->parentWidget();
314
315 QWidget *nativeParent = w;
316 if (!w->internalWinId())
317 nativeParent = w->nativeParentWidget();
318 // This does the same as effectiveWinId(), but since it is possible
319 // to not have a native parent widget due to a special hack in
320 // qwidget for reparenting widgets to a different X11 screen,
321 // added additional check to make sure native parent widget exists.
322 if (!nativeParent || !nativeParent->internalWinId())
323 return;
324 WId winid = nativeParent->internalWinId();
325
326 if (w->isWindow() || w->testAttribute(Qt::WA_SetCursor)) {
327#ifndef QT_NO_CURSOR
328 QCursor *oc = QApplication::overrideCursor();
329 if (oc) {
330 XDefineCursor(X11->display, winid, oc->handle());
331 } else if (w->isEnabled()) {
332 XDefineCursor(X11->display, winid, w->cursor().handle());
333 } else {
334 // enforce the windows behavior of clearing the cursor on
335 // disabled widgets
336 XDefineCursor(X11->display, winid, XNone);
337 }
338#endif
339 } else {
340 XDefineCursor(X11->display, winid, XNone);
341 }
342}
343
344Q_GUI_EXPORT void qt_x11_enforce_cursor(QWidget * w)
345{
346 qt_x11_enforce_cursor(w, false);
347}
348
349Q_GUI_EXPORT void qt_x11_wait_for_window_manager(QWidget* w)
350{
351 if (!w || (!w->isWindow() && !w->internalWinId()))
352 return;
353 QApplication::flush();
354 XEvent ev;
355 QElapsedTimer t;
356 t.start();
357 static const int maximumWaitTime = 2000;
358 if (!w->testAttribute(Qt::WA_WState_Created))
359 return;
360
361 WId winid = w->internalWinId();
362
363 // first deliver events that are already in the local queue
364 QApplication::sendPostedEvents();
365
366 // the normal sequence is:
367 // ... ConfigureNotify ... ReparentNotify ... MapNotify ... Expose
368 // with X11BypassWindowManagerHint:
369 // ConfigureNotify ... MapNotify ... Expose
370
371 enum State {
372 Initial, Mapped
373 } state = Initial;
374
375 do {
376 if (XEventsQueued(X11->display, QueuedAlready)) {
377 XNextEvent(X11->display, &ev);
378 qApp->x11ProcessEvent(&ev);
379
380 switch (state) {
381 case Initial:
382 if (ev.type == MapNotify && ev.xany.window == winid)
383 state = Mapped;
384 break;
385 case Mapped:
386 if (ev.type == Expose && ev.xany.window == winid)
387 return;
388 break;
389 }
390 } else {
391 if (!XEventsQueued(X11->display, QueuedAfterFlush))
392 qApp->syncX(); // non-busy wait
393 }
394 if (t.elapsed() > maximumWaitTime)
395 return;
396 } while(1);
397}
398
399void qt_change_net_wm_state(const QWidget* w, bool set, Atom one, Atom two = 0)
400{
401 if (!w->isVisible()) // not managed by the window manager
402 return;
403
404 XEvent e;
405 e.xclient.type = ClientMessage;
406 e.xclient.message_type = ATOM(_NET_WM_STATE);
407 e.xclient.display = X11->display;
408 e.xclient.window = w->internalWinId();
409 e.xclient.format = 32;
410 e.xclient.data.l[0] = set ? 1 : 0;
411 e.xclient.data.l[1] = one;
412 e.xclient.data.l[2] = two;
413 e.xclient.data.l[3] = 0;
414 e.xclient.data.l[4] = 0;
415 XSendEvent(X11->display, RootWindow(X11->display, w->x11Info().screen()),
416 false, (SubstructureNotifyMask | SubstructureRedirectMask), &e);
417}
418
419struct QX11WindowAttributes {
420 const XWindowAttributes *att;
421};
422
423void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const XWindowAttributes &a)
424{
425 QX11WindowAttributes att;
426 att.att = &a;
427 qt_x11_getX11InfoForWindow(xinfo,att);
428}
429
430
431static QVector<Atom> getNetWmState(QWidget *w)
432{
433 QVector<Atom> returnValue;
434
435 // Don't read anything, just get the size of the property data
436 Atom actualType;
437 int actualFormat;
438 ulong propertyLength;
439 ulong bytesLeft;
440 uchar *propertyData = 0;
441 if (XGetWindowProperty(X11->display, w->internalWinId(), ATOM(_NET_WM_STATE), 0, 0,
442 False, XA_ATOM, &actualType, &actualFormat,
443 &propertyLength, &bytesLeft, &propertyData) == Success
444 && actualType == XA_ATOM && actualFormat == 32) {
445 returnValue.resize(bytesLeft / 4);
446 XFree((char*) propertyData);
447
448 // fetch all data
449 if (XGetWindowProperty(X11->display, w->internalWinId(), ATOM(_NET_WM_STATE), 0,
450 returnValue.size(), False, XA_ATOM, &actualType, &actualFormat,
451 &propertyLength, &bytesLeft, &propertyData) != Success) {
452 returnValue.clear();
453 } else if (propertyLength != (ulong)returnValue.size()) {
454 returnValue.resize(propertyLength);
455 }
456
457 // put it into netWmState
458 if (!returnValue.isEmpty()) {
459 memcpy(returnValue.data(), propertyData, returnValue.size() * sizeof(Atom));
460 }
461 XFree((char*) propertyData);
462 }
463
464 return returnValue;
465}
466
467void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
468{
469 Q_Q(QWidget);
470 Qt::WindowType type = q->windowType();
471 Qt::WindowFlags &flags = data.window_flags;
472 QWidget *parentWidget = q->parentWidget();
473
474 if (type == Qt::ToolTip)
475 flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint;
476 if (type == Qt::Popup)
477 flags |= Qt::X11BypassWindowManagerHint;
478
479 bool topLevel = (flags & Qt::Window);
480 bool popup = (type == Qt::Popup);
481 bool dialog = (type == Qt::Dialog
482 || type == Qt::Sheet);
483 bool desktop = (type == Qt::Desktop);
484 bool tool = (type == Qt::Tool || type == Qt::SplashScreen
485 || type == Qt::ToolTip || type == Qt::Drawer);
486
487#ifdef ALIEN_DEBUG
488 qDebug() << "QWidgetPrivate::create_sys START:" << q << "topLevel?" << topLevel << "WId:"
489 << window << "initializeWindow:" << initializeWindow << "destroyOldWindow" << destroyOldWindow;
490#endif
491 if (topLevel) {
492 if (parentWidget) { // if our parent stays on top, so must we
493 QWidget *ptl = parentWidget->window();
494 if(ptl && (ptl->windowFlags() & Qt::WindowStaysOnTopHint))
495 flags |= Qt::WindowStaysOnTopHint;
496 }
497
498 if (type == Qt::SplashScreen) {
499 if (X11->isSupportedByWM(ATOM(_NET_WM_WINDOW_TYPE_SPLASH))) {
500 flags &= ~Qt::X11BypassWindowManagerHint;
501 } else {
502 flags |= Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint;
503 }
504 }
505 // All these buttons depend on the system menu, so we enable it
506 if (flags & (Qt::WindowMinimizeButtonHint
507 | Qt::WindowMaximizeButtonHint
508 | Qt::WindowContextHelpButtonHint))
509 flags |= Qt::WindowSystemMenuHint;
510 }
511
512
513 Window parentw, destroyw = 0;
514 WId id = 0;
515
516 // always initialize
517 if (!window)
518 initializeWindow = true;
519
520 QX11Info *parentXinfo = parentWidget ? &parentWidget->d_func()->xinfo : 0;
521
522 if (desktop &&
523 qt_x11_create_desktop_on_screen >= 0 &&
524 qt_x11_create_desktop_on_screen != xinfo.screen()) {
525 // desktop on a certain screen other than the default requested
526 QX11InfoData *xd = &X11->screens[qt_x11_create_desktop_on_screen];
527 xinfo.setX11Data(xd);
528 } else if (parentXinfo && (parentXinfo->screen() != xinfo.screen()
529 || (parentXinfo->visual() != xinfo.visual()
530 && !q->inherits("QGLWidget"))))
531 {
532 // QGLWidgets have to be excluded here as they have a
533 // specially crafted QX11Info structure which can't be swapped
534 // out with the parent widgets QX11Info. The parent visual,
535 // for instance, might not even be GL capable.
536 xinfo = *parentXinfo;
537 }
538
539 //get display, screen number, root window and desktop geometry for
540 //the current screen
541 Display *dpy = X11->display;
542 int scr = xinfo.screen();
543 Window root_win = RootWindow(dpy, scr);
544 int sw = DisplayWidth(dpy,scr);
545 int sh = DisplayHeight(dpy,scr);
546
547 if (desktop) { // desktop widget
548 dialog = popup = false; // force these flags off
549 data.crect.setRect(0, 0, sw, sh);
550 } else if (topLevel && !q->testAttribute(Qt::WA_Resized)) {
551 QDesktopWidget *desktopWidget = qApp->desktop();
552 if (desktopWidget->isVirtualDesktop()) {
553 QRect r = desktopWidget->screenGeometry();
554 sw = r.width();
555 sh = r.height();
556 }
557
558 int width = sw / 2;
559 int height = 4 * sh / 10;
560 if (extra) {
561 width = qMax(qMin(width, extra->maxw), extra->minw);
562 height = qMax(qMin(height, extra->maxh), extra->minh);
563 }
564 data.crect.setSize(QSize(width, height));
565 }
566
567 parentw = topLevel ? root_win : parentWidget->effectiveWinId();
568
569 XSetWindowAttributes wsa;
570
571 if (window) { // override the old window
572 if (destroyOldWindow) {
573 if (topLevel)
574 X11->dndEnable(q, false);
575 destroyw = data.winid;
576 }
577 id = window;
578 setWinId(window);
579 XWindowAttributes a;
580 XGetWindowAttributes(dpy, window, &a);
581 data.crect.setRect(a.x, a.y, a.width, a.height);
582
583 if (a.map_state == IsUnmapped)
584 q->setAttribute(Qt::WA_WState_Visible, false);
585 else
586 q->setAttribute(Qt::WA_WState_Visible);
587
588 qt_x11_getX11InfoForWindow(&xinfo,a);
589
590 } else if (desktop) { // desktop widget
591#ifdef QWIDGET_EXTRA_DEBUG
592 qDebug() << "create desktop";
593#endif
594 id = (WId)parentw; // id = root window
595// QWidget *otherDesktop = find(id); // is there another desktop?
596// if (otherDesktop && otherDesktop->testWFlags(Qt::WPaintDesktop)) {
597// otherDesktop->d->setWinId(0); // remove id from widget mapper
598// d->setWinId(id); // make sure otherDesktop is
599// otherDesktop->d->setWinId(id); // found first
600// } else {
601 setWinId(id);
602// }
603 } else if (topLevel || q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) {
604#ifdef QWIDGET_EXTRA_DEBUG
605 static int topLevels = 0;
606 static int children = 0;
607 if (parentw == root_win)
608 qDebug() << "create toplevel" << ++topLevels;
609 else
610 qDebug() << "create child" << ++children;
611#endif
612 QRect safeRect = data.crect; //##### must handle huge sizes as well.... i.e. wrect
613 if (safeRect.width() < 1|| safeRect.height() < 1) {
614 if (topLevel) {
615 // top-levels must be at least 1x1
616 safeRect.setSize(safeRect.size().expandedTo(QSize(1, 1)));
617 } else {
618 // create it way off screen, and rely on
619 // setWSGeometry() to do the right thing with it later
620 safeRect = QRect(-1000,-1000,1,1);
621 }
622 }
623#ifndef QT_NO_XRENDER
624 int screen = xinfo.screen();
625 if (topLevel && X11->use_xrender
626 && xinfo.depth() != 32 && X11->argbVisuals[screen]
627 && q->testAttribute(Qt::WA_TranslucentBackground))
628 {
629 QX11InfoData *xd = xinfo.getX11Data(true);
630
631 xd->screen = screen;
632 xd->visual = X11->argbVisuals[screen];
633 xd->colormap = X11->argbColormaps[screen];
634 xd->depth = 32;
635 xd->defaultVisual = false;
636 xd->defaultColormap = false;
637 xd->cells = xd->visual->map_entries;
638 xinfo.setX11Data(xd);
639 }
640#endif
641 if (xinfo.defaultVisual() && xinfo.defaultColormap()) {
642 id = (WId)qt_XCreateSimpleWindow(q, dpy, parentw,
643 safeRect.left(), safeRect.top(),
644 safeRect.width(), safeRect.height(),
645 0,
646 BlackPixel(dpy, xinfo.screen()),
647 WhitePixel(dpy, xinfo.screen()));
648 } else {
649 wsa.background_pixel = WhitePixel(dpy, xinfo.screen());
650 wsa.border_pixel = BlackPixel(dpy, xinfo.screen());
651 wsa.colormap = xinfo.colormap();
652 id = (WId)qt_XCreateWindow(q, dpy, parentw,
653 safeRect.left(), safeRect.top(),
654 safeRect.width(), safeRect.height(),
655 0, xinfo.depth(), InputOutput,
656 (Visual *) xinfo.visual(),
657 CWBackPixel|CWBorderPixel|CWColormap,
658 &wsa);
659 }
660
661 setWinId(id); // set widget id/handle + hd
662 }
663
664#ifndef QT_NO_XRENDER
665 if (picture) {
666 XRenderFreePicture(X11->display, picture);
667 picture = 0;
668 }
669
670 if (X11->use_xrender && !desktop && q->internalWinId()) {
671 XRenderPictFormat *format = XRenderFindVisualFormat(dpy, (Visual *) xinfo.visual());
672 if (format)
673 picture = XRenderCreatePicture(dpy, id, format, 0, 0);
674 }
675#endif // QT_NO_XRENDER
676
677 QtMWMHints mwmhints;
678 mwmhints.flags = 0L;
679 mwmhints.functions = 0L;
680 mwmhints.decorations = 0;
681 mwmhints.input_mode = 0L;
682 mwmhints.status = 0L;
683
684 if (topLevel) {
685 ulong wsa_mask = 0;
686 if (type != Qt::SplashScreen) { // && customize) {
687 mwmhints.flags |= MWM_HINTS_DECORATIONS;
688
689 bool customize = flags & Qt::CustomizeWindowHint;
690 if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) {
691 mwmhints.decorations |= MWM_DECOR_BORDER;
692 mwmhints.decorations |= MWM_DECOR_RESIZEH;
693
694 if (flags & Qt::WindowTitleHint)
695 mwmhints.decorations |= MWM_DECOR_TITLE;
696
697 if (flags & Qt::WindowSystemMenuHint)
698 mwmhints.decorations |= MWM_DECOR_MENU;
699
700 if (flags & Qt::WindowMinimizeButtonHint) {
701 mwmhints.decorations |= MWM_DECOR_MINIMIZE;
702 mwmhints.functions |= MWM_FUNC_MINIMIZE;
703 }
704
705 if (flags & Qt::WindowMaximizeButtonHint) {
706 mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
707 mwmhints.functions |= MWM_FUNC_MAXIMIZE;
708 }
709
710 if (flags & Qt::WindowCloseButtonHint)
711 mwmhints.functions |= MWM_FUNC_CLOSE;
712 }
713 } else {
714 // if type == Qt::SplashScreen
715 mwmhints.decorations = MWM_DECOR_ALL;
716 }
717
718 if (tool) {
719 wsa.save_under = True;
720 wsa_mask |= CWSaveUnder;
721 }
722
723 if (flags & Qt::X11BypassWindowManagerHint) {
724 wsa.override_redirect = True;
725 wsa_mask |= CWOverrideRedirect;
726 }
727
728 if (wsa_mask && initializeWindow) {
729 Q_ASSERT(id);
730 XChangeWindowAttributes(dpy, id, wsa_mask, &wsa);
731 }
732
733 if (mwmhints.functions != 0) {
734 mwmhints.flags |= MWM_HINTS_FUNCTIONS;
735 mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
736 } else {
737 mwmhints.functions = MWM_FUNC_ALL;
738 }
739
740 if (!(flags & Qt::FramelessWindowHint)
741 && flags & Qt::CustomizeWindowHint
742 && flags & Qt::WindowTitleHint
743 && !(flags &
744 (Qt::WindowMinimizeButtonHint
745 | Qt::WindowMaximizeButtonHint
746 | Qt::WindowCloseButtonHint))) {
747 // a special case - only the titlebar without any button
748 mwmhints.flags = MWM_HINTS_FUNCTIONS;
749 mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
750 mwmhints.decorations = 0;
751 }
752 }
753
754 if (!initializeWindow) {
755 // do no initialization
756 } else if (popup) { // popup widget
757 // set EWMH window types
758 setNetWmWindowTypes();
759
760 wsa.override_redirect = True;
761 wsa.save_under = True;
762 Q_ASSERT(id);
763 XChangeWindowAttributes(dpy, id, CWOverrideRedirect | CWSaveUnder,
764 &wsa);
765 } else if (topLevel && !desktop) { // top-level widget
766 if (!X11->wm_client_leader)
767 create_wm_client_leader();
768
769 // note: WM_TRANSIENT_FOR is set in QWidgetPrivate::show_sys()
770
771 XSizeHints size_hints;
772 size_hints.flags = USSize | PSize | PWinGravity;
773 size_hints.x = data.crect.left();
774 size_hints.y = data.crect.top();
775 size_hints.width = data.crect.width();
776 size_hints.height = data.crect.height();
777 size_hints.win_gravity =
778 QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
779
780 XWMHints wm_hints; // window manager hints
781 memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
782 wm_hints.flags = InputHint | StateHint | WindowGroupHint;
783 wm_hints.input = q->testAttribute(Qt::WA_X11DoNotAcceptFocus) ? False : True;
784 wm_hints.initial_state = NormalState;
785 wm_hints.window_group = X11->wm_client_leader;
786
787 XClassHint class_hint;
788 QByteArray appName = qAppName().toLatin1();
789 class_hint.res_name = appName.data(); // application name
790 class_hint.res_class = const_cast<char *>(QX11Info::appClass()); // application class
791
792 XSetWMProperties(dpy, id, 0, 0,
793 qApp->d_func()->argv, qApp->d_func()->argc,
794 &size_hints, &wm_hints, &class_hint);
795
796 XResizeWindow(dpy, id,
797 qBound(1, data.crect.width(), XCOORD_MAX),
798 qBound(1, data.crect.height(), XCOORD_MAX));
799 XStoreName(dpy, id, appName.data());
800 Atom protocols[5];
801 int n = 0;
802 protocols[n++] = ATOM(WM_DELETE_WINDOW); // support del window protocol
803 protocols[n++] = ATOM(WM_TAKE_FOCUS); // support take focus window protocol
804 protocols[n++] = ATOM(_NET_WM_PING); // support _NET_WM_PING protocol
805#ifndef QT_NO_XSYNC
806 protocols[n++] = ATOM(_NET_WM_SYNC_REQUEST); // support _NET_WM_SYNC_REQUEST protocol
807#endif // QT_NO_XSYNC
808 if (flags & Qt::WindowContextHelpButtonHint)
809 protocols[n++] = ATOM(_NET_WM_CONTEXT_HELP);
810 XSetWMProtocols(dpy, id, protocols, n);
811
812 // set mwm hints
813 SetMWMHints(dpy, id, mwmhints);
814
815 // set EWMH window types
816 setNetWmWindowTypes();
817
818 // set _NET_WM_PID
819 long curr_pid = getpid();
820 XChangeProperty(dpy, id, ATOM(_NET_WM_PID), XA_CARDINAL, 32, PropModeReplace,
821 (unsigned char *) &curr_pid, 1);
822
823 // when we create a toplevel widget, the frame strut should be dirty
824 data.fstrut_dirty = 1;
825
826 // declare the widget's window role
827 if (QTLWExtra *topData = maybeTopData()) {
828 if (!topData->role.isEmpty()) {
829 QByteArray windowRole = topData->role.toUtf8();
830 XChangeProperty(dpy, id,
831 ATOM(WM_WINDOW_ROLE), XA_STRING, 8, PropModeReplace,
832 (unsigned char *)windowRole.constData(), windowRole.length());
833 }
834 }
835
836 // set client leader property
837 XChangeProperty(dpy, id, ATOM(WM_CLIENT_LEADER),
838 XA_WINDOW, 32, PropModeReplace,
839 (unsigned char *)&X11->wm_client_leader, 1);
840 } else {
841 // non-toplevel widgets don't have a frame, so no need to
842 // update the strut
843 data.fstrut_dirty = 0;
844 }
845
846 if (initializeWindow && q->internalWinId()) {
847 // don't erase when resizing
848 wsa.bit_gravity = QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
849 Q_ASSERT(id);
850 XChangeWindowAttributes(dpy, id, CWBitGravity, &wsa);
851 }
852
853 // set X11 event mask
854 if (desktop) {
855// QWidget* main_desktop = find(id);
856// if (main_desktop->testWFlags(Qt::WPaintDesktop))
857// XSelectInput(dpy, id, stdDesktopEventMask | ExposureMask);
858// else
859 XSelectInput(dpy, id, stdDesktopEventMask);
860 } else if (q->internalWinId()) {
861 XSelectInput(dpy, id, stdWidgetEventMask);
862#if !defined (QT_NO_TABLET)
863 QTabletDeviceDataList *tablet_list = qt_tablet_devices();
864 if (X11->ptrXSelectExtensionEvent) {
865 for (int i = 0; i < tablet_list->size(); ++i) {
866 QTabletDeviceData tablet = tablet_list->at(i);
867 X11->ptrXSelectExtensionEvent(dpy, id, reinterpret_cast<XEventClass*>(tablet.eventList),
868 tablet.eventCount);
869 }
870 }
871#endif
872 }
873
874 if (desktop) {
875 q->setAttribute(Qt::WA_WState_Visible);
876 } else if (topLevel) { // set X cursor
877 if (initializeWindow) {
878 qt_x11_enforce_cursor(q);
879
880 if (QTLWExtra *topData = maybeTopData())
881 if (!topData->caption.isEmpty())
882 setWindowTitle_helper(topData->caption);
883
884 //always enable dnd: it's not worth the effort to maintain the state
885 // NOTE: this always creates topData()
886 X11->dndEnable(q, true);
887
888 if (maybeTopData() && maybeTopData()->opacity != 255)
889 q->setWindowOpacity(maybeTopData()->opacity/255.);
890
891 }
892 } else if (q->internalWinId()) {
893 qt_x11_enforce_cursor(q);
894 if (QWidget *p = q->parentWidget()) // reset the cursor on the native parent
895 qt_x11_enforce_cursor(p);
896 }
897
898 if (extra && !extra->mask.isEmpty() && q->internalWinId())
899 XShapeCombineRegion(X11->display, q->internalWinId(), ShapeBounding, 0, 0,
900 extra->mask.handle(), ShapeSet);
901
902 if (q->hasFocus() && q->testAttribute(Qt::WA_InputMethodEnabled)) {
903 QInputContext *inputContext = q->inputContext();
904 if (inputContext)
905 inputContext->setFocusWidget(q);
906 }
907
908 if (destroyw)
909 qt_XDestroyWindow(q, dpy, destroyw);
910
911 // newly created windows are positioned at the window system's
912 // (0,0) position. If the parent uses wrect mapping to expand the
913 // coordinate system, we must also adjust this widget's window
914 // system position
915 if (!topLevel && !parentWidget->data->wrect.topLeft().isNull())
916 setWSGeometry();
917 else if (topLevel && (data.crect.width() == 0 || data.crect.height() == 0))
918 q->setAttribute(Qt::WA_OutsideWSRange, true);
919
920 if (!topLevel && q->testAttribute(Qt::WA_NativeWindow) && q->testAttribute(Qt::WA_Mapped)) {
921 Q_ASSERT(q->internalWinId());
922 XMapWindow(X11->display, q->internalWinId());
923 // Ensure that mapped alien widgets are flushed immediately when re-created as native widgets.
924 if (QWindowSurface *surface = q->windowSurface())
925 surface->flush(q, q->rect(), q->mapTo(surface->window(), QPoint()));
926 }
927
928#ifdef ALIEN_DEBUG
929 qDebug() << "QWidgetPrivate::create_sys END:" << q;
930#endif
931}
932
933static void qt_x11_recreateWidget(QWidget *widget)
934{
935 if (widget->inherits("QGLWidget")) {
936 // We send QGLWidgets a ParentChange event which causes them to
937 // recreate their GL context, which in turn causes them to choose
938 // their visual again. Now that WA_TranslucentBackground is set,
939 // QGLContext::chooseVisual will select an ARGB visual.
940 QEvent e(QEvent::ParentChange);
941 QApplication::sendEvent(widget, &e);
942 } else {
943 // For regular widgets, reparent them with their parent which
944 // also triggers a recreation of the native window
945 QPoint pos = widget->pos();
946 bool visible = widget->isVisible();
947 if (visible)
948 widget->hide();
949
950 widget->setParent(widget->parentWidget(), widget->windowFlags());
951 widget->move(pos);
952 if (visible)
953 widget->show();
954 }
955}
956
957static void qt_x11_recreateNativeWidgetsRecursive(QWidget *widget)
958{
959 if (widget->internalWinId())
960 qt_x11_recreateWidget(widget);
961
962 const QObjectList &children = widget->children();
963 for (int i = 0; i < children.size(); ++i) {
964 QWidget *child = qobject_cast<QWidget*>(children.at(i));
965 if (child)
966 qt_x11_recreateNativeWidgetsRecursive(child);
967 }
968}
969
970void QWidgetPrivate::x11UpdateIsOpaque()
971{
972#ifndef QT_NO_XRENDER
973 Q_Q(QWidget);
974 if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
975 return;
976
977 bool topLevel = (data.window_flags & Qt::Window);
978 int screen = xinfo.screen();
979 if (topLevel && X11->use_xrender
980 && X11->argbVisuals[screen] && xinfo.depth() != 32)
981 {
982 qt_x11_recreateNativeWidgetsRecursive(q);
983 }
984#endif
985}
986
987/*
988 Returns true if the background is inherited; otherwise returns
989 false.
990
991 Mainly used in the paintOnScreen case.
992*/
993bool QWidgetPrivate::isBackgroundInherited() const
994{
995 Q_Q(const QWidget);
996
997 // windows do not inherit their background
998 if (q->isWindow() || q->windowType() == Qt::SubWindow)
999 return false;
1000
1001 if (q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_OpaquePaintEvent))
1002 return false;
1003
1004 const QPalette &pal = q->palette();
1005 QPalette::ColorRole bg = q->backgroundRole();
1006 QBrush brush = pal.brush(bg);
1007
1008 // non opaque brushes leaves us no choice, we must inherit
1009 if (!q->autoFillBackground() || !brush.isOpaque())
1010 return true;
1011
1012 if (brush.style() == Qt::SolidPattern) {
1013 // the background is just a solid color. If there is no
1014 // propagated contents, then we claim as performance
1015 // optimization that it was not inheritet. This is the normal
1016 // case in standard Windows or Motif style.
1017 const QWidget *w = q->parentWidget();
1018 if (!w->d_func()->isBackgroundInherited())
1019 return false;
1020 }
1021
1022 return true;
1023}
1024
1025void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1026{
1027 Q_D(QWidget);
1028 d->aboutToDestroy();
1029 if (!isWindow() && parentWidget())
1030 parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
1031 d->deactivateWidgetCleanup();
1032 if (testAttribute(Qt::WA_WState_Created)) {
1033 setAttribute(Qt::WA_WState_Created, false);
1034 QObjectList childList = children();
1035 for (int i = 0; i < childList.size(); ++i) { // destroy all widget children
1036 register QObject *obj = childList.at(i);
1037 if (obj->isWidgetType())
1038 static_cast<QWidget*>(obj)->destroy(destroySubWindows,
1039 destroySubWindows);
1040 }
1041 if (QWidgetPrivate::mouseGrabber == this)
1042 releaseMouse();
1043 if (QWidgetPrivate::keyboardGrabber == this)
1044 releaseKeyboard();
1045 if (isWindow())
1046 X11->deferred_map.removeAll(this);
1047 if (isModal()) {
1048 // just be sure we leave modal
1049 QApplicationPrivate::leaveModal(this);
1050 }
1051 else if ((windowType() == Qt::Popup))
1052 qApp->d_func()->closePopup(this);
1053
1054#ifndef QT_NO_XRENDER
1055 if (d->picture) {
1056 if (destroyWindow)
1057 XRenderFreePicture(X11->display, d->picture);
1058 d->picture = 0;
1059 }
1060#endif // QT_NO_XRENDER
1061
1062 // delete the _NET_WM_USER_TIME_WINDOW
1063 qt_net_remove_user_time(this);
1064
1065 if ((windowType() == Qt::Desktop)) {
1066 if (acceptDrops())
1067 X11->dndEnable(this, false);
1068 } else {
1069 if (isWindow())
1070 X11->dndEnable(this, false);
1071 if (destroyWindow)
1072 qt_XDestroyWindow(this, X11->display, data->winid);
1073 }
1074 QT_TRY {
1075 d->setWinId(0);
1076 } QT_CATCH (const std::bad_alloc &) {
1077 // swallow - destructors must not throw
1078 }
1079
1080 extern void qPRCleanup(QWidget *widget); // from qapplication_x11.cpp
1081 if (testAttribute(Qt::WA_WState_Reparented))
1082 qPRCleanup(this);
1083
1084 if(d->ic) {
1085 delete d->ic;
1086 } else {
1087 // release previous focus information participating with
1088 // preedit preservation of qic
1089 QInputContext *qic = QApplicationPrivate::inputContext;
1090 if (qic)
1091 qic->widgetDestroyed(this);
1092 }
1093 }
1094}
1095
1096void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
1097{
1098 Q_Q(QWidget);
1099#ifdef ALIEN_DEBUG
1100 qDebug() << "QWidgetPrivate::setParent_sys START" << q << "parent:" << parent;
1101#endif
1102 QX11Info old_xinfo = xinfo;
1103 if (parent && parent->windowType() == Qt::Desktop) {
1104 // make sure the widget is created on the same screen as the
1105 // programmer specified desktop widget
1106 xinfo = parent->d_func()->xinfo;
1107 parent = 0;
1108 }
1109
1110 QTLWExtra *topData = maybeTopData();
1111 bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
1112 if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
1113 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
1114 extern void qPRCreate(const QWidget *, Window);
1115#ifndef QT_NO_CURSOR
1116 QCursor oldcurs;
1117#endif
1118
1119 // dnd unregister (we will register again below)
1120 if (q->testAttribute(Qt::WA_DropSiteRegistered))
1121 q->setAttribute(Qt::WA_DropSiteRegistered, false);
1122
1123 // if we are a top then remove our dnd prop for now
1124 // it will get rest later
1125 if (q->isWindow() && wasCreated)
1126 X11->dndEnable(q, false);
1127
1128 if (topData)
1129 qt_net_remove_user_time(q);
1130
1131// QWidget *oldparent = q->parentWidget();
1132 WId old_winid = wasCreated ? data.winid : 0;
1133 if ((q->windowType() == Qt::Desktop))
1134 old_winid = 0;
1135 setWinId(0);
1136
1137#ifndef QT_NO_XRENDER
1138 if (picture) {
1139 XRenderFreePicture(X11->display, picture);
1140 picture = 0;
1141 }
1142#endif
1143
1144 // hide and reparent our own window away. Otherwise we might get
1145 // destroyed when emitting the child remove event below. See QWorkspace.
1146 if (wasCreated && old_winid) {
1147 XUnmapWindow(X11->display, old_winid);
1148 if (!old_xinfo.screen() != xinfo.screen())
1149 XReparentWindow(X11->display, old_winid, RootWindow(X11->display, xinfo.screen()), 0, 0);
1150 }
1151 if (topData) {
1152 topData->parentWinId = 0;
1153 // zero the frame strut and mark it dirty
1154 topData->frameStrut.setCoords(0, 0, 0, 0);
1155
1156 // reparenting from top-level, make sure show() works again
1157 topData->waitingForMapNotify = 0;
1158 topData->validWMState = 0;
1159 }
1160 data.fstrut_dirty = (!parent || (f & Qt::Window)); // toplevels get a dirty framestrut
1161
1162 QObjectPrivate::setParent_helper(parent);
1163 bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
1164
1165 data.window_flags = f;
1166 q->setAttribute(Qt::WA_WState_Created, false);
1167 q->setAttribute(Qt::WA_WState_Visible, false);
1168 q->setAttribute(Qt::WA_WState_Hidden, false);
1169 adjustFlags(data.window_flags, q);
1170 // keep compatibility with previous versions, we need to preserve the created state
1171 // (but we recreate the winId for the widget being reparented, again for compatibility)
1172 if (wasCreated)
1173 createWinId();
1174 if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
1175 q->setAttribute(Qt::WA_WState_Hidden);
1176 q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
1177