1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
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 "qabstracteventdispatcher.h"
48#include "qnamespace.h"
49#include "qpainter.h"
50#include "qbitmap.h"
51#include "qlayout.h"
52#include "qtextcodec.h"
53#include "qelapsedtimer.h"
54#include "qcursor.h"
55#include "qstack.h"
56#include "qcolormap.h"
57#include "qdebug.h"
58#include "qmenu.h"
59#include "private/qmenu_p.h"
60#include "private/qbackingstore_p.h"
61#include "private/qwindowsurface_x11_p.h"
62
63//extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); //qapplication_x11.cpp
64
65#include <private/qpixmap_x11_p.h>
66#include <private/qpaintengine_x11_p.h>
67#include "qt_x11_p.h"
68#include "qx11info_x11.h"
69
70#include <stdlib.h>
71
72//#define ALIEN_DEBUG
73
74// defined in qapplication_x11.cpp
75//bool qt_wstate_iconified(WId);
76//void qt_updated_rootinfo();
77
78
79#if !defined(QT_NO_IM)
80#include "qinputcontext.h"
81#include "qinputcontextfactory.h"
82#endif
83
84#include "qwidget_p.h"
85
86#define XCOORD_MAX 16383
87#define WRECT_MAX 8191
88
89QT_BEGIN_NAMESPACE
90
91extern bool qt_nograb();
92
93QWidget *QWidgetPrivate::mouseGrabber = 0;
94QWidget *QWidgetPrivate::keyboardGrabber = 0;
95
96void qt_net_remove_user_time(QWidget *tlw);
97void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp);
98
99int qt_x11_create_desktop_on_screen = -1;
100
101extern void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp);
102
103// MWM support
104struct QtMWMHints {
105 ulong flags, functions, decorations;
106 long input_mode;
107 ulong status;
108};
109
110enum {
111 MWM_HINTS_FUNCTIONS = (1L << 0),
112
113 MWM_FUNC_ALL = (1L << 0),
114 MWM_FUNC_RESIZE = (1L << 1),
115 MWM_FUNC_MOVE = (1L << 2),
116 MWM_FUNC_MINIMIZE = (1L << 3),
117 MWM_FUNC_MAXIMIZE = (1L << 4),
118 MWM_FUNC_CLOSE = (1L << 5),
119
120 MWM_HINTS_DECORATIONS = (1L << 1),
121
122 MWM_DECOR_ALL = (1L << 0),
123 MWM_DECOR_BORDER = (1L << 1),
124 MWM_DECOR_RESIZEH = (1L << 2),
125 MWM_DECOR_TITLE = (1L << 3),
126 MWM_DECOR_MENU = (1L << 4),
127 MWM_DECOR_MINIMIZE = (1L << 5),
128 MWM_DECOR_MAXIMIZE = (1L << 6),
129
130 MWM_HINTS_INPUT_MODE = (1L << 2),
131
132 MWM_INPUT_MODELESS = 0L,
133 MWM_INPUT_PRIMARY_APPLICATION_MODAL = 1L,
134 MWM_INPUT_FULL_APPLICATION_MODAL = 3L
135};
136
137
138static QtMWMHints GetMWMHints(Display *display, Window window)
139{
140 QtMWMHints mwmhints;
141
142 Atom type;
143 int format;
144 ulong nitems, bytesLeft;
145 uchar *data = 0;
146 if ((XGetWindowProperty(display, window, ATOM(_MOTIF_WM_HINTS), 0, 5, false,
147 ATOM(_MOTIF_WM_HINTS), &type, &format, &nitems, &bytesLeft,
148 &data) == Success)
149 && (type == ATOM(_MOTIF_WM_HINTS)
150 && format == 32
151 && nitems >= 5)) {
152 mwmhints = *(reinterpret_cast<QtMWMHints *>(data));
153 } else {
154 mwmhints.flags = 0L;
155 mwmhints.functions = MWM_FUNC_ALL;
156 mwmhints.decorations = MWM_DECOR_ALL;
157 mwmhints.input_mode = 0L;
158 mwmhints.status = 0L;
159 }
160
161 if (data)
162 XFree(data);
163
164 return mwmhints;
165}
166
167static void SetMWMHints(Display *display, Window window, const QtMWMHints &mwmhints)
168{
169 if (mwmhints.flags != 0l) {
170 XChangeProperty(display, window, ATOM(_MOTIF_WM_HINTS), ATOM(_MOTIF_WM_HINTS), 32,
171 PropModeReplace, (unsigned char *) &mwmhints, 5);
172 } else {
173 XDeleteProperty(display, window, ATOM(_MOTIF_WM_HINTS));
174 }
175}
176
177// Returns true if we should set WM_TRANSIENT_FOR on \a w
178static inline bool isTransient(const QWidget *w)
179{
180 return ((w->windowType() == Qt::Dialog
181 || w->windowType() == Qt::Sheet
182 || w->windowType() == Qt::Tool
183 || w->windowType() == Qt::SplashScreen
184 || w->windowType() == Qt::ToolTip
185 || w->windowType() == Qt::Drawer
186 || w->windowType() == Qt::Popup)
187 && !w->testAttribute(Qt::WA_X11BypassTransientForHint));
188}
189
190static void do_size_hints(QWidget* widget, QWExtra *x);
191
192/*****************************************************************************
193 QWidget member functions
194 *****************************************************************************/
195
196const uint stdWidgetEventMask = // X event mask
197 (uint)(
198 KeyPressMask | KeyReleaseMask |
199 ButtonPressMask | ButtonReleaseMask |
200 KeymapStateMask |
201 ButtonMotionMask | PointerMotionMask |
202 EnterWindowMask | LeaveWindowMask |
203 FocusChangeMask |
204 ExposureMask |
205 PropertyChangeMask |
206 StructureNotifyMask
207 );
208
209const uint stdDesktopEventMask = // X event mask
210 (uint)(
211 KeymapStateMask |
212 EnterWindowMask | LeaveWindowMask |
213 PropertyChangeMask
214 );
215
216
217/*
218 The qt_ functions below are implemented in qwidgetcreate_x11.cpp.
219*/
220
221Window qt_XCreateWindow(const QWidget *creator,
222 Display *display, Window parent,
223 int x, int y, uint w, uint h,
224 int borderwidth, int depth,
225 uint windowclass, Visual *visual,
226 ulong valuemask, XSetWindowAttributes *attributes);
227Window qt_XCreateSimpleWindow(const QWidget *creator,
228 Display *display, Window parent,
229 int x, int y, uint w, uint h, int borderwidth,
230 ulong border, ulong background);
231void qt_XDestroyWindow(const QWidget *destroyer,
232 Display *display, Window window);
233
234
235static void qt_insert_sip(QWidget* scrolled_widget, int dx, int dy)
236{
237 if (!scrolled_widget->isWindow() && !scrolled_widget->internalWinId())
238 return;
239 QX11Data::ScrollInProgress sip = { X11->sip_serial++, scrolled_widget, dx, dy };
240 X11->sip_list.append(sip);
241
242 XClientMessageEvent client_message;
243 client_message.type = ClientMessage;
244 client_message.window = scrolled_widget->internalWinId();
245 client_message.format = 32;
246 client_message.message_type = ATOM(_QT_SCROLL_DONE);
247 client_message.data.l[0] = sip.id;
248
249 XSendEvent(X11->display, scrolled_widget->internalWinId(), False, NoEventMask,
250 (XEvent*)&client_message);
251}
252
253static int qt_sip_count(QWidget* scrolled_widget)
254{
255 int sips=0;
256
257 for (int i = 0; i < X11->sip_list.size(); ++i) {
258 const QX11Data::ScrollInProgress &sip = X11->sip_list.at(i);
259 if (sip.scrolled_widget == scrolled_widget)
260 sips++;
261 }
262
263 return sips;
264}
265
266static void create_wm_client_leader()
267{
268 if (X11->wm_client_leader) return;
269
270 X11->wm_client_leader =
271 XCreateSimpleWindow(X11->display,
272 QX11Info::appRootWindow(),
273 0, 0, 1, 1, 0, 0, 0);
274
275 // set client leader property to itself
276 XChangeProperty(X11->display,
277 X11->wm_client_leader, ATOM(WM_CLIENT_LEADER),
278 XA_WINDOW, 32, PropModeReplace,
279 (unsigned char *)&X11->wm_client_leader, 1);
280
281#ifndef QT_NO_SESSIONMANAGER
282 // If we are session managed, inform the window manager about it
283 QByteArray session = qApp->sessionId().toLatin1();
284 if (!session.isEmpty()) {
285 XChangeProperty(X11->display,
286 X11->wm_client_leader, ATOM(SM_CLIENT_ID),
287 XA_STRING, 8, PropModeReplace,
288 (unsigned char *)session.data(), session.size());
289 }
290#endif
291}
292
293/*!
294 \internal
295 Update the X11 cursor of the widget w.
296 \a force is true if this function is called from dispatchEnterLeave, it means that the
297 mouse is actually directly under this widget.
298 */
299void qt_x11_enforce_cursor(QWidget * w, bool force)
300{
301 if (!w->testAttribute(Qt::WA_WState_Created))
302 return;
303
304 static QPointer<QWidget> lastUnderMouse = 0;
305 if (force) {
306 lastUnderMouse = w;
307 } else if (lastUnderMouse && lastUnderMouse->effectiveWinId() == w->effectiveWinId()) {
308 w = lastUnderMouse;
309 } else if (!w->internalWinId()) {
310 return; //the mouse is not under this widget, and it's not native, so don't change it
311 }
312
313 while (!w->internalWinId() && w->parentWidget() && !w->isWindow() && !w->testAttribute(Qt::WA_SetCursor))
314 w = w->parentWidget();
315
316 QWidget *nativeParent = w;
317 if (!w->internalWinId())
318 nativeParent = w->nativeParentWidget();
319 // This does the same as effectiveWinId(), but since it is possible
320 // to not have a native parent widget due to a special hack in
321 // qwidget for reparenting widgets to a different X11 screen,
322 // added additional check to make sure native parent widget exists.
323 if (!nativeParent || !nativeParent->internalWinId())
324 return;
325 WId winid = nativeParent->internalWinId();
326
327 if (w->isWindow() || w->testAttribute(Qt::WA_SetCursor)) {
328#ifndef QT_NO_CURSOR
329 QCursor *oc = QApplication::overrideCursor();
330 if (oc) {
331 XDefineCursor(X11->display, winid, oc->handle());
332 } else if (w->isEnabled()) {
333 XDefineCursor(X11->display, winid, w->cursor().handle());
334 } else {
335 // enforce the windows behavior of clearing the cursor on
336 // disabled widgets
337 XDefineCursor(X11->display, winid, XNone);
338 }
339#endif
340 } else {
341 XDefineCursor(X11->display, winid, XNone);
342 }
343}
344
345Q_GUI_EXPORT void qt_x11_enforce_cursor(QWidget * w)
346{
347 qt_x11_enforce_cursor(w, false);
348}
349
350void qt_x11_wait_for_window_manager(QWidget *w, bool sendPostedEvents)
351{
352 if (!w || (!w->isWindow() && !w->internalWinId()))
353 return;
354 QApplication::flush();
355 XEvent ev;
356 QElapsedTimer t;
357 t.start();
358 static const int maximumWaitTime = 2000;
359 if (!w->testAttribute(Qt::WA_WState_Created))
360 return;
361
362 WId winid = w->internalWinId();
363
364 // first deliver events that are already in the local queue
365 if (sendPostedEvents)
366 QApplication::sendPostedEvents();
367
368 // the normal sequence is:
369 // ... ConfigureNotify ... ReparentNotify ... MapNotify ... Expose
370 // with X11BypassWindowManagerHint:
371 // ConfigureNotify ... MapNotify ... Expose
372
373 enum State {
374 Initial, Mapped
375 } state = Initial;
376
377 do {
378 if (XEventsQueued(X11->display, QueuedAlready)) {
379 XNextEvent(X11->display, &ev);
380 // Pass the event through the event dispatcher filter so that applications
381 // which install an event filter on the dispatcher get to handle it first.
382 if (!QAbstractEventDispatcher::instance()->filterEvent(&ev)) {
383 qApp->x11ProcessEvent(&ev);
384
385 switch (state) {
386 case Initial:
387 if (ev.type == MapNotify && ev.xany.window == winid)
388 state = Mapped;
389 break;
390 case Mapped:
391 if (ev.type == Expose && ev.xany.window == winid)
392 return;
393 break;
394 }
395 }
396 } else {
397 if (!XEventsQueued(X11->display, QueuedAfterFlush))
398 qApp->syncX(); // non-busy wait
399 }
400 if (t.elapsed() > maximumWaitTime)
401 return;
402 } while(1);
403}
404
405Q_GUI_EXPORT void qt_x11_wait_for_window_manager(QWidget *w)
406{
407 qt_x11_wait_for_window_manager(w, true);
408}
409
410void qt_change_net_wm_state(const QWidget* w, bool set, Atom one, Atom two = 0)
411{
412 if (!w->isVisible()) // not managed by the window manager
413 return;
414
415 XEvent e;
416 e.xclient.type = ClientMessage;
417 e.xclient.message_type = ATOM(_NET_WM_STATE);
418 e.xclient.display = X11->display;
419 e.xclient.window = w->internalWinId();
420 e.xclient.format = 32;
421 e.xclient.data.l[0] = set ? 1 : 0;
422 e.xclient.data.l[1] = one;
423 e.xclient.data.l[2] = two;
424 e.xclient.data.l[3] = 0;
425 e.xclient.data.l[4] = 0;
426 XSendEvent(X11->display, RootWindow(X11->display, w->x11Info().screen()),
427 false, (SubstructureNotifyMask | SubstructureRedirectMask), &e);
428}
429
430struct QX11WindowAttributes {
431 const XWindowAttributes *att;
432};
433
434void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const XWindowAttributes &a)
435{
436 QX11WindowAttributes att;
437 att.att = &a;
438 qt_x11_getX11InfoForWindow(xinfo,att);
439}
440
441
442static QVector<Atom> getNetWmState(QWidget *w)
443{
444 QVector<Atom> returnValue;
445
446 // Don't read anything, just get the size of the property data
447 Atom actualType;
448 int actualFormat;
449 ulong propertyLength;
450 ulong bytesLeft;
451 uchar *propertyData = 0;
452 if (XGetWindowProperty(X11->display, w->internalWinId(), ATOM(_NET_WM_STATE), 0, 0,
453 False, XA_ATOM, &actualType, &actualFormat,
454 &propertyLength, &bytesLeft, &propertyData) == Success
455 && actualType == XA_ATOM && actualFormat == 32) {
456 returnValue.resize(bytesLeft / 4);
457 XFree((char*) propertyData);
458 propertyData = 0;
459
460 // fetch all data
461 if (XGetWindowProperty(X11->display, w->internalWinId(), ATOM(_NET_WM_STATE), 0,
462 returnValue.size(), False, XA_ATOM, &actualType, &actualFormat,
463 &propertyLength, &bytesLeft, &propertyData) != Success) {
464 returnValue.clear();
465 } else if (propertyLength != (ulong)returnValue.size()) {
466 returnValue.resize(propertyLength);
467 }
468
469 // put it into netWmState
470 if (!returnValue.isEmpty()) {
471 memcpy(returnValue.data(), propertyData, returnValue.size() * sizeof(Atom));
472 }
473 if (propertyData)
474 XFree((char*) propertyData);
475 }
476
477 return returnValue;
478}
479
480void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
481{
482 Q_Q(QWidget);
483 Qt::WindowType type = q->windowType();
484 Qt::WindowFlags &flags = data.window_flags;
485 QWidget *parentWidget = q->parentWidget();
486
487 if (type == Qt::ToolTip)
488 flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint;
489 if (type == Qt::Popup)
490 flags |= Qt::X11BypassWindowManagerHint;
491
492 bool topLevel = (flags & Qt::Window);
493 bool popup = (type == Qt::Popup);
494 bool desktop = (type == Qt::Desktop);
495 bool tool = (type == Qt::Tool || type == Qt::SplashScreen
496 || type == Qt::ToolTip || type == Qt::Drawer);
497
498#ifdef ALIEN_DEBUG
499 qDebug() << "QWidgetPrivate::create_sys START:" << q << "topLevel?" << topLevel << "WId:"
500 << window << "initializeWindow:" << initializeWindow << "destroyOldWindow" << destroyOldWindow;
501#endif
502 if (topLevel) {
503 if (parentWidget) { // if our parent stays on top, so must we
504 QWidget *ptl = parentWidget->window();
505 if(ptl && (ptl->windowFlags() & Qt::WindowStaysOnTopHint))
506 flags |= Qt::WindowStaysOnTopHint;
507 }
508
509 if (type == Qt::SplashScreen) {
510 if (X11->isSupportedByWM(ATOM(_NET_WM_WINDOW_TYPE_SPLASH))) {
511 flags &= ~Qt::X11BypassWindowManagerHint;
512 } else {
513 flags |= Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint;
514 }
515 }
516 // All these buttons depend on the system menu, so we enable it
517 if (flags & (Qt::WindowMinimizeButtonHint
518 | Qt::WindowMaximizeButtonHint
519 | Qt::WindowContextHelpButtonHint))
520 flags |= Qt::WindowSystemMenuHint;
521 }
522
523
524 Window parentw, destroyw = 0;
525 WId id = 0;
526
527 // always initialize
528 if (!window)
529 initializeWindow = true;
530
531 QX11Info *parentXinfo = parentWidget ? &parentWidget->d_func()->xinfo : 0;
532
533 if (desktop &&
534 qt_x11_create_desktop_on_screen >= 0 &&
535 qt_x11_create_desktop_on_screen != xinfo.screen()) {
536 // desktop on a certain screen other than the default requested
537 QX11InfoData *xd = &X11->screens[qt_x11_create_desktop_on_screen];
538 xinfo.setX11Data(xd);
539 } else if (parentXinfo && (parentXinfo->screen() != xinfo.screen()
540 || (parentXinfo->visual() != xinfo.visual()
541 && !q->inherits("QGLWidget"))))
542 {
543 // QGLWidgets have to be excluded here as they have a
544 // specially crafted QX11Info structure which can't be swapped
545 // out with the parent widgets QX11Info. The parent visual,
546 // for instance, might not even be GL capable.
547 xinfo = *parentXinfo;
548 }
549
550 //get display, screen number, root window and desktop geometry for
551 //the current screen
552 Display *dpy = X11->display;
553 int scr = xinfo.screen();
554 Window root_win = RootWindow(dpy, scr);
555 int sw = DisplayWidth(dpy,scr);
556 int sh = DisplayHeight(dpy,scr);
557
558 if (desktop) { // desktop widget
559 popup = false; // force these flags off
560 data.crect.setRect(0, 0, sw, sh);
561 } else if (topLevel && !q->testAttribute(Qt::WA_Resized)) {
562 QDesktopWidget *desktopWidget = qApp->desktop();
563 if (desktopWidget->isVirtualDesktop()) {
564 QRect r = desktopWidget->screenGeometry();
565 sw = r.width();
566 sh = r.height();
567 }
568
569 int width = sw / 2;
570 int height = 4 * sh / 10;
571 if (extra) {
572 width = qMax(qMin(width, extra->maxw), extra->minw);
573 height = qMax(qMin(height, extra->maxh), extra->minh);
574 }
575 data.crect.setSize(QSize(width, height));
576 }
577
578 parentw = topLevel ? root_win : parentWidget->effectiveWinId();
579
580 XSetWindowAttributes wsa;
581
582 if (window) { // override the old window
583 if (destroyOldWindow) {
584 if (topLevel)
585 X11->dndEnable(q, false);
586 destroyw = data.winid;
587 }
588 id = window;
589 setWinId(window);
590 XWindowAttributes a;
591 XGetWindowAttributes(dpy, window, &a);
592 data.crect.setRect(a.x, a.y, a.width, a.height);
593
594 if (a.map_state == IsUnmapped)
595 q->setAttribute(Qt::WA_WState_Visible, false);
596 else
597 q->setAttribute(Qt::WA_WState_Visible);
598
599 qt_x11_getX11InfoForWindow(&xinfo,a);
600
601 } else if (desktop) { // desktop widget
602#ifdef QWIDGET_EXTRA_DEBUG
603 qDebug() << "create desktop";
604#endif
605 id = (WId)parentw; // id = root window
606// QWidget *otherDesktop = find(id); // is there another desktop?
607// if (otherDesktop && otherDesktop->testWFlags(Qt::WPaintDesktop)) {
608// otherDesktop->d->setWinId(0); // remove id from widget mapper
609// d->setWinId(id); // make sure otherDesktop is
610// otherDesktop->d->setWinId(id); // found first
611// } else {
612 setWinId(id);
613// }
614 } else if (topLevel || q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) {
615#ifdef QWIDGET_EXTRA_DEBUG
616 static int topLevels = 0;
617 static int children = 0;
618 if (parentw == root_win)
619 qDebug() << "create toplevel" << ++topLevels;
620 else
621 qDebug() << "create child" << ++children;
622#endif
623 QRect safeRect = data.crect; //##### must handle huge sizes as well.... i.e. wrect
624 if (safeRect.width() < 1|| safeRect.height() < 1) {
625 if (topLevel) {
626 // top-levels must be at least 1x1
627 safeRect.setSize(safeRect.size().expandedTo(QSize(1, 1)));
628 } else {
629 // create it way off screen, and rely on
630 // setWSGeometry() to do the right thing with it later
631 safeRect = QRect(-1000,-1000,1,1);
632 }
633 }
634#ifndef QT_NO_XRENDER
635 int screen = xinfo.screen();
636 if (topLevel && X11->use_xrender
637 && xinfo.depth() != 32 && X11->argbVisuals[screen]
638 && q->testAttribute(Qt::WA_TranslucentBackground))
639 {
640 QX11InfoData *xd = xinfo.getX11Data(true);
641
642 xd->screen = screen;
643 xd->visual = X11->argbVisuals[screen];
644 xd->colormap = X11->argbColormaps[screen];
645 xd->depth = 32;
646 xd->defaultVisual = false;
647 xd->defaultColormap = false;
648 xd->cells = xd->visual->map_entries;
649 xinfo.setX11Data(xd);
650 }
651#endif
652 if (xinfo.defaultVisual() && xinfo.defaultColormap()) {
653 id = (WId)qt_XCreateSimpleWindow(q, dpy, parentw,
654 safeRect.left(), safeRect.top(),
655 safeRect.width(), safeRect.height(),
656 0,
657 BlackPixel(dpy, xinfo.screen()),
658 WhitePixel(dpy, xinfo.screen()));
659 } else {
660 wsa.background_pixel = WhitePixel(dpy, xinfo.screen());
661 wsa.border_pixel = BlackPixel(dpy, xinfo.screen());
662 wsa.colormap = xinfo.colormap();
663 id = (WId)qt_XCreateWindow(q, dpy, parentw,
664 safeRect.left(), safeRect.top(),
665 safeRect.width(), safeRect.height(),
666 0, xinfo.depth(), InputOutput,
667 (Visual *) xinfo.visual(),
668 CWBackPixel|CWBorderPixel|CWColormap,
669 &wsa);
670 }
671
672 setWinId(id); // set widget id/handle + hd
673 }
674
675#ifndef QT_NO_XRENDER
676 if (picture) {
677 XRenderFreePicture(X11->display, picture);
678 picture = 0;
679 }
680
681 if (X11->use_xrender && !desktop && q->internalWinId()) {
682 XRenderPictFormat *format = XRenderFindVisualFormat(dpy, (Visual *) xinfo.visual());
683 if (format)
684 picture = XRenderCreatePicture(dpy, id, format, 0, 0);
685 }
686#endif // QT_NO_XRENDER
687
688 QtMWMHints mwmhints;
689 mwmhints.flags = 0L;
690 mwmhints.functions = 0L;
691 mwmhints.decorations = 0;
692 mwmhints.input_mode = 0L;
693 mwmhints.status = 0L;
694
695 if (topLevel) {
696 ulong wsa_mask = 0;
697 if (type != Qt::SplashScreen) { // && customize) {
698 mwmhints.flags |= MWM_HINTS_DECORATIONS;
699
700 bool customize = flags & Qt::CustomizeWindowHint;
701 if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) {
702 mwmhints.decorations |= MWM_DECOR_BORDER;
703 mwmhints.decorations |= MWM_DECOR_RESIZEH;
704
705 if (flags & Qt::WindowTitleHint)
706 mwmhints.decorations |= MWM_DECOR_TITLE;
707
708 if (flags & Qt::WindowSystemMenuHint)
709 mwmhints.decorations |= MWM_DECOR_MENU;
710
711 if (flags & Qt::WindowMinimizeButtonHint) {
712 mwmhints.decorations |= MWM_DECOR_MINIMIZE;
713 mwmhints.functions |= MWM_FUNC_MINIMIZE;
714 }
715
716 if (flags & Qt::WindowMaximizeButtonHint) {
717 mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
718 mwmhints.functions |= MWM_FUNC_MAXIMIZE;
719 }
720
721 if (flags & Qt::WindowCloseButtonHint)
722 mwmhints.functions |= MWM_FUNC_CLOSE;
723 }
724 } else {
725 // if type == Qt::SplashScreen
726 mwmhints.decorations = MWM_DECOR_ALL;
727 }
728
729 if (tool) {
730 wsa.save_under = True;
731 wsa_mask |= CWSaveUnder;
732 }
733
734 if (flags & Qt::X11BypassWindowManagerHint) {
735 wsa.override_redirect = True;
736 wsa_mask |= CWOverrideRedirect;
737 }
738
739 if (wsa_mask && initializeWindow) {
740 Q_ASSERT(id);
741 XChangeWindowAttributes(dpy, id, wsa_mask, &wsa);
742 }
743
744 if (mwmhints.functions != 0) {
745 mwmhints.flags |= MWM_HINTS_FUNCTIONS;
746 mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
747 } else {
748 mwmhints.functions = MWM_FUNC_ALL;
749 }
750
751 if (!(flags & Qt::FramelessWindowHint)
752 && flags & Qt::CustomizeWindowHint
753 && flags & Qt::WindowTitleHint
754 && !(flags &
755 (Qt::WindowMinimizeButtonHint
756 | Qt::WindowMaximizeButtonHint
757 | Qt::WindowCloseButtonHint))) {
758 // a special case - only the titlebar without any button
759 mwmhints.flags = MWM_HINTS_FUNCTIONS;
760 mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
761 mwmhints.decorations = 0;
762 }
763 }
764
765 if (!initializeWindow) {
766 // do no initialization
767 } else if (popup) { // popup widget
768 // set EWMH window types
769 setNetWmWindowTypes();
770
771 wsa.override_redirect = True;
772 wsa.save_under = True;
773 Q_ASSERT(id);
774 XChangeWindowAttributes(dpy, id, CWOverrideRedirect | CWSaveUnder,
775 &wsa);
776 } else if (topLevel && !desktop) { // top-level widget
777 if (!X11->wm_client_leader)
778 create_wm_client_leader();
779
780 // note: WM_TRANSIENT_FOR is set in QWidgetPrivate::show_sys()
781
782 XSizeHints size_hints;
783 memset(&size_hints, 0, sizeof(size_hints));
784 size_hints.flags = USSize | PSize | PWinGravity;
785 size_hints.x = data.crect.left();
786 size_hints.y = data.crect.top();
787 size_hints.width = data.crect.width();
788 size_hints.height = data.crect.height();
789 size_hints.win_gravity =
790 QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
791
792 XWMHints wm_hints; // window manager hints
793 memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
794 wm_hints.flags = InputHint | StateHint | WindowGroupHint;
795 wm_hints.input = q->testAttribute(Qt::WA_X11DoNotAcceptFocus) ? False : True;
796 wm_hints.initial_state = NormalState;
797 wm_hints.window_group = X11->wm_client_leader;
798
799 XClassHint class_hint;
800 QByteArray appName = qAppName().toLatin1();
801 class_hint.res_name = appName.data(); // application name
802 class_hint.res_class = const_cast<char *>(QX11Info::appClass()); // application class
803
804 XSetWMProperties(dpy, id, 0, 0,
805 qApp->d_func()->argv, qApp->d_func()->argc,
806 &size_hints, &wm_hints, &class_hint);
807
808 XResizeWindow(dpy, id,
809 qBound(1, data.crect.width(), XCOORD_MAX),
810 qBound(1, data.crect.height(), XCOORD_MAX));
811 XStoreName(dpy, id, appName.data());
812 Atom protocols[5];
813 int n = 0;
814 protocols[n++] = ATOM(WM_DELETE_WINDOW); // support del window protocol
815 protocols[n++] = ATOM(WM_TAKE_FOCUS); // support take focus window protocol
816 protocols[n++] = ATOM(_NET_WM_PING); // support _NET_WM_PING protocol
817#ifndef QT_NO_XSYNC
818 protocols[n++] = ATOM(_NET_WM_SYNC_REQUEST); // support _NET_WM_SYNC_REQUEST protocol
819#endif // QT_NO_XSYNC
820 if (flags & Qt::WindowContextHelpButtonHint)
821 protocols[n++] = ATOM(_NET_WM_CONTEXT_HELP);
822 XSetWMProtocols(dpy, id, protocols, n);
823
824 // set mwm hints
825 SetMWMHints(dpy, id, mwmhints);
826
827 // set EWMH window types
828 setNetWmWindowTypes();
829
830 // set _NET_WM_PID
831 long curr_pid = getpid();
832 XChangeProperty(dpy, id, ATOM(_NET_WM_PID), XA_CARDINAL, 32, PropModeReplace,
833 (unsigned char *) &curr_pid, 1);
834
835 // when we create a toplevel widget, the frame strut should be dirty
836 data.fstrut_dirty = 1;
837
838 // declare the widget's window role
839 if (QTLWExtra *topData = maybeTopData()) {
840 if (!topData->role.isEmpty()) {
841 QByteArray windowRole = topData->role.toUtf8();
842 XChangeProperty(dpy, id,
843 ATOM(WM_WINDOW_ROLE), XA_STRING, 8, PropModeReplace,
844 (unsigned char *)windowRole.constData(), windowRole.length());
845 }
846 }
847
848 // set client leader property
849 XChangeProperty(dpy, id, ATOM(WM_CLIENT_LEADER),
850 XA_WINDOW, 32, PropModeReplace,
851 (unsigned char *)&X11->wm_client_leader, 1);
852 } else {
853 // non-toplevel widgets don't have a frame, so no need to
854 // update the strut
855 data.fstrut_dirty = 0;
856 }
857
858 if (initializeWindow && q->internalWinId()) {
859 // don't erase when resizing
860 wsa.bit_gravity = QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
861 Q_ASSERT(id);
862 XChangeWindowAttributes(dpy, id, CWBitGravity, &wsa);
863 }
864
865 // set X11 event mask
866 if (desktop) {
867// QWidget* main_desktop = find(id);
868// if (main_desktop->testWFlags(Qt::WPaintDesktop))
869// XSelectInput(dpy, id, stdDesktopEventMask | ExposureMask);
870// else
871 XSelectInput(dpy, id, stdDesktopEventMask);
872 } else if (q->internalWinId()) {
873 XSelectInput(dpy, id, stdWidgetEventMask);
874#if !defined (QT_NO_TABLET)
875 QTabletDeviceDataList *tablet_list = qt_tablet_devices();
876 if (X11->ptrXSelectExtensionEvent) {
877 for (int i = 0; i < tablet_list->size(); ++i) {
878 QTabletDeviceData tablet = tablet_list->at(i);
879 X11->ptrXSelectExtensionEvent(dpy, id, reinterpret_cast<XEventClass*>(tablet.eventList),
880 tablet.eventCount);
881 }
882 }
883#endif
884 }
885
886 if (desktop) {
887 q->setAttribute(Qt::WA_WState_Visible);
888 } else if (topLevel) { // set X cursor
889 if (initializeWindow) {
890 qt_x11_enforce_cursor(q);
891
892 if (QTLWExtra *topData = maybeTopData())
893 if (!topData->caption.isEmpty())
894 setWindowTitle_helper(topData->caption);
895
896 //always enable dnd: it's not worth the effort to maintain the state
897 // NOTE: this always creates topData()
898 X11->dndEnable(q, true);
899
900 if (maybeTopData() && maybeTopData()->opacity != 255)
901 q->setWindowOpacity(maybeTopData()->opacity/255.);
902
903 }
904 } else if (q->internalWinId()) {
905 qt_x11_enforce_cursor(q);
906 if (QWidget *p = q->parentWidget()) // reset the cursor on the native parent
907 qt_x11_enforce_cursor(p);
908 }
909
910 if (extra && !extra->mask.isEmpty() && q->internalWinId())
911 XShapeCombineRegion(X11->display, q->internalWinId(), ShapeBounding, 0, 0,
912 extra->mask.handle(), ShapeSet);
913#ifndef QT_NO_IM
914 if (q->hasFocus() && q->testAttribute(Qt::WA_InputMethodEnabled)) {
915 QInputContext *inputContext = q->inputContext();
916 if (inputContext)
917 inputContext->setFocusWidget(q);
918 }
919#endif
920 if (destroyw) {
921 qt_XDestroyWindow(q, dpy, destroyw);
922 if (QTLWExtra *topData = maybeTopData()) {
923#ifndef QT_NO_XSYNC
924 if (topData->syncUpdateCounter)
925 XSyncDestroyCounter(dpy, topData->syncUpdateCounter);
926#endif
927 // we destroyed our old window - reset the top-level state
928 createTLSysExtra();
929 }
930 }
931
932 // newly created windows are positioned at the window system's
933 // (0,0) position. If the parent uses wrect mapping to expand the
934 // coordinate system, we must also adjust this widget's window
935 // system position
936 if (!topLevel && !parentWidget->data->wrect.topLeft().isNull())
937 setWSGeometry();
938 else if (topLevel && (data.crect.width() == 0 || data.crect.height() == 0))
939 q->setAttribute(Qt::WA_OutsideWSRange, true);
940
941 if (!topLevel && q->testAttribute(Qt::WA_NativeWindow) && q->testAttribute(Qt::WA_Mapped)) {
942 Q_ASSERT(q->internalWinId());
943 XMapWindow(X11->display, q->internalWinId());
944 // Ensure that mapped alien widgets are flushed immediately when re-created as native widgets.
945 if (QWindowSurface *surface = q->windowSurface())
946 surface->flush(q, q->rect(), q->mapTo(surface->window(), QPoint()));
947 }
948
949#ifdef ALIEN_DEBUG
950 qDebug() << "QWidgetPrivate::create_sys END:" << q;
951#endif
952}
953
954static void qt_x11_recreateWidget(QWidget *widget)
955{
956 if (widget->inherits("QGLWidget")) {
957 // We send QGLWidgets a ParentChange event which causes them to
958 // recreate their GL context, which in turn causes them to choose
959 // their visual again. Now that WA_TranslucentBackground is set,
960 // QGLContext::chooseVisual will select an ARGB visual.
961
962 // QGLWidget expects a ParentAboutToChange to be sent first
963 QEvent aboutToChangeEvent(QEvent::ParentAboutToChange);
964 QApplication::sendEvent(widget, &aboutToChangeEvent);
965
966 QEvent parentChangeEvent(QEvent::ParentChange);
967 QApplication::sendEvent(widget, &parentChangeEvent);
968 } else {
969 // For regular widgets, reparent them with their parent which
970 // also triggers a recreation of the native window
971 QPoint pos = widget->pos();
972 bool visible = widget->isVisible();
973 if (visible)
974 widget->hide();
975
976 widget->setParent(widget->parentWidget(), widget->windowFlags());
977 widget->move(pos);
978 if (visible)
979 widget->show();
980 }
981}
982
983static void qt_x11_recreateNativeWidgetsRecursive(QWidget *widget)
984{
985 if (widget->internalWinId())
986 qt_x11_recreateWidget(widget);
987
988 const QObjectList &children = widget->children();
989 for (int i = 0; i < children.size(); ++i) {
990 QWidget *child = qobject_cast<QWidget*>(children.at(i));
991 if (child)
992 qt_x11_recreateNativeWidgetsRecursive(child);
993 }
994}
995
996void QWidgetPrivate::x11UpdateIsOpaque()
997{
998#ifndef QT_NO_XRENDER
999 Q_Q(QWidget);
1000 if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
1001 return;
1002
1003 bool topLevel = (data.window_flags & Qt::Window);
1004 int screen = xinfo.screen();
1005 if (topLevel && X11->use_xrender
1006 && X11->argbVisuals[screen] && xinfo.depth() != 32)
1007 {
1008 qt_x11_recreateNativeWidgetsRecursive(q);
1009 }
1010#endif
1011}
1012
1013/*
1014 Returns true if the background is inherited; otherwise returns
1015 false.
1016
1017 Mainly used in the paintOnScreen case.
1018*/
1019bool QWidgetPrivate::isBackgroundInherited() const
1020{
1021 Q_Q(const QWidget);
1022
1023 // windows do not inherit their background
1024 if (q->isWindow() || q->windowType() == Qt::SubWindow)
1025 return false;
1026
1027 if (q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_OpaquePaintEvent))
1028 return false;
1029
1030 const QPalette &pal = q->palette();
1031 QPalette::ColorRole bg = q->backgroundRole();
1032 QBrush brush = pal.brush(bg);
1033
1034 // non opaque brushes leaves us no choice, we must inherit
1035 if (!q->autoFillBackground() || !brush.isOpaque())
1036 return true;
1037
1038 if (brush.style() == Qt::SolidPattern) {
1039 // the background is just a solid color. If there is no
1040 // propagated contents, then we claim as performance
1041 // optimization that it was not inheritet. This is the normal
1042 // case in standard Windows or Motif style.
1043 const QWidget *w = q->parentWidget();
1044 if (!w->d_func()->isBackgroundInherited())
1045 return false;
1046 }
1047
1048 return true;
1049}
1050
1051void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1052{
1053 Q_D(QWidget);
1054 d->aboutToDestroy();
1055 if (!isWindow() && parentWidget())
1056 parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
1057 d->deactivateWidgetCleanup();
1058 if (testAttribute(Qt::WA_WState_Created)) {
1059 setAttribute(Qt::WA_WState_Created, false);
1060 QObjectList childList = children();
1061 for (int i = 0; i < childList.size(); ++i) { // destroy all widget children
1062 register QObject *obj = childList.at(i);
1063 if (obj->isWidgetType())
1064 static_cast<QWidget*>(obj)->destroy(destroySubWindows,
1065 destroySubWindows);
1066 }
1067 if (QWidgetPrivate::mouseGrabber == this)
1068 releaseMouse();
1069 if (QWidgetPrivate::keyboardGrabber == this)
1070 releaseKeyboard();
1071 if (isWindow())
1072 X11->deferred_map.removeAll(this);
1073 if (isModal()) {
1074 // just be sure we leave modal
1075 QApplicationPrivate::leaveModal(this);
1076 }
1077 else if ((windowType() == Qt::Popup))
1078 qApp->d_func()->closePopup(this);
1079
1080#ifndef QT_NO_XRENDER
1081 if (d->picture) {
1082 if (destroyWindow)
1083 XRenderFreePicture(X11->display, d->picture);
1084 d->picture = 0;
1085 }
1086#endif // QT_NO_XRENDER
1087
1088 // delete the _NET_WM_USER_TIME_WINDOW
1089 qt_net_remove_user_time(this);
1090
1091 if ((windowType() == Qt::Desktop)) {
1092 if (acceptDrops())
1093 X11->dndEnable(this, false);
1094 } else {
1095 if (isWindow())
1096 X11->dndEnable(this, false);
1097 if (destroyWindow)
1098 qt_XDestroyWindow(this, X11->display, data->winid);
1099 }
1100 QT_TRY {
1101 d->setWinId(0);
1102 } QT_CATCH (const std::bad_alloc &) {
1103 // swallow - destructors must not throw
1104 }
1105
1106 extern void qPRCleanup(QWidget *widget); // from qapplication_x11.cpp
1107 if (testAttribute(Qt::WA_WState_Reparented))
1108 qPRCleanup(this);
1109#ifndef QT_NO_IM
1110 if(d->ic) {
1111 delete d->ic;
1112 } else {
1113 // release previous focus information participating with
1114 // preedit preservation of qic
1115 QInputContext *qic = QApplicationPrivate::inputContext;
1116 if (qic)
1117 qic->widgetDestroyed(this);
1118 }
1119#endif
1120 }
1121}
1122
1123void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
1124{
1125 Q_Q(QWidget);
1126#ifdef ALIEN_DEBUG
1127 qDebug() << "QWidgetPrivate::setParent_sys START" << q << "parent:" << parent;
1128#endif
1129 QX11Info old_xinfo = xinfo;
1130 if (parent && parent->windowType() == Qt::Desktop) {
1131 // make sure the widget is created on the same screen as the
1132 // programmer specified desktop widget
1133 xinfo = parent->d_func()->xinfo;
1134 parent = 0;
1135 }
1136
1137 QTLWExtra *topData = maybeTopData();
1138 bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
1139 if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
1140 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
1141 extern void qPRCreate(const QWidget *, Window);
1142#ifndef QT_NO_CURSOR
1143 QCursor oldcurs;
1144#endif
1145
1146 // dnd unregister (we will register again below)
1147 if (q->testAttribute(Qt::WA_DropSiteRegistered))
1148 q->setAttribute(Qt::WA_DropSiteRegistered, false);
1149
1150 // if we are a top then remove our dnd prop for now
1151 // it will get rest later
1152 if (q->isWindow() && wasCreated)
1153 X11->dndEnable(q, false);
1154
1155 if (topData)
1156 qt_net_remove_user_time(q);
1157
1158// QWidget *oldparent = q->parentWidget();
1159 WId old_winid = wasCreated ? data.winid : 0;
1160 if ((q->windowType() == Qt::Desktop))
1161 old_winid = 0;
1162 setWinId(0);
1163
1164#ifndef QT_NO_XRENDER
1165 if (picture) {
1166 XRenderFreePicture(X11->display, picture);
1167 picture = 0;
1168 }
1169#endif
1170
1171 // hide and reparent our own window away. Otherwise we might get
1172 // destroyed when emitting the child remove event below. See QWorkspace.
1173 if (wasCreated && old_winid) {
1174 XUnmapWindow(X11->display, old_winid);
1175 if (!old_xinfo.screen() != xinfo.screen())
1176 XReparentWindow(X11->display, old_winid, RootWindow(X11->display, xinfo.screen()), 0, 0);
1177 }
1178 if (topData) {
1179 topData->parentWinId = 0;
1180 // zero the frame strut and mark it dirty
1181 topData->frameStrut.setCoords(0, 0, 0, 0);
1182
1183 // reparenting from top-level, make sure show() works again
1184 topData->waitingForMapNotify = 0;
1185 topData->validWMState = 0;
1186 }
1187 data.fstrut_dirty = (!parent || (f & Qt::Window)); // toplevels get a dirty framestrut
1188
1189 QObjectPrivate::setParent_helper(parent);
1190 bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
1191
1192 data.window_flags = f;
1193 q->setAttribute(Qt::WA_WState_Created, false);
1194 q->setAttribute(Qt::WA_WState_Visible, false);
1195 q->setAttribute(Qt::WA_WState_Hidden, false);
1196 adjustFlags(data.window_flags, q);
1197 // keep compatibility with previous versions, we need to preserve the created state
1198 // (but we recreate the winId for the widget being reparented, again for compatibility)
1199 if (wasCreated)
1200 createWinId();
1201 if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
1202 q->setAttribute(Qt::WA_WState_Hidden);
1203 q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
1204
1205 if (wasCreated) {
1206 QObjectList chlist = q->children();
1207 for (int i = 0; i < chlist.size(); ++i) { // reparent children
1208 QObject *obj = chlist.at(i);
1209 if (obj->isWidgetType()) {
1210 QWidget *w = (QWidget *)obj;
1211 if (!w->testAttribute(Qt::WA_WState_Created))
1212 continue;
1213 if (xinfo.screen() != w->d_func()->xinfo.screen()) {
1214 // ### force setParent() to not shortcut out (because
1215 // ### we're setting the parent to the current parent)
1216 // ### setParent will add child back to the list
1217 // ### of children so we need to make sure the
1218 // ### widget won't be added twice.
1219 w->d_func()->parent = 0;
1220 this->children.removeOne(w);
1221 w->setParent(q);
1222 } else if (!w->isWindow()) {
1223 w->d_func()->invalidateBuffer(w->rect());
1224 if (w->internalWinId()) {
1225 if (w->testAttribute(Qt::WA_NativeWindow)) {
1226 QWidget *nativeParentWidget = w->nativeParentWidget();
1227 // Qt::WA_NativeWindow ensures that we always have a nativeParentWidget
1228 Q_ASSERT(nativeParentWidget != 0);
1229 QPoint p = w->mapTo(nativeParentWidget, QPoint());
1230 XReparentWindow(X11->display,
1231 w->internalWinId(),
1232 nativeParentWidget->internalWinId(),
1233 p.x(), p.y());
1234 } else {
1235 w->d_func()->setParent_sys(q, w->data->window_flags);
1236 }
1237 }
1238 } else if (isTransient(w)) {
1239 /*
1240 when reparenting toplevel windows with toplevel-transient children,
1241 we need to make sure that the window manager gets the updated
1242 WM_TRANSIENT_FOR information... unfortunately, some window managers
1243 don't handle changing WM_TRANSIENT_FOR before the toplevel window is
1244 visible, so we unmap and remap all toplevel-transient children *after*
1245 the toplevel parent has been mapped. thankfully, this is easy in Qt :)
1246
1247 note that the WM_TRANSIENT_FOR hint is actually updated in
1248 QWidgetPrivate::show_sys()
1249 */
1250 if (w->internalWinId())
1251 XUnmapWindow(X11->display, w->internalWinId());
1252 QApplication::postEvent(w, new QEvent(QEvent::ShowWindowRequest));
1253 }
1254 }
1255 }
1256 qPRCreate(q, old_winid);
1257 updateSystemBackground();
1258
1259 if (old_winid) {
1260 Window *cmwret;
1261 int count;
1262 if (XGetWMColormapWindows(X11->display, old_winid, &cmwret, &count)) {
1263 Window *cmw;
1264 int cmw_size = sizeof(Window)*count;
1265 cmw = new Window[count];
1266 memcpy((char *)cmw, (char *)cmwret, cmw_size);
1267 XFree((char *)cmwret);
1268 int i;
1269 for (i=0; i<count; i++) {
1270 if (cmw[i] == old_winid) {
1271 cmw[i] = q->internalWinId();
1272 break;
1273 }
1274 }
1275 int top_count;
1276 if (XGetWMColormapWindows(X11->display, q->window()->internalWinId(),
1277 &cmwret, &top_count))
1278 {
1279 Window *merged_cmw = new Window[count + top_count];
1280 memcpy((char *)merged_cmw, (char *)cmw, cmw_size);
1281 memcpy((char *)merged_cmw + cmw_size, (char *)cmwret, sizeof(Window)*top_count);
1282 delete [] cmw;
1283 XFree((char *)cmwret);
1284 cmw = merged_cmw;
1285 count += top_count;
1286 }
1287
1288 XSetWMColormapWindows(X11->display, q->window()->internalWinId(), cmw, count);
1289 delete [] cmw;
1290 }
1291
1292 qt_XDestroyWindow(q, X11->display, old_winid);
1293 }
1294 }
1295
1296 // check if we need to register our dropsite
1297 if (q->testAttribute(Qt::WA_AcceptDrops)
1298 || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))) {
1299 q->setAttribute(Qt::WA_DropSiteRegistered, true);
1300 }
1301#if !defined(QT_NO_IM)
1302 ic = 0;
1303#endif
1304 invalidateBuffer(q->rect());
1305#ifdef ALIEN_DEBUG
1306 qDebug() << "QWidgetPrivate::setParent_sys END" << q;
1307#endif
1308}
1309
1310QPoint QWidgetPrivate::mapToGlobal(const QPoint &pos) const
1311{
1312 Q_Q(const QWidget);
1313 if (!q->testAttribute(Qt::WA_WState_Created) || !q->internalWinId()) {
1314 QPoint p = pos + q->data->crect.topLeft();
1315 //cannot trust that !isWindow() implies parentWidget() before create
1316 return (q->isWindow() || !q->parentWidget()) ? p : q->parentWidget()->d_func()->mapToGlobal(p);
1317 }
1318 int x, y;
1319 Window child;
1320 QPoint p = mapToWS(pos);
1321 XTranslateCoordinates(X11->display, q->internalWinId(),
1322 QApplication::desktop()->screen(xinfo.screen())->internalWinId(),
1323 p.x(), p.y(), &x, &y, &child);
1324 return QPoint(x, y);
1325}
1326
1327QPoint QWidgetPrivate::mapFromGlobal(const QPoint &pos) const
1328{
1329 Q_Q(const QWidget);
1330 if (!q->testAttribute(Qt::WA_WState_Created) || !q->internalWinId()) {
1331 //cannot trust that !isWindow() implies parentWidget() before create
1332 QPoint p = (q->isWindow() || !q->parentWidget()) ? pos : q->parentWidget()->d_func()->mapFromGlobal(pos);
1333 return p - q->data->crect.topLeft();
1334 }
1335 int x, y;
1336 Window child;
1337 XTranslateCoordinates(X11->display,
1338 QApplication::desktop()->screen(xinfo.screen())->internalWinId(),
1339 q->internalWinId(), pos.x(), pos.y(), &x, &y, &child);
1340 return mapFromWS(QPoint(x, y));
1341}
1342
1343QPoint QWidget::mapToGlobal(const QPoint &pos) const
1344{
1345 Q_D(const QWidget);
1346 return d->mapToGlobal(pos);
1347}
1348
1349QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1350{
1351 Q_D(const QWidget);
1352 return d->mapFromGlobal(pos);
1353}
1354
1355void QWidgetPrivate::updateSystemBackground()
1356{
1357 Q_Q(QWidget);
1358 if (!q->testAttribute(Qt::WA_WState_Created) || !q->internalWinId())
1359 return;
1360 QBrush brush = q->palette().brush(QPalette::Active, q->backgroundRole());
1361 Qt::WindowType type = q->windowType();
1362 if (brush.style() == Qt::NoBrush
1363 || q->testAttribute(Qt::WA_NoSystemBackground)
1364 || q->testAttribute(Qt::WA_UpdatesDisabled)
1365 || type == Qt::Popup || type == Qt::ToolTip) {
1366 if (QX11Info::isCompositingManagerRunning()
1367 && q->testAttribute(Qt::WA_TranslucentBackground)
1368 && !(q->parent()))
1369 XSetWindowBackground(X11->display, q->internalWinId(),
1370 QColormap::instance(xinfo.screen()).pixel(Qt::transparent));
1371 else
1372 XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), XNone);
1373 }
1374 else if (brush.style() == Qt::SolidPattern && brush.isOpaque())
1375 XSetWindowBackground(X11->display, q->internalWinId(),
1376 QColormap::instance(xinfo.screen()).pixel(brush.color()));
1377 else if (isBackgroundInherited())
1378 XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), ParentRelative);
1379 else if (brush.style() == Qt::TexturePattern) {
1380 extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap); // qpixmap_x11.cpp
1381 XSetWindowBackgroundPixmap(X11->display, q->internalWinId(),
1382 static_cast<QX11PixmapData*>(qt_toX11Pixmap(brush.texture()).data.data())->x11ConvertToDefaultDepth());
1383 } else
1384 XSetWindowBackground(X11->display, q->internalWinId(),
1385 QColormap::instance(xinfo.screen()).pixel(brush.color()));
1386}
1387
1388#ifndef QT_NO_CURSOR
1389void QWidgetPrivate::setCursor_sys(const QCursor &)
1390{
1391 Q_Q(QWidget);
1392 qt_x11_enforce_cursor(q);
1393 XFlush(X11->display);
1394}
1395
1396void QWidgetPrivate::unsetCursor_sys()
1397{
1398 Q_Q(QWidget);
1399 qt_x11_enforce_cursor(q);
1400 XFlush(X11->display);
1401}
1402#endif
1403
1404static XTextProperty*
1405qstring_to_xtp(const QString& s)
1406{
1407 static XTextProperty tp = { 0, 0, 0, 0 };
1408 static bool free_prop = true; // we can't free tp.value in case it references
1409 // the data of the static QCString below.
1410 if (tp.value) {
1411 if (free_prop)
1412 XFree(tp.value);
1413 tp.value = 0;
1414 free_prop = true;
1415 }
1416
1417 static const QTextCodec* mapper = QTextCodec::codecForLocale();
1418 int errCode = 0;
1419 if (mapper) {
1420 QByteArray mapped = mapper->fromUnicode(s);
1421 char* tl[2];
1422 tl[0] = mapped.data();
1423 tl[1] = 0;
1424 errCode = XmbTextListToTextProperty(X11->display, tl, 1, XStdICCTextStyle, &tp);
1425#if defined(QT_DEBUG)
1426 if (errCode < 0)
1427 qDebug("qstring_to_xtp result code %d", errCode);
1428#endif
1429 }
1430 if (!mapper || errCode < 0) {
1431 static QByteArray qcs;
1432 qcs = s.toAscii();
1433 tp.value = (uchar*)qcs.data();
1434 tp.encoding = XA_STRING;
1435 tp.format = 8;
1436 tp.nitems = qcs.length();
1437 free_prop = false;
1438 }
1439
1440 // ### If we knew WM could understand unicode, we could use
1441 // ### a much simpler, cheaper encoding...
1442 /*
1443 tp.value = (XChar2b*)s.unicode();
1444 tp.encoding = XA_UNICODE; // wish
1445 tp.format = 16;
1446 tp.nitems = s.length();
1447 */
1448
1449 return &tp;
1450}
1451
1452void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
1453{
1454 Q_Q(QWidget);
1455 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1456 if (!q->internalWinId())
1457 return;
1458 XSetWMName(X11->display, q->internalWinId(), qstring_to_xtp(caption));
1459
1460 QByteArray net_wm_name = caption.toUtf8();
1461 XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_NAME), ATOM(UTF8_STRING), 8,
1462 PropModeReplace, (unsigned char *)net_wm_name.data(), net_wm_name.size());
1463}
1464
1465void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
1466{
1467 Q_Q(QWidget);
1468 if (!q->testAttribute(Qt::WA_WState_Created))
1469 return;
1470 QTLWExtra *topData = this->topData();
1471 if (topData->iconPixmap && !forceReset)
1472 // already been set
1473 return;
1474
1475 // preparing images to set the _NET_WM_ICON property
1476 QIcon icon = q->windowIcon();
1477 QVector<long> icon_data;
1478 Qt::HANDLE pixmap_handle = 0;
1479 if (!icon.isNull()) {
1480 QList<QSize> availableSizes = icon.availableSizes();
1481 if(availableSizes.isEmpty()) {
1482 // try to use default sizes since the icon can be a scalable image like svg.
1483 availableSizes.push_back(QSize(16,16));
1484 availableSizes.push_back(QSize(32,32));
1485 availableSizes.push_back(QSize(64,64));
1486 availableSizes.push_back(QSize(128,128));
1487 }
1488 for(int i = 0; i < availableSizes.size(); ++i) {
1489 QSize size = availableSizes.at(i);
1490 QPixmap pixmap = icon.pixmap(size);
1491 if (!pixmap.isNull()) {
1492 QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
1493 int pos = icon_data.size();
1494 icon_data.resize(pos + 2 + image.width()*image.height());
1495 icon_data[pos++] = image.width();
1496 icon_data[pos++] = image.height();
1497 if (sizeof(long) == sizeof(quint32)) {
1498 memcpy(icon_data.data() + pos, image.scanLine(0), image.byteCount());
1499 } else {
1500 for (int y = 0; y < image.height(); ++y) {
1501 uint *scanLine = reinterpret_cast<uint *>(image.scanLine(y));
1502 for (int x = 0; x < image.width(); ++x)
1503 icon_data[pos + y*image.width() + x] = scanLine[x];
1504 }
1505 }
1506 }
1507 }
1508 if (!icon_data.isEmpty()) {
1509 extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap);
1510 /*
1511 if the app is running on an unknown desktop, or it is not
1512 using the default visual, convert the icon to 1bpp as stated
1513 in the ICCCM section 4.1.2.4; otherwise, create the icon pixmap
1514 in the default depth (even though this violates the ICCCM)
1515 */
1516 if (X11->desktopEnvironment == DE_UNKNOWN
1517 || !QX11Info::appDefaultVisual(xinfo.screen())
1518 || !QX11Info::appDefaultColormap(xinfo.screen())) {
1519 // unknown DE or non-default visual/colormap, use 1bpp bitmap
1520 if (!forceReset || !topData->iconPixmap)
1521 topData->iconPixmap = new QPixmap(qt_toX11Pixmap(QBitmap(icon.pixmap(QSize(64,64)))));
1522 pixmap_handle = topData->iconPixmap->handle();
1523 } else {
1524 // default depth, use a normal pixmap (even though this
1525 // violates the ICCCM), since this works on all DEs known to Qt
1526 if (!forceReset || !topData->iconPixmap)
1527 topData->iconPixmap = new QPixmap(qt_toX11Pixmap(icon.pixmap(QSize(64,64))));
1528 pixmap_handle = static_cast<QX11PixmapData*>(topData->iconPixmap->data.data())->x11ConvertToDefaultDepth();
1529 }
1530 }
1531 }
1532
1533 if (!q->internalWinId())
1534 return;
1535
1536 if (!icon_data.isEmpty()) {
1537 XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON), XA_CARDINAL, 32,
1538 PropModeReplace, (unsigned char *) icon_data.data(),
1539 icon_data.size());
1540 } else {
1541 XDeleteProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON));
1542 }
1543
1544 XWMHints *h = XGetWMHints(X11->display, q->internalWinId());
1545 XWMHints wm_hints;
1546 if (!h) {
1547 memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
1548 h = &wm_hints;
1549 }
1550
1551 if (pixmap_handle) {
1552 h->icon_pixmap = pixmap_handle;
1553 h->flags |= IconPixmapHint;
1554 } else {
1555 h->icon_pixmap = 0;
1556 h->flags &= ~(IconPixmapHint | IconMaskHint);
1557 }
1558
1559 XSetWMHints(X11->display, q->internalWinId(), h);
1560 if (h != &wm_hints)
1561 XFree((char *)h);
1562}
1563
1564void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
1565{
1566 Q_Q(QWidget);
1567 if (!q->internalWinId())
1568 return;
1569 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1570 XSetWMIconName(X11->display, q->internalWinId(), qstring_to_xtp(iconText));
1571
1572 QByteArray icon_name = iconText.toUtf8();
1573 XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON_NAME), ATOM(UTF8_STRING), 8,
1574 PropModeReplace, (unsigned char *) icon_name.constData(), icon_name.size());
1575}
1576
1577
1578void QWidget::grabMouse()
1579{
1580 if (isVisible() && !qt_nograb()) {
1581 if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1582 QWidgetPrivate::mouseGrabber->releaseMouse();
1583 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1584#ifndef QT_NO_DEBUG
1585 int status =
1586#endif
1587 XGrabPointer(X11->display, effectiveWinId(), False,
1588 (uint)(ButtonPressMask | ButtonReleaseMask |
1589 PointerMotionMask | EnterWindowMask |
1590 LeaveWindowMask),
1591 GrabModeAsync, GrabModeAsync,
1592 XNone, XNone, X11->time);
1593#ifndef QT_NO_DEBUG
1594 if (status) {
1595 const char *s =
1596 status == GrabNotViewable ? "\"GrabNotViewable\"" :
1597 status == AlreadyGrabbed ? "\"AlreadyGrabbed\"" :
1598 status == GrabFrozen ? "\"GrabFrozen\"" :
1599 status == GrabInvalidTime ? "\"GrabInvalidTime\"" :
1600 "<?>";
1601 qWarning("QWidget::grabMouse: Failed with %s", s);
1602 }
1603#endif
1604 QWidgetPrivate::mouseGrabber = this;
1605 }
1606}
1607
1608
1609#ifndef QT_NO_CURSOR
1610void QWidget::grabMouse(const QCursor &cursor)
1611{
1612 if (!qt_nograb()) {
1613 if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1614 QWidgetPrivate::mouseGrabber->releaseMouse();
1615 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1616#ifndef QT_NO_DEBUG
1617 int status =
1618#endif
1619 XGrabPointer(X11->display, effectiveWinId(), False,
1620 (uint)(ButtonPressMask | ButtonReleaseMask |
1621 PointerMotionMask | EnterWindowMask | LeaveWindowMask),
1622 GrabModeAsync, GrabModeAsync,
1623 XNone, cursor.handle(), X11->time);
1624#ifndef QT_NO_DEBUG
1625 if (status) {
1626 const char *s =
1627 status == GrabNotViewable ? "\"GrabNotViewable\"" :
1628 status == AlreadyGrabbed ? "\"AlreadyGrabbed\"" :
1629 status == GrabFrozen ? "\"GrabFrozen\"" :
1630 status == GrabInvalidTime ? "\"GrabInvalidTime\"" :
1631 "<?>";
1632 qWarning("QWidget::grabMouse: Failed with %s", s);
1633 }
1634#endif
1635 QWidgetPrivate::mouseGrabber = this;
1636 }
1637}
1638#endif
1639
1640
1641void QWidget::releaseMouse()
1642{
1643 if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) {
1644 XUngrabPointer(X11->display, X11->time);
1645 XFlush(X11->display);
1646 QWidgetPrivate::mouseGrabber = 0;
1647 }
1648}
1649
1650
1651void QWidget::grabKeyboard()
1652{
1653 if (!qt_nograb()) {
1654 if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this)
1655 QWidgetPrivate::keyboardGrabber->releaseKeyboard();
1656 XGrabKeyboard(X11->display, effectiveWinId(), False, GrabModeAsync, GrabModeAsync,
1657 X11->time);
1658 QWidgetPrivate::keyboardGrabber = this;
1659 }
1660}
1661
1662
1663void QWidget::releaseKeyboard()
1664{
1665 if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) {
1666 XUngrabKeyboard(X11->display, X11->time);
1667 QWidgetPrivate::keyboardGrabber = 0;
1668 }
1669}
1670
1671
1672QWidget *QWidget::mouseGrabber()
1673{
1674 return QWidgetPrivate::mouseGrabber;
1675}
1676
1677
1678QWidget *QWidget::keyboardGrabber()
1679{
1680 return QWidgetPrivate::keyboardGrabber;
1681}
1682
1683void QWidget::activateWindow()
1684{
1685 QWidget *tlw = window();
1686 if (tlw->isVisible() && !tlw->d_func()->topData()->embedded && !X11->deferred_map.contains(tlw)) {
1687 if (X11->userTime == 0)
1688 X11->userTime = X11->time;
1689 qt_net_update_user_time(tlw, X11->userTime);
1690
1691 if (X11->isSupportedByWM(ATOM(_NET_ACTIVE_WINDOW))
1692 && !(tlw->windowFlags() & Qt::X11BypassWindowManagerHint)) {
1693 XEvent e;
1694 e.xclient.type = ClientMessage;
1695 e.xclient.message_type = ATOM(_NET_ACTIVE_WINDOW);
1696 e.xclient.display = X11->display;
1697 e.xclient.window = tlw->internalWinId();
1698 e.xclient.format = 32;
1699 e.xclient.data.l[0] = 1; // 1 == application
1700 e.xclient.data.l[1] = X11->userTime;
1701 if (QWidget *aw = QApplication::activeWindow())
1702 e.xclient.data.l[2] = aw->internalWinId();
1703 else
1704 e.xclient.data.l[2] = XNone;
1705 e.xclient.data.l[3] = 0;
1706 e.xclient.data.l[4] = 0;
1707 XSendEvent(X11->display, RootWindow(X11->display, tlw->x11Info().screen()),
1708 false, SubstructureNotifyMask | SubstructureRedirectMask, &e);
1709 } else {
1710 if (!qt_widget_private(tlw)->topData()->waitingForMapNotify)
1711 XSetInputFocus(X11->display, tlw->internalWinId(), XRevertToParent, X11->time);
1712 }
1713 }
1714}
1715
1716void QWidget::setWindowState(Qt::WindowStates newstate)
1717{
1718 Q_D(QWidget);
1719 bool needShow = false;
1720 Qt::WindowStates oldstate = windowState();
1721 if (oldstate == newstate)
1722 return;
1723 if (isWindow()) {
1724 // Ensure the initial size is valid, since we store it as normalGeometry below.
1725 if (!testAttribute(Qt::WA_Resized) && !isVisible())
1726 adjustSize();
1727
1728 QTLWExtra *top = d->topData();
1729
1730 if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) {
1731 if (X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ))
1732 && X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT))) {
1733 if ((newstate & Qt::WindowMaximized) && !(oldstate & Qt::WindowFullScreen))
1734 top->normalGeometry = geometry();
1735 qt_change_net_wm_state(this, (newstate & Qt::WindowMaximized),
1736 ATOM(_NET_WM_STATE_MAXIMIZED_HORZ),
1737 ATOM(_NET_WM_STATE_MAXIMIZED_VERT));
1738 } else if (! (newstate & Qt::WindowFullScreen)) {
1739 if (newstate & Qt::WindowMaximized) {
1740 // save original geometry
1741 const QRect normalGeometry = geometry();
1742
1743 if (isVisible()) {
1744 data->fstrut_dirty = true;
1745 const QRect maxRect = QApplication::desktop()->availableGeometry(this);
1746 const QRect r = top->normalGeometry;
1747 const QRect fs = d->frameStrut();
1748 setGeometry(maxRect.x() + fs.left(),
1749 maxRect.y() + fs.top(),
1750 maxRect.width() - fs.left() - fs.right(),
1751 maxRect.height() - fs.top() - fs.bottom());
1752 top->normalGeometry = r;
1753 }
1754
1755 if (top->normalGeometry.width() < 0)
1756 top->normalGeometry = normalGeometry;
1757 } else {
1758 // restore original geometry
1759 setGeometry(top->normalGeometry);
1760 }
1761 }
1762 }
1763
1764 if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) {
1765 if (X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN))) {
1766 if (newstate & Qt::WindowFullScreen) {
1767 top->normalGeometry = geometry();
1768 top->fullScreenOffset = d->frameStrut().topLeft();
1769 }
1770 qt_change_net_wm_state(this, (newstate & Qt::WindowFullScreen),
1771 ATOM(_NET_WM_STATE_FULLSCREEN));
1772 } else {
1773 needShow = isVisible();
1774
1775 if (newstate & Qt::WindowFullScreen) {
1776 data->fstrut_dirty = true;
1777 const QRect normalGeometry = geometry();
1778 const QPoint fullScreenOffset = d->frameStrut().topLeft();
1779
1780 top->savedFlags = windowFlags();
1781 setParent(0, Qt::Window | Qt::FramelessWindowHint);
1782 const QRect r = top->normalGeometry;
1783 setGeometry(qApp->desktop()->screenGeometry(this));
1784 top->normalGeometry = r;
1785
1786 if (top->normalGeometry.width() < 0) {
1787 top->normalGeometry = normalGeometry;
1788 top->fullScreenOffset = fullScreenOffset;
1789 }
1790 } else {
1791 setParent(0, top->savedFlags);
1792
1793 if (newstate & Qt::WindowMaximized) {
1794 // from fullscreen to maximized
1795 data->fstrut_dirty = true;
1796 const QRect maxRect = QApplication::desktop()->availableGeometry(this);
1797 const QRect r = top->normalGeometry;
1798 const QRect fs = d->frameStrut();
1799 setGeometry(maxRect.x() + fs.left(),
1800 maxRect.y() + fs.top(),
1801 maxRect.width() - fs.left() - fs.right(),
1802 maxRect.height() - fs.top() - fs.bottom());
1803 top->normalGeometry = r;
1804 } else {
1805 // restore original geometry
1806 setGeometry(top->normalGeometry.adjusted(-top->fullScreenOffset.x(),
1807 -top->fullScreenOffset.y(),
1808 -top->fullScreenOffset.x(),
1809 -top->fullScreenOffset.y()));
1810 }
1811 }
1812 }
1813 }
1814
1815 createWinId();
1816 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1817 if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) {
1818 if (isVisible()) {
1819 if (newstate & Qt::WindowMinimized) {
1820 XEvent e;
1821 e.xclient.type = ClientMessage;
1822 e.xclient.message_type = ATOM(WM_CHANGE_STATE);
1823 e.xclient.display = X11->display;
1824 e.xclient.window = data->winid;
1825 e.xclient.format = 32;
1826 e.xclient.data.l[0] = IconicState;
1827 e.xclient.data.l[1] = 0;
1828 e.xclient.data.l[2] = 0;
1829 e.xclient.data.l[3] = 0;
1830 e.xclient.data.l[4] = 0;
1831 XSendEvent(X11->display,
1832 RootWindow(X11->display,d->xinfo.screen()),
1833 False, (SubstructureNotifyMask|SubstructureRedirectMask), &e);
1834 } else {
1835 setAttribute(Qt::WA_Mapped);
1836 XMapWindow(X11->display, effectiveWinId());
1837 }
1838 }
1839
1840 needShow = false;
1841 }
1842 }
1843
1844 data->window_state = newstate;
1845
1846 if (needShow)
1847 show();
1848
1849 if (newstate & Qt::WindowActive)
1850 activateWindow();
1851
1852 QWindowStateChangeEvent e(oldstate);
1853 QApplication::sendEvent(this, &e);
1854}
1855
1856/*!
1857 \internal
1858 Platform-specific part of QWidget::show().
1859*/
1860
1861void QWidgetPrivate::show_sys()
1862{
1863 Q_Q(QWidget);
1864 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
1865
1866 if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
1867 invalidateBuffer(q->rect());
1868 q->setAttribute(Qt::WA_Mapped);
1869 if (QTLWExtra *tlwExtra = maybeTopData())
1870 tlwExtra->waitingForMapNotify = 0;
1871 return;
1872 }
1873
1874 if (q->isWindow()) {
1875 XWMHints *h = XGetWMHints(X11->display, q->internalWinId());
1876 XWMHints wm_hints;
1877 bool got_hints = h != 0;
1878 if (!got_hints) {
1879 memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
1880 h = &wm_hints;
1881 }
1882 h->initial_state = q->isMinimized() ? IconicState : NormalState;
1883 h->flags |= StateHint;
1884 XSetWMHints(X11->display, q->internalWinId(), h);
1885 if (got_hints)
1886 XFree((char *)h);
1887
1888 // update WM_NORMAL_HINTS
1889 do_size_hints(q, extra);
1890
1891 // udpate WM_TRANSIENT_FOR
1892 if (isTransient(q)) {
1893 QWidget *p = q->parentWidget();
1894
1895#ifndef QT_NO_MENU
1896 // hackish ... try to find the main window related to this QMenu
1897 if (qobject_cast<QMenu *>(q)) {
1898 p = static_cast<QMenuPrivate*>(this)->causedPopup.widget;
1899 if (!p)
1900 p = q->parentWidget();
1901 if (!p)
1902 p = QApplication::widgetAt(q->pos());
1903 if (!p)
1904 p = qApp->activeWindow();
1905 }
1906#endif
1907 if (p)
1908 p = p->window();
1909 if (p) {
1910 // transient for window
1911 XSetTransientForHint(X11->display, q->internalWinId(), p->internalWinId());
1912 } else {
1913 // transient for group
1914 XSetTransientForHint(X11->display, q->internalWinId(), X11->wm_client_leader);
1915 }
1916 }
1917
1918 // update _MOTIF_WM_HINTS
1919 QtMWMHints mwmhints = GetMWMHints(X11->display, q->internalWinId());
1920
1921 if (data.window_modality != Qt::NonModal) {
1922 switch (data.window_modality) {
1923 case Qt::WindowModal:
1924 mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL;
1925 break;
1926 case Qt::ApplicationModal:
1927 default:
1928 mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL;
1929 break;
1930 }
1931 mwmhints.flags |= MWM_HINTS_INPUT_MODE;
1932 } else {
1933 mwmhints.input_mode = MWM_INPUT_MODELESS;
1934 mwmhints.flags &= ~MWM_HINTS_INPUT_MODE;
1935 }
1936
1937 if (q->minimumSize() == q->maximumSize()) {
1938 // fixed size, remove the resize handle (since mwm/dtwm
1939 // isn't smart enough to do it itself)
1940 mwmhints.flags |= MWM_HINTS_FUNCTIONS;
1941 if (mwmhints.functions == MWM_FUNC_ALL) {
1942 mwmhints.functions = MWM_FUNC_MOVE;
1943 } else {
1944 mwmhints.functions &= ~MWM_FUNC_RESIZE;
1945 }
1946
1947 if (mwmhints.decorations == MWM_DECOR_ALL) {
1948 mwmhints.flags |= MWM_HINTS_DECORATIONS;
1949 mwmhints.decorations = (MWM_DECOR_BORDER
1950 | MWM_DECOR_TITLE
1951 | MWM_DECOR_MENU);
1952 } else {
1953 mwmhints.decorations &= ~MWM_DECOR_RESIZEH;
1954 }
1955
1956 if (q->windowFlags() & Qt::WindowMinimizeButtonHint) {
1957 mwmhints.flags |= MWM_HINTS_DECORATIONS;
1958 mwmhints.decorations |= MWM_DECOR_MINIMIZE;
1959 mwmhints.functions |= MWM_FUNC_MINIMIZE;
1960 }
1961 if (q->windowFlags() & Qt::WindowMaximizeButtonHint) {
1962 mwmhints.flags |= MWM_HINTS_DECORATIONS;
1963 mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
1964 mwmhints.functions |= MWM_FUNC_MAXIMIZE;
1965 }
1966 if (q->windowFlags() & Qt::WindowCloseButtonHint)
1967 mwmhints.functions |= MWM_FUNC_CLOSE;
1968 }
1969
1970 SetMWMHints(X11->display, q->internalWinId(), mwmhints);
1971
1972 // update _NET_WM_STATE
1973 QVector<Atom> netWmState = getNetWmState(q);
1974
1975 Qt::WindowFlags flags = q->windowFlags();
1976 if (flags & Qt::WindowStaysOnTopHint) {
1977 if (flags & Qt::WindowStaysOnBottomHint)
1978 qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
1979 if (!netWmState.contains(ATOM(_NET_WM_STATE_ABOVE)))
1980 netWmState.append(ATOM(_NET_WM_STATE_ABOVE));
1981 if (!netWmState.contains(ATOM(_NET_WM_STATE_STAYS_ON_TOP)))
1982 netWmState.append(ATOM(_NET_WM_STATE_STAYS_ON_TOP));
1983 } else if (flags & Qt::WindowStaysOnBottomHint) {
1984 if (!netWmState.contains(ATOM(_NET_WM_STATE_BELOW)))
1985 netWmState.append(ATOM(_NET_WM_STATE_BELOW));
1986 }
1987 if (q->isFullScreen()) {
1988 if (!netWmState.contains(ATOM(_NET_WM_STATE_FULLSCREEN)))
1989 netWmState.append(ATOM(_NET_WM_STATE_FULLSCREEN));
1990 }
1991 if (q->isMaximized()) {
1992 if (!netWmState.contains(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ)))
1993 netWmState.append(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ));
1994 if (!netWmState.contains(ATOM(_NET_WM_STATE_MAXIMIZED_VERT)))
1995 netWmState.append(ATOM(_NET_WM_STATE_MAXIMIZED_VERT));
1996 }
1997 if (data.window_modality != Qt::NonModal) {
1998 if (!netWmState.contains(ATOM(_NET_WM_STATE_MODAL)))
1999 netWmState.append(ATOM(_NET_WM_STATE_MODAL));
2000 }
2001
2002 if (!netWmState.isEmpty()) {
2003 XChangeProperty(X11->display, q->internalWinId(),
2004 ATOM(_NET_WM_STATE), XA_ATOM, 32, PropModeReplace,
2005 (unsigned char *) netWmState.data(), netWmState.size());
2006 } else {
2007 XDeleteProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_STATE));
2008 }
2009
2010 // set _NET_WM_USER_TIME
2011 Time userTime = X11->userTime;
2012 bool setUserTime = false;
2013 if (q->testAttribute(Qt::WA_ShowWithoutActivating)) {
2014 userTime = 0;
2015 setUserTime = true;
2016 } else if (userTime != CurrentTime) {
2017 setUserTime = true;
2018 }
2019 if (setUserTime)
2020 qt_net_update_user_time(q, userTime);
2021
2022#ifndef QT_NO_XSYNC
2023 if (!topData()->syncUpdateCounter) {
2024 XSyncValue value;
2025 XSyncIntToValue(&value, 0);
2026 topData()->syncUpdateCounter = XSyncCreateCounter(X11->display, value);
2027
2028 XChangeProperty(X11->display, q->internalWinId(),
2029 ATOM(_NET_WM_SYNC_REQUEST_COUNTER),
2030 XA_CARDINAL,
2031 32, PropModeReplace,
2032 (uchar *) &topData()->syncUpdateCounter, 1);
2033
2034 topData()->newCounterValueHi = 0;
2035 topData()->newCounterValueLo = 0;
2036 }
2037#endif
2038
2039 if (!topData()->embedded
2040 && (topData()->validWMState || topData()->waitingForMapNotify)
2041 && !q->isMinimized()) {
2042 X11->deferred_map.append(q);
2043 return;
2044 }
2045
2046 if (q->isMaximized() && !q->isFullScreen()
2047 && !(X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ))
2048 && X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT)))) {
2049 XMapWindow(X11->display, q->internalWinId());
2050 data.fstrut_dirty = true;
2051 qt_x11_wait_for_window_manager(q);
2052
2053 // if the wm was not smart enough to adjust our size, do that manually
2054 QRect maxRect = QApplication::desktop()->availableGeometry(q);
2055
2056 QTLWExtra *top = topData();
2057 QRect normalRect = top->normalGeometry;
2058 const QRect fs = frameStrut();
2059
2060 q->setGeometry(maxRect.x() + fs.left(),
2061 maxRect.y() + fs.top(),
2062 maxRect.width() - fs.left() - fs.right(),
2063 maxRect.height() - fs.top() - fs.bottom());
2064
2065 // restore the original normalGeometry
2066 top->normalGeometry = normalRect;
2067 // internalSetGeometry() clears the maximized flag... make sure we set it back
2068 data.window_state = data.window_state | Qt::WindowMaximized;
2069 q->setAttribute(Qt::WA_Mapped);
2070 return;
2071 }
2072
2073 if (q->isFullScreen() && !X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN))) {
2074 XMapWindow(X11->display, q->internalWinId());
2075 qt_x11_wait_for_window_manager(q);
2076 q->setAttribute(Qt::WA_Mapped);
2077 return;
2078 }
2079 }
2080
2081 invalidateBuffer(q->rect());
2082
2083 if (q->testAttribute(Qt::WA_OutsideWSRange))
2084 return;
2085 q->setAttribute(Qt::WA_Mapped);
2086 if (q->isWindow())
2087 topData()->waitingForMapNotify = 1;
2088
2089 if (!q->isWindow()
2090 && (!q->autoFillBackground()
2091 || q->palette().brush(q->backgroundRole()).style() == Qt::LinearGradientPattern)) {
2092 if (q->internalWinId()) {
2093 XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), XNone);
2094 XMapWindow(X11->display, q->internalWinId());
2095 updateSystemBackground();
2096 }
2097 return;
2098 }
2099
2100 if (q->internalWinId())
2101 XMapWindow(X11->display, q->internalWinId());
2102
2103 // Freedesktop.org Startup Notification
2104 if (X11->startupId && q->isWindow()) {
2105 QByteArray message("remove: ID=");
2106 message.append(X11->startupId);
2107 sendStartupMessage(message.constData());
2108 X11->startupId = 0;
2109 }
2110}
2111
2112/*!
2113 \internal
2114 Platform-specific part of QWidget::show().
2115*/
2116
2117void QWidgetPrivate::sendStartupMessage(const char *message) const
2118{
2119 Q_Q(const QWidget);
2120
2121 if (!message)
2122 return;
2123
2124 XEvent xevent;
2125 xevent.xclient.type = ClientMessage;
2126 xevent.xclient.message_type = ATOM(_NET_STARTUP_INFO_BEGIN);
2127 xevent.xclient.display = X11->display;
2128 xevent.xclient.window = q->internalWinId();
2129 xevent.xclient.format = 8;
2130
2131 Window rootWindow = RootWindow(X11->display, DefaultScreen(X11->display));
2132 uint sent = 0;
2133 uint length = strlen(message) + 1;
2134 do {
2135 if (sent == 20)
2136 xevent.xclient.message_type = ATOM(_NET_STARTUP_INFO);
2137
2138 for (uint i = 0; i < 20 && i + sent <= length; i++)
2139 xevent.xclient.data.b[i] = message[i + sent++];
2140
2141 XSendEvent(X11->display, rootWindow, false, PropertyChangeMask, &xevent);
2142 } while (sent <= length);
2143}
2144
2145void QWidgetPrivate::setNetWmWindowTypes()
2146{
2147 Q_Q(QWidget);
2148 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2149
2150 if (!q->isWindow()) {
2151 if (q->internalWinId())
2152 XDeleteProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_WINDOW_TYPE));
2153 return;
2154 }
2155
2156 QVector<long> windowTypes;
2157
2158 // manual selection 1 (these are never set by Qt and take precedence)
2159 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDesktop))
2160 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DESKTOP));
2161 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDock))
2162 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DOCK));
2163 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeNotification))
2164 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_NOTIFICATION));
2165
2166 // manual selection 2 (Qt uses these during auto selection);
2167 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeUtility))
2168 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_UTILITY));
2169 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeSplash))
2170 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_SPLASH));
2171 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDialog))
2172 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DIALOG));
2173 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeToolTip))
2174 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_TOOLTIP));
2175
2176 // manual selection 3 (these can be set by Qt, but don't have a
2177 // corresponding Qt::WindowType). note that order of the *MENU
2178 // atoms is important
2179 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeMenu))
2180 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_MENU));
2181 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu))
2182 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU));
2183 if (q->testAttribute(Qt::WA_X11NetWmWindowTypePopupMenu))
2184 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_POPUP_MENU));
2185 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeToolBar))
2186 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_TOOLBAR));
2187 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeCombo))
2188 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_COMBO));
2189 if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDND))
2190 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DND));
2191
2192 // automatic selection
2193 switch (q->windowType()) {
2194 case Qt::Dialog:
2195 case Qt::Sheet:
2196 // dialog netwm type
2197 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DIALOG));
2198 break;
2199
2200 case Qt::Tool:
2201 case Qt::Drawer:
2202 // utility netwm type
2203 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_UTILITY));
2204 break;
2205
2206 case Qt::ToolTip:
2207 // tooltip netwm type
2208 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_TOOLTIP));
2209 break;
2210
2211 case Qt::SplashScreen:
2212 // splash netwm type
2213 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_SPLASH));
2214 break;
2215
2216 default:
2217 break;
2218 }
2219
2220 if (q->windowFlags() & Qt::FramelessWindowHint) {
2221 // override netwm type - quick and easy for KDE noborder
2222 windowTypes.append(ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
2223 }
2224
2225 // normal netwm type - default
2226 windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_NORMAL));
2227
2228 if (!windowTypes.isEmpty()) {
2229 XChangeProperty(X11->display, q->winId(), ATOM(_NET_WM_WINDOW_TYPE), XA_ATOM, 32,
2230 PropModeReplace, (unsigned char *) windowTypes.constData(),
2231 windowTypes.count());
2232 } else {
2233 XDeleteProperty(X11->display, q->winId(), ATOM(_NET_WM_WINDOW_TYPE));
2234 }
2235}
2236
2237/*!
2238 \internal
2239 Platform-specific part of QWidget::hide().
2240*/
2241
2242void QWidgetPrivate::hide_sys()
2243{
2244 Q_Q(QWidget);
2245 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2246 deactivateWidgetCleanup();
2247 if (q->isWindow()) {
2248 X11->deferred_map.removeAll(q);
2249 if (q->internalWinId()) // in nsplugin, may be 0
2250 XWithdrawWindow(X11->display, q->internalWinId(), xinfo.screen());
2251 XFlush(X11->display);
2252 } else {
2253 invalidateBuffer(q->rect());
2254 if (q->internalWinId()) // in nsplugin, may be 0
2255 XUnmapWindow(X11->display, q->internalWinId());
2256 }
2257 q->setAttribute(Qt::WA_Mapped, false);
2258}
2259
2260void QWidgetPrivate::setFocus_sys()
2261{
2262
2263}
2264
2265
2266void QWidgetPrivate::raise_sys()
2267{
2268 Q_Q(QWidget);
2269 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2270 if (q->internalWinId())
2271 XRaiseWindow(X11->display, q->internalWinId());
2272}
2273
2274void QWidgetPrivate::lower_sys()
2275{
2276 Q_Q(QWidget);
2277 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2278 if (q->internalWinId())
2279 XLowerWindow(X11->display, q->internalWinId());
2280 if(!q->isWindow())
2281 invalidateBuffer(q->rect());
2282}
2283
2284void QWidgetPrivate::stackUnder_sys(QWidget* w)
2285{
2286 Q_Q(QWidget);
2287 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2288 if (q->internalWinId() && w->internalWinId()) {
2289 Window stack[2];
2290 stack[0] = w->internalWinId();;
2291 stack[1] = q->internalWinId();
2292 XRestackWindows(X11->display, stack, 2);
2293 }
2294 if(!q->isWindow() || !w->internalWinId())
2295 invalidateBuffer(q->rect());
2296}
2297
2298
2299static void do_size_hints(QWidget* widget, QWExtra *x)
2300{
2301 Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
2302 XSizeHints s;
2303 memset(&s, 0, sizeof(s));
2304 if (x) {
2305 QRect g = widget->geometry();
2306 s.x = g.x();
2307 s.y = g.y();
2308 s.width = g.width();
2309 s.height = g.height();
2310 if (x->minw > 0 || x->minh > 0) {
2311 // add minimum size hints
2312 s.flags |= PMinSize;
2313 s.min_width = qMin(XCOORD_MAX, x->minw);
2314 s.min_height = qMin(XCOORD_MAX, x->minh);
2315 }
2316 if (x->maxw < QWIDGETSIZE_MAX || x->maxh < QWIDGETSIZE_MAX) {
2317 // add maximum size hints
2318 s.flags |= PMaxSize;
2319 s.max_width = qMin(XCOORD_MAX, x->maxw);
2320 s.max_height = qMin(XCOORD_MAX, x->maxh);
2321 }
2322 if (x->topextra &&
2323 (x->topextra->incw > 0 || x->topextra->inch > 0)) {
2324 // add resize increment hints
2325 s.flags |= PResizeInc | PBaseSize;
2326 s.width_inc = x->topextra->incw;
2327 s.height_inc = x->topextra->inch;
2328 s.base_width = x->topextra->basew;
2329 s.base_height = x->topextra->baseh;
2330 }
2331 }
2332 if (widget->testAttribute(Qt::WA_Moved)) {
2333 // user (i.e. command-line) specified position
2334 s.flags |= USPosition;
2335 s.flags |= PPosition;
2336 }
2337 if (widget->testAttribute(Qt::WA_Resized)) {
2338 // user (i.e. command-line) specified size
2339 s.flags |= USSize;
2340 s.flags |= PSize;
2341 }
2342 s.flags |= PWinGravity;
2343 if (widget->testAttribute(Qt::WA_Moved) && x && x->topextra && !x->topextra->posFromMove) {
2344 // position came from setGeometry(), tell the WM that we don't
2345 // want our window gravity-shifted
2346 s.win_gravity = StaticGravity;
2347 } else {
2348 // position came from move()
2349 s.x = widget->x();
2350 s.y = widget->y();
2351 s.win_gravity = QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
2352 }
2353 if (widget->internalWinId())
2354 XSetWMNormalHints(X11->display, widget->internalWinId(), &s);
2355}
2356
2357
2358/*
2359 Helper function for non-toplevel widgets. Helps to map Qt's 32bit
2360 coordinate system to X11's 16bit coordinate system.
2361
2362 Sets the geometry of the widget to data.crect, but clipped to sizes
2363 that X can handle. Unmaps widgets that are completely outside the
2364 valid range.
2365
2366 Maintains data.wrect, which is the geometry of the X widget,
2367 measured in this widget's coordinate system.
2368
2369 if the parent is not clipped, parentWRect is empty, otherwise
2370 parentWRect is the geometry of the parent's X rect, measured in
2371 parent's coord sys
2372 */
2373void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
2374{
2375 Q_Q(QWidget);
2376 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2377
2378 /*
2379 There are up to four different coordinate systems here:
2380 Qt coordinate system for this widget.
2381 X coordinate system for this widget (relative to wrect).
2382 Qt coordinate system for parent
2383 X coordinate system for parent (relative to parent's wrect).
2384 */
2385 Display *dpy = xinfo.display();
2386 QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
2387 QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
2388 QRect wrect;
2389 //xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys)
2390 QRect xrect = data.crect;
2391
2392 const QWidget *const parent = q->parentWidget();
2393 QRect parentWRect = parent->data->wrect;
2394
2395 if (parentWRect.isValid()) {
2396 // parent is clipped, and we have to clip to the same limit as parent
2397 if (!parentWRect.contains(xrect)) {
2398 xrect &= parentWRect;
2399 wrect = xrect;
2400 //translate from parent's to my Qt coord sys
2401 wrect.translate(-data.crect.topLeft());
2402 }
2403 //translate from parent's Qt coords to parent's X coords
2404 xrect.translate(-parentWRect.topLeft());
2405
2406 } else {
2407 // parent is not clipped, we may or may not have to clip
2408
2409 if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
2410 // This is where the main optimization is: we are already
2411 // clipped, and if our clip is still valid, we can just
2412 // move our window, and do not need to move or clip
2413 // children
2414
2415 QRect vrect = xrect & parent->rect();
2416 vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
2417 if (data.wrect.contains(vrect)) {
2418 xrect = data.wrect;
2419 xrect.translate(data.crect.topLeft());
2420 if (data.winid)
2421 XMoveWindow(dpy, data.winid, xrect.x(), xrect.y());
2422 return;
2423 }
2424 }
2425
2426 if (!validRange.contains(xrect)) {
2427 // we are too big, and must clip
2428 xrect &=wrectRange;
2429 wrect = xrect;
2430 wrect.translate(-data.crect.topLeft());
2431 //parent's X coord system is equal to parent's Qt coord
2432 //sys, so we don't need to map xrect.
2433 }
2434
2435 }
2436
2437 // unmap if we are outside the valid window system coord system
2438 bool outsideRange = !xrect.isValid();
2439 bool mapWindow = false;
2440 if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
2441 q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
2442 if (outsideRange) {
2443 if (data.winid)
2444 XUnmapWindow(dpy, data.winid);
2445 q->setAttribute(Qt::WA_Mapped, false);
2446 } else if (!q->isHidden()) {
2447 mapWindow = true;
2448 }
2449 }
2450
2451 if (outsideRange)
2452 return;
2453
2454 bool jump = (data.wrect != wrect);
2455 data.wrect = wrect;
2456
2457
2458 // and now recursively for all children...
2459 // ### can be optimized
2460 for (int i = 0; i < children.size(); ++i) {
2461 QObject *object = children.at(i);
2462 if (object->isWidgetType()) {
2463 QWidget *w = static_cast<QWidget *>(object);
2464 if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
2465 w->d_func()->setWSGeometry(jump);
2466 }
2467 }
2468
2469 if (data.winid) {
2470 // move ourselves to the new position and map (if necessary) after
2471 // the movement. Rationale: moving unmapped windows is much faster
2472 // than moving mapped windows
2473 if (jump) //avoid flicker when jumping
2474 XSetWindowBackgroundPixmap(dpy, data.winid, XNone);
2475 if (!parent->internalWinId())
2476 xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
2477 XMoveResizeWindow(dpy, data.winid, xrect.x(), xrect.y(), xrect.width(), xrect.height());
2478 }
2479
2480 //to avoid flicker, we have to show children after the helper widget has moved
2481 if (jump) {
2482 for (int i = 0; i < children.size(); ++i) {
2483 QObject *object = children.at(i);
2484 if (object->isWidgetType()) {
2485 QWidget *w = static_cast<QWidget *>(object);
2486 if (!w->testAttribute(Qt::WA_OutsideWSRange) && !w->testAttribute(Qt::WA_Mapped) && !w->isHidden()) {
2487 w->setAttribute(Qt::WA_Mapped);
2488 if (w->internalWinId())
2489 XMapWindow(dpy, w->data->winid);
2490 }
2491 }
2492 }
2493 }
2494
2495
2496 if (jump && data.winid)
2497 XClearArea(dpy, data.winid, 0, 0, wrect.width(), wrect.height(), True);
2498
2499 if (mapWindow && !dontShow) {
2500 q->setAttribute(Qt::WA_Mapped);
2501 if (data.winid)
2502 XMapWindow(dpy, data.winid);
2503 }
2504}
2505
2506void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
2507{
2508 Q_Q(QWidget);
2509 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2510 Display *dpy = X11->display;
2511
2512 if ((q->windowType() == Qt::Desktop))
2513 return;
2514 if (q->isWindow()) {
2515 if (!X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT))
2516 && !X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ)))
2517 data.window_state &= ~Qt::WindowMaximized;
2518 if (!X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN)))
2519 data.window_state &= ~Qt::WindowFullScreen;
2520 if (QTLWExtra *topData = maybeTopData())
2521 topData->normalGeometry = QRect(0,0,-1,-1);
2522 } else {
2523 uint s = data.window_state;
2524 s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen);
2525 data.window_state = s;
2526 }
2527 if (extra) { // any size restrictions?
2528 w = qMin(w,extra->maxw);
2529 h = qMin(h,extra->maxh);
2530 w = qMax(w,extra->minw);
2531 h = qMax(h,extra->minh);
2532 }
2533 QPoint oldPos(q->pos());
2534 QSize oldSize(q->size());
2535 QRect oldGeom(data.crect);
2536 QRect r(x, y, w, h);
2537
2538 // We only care about stuff that changes the geometry, or may
2539 // cause the window manager to change its state
2540 if (!q->isWindow() && oldGeom == r)
2541 return;
2542
2543 data.crect = r;
2544 bool isResize = q->size() != oldSize;
2545
2546 if (q->isWindow()) {
2547 if (w == 0 || h == 0) {
2548 q->setAttribute(Qt::WA_OutsideWSRange, true);
2549 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
2550 hide_sys();
2551 } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
2552 q->setAttribute(Qt::WA_OutsideWSRange, false);
2553
2554 // put the window in its place and show it
2555 if (data.winid)
2556 XMoveResizeWindow(dpy, data.winid, x, y, w, h);
2557 topData()->posFromMove = false; // force StaticGravity
2558 do_size_hints(q, extra);
2559 show_sys();
2560 } else {
2561 q->setAttribute(Qt::WA_OutsideWSRange, false);
2562 if (!q->isVisible())
2563 do_size_hints(q, extra);
2564 if (isMove) {
2565 if ((data.window_flags & Qt::X11BypassWindowManagerHint) == Qt::X11BypassWindowManagerHint
2566 // work around 4Dwm's incompliance with ICCCM 4.1.5
2567 || X11->desktopEnvironment == DE_4DWM) {
2568 if (data.winid)
2569 XMoveResizeWindow(dpy, data.winid, x, y, w, h);
2570 } else if (q->isVisible()
2571 && topData()->validWMState
2572 && X11->isSupportedByWM(ATOM(_NET_MOVERESIZE_WINDOW))) {
2573 XEvent e;
2574 e.xclient.type = ClientMessage;
2575 e.xclient.message_type = ATOM(_NET_MOVERESIZE_WINDOW);
2576 e.xclient.display = X11->display;
2577 e.xclient.window = q->internalWinId();
2578 e.xclient.format = 32;
2579 e.xclient.data.l[0] = StaticGravity | 1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12;
2580 e.xclient.data.l[1] = x;
2581 e.xclient.data.l[2] = y;
2582 e.xclient.data.l[3] = w;
2583 e.xclient.data.l[4] = h;
2584 XSendEvent(X11->display, RootWindow(X11->display, q->x11Info().screen()),
2585 false, (SubstructureNotifyMask | SubstructureRedirectMask), &e);
2586 } else if (data.winid) {
2587 // pos() is right according to ICCCM 4.1.5
2588 XMoveResizeWindow(dpy, data.winid, q->pos().x(), q->pos().y(), w, h);
2589 }
2590 } else if (isResize && data.winid) {
2591 if (!q->isVisible()
2592 && topData()->validWMState
2593 && !q->testAttribute(Qt::WA_PendingMoveEvent)) {
2594 /*
2595 even though we've not visible, we could be in a
2596 race w/ the window manager, and it may ignore
2597 our ConfigureRequest. setting posFromMove to
2598 false makes sure that doDeferredMap() in
2599 qapplication_x11.cpp keeps the window in the
2600 right place
2601 */
2602 topData()->posFromMove = false;
2603 }
2604 XResizeWindow(dpy, data.winid, w, h);
2605 }
2606 }
2607 if (isResize && !q->testAttribute(Qt::WA_DontShowOnScreen)) // set config pending only on resize, see qapplication_x11.cpp, translateConfigEvent()
2608 q->setAttribute(Qt::WA_WState_ConfigPending);
2609
2610 } else {
2611 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
2612 const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
2613 const bool disableInTopLevelResize = inTopLevelResize && q->internalWinId();
2614 if (disableInTopLevelResize) {
2615 // Top-level resize optimization does not work for native child widgets;
2616 // disable it for this particular widget.
2617 tlwExtra->inTopLevelResize = false;
2618 }
2619
2620 if (!isResize && (!inTopLevelResize || disableInTopLevelResize) && q->isVisible()) {
2621 moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
2622 }
2623 if (q->testAttribute(Qt::WA_WState_Created))
2624 setWSGeometry();
2625
2626 if (isResize && (!inTopLevelResize || disableInTopLevelResize) && q->isVisible())
2627 invalidateBuffer_resizeHelper(oldPos, oldSize);
2628
2629 if (disableInTopLevelResize)
2630 tlwExtra->inTopLevelResize = true;
2631 }
2632
2633 if (q->isVisible()) {
2634 if (isMove && q->pos() != oldPos) {
2635 if (X11->desktopEnvironment != DE_4DWM) {
2636 // pos() is right according to ICCCM 4.1.5
2637 QMoveEvent e(q->pos(), oldPos);
2638 QApplication::sendEvent(q, &e);
2639 } else {
2640 // work around 4Dwm's incompliance with ICCCM 4.1.5
2641 QMoveEvent e(data.crect.topLeft(), oldGeom.topLeft());
2642 QApplication::sendEvent(q, &e);
2643 }
2644 }
2645 if (isResize) {
2646 static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
2647 // If we have a backing store with static contents, we have to disable the top-level
2648 // resize optimization in order to get invalidated regions for resized widgets.
2649 // The optimization discards all invalidateBuffer() calls since we're going to
2650 // repaint everything anyways, but that's not the case with static contents.
2651 const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
2652 && !extra->topextra->inTopLevelResize
2653 && (!extra->topextra->backingStore
2654 || !extra->topextra->backingStore->hasStaticContents());
2655 if (setTopLevelResize)
2656 extra->topextra->inTopLevelResize = true;
2657 QResizeEvent e(q->size(), oldSize);
2658 QApplication::sendEvent(q, &e);
2659 if (setTopLevelResize)
2660 extra->topextra->inTopLevelResize = false;
2661 }
2662 } else {
2663 if (isMove && q->pos() != oldPos)
2664 q->setAttribute(Qt::WA_PendingMoveEvent, true);
2665 if (isResize)
2666 q->setAttribute(Qt::WA_PendingResizeEvent, true);
2667 }
2668}
2669
2670void QWidgetPrivate::setConstraints_sys()
2671{
2672 Q_Q(QWidget);
2673#ifdef ALIEN_DEBUG
2674 qDebug() << "QWidgetPrivate::setConstraints_sys START" << q;
2675#endif
2676 if (q->testAttribute(Qt::WA_WState_Created)) {
2677 do_size_hints(q, extra);
2678 QtMWMHints mwmHints = GetMWMHints(X11->display, q->internalWinId());
2679 const bool wasFuncResize = mwmHints.functions & MWM_FUNC_RESIZE;
2680 if (q->minimumSize() == q->maximumSize())
2681 mwmHints.functions &= ~MWM_FUNC_RESIZE;
2682 else
2683 mwmHints.functions |= MWM_FUNC_RESIZE;
2684 if (wasFuncResize != (mwmHints.functions & MWM_FUNC_RESIZE))
2685 SetMWMHints(X11->display, q->internalWinId(), mwmHints);
2686 }
2687#ifdef ALIEN_DEBUG
2688 qDebug() << "QWidgetPrivate::setConstraints_sys END" << q;
2689#endif
2690}
2691
2692void QWidgetPrivate::scroll_sys(int dx, int dy)
2693{
2694 Q_Q(QWidget);
2695
2696 scrollChildren(dx, dy);
2697 if (!paintOnScreen()) {
2698 scrollRect(q->rect(), dx, dy);
2699 } else {
2700 scroll_sys(dx, dy, QRect());
2701 }
2702}
2703
2704void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
2705{
2706 Q_Q(QWidget);
2707
2708 if (!paintOnScreen()) {
2709 scrollRect(r, dx, dy);
2710 return;
2711 }
2712 bool valid_rect = r.isValid();
2713 bool just_update = qAbs(dx) > q->width() || qAbs(dy) > q->height();
2714 QRect sr = valid_rect ? r : clipRect();
2715 if (just_update)
2716 q->update();
2717 else if (!valid_rect)
2718 dirty.translate(dx, dy);
2719
2720 int x1, y1, x2, y2, w = sr.width(), h = sr.height();
2721 if (dx > 0) {
2722 x1 = sr.x();
2723 x2 = x1+dx;
2724 w -= dx;
2725 } else {
2726 x2 = sr.x();
2727 x1 = x2-dx;
2728 w += dx;
2729 }
2730 if (dy > 0) {
2731 y1 = sr.y();
2732 y2 = y1+dy;
2733 h -= dy;
2734 } else {
2735 y2 = sr.y();
2736 y1 = y2-dy;
2737 h += dy;
2738 }
2739
2740 if (dx == 0 && dy == 0)
2741 return;
2742
2743 Display *dpy = X11->display;
2744 // Want expose events
2745 if (w > 0 && h > 0 && !just_update && q->internalWinId()) {
2746 GC gc = XCreateGC(dpy, q->internalWinId(), 0, 0);
2747 XSetGraphicsExposures(dpy, gc, True);
2748 XCopyArea(dpy, q->internalWinId(), q->internalWinId(), gc, x1, y1, w, h, x2, y2);
2749 XFreeGC(dpy, gc);
2750 }
2751
2752 if (!valid_rect && !children.isEmpty()) { // scroll children
2753 QPoint pd(dx, dy);
2754 for (int i = 0; i < children.size(); ++i) { // move all children
2755 register QObject *object = children.at(i);
2756 if (object->isWidgetType()) {
2757 QWidget *w = static_cast<QWidget *>(object);
2758 if (!w->isWindow())
2759 w->move(w->pos() + pd);
2760 }
2761 }
2762 }
2763
2764 if (just_update)
2765 return;
2766
2767 // Don't let the server be bogged-down with repaint events
2768 bool repaint_immediately = (qt_sip_count(q) < 3 && !q->testAttribute(Qt::WA_WState_InPaintEvent));
2769
2770 if (dx) {
2771 int x = x2 == sr.x() ? sr.x()+w : sr.x();
2772 if (repaint_immediately)
2773 q->repaint(x, sr.y(), qAbs(dx), sr.height());
2774 else if (q->internalWinId())
2775 XClearArea(dpy, data.winid, x, sr.y(), qAbs(dx), sr.height(), True);
2776 }
2777 if (dy) {
2778 int y = y2 == sr.y() ? sr.y()+h : sr.y();
2779 if (repaint_immediately)
2780 q->repaint(sr.x(), y, sr.width(), qAbs(dy));
2781 else if (q->internalWinId())
2782 XClearArea(dpy, data.winid, sr.x(), y, sr.width(), qAbs(dy), True);
2783 }
2784
2785 qt_insert_sip(q, dx, dy); // #### ignores r
2786}
2787
2788int QWidget::metric(PaintDeviceMetric m) const
2789{
2790 Q_D(const QWidget);
2791 int val;
2792 if (m == PdmWidth) {
2793 val = data->crect.width();
2794 } else if (m == PdmHeight) {
2795 val = data->crect.height();
2796 } else {
2797 Display *dpy = X11->display;
2798 int scr = d->xinfo.screen();
2799 switch (m) {
2800 case PdmDpiX:
2801 case PdmPhysicalDpiX:
2802 if (d->extra && d->extra->customDpiX)
2803 val = d->extra->customDpiX;
2804 else if (d->parent)
2805 val = static_cast<QWidget *>(d->parent)->metric(m);
2806 else
2807 val = QX11Info::appDpiX(scr);
2808 break;
2809 case PdmDpiY:
2810 case PdmPhysicalDpiY:
2811 if (d->extra && d->extra->customDpiY)
2812 val = d->extra->customDpiY;
2813 else if (d->parent)
2814 val = static_cast<QWidget *>(d->parent)->metric(m);
2815 else
2816 val = QX11Info::appDpiY(scr);
2817 break;
2818 case PdmWidthMM:
2819 val = (DisplayWidthMM(dpy,scr)*data->crect.width())/
2820 DisplayWidth(dpy,scr);
2821 break;
2822 case PdmHeightMM:
2823 val = (DisplayHeightMM(dpy,scr)*data->crect.height())/
2824 DisplayHeight(dpy,scr);
2825 break;
2826 case PdmNumColors:
2827 val = d->xinfo.cells();
2828 break;
2829 case PdmDepth:
2830 val = d->xinfo.depth();
2831 break;
2832 default:
2833 val = 0;
2834 qWarning("QWidget::metric: Invalid metric command");
2835 }
2836 }
2837 return val;
2838}
2839
2840void QWidgetPrivate::createSysExtra()
2841{
2842 extra->compress_events = true;
2843 extra->xDndProxy = 0;
2844}
2845
2846void QWidgetPrivate::deleteSysExtra()
2847{
2848}
2849
2850void QWidgetPrivate::createTLSysExtra()
2851{
2852 extra->topextra->spont_unmapped = 0;
2853 extra->topextra->dnd = 0;
2854 extra->topextra->validWMState = 0;
2855 extra->topextra->waitingForMapNotify = 0;
2856 extra->topextra->parentWinId = 0;
2857 extra->topextra->userTimeWindow = 0;
2858#ifndef QT_NO_XSYNC
2859 extra->topextra->syncUpdateCounter = 0;
2860 extra->topextra->syncRequestTimestamp = 0;
2861 extra->topextra->newCounterValueHi = 0;
2862 extra->topextra->newCounterValueLo = 0;
2863#endif
2864}
2865
2866void QWidgetPrivate::deleteTLSysExtra()
2867{
2868 // don't destroy input context here. it will be destroyed in
2869 // QWidget::destroy() destroyInputContext();
2870#ifndef QT_NO_XSYNC
2871 if (extra && extra->topextra && extra->topextra->syncUpdateCounter) {
2872 XSyncDestroyCounter(X11->display, extra->topextra->syncUpdateCounter);
2873 extra->topextra->syncUpdateCounter = 0;
2874 }
2875#endif
2876}
2877
2878void QWidgetPrivate::registerDropSite(bool on)
2879{
2880 Q_UNUSED(on);
2881}
2882
2883void QWidgetPrivate::setMask_sys(const QRegion &region)
2884{
2885 Q_Q(QWidget);
2886 if (!q->internalWinId())
2887 return;
2888
2889 if (region.isEmpty()) {
2890 XShapeCombineMask(X11->display, q->internalWinId(), ShapeBounding, 0, 0,
2891 XNone, ShapeSet);
2892 } else {
2893 XShapeCombineRegion(X11->display, q->internalWinId(), ShapeBounding, 0, 0,
2894 region.handle(), ShapeSet);
2895 }
2896}
2897
2898/*!
2899 \internal
2900
2901 Computes the frame rectangle when needed. This is an internal function, you
2902 should never call this.
2903*/
2904
2905void QWidgetPrivate::updateFrameStrut()
2906{
2907 Q_Q(QWidget);
2908
2909 QTLWExtra *top = topData();
2910 if (!top->validWMState) {
2911 return;
2912 }
2913 if (!q->isWindow() && !q->internalWinId()) {
2914 data.fstrut_dirty = false;
2915 return;
2916 }
2917
2918 Atom type_ret;
2919 Window l = q->effectiveWinId(), w = l, p, r; // target window, its parent, root
2920 Window *c;
2921 int i_unused;
2922 unsigned int nc;
2923 unsigned char *data_ret;
2924 unsigned long l_unused;
2925
2926 while (XQueryTree(X11->display, w, &r, &p, &c, &nc)) {
2927 if (c && nc > 0)
2928 XFree(c);
2929
2930 if (! p) {
2931 qWarning("QWidget::updateFrameStrut: No parent");
2932 return;
2933 }
2934
2935 // if the parent window is the root window, an Enlightenment virtual root or
2936 // a NET WM virtual root window, stop here
2937 data_ret = 0;
2938 if (p == r ||
2939 (XGetWindowProperty(X11->display, p,
2940 ATOM(ENLIGHTENMENT_DESKTOP), 0, 1, False, XA_CARDINAL,
2941 &type_ret, &i_unused, &l_unused, &l_unused,
2942 &data_ret) == Success &&
2943 type_ret == XA_CARDINAL)) {
2944 if (data_ret)
2945 XFree(data_ret);
2946
2947 break;
2948 } else if (X11->isSupportedByWM(ATOM(_NET_VIRTUAL_ROOTS)) && X11->net_virtual_root_list) {
2949 int i = 0;
2950 while (X11->net_virtual_root_list[i] != 0) {
2951 if (X11->net_virtual_root_list[i++] == p)
2952 break;
2953 }
2954 }
2955
2956 l = w;
2957 w = p;
2958 }
2959
2960 // we have our window
2961 int transx, transy;
2962 XWindowAttributes wattr;
2963 if (XTranslateCoordinates(X11->display, l, w,
2964 0, 0, &transx, &transy, &p) &&
2965 XGetWindowAttributes(X11->display, w, &wattr)) {
2966 top->frameStrut.setCoords(transx,
2967 transy,
2968 wattr.width - data.crect.width() - transx,
2969 wattr.height - data.crect.height() - transy);
2970
2971 // add the border_width for the window managers frame... some window managers
2972 // do not use a border_width of zero for their frames, and if we the left and
2973 // top strut, we ensure that pos() is absolutely correct. frameGeometry()
2974 // will still be incorrect though... perhaps i should have foffset as well, to
2975 // indicate the frame offset (equal to the border_width on X).
2976 // - Brad
2977 top->frameStrut.adjust(wattr.border_width,
2978 wattr.border_width,
2979 wattr.border_width,
2980 wattr.border_width);
2981 }
2982
2983 data.fstrut_dirty = false;
2984}
2985
2986void QWidgetPrivate::setWindowOpacity_sys(qreal opacity)
2987{
2988 Q_Q(QWidget);
2989 ulong value = ulong(opacity * 0xffffffff);
2990 XChangeProperty(QX11Info::display(), q->internalWinId(), ATOM(_NET_WM_WINDOW_OPACITY), XA_CARDINAL,
2991 32, PropModeReplace, (uchar*)&value, 1);
2992}
2993
2994const QX11Info &QWidget::x11Info() const
2995{
2996 Q_D(const QWidget);
2997 return d->xinfo;
2998}
2999
3000void QWidgetPrivate::setWindowRole()
3001{
3002 Q_Q(QWidget);
3003 if (!q->internalWinId())
3004 return;
3005 QByteArray windowRole = topData()->role.toUtf8();
3006 XChangeProperty(X11->display, q->internalWinId(),
3007 ATOM(WM_WINDOW_ROLE), XA_STRING, 8, PropModeReplace,
3008 (unsigned char *)windowRole.constData(), windowRole.length());
3009}
3010
3011Q_GLOBAL_STATIC(QX11PaintEngine, qt_widget_paintengine)
3012QPaintEngine *QWidget::paintEngine() const
3013{
3014 Q_D(const QWidget);
3015 if (qt_widget_paintengine()->isActive()) {
3016 if (d->extraPaintEngine)
3017 return d->extraPaintEngine;
3018 QWidget *self = const_cast<QWidget *>(this);
3019 self->d_func()->extraPaintEngine = new QX11PaintEngine();
3020 return d->extraPaintEngine;
3021 }
3022 return qt_widget_paintengine();
3023}
3024
3025QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
3026{
3027 return new QX11WindowSurface(q_func());
3028}
3029
3030Qt::HANDLE QWidget::x11PictureHandle() const
3031{
3032#ifndef QT_NO_XRENDER
3033 Q_D(const QWidget);
3034 if (!internalWinId() && testAttribute(Qt::WA_WState_Created))
3035 (void)winId(); // enforce native window
3036 return d->picture;
3037#else
3038 return 0;
3039#endif // QT_NO_XRENDER
3040}
3041
3042#ifndef QT_NO_XRENDER
3043XRenderColor QX11Data::preMultiply(const QColor &c)
3044{
3045 XRenderColor color;
3046 const uint A = c.alpha(),
3047 R = c.red(),
3048 G = c.green(),
3049 B = c.blue();
3050 color.alpha = (A | A << 8);
3051 color.red = (R | R << 8) * color.alpha / 0x10000;
3052 color.green = (G | G << 8) * color.alpha / 0x10000;
3053 color.blue = (B | B << 8) * color.alpha / 0x10000;
3054 return color;
3055}
3056Picture QX11Data::getSolidFill(int screen, const QColor &c)
3057{
3058 if (!X11->use_xrender)
3059 return XNone;
3060
3061 XRenderColor color = preMultiply(c);
3062 for (int i = 0; i < X11->solid_fill_count; ++i) {
3063 if (X11->solid_fills[i].screen == screen
3064 && X11->solid_fills[i].color.alpha == color.alpha
3065 && X11->solid_fills[i].color.red == color.red
3066 && X11->solid_fills[i].color.green == color.green
3067 && X11->solid_fills[i].color.blue == color.blue)
3068 return X11->solid_fills[i].picture;
3069 }
3070 // none found, replace one
3071 int i = qrand() % 16;
3072
3073 if (X11->solid_fills[i].screen != screen && X11->solid_fills[i].picture) {
3074 XRenderFreePicture (X11->display, X11->solid_fills[i].picture);
3075 X11->solid_fills[i].picture = 0;
3076 }
3077
3078 if (!X11->solid_fills[i].picture) {
3079 Pixmap pixmap = XCreatePixmap (X11->display, RootWindow (X11->display, screen), 1, 1, 32);
3080 XRenderPictureAttributes attrs;
3081 attrs.repeat = True;
3082 X11->solid_fills[i].picture = XRenderCreatePicture (X11->display, pixmap,
3083 XRenderFindStandardFormat(X11->display, PictStandardARGB32),
3084 CPRepeat, &attrs);
3085 XFreePixmap (X11->display, pixmap);
3086 }
3087
3088 X11->solid_fills[i].color = color;
3089 X11->solid_fills[i].screen = screen;
3090 XRenderFillRectangle (X11->display, PictOpSrc, X11->solid_fills[i].picture, &color, 0, 0, 1, 1);
3091 return X11->solid_fills[i].picture;
3092}
3093#endif
3094
3095void QWidgetPrivate::setModal_sys()
3096{
3097}
3098
3099void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const QX11WindowAttributes &att)
3100{
3101 QX11InfoData* xd = xinfo->getX11Data(true);
3102 const XWindowAttributes &a = *(att.att);
3103 // find which screen the window is on...
3104 xd->screen = QX11Info::appScreen(); // by default, use the default :)
3105 int i;
3106 for (i = 0; i < ScreenCount(X11->display); i++) {
3107 if (RootWindow(X11->display, i) == a.root) {
3108 xd->screen = i;
3109 break;
3110 }
3111 }
3112
3113 xd->depth = a.depth;
3114 xd->cells = DisplayCells(X11->display, xd->screen);
3115 xd->visual = a.visual;
3116 xd->defaultVisual = (XVisualIDFromVisual((Visual *) a.visual) ==
3117 XVisualIDFromVisual((Visual *) QX11Info::appVisual(xinfo->screen())));
3118 xd->colormap = a.colormap;
3119 xd->defaultColormap = (a.colormap == QX11Info::appColormap(xinfo->screen()));
3120 xinfo->setX11Data(xd);
3121}
3122
3123void QWidgetPrivate::updateX11AcceptFocus()
3124{
3125 Q_Q(QWidget);
3126 if (!q->isWindow() || !q->internalWinId())
3127 return;
3128
3129 XWMHints *h = XGetWMHints(X11->display, q->internalWinId());
3130 XWMHints wm_hints;
3131 if (!h) {
3132 memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
3133 h = &wm_hints;
3134 }
3135 h->flags |= InputHint;
3136 h->input = q->testAttribute(Qt::WA_X11DoNotAcceptFocus) ? False : True;
3137
3138 XSetWMHints(X11->display, q->internalWinId(), h);
3139 if (h != &wm_hints)
3140 XFree((char *)h);
3141}
3142
3143QT_END_NAMESPACE
3144