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

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

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

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