--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/kernel/qwidget_x11.cpp Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,3029 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qevent.h"
+#include "qwidget.h"
+#include "qdesktopwidget.h"
+#include "qapplication.h"
+#include "qapplication_p.h"
+#include "qnamespace.h"
+#include "qpainter.h"
+#include "qbitmap.h"
+#include "qlayout.h"
+#include "qtextcodec.h"
+#include "qdatetime.h"
+#include "qcursor.h"
+#include "qstack.h"
+#include "qcolormap.h"
+#include "qdebug.h"
+#include "qmenu.h"
+#include "private/qmenu_p.h"
+#include "private/qbackingstore_p.h"
+#include "private/qwindowsurface_x11_p.h"
+
+//extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); //qapplication_x11.cpp
+
+#include <private/qpixmap_x11_p.h>
+#include <private/qpaintengine_x11_p.h>
+#include "qt_x11_p.h"
+#include "qx11info_x11.h"
+
+#include <stdlib.h>
+
+//#define ALIEN_DEBUG
+
+// defined in qapplication_x11.cpp
+//bool qt_wstate_iconified(WId);
+//void qt_updated_rootinfo();
+
+
+#if !defined(QT_NO_IM)
+#include "qinputcontext.h"
+#include "qinputcontextfactory.h"
+#endif
+
+#include "qwidget_p.h"
+
+#define XCOORD_MAX 16383
+#define WRECT_MAX 8191
+
+QT_BEGIN_NAMESPACE
+
+extern bool qt_nograb();
+
+QWidget *QWidgetPrivate::mouseGrabber = 0;
+QWidget *QWidgetPrivate::keyboardGrabber = 0;
+
+void qt_net_remove_user_time(QWidget *tlw);
+void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp);
+
+int qt_x11_create_desktop_on_screen = -1;
+
+extern void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp);
+
+// MWM support
+struct QtMWMHints {
+ ulong flags, functions, decorations;
+ long input_mode;
+ ulong status;
+};
+
+enum {
+ MWM_HINTS_FUNCTIONS = (1L << 0),
+
+ MWM_FUNC_ALL = (1L << 0),
+ MWM_FUNC_RESIZE = (1L << 1),
+ MWM_FUNC_MOVE = (1L << 2),
+ MWM_FUNC_MINIMIZE = (1L << 3),
+ MWM_FUNC_MAXIMIZE = (1L << 4),
+ MWM_FUNC_CLOSE = (1L << 5),
+
+ MWM_HINTS_DECORATIONS = (1L << 1),
+
+ MWM_DECOR_ALL = (1L << 0),
+ MWM_DECOR_BORDER = (1L << 1),
+ MWM_DECOR_RESIZEH = (1L << 2),
+ MWM_DECOR_TITLE = (1L << 3),
+ MWM_DECOR_MENU = (1L << 4),
+ MWM_DECOR_MINIMIZE = (1L << 5),
+ MWM_DECOR_MAXIMIZE = (1L << 6),
+
+ MWM_HINTS_INPUT_MODE = (1L << 2),
+
+ MWM_INPUT_MODELESS = 0L,
+ MWM_INPUT_PRIMARY_APPLICATION_MODAL = 1L,
+ MWM_INPUT_FULL_APPLICATION_MODAL = 3L
+};
+
+
+static QtMWMHints GetMWMHints(Display *display, Window window)
+{
+ QtMWMHints mwmhints;
+
+ Atom type;
+ int format;
+ ulong nitems, bytesLeft;
+ uchar *data = 0;
+ if ((XGetWindowProperty(display, window, ATOM(_MOTIF_WM_HINTS), 0, 5, false,
+ ATOM(_MOTIF_WM_HINTS), &type, &format, &nitems, &bytesLeft,
+ &data) == Success)
+ && (type == ATOM(_MOTIF_WM_HINTS)
+ && format == 32
+ && nitems >= 5)) {
+ mwmhints = *(reinterpret_cast<QtMWMHints *>(data));
+ } else {
+ mwmhints.flags = 0L;
+ mwmhints.functions = MWM_FUNC_ALL;
+ mwmhints.decorations = MWM_DECOR_ALL;
+ mwmhints.input_mode = 0L;
+ mwmhints.status = 0L;
+ }
+
+ if (data)
+ XFree(data);
+
+ return mwmhints;
+}
+
+static void SetMWMHints(Display *display, Window window, const QtMWMHints &mwmhints)
+{
+ if (mwmhints.flags != 0l) {
+ XChangeProperty(display, window, ATOM(_MOTIF_WM_HINTS), ATOM(_MOTIF_WM_HINTS), 32,
+ PropModeReplace, (unsigned char *) &mwmhints, 5);
+ } else {
+ XDeleteProperty(display, window, ATOM(_MOTIF_WM_HINTS));
+ }
+}
+
+// Returns true if we should set WM_TRANSIENT_FOR on \a w
+static inline bool isTransient(const QWidget *w)
+{
+ return ((w->windowType() == Qt::Dialog
+ || w->windowType() == Qt::Sheet
+ || w->windowType() == Qt::Tool
+ || w->windowType() == Qt::SplashScreen
+ || w->windowType() == Qt::ToolTip
+ || w->windowType() == Qt::Drawer
+ || w->windowType() == Qt::Popup)
+ && !w->testAttribute(Qt::WA_X11BypassTransientForHint));
+}
+
+static void do_size_hints(QWidget* widget, QWExtra *x);
+
+/*****************************************************************************
+ QWidget member functions
+ *****************************************************************************/
+
+const uint stdWidgetEventMask = // X event mask
+ (uint)(
+ KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ KeymapStateMask |
+ ButtonMotionMask | PointerMotionMask |
+ EnterWindowMask | LeaveWindowMask |
+ FocusChangeMask |
+ ExposureMask |
+ PropertyChangeMask |
+ StructureNotifyMask
+ );
+
+const uint stdDesktopEventMask = // X event mask
+ (uint)(
+ KeymapStateMask |
+ EnterWindowMask | LeaveWindowMask |
+ PropertyChangeMask
+ );
+
+
+/*
+ The qt_ functions below are implemented in qwidgetcreate_x11.cpp.
+*/
+
+Window qt_XCreateWindow(const QWidget *creator,
+ Display *display, Window parent,
+ int x, int y, uint w, uint h,
+ int borderwidth, int depth,
+ uint windowclass, Visual *visual,
+ ulong valuemask, XSetWindowAttributes *attributes);
+Window qt_XCreateSimpleWindow(const QWidget *creator,
+ Display *display, Window parent,
+ int x, int y, uint w, uint h, int borderwidth,
+ ulong border, ulong background);
+void qt_XDestroyWindow(const QWidget *destroyer,
+ Display *display, Window window);
+
+
+static void qt_insert_sip(QWidget* scrolled_widget, int dx, int dy)
+{
+ if (!scrolled_widget->isWindow() && !scrolled_widget->internalWinId())
+ return;
+ QX11Data::ScrollInProgress sip = { X11->sip_serial++, scrolled_widget, dx, dy };
+ X11->sip_list.append(sip);
+
+ XClientMessageEvent client_message;
+ client_message.type = ClientMessage;
+ client_message.window = scrolled_widget->internalWinId();
+ client_message.format = 32;
+ client_message.message_type = ATOM(_QT_SCROLL_DONE);
+ client_message.data.l[0] = sip.id;
+
+ XSendEvent(X11->display, scrolled_widget->internalWinId(), False, NoEventMask,
+ (XEvent*)&client_message);
+}
+
+static int qt_sip_count(QWidget* scrolled_widget)
+{
+ int sips=0;
+
+ for (int i = 0; i < X11->sip_list.size(); ++i) {
+ const QX11Data::ScrollInProgress &sip = X11->sip_list.at(i);
+ if (sip.scrolled_widget == scrolled_widget)
+ sips++;
+ }
+
+ return sips;
+}
+
+static void create_wm_client_leader()
+{
+ if (X11->wm_client_leader) return;
+
+ X11->wm_client_leader =
+ XCreateSimpleWindow(X11->display,
+ QX11Info::appRootWindow(),
+ 0, 0, 1, 1, 0, 0, 0);
+
+ // set client leader property to itself
+ XChangeProperty(X11->display,
+ X11->wm_client_leader, ATOM(WM_CLIENT_LEADER),
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)&X11->wm_client_leader, 1);
+
+#ifndef QT_NO_SESSIONMANAGER
+ // If we are session managed, inform the window manager about it
+ QByteArray session = qApp->sessionId().toLatin1();
+ if (!session.isEmpty()) {
+ XChangeProperty(X11->display,
+ X11->wm_client_leader, ATOM(SM_CLIENT_ID),
+ XA_STRING, 8, PropModeReplace,
+ (unsigned char *)session.data(), session.size());
+ }
+#endif
+}
+
+/*!
+ \internal
+ Update the X11 cursor of the widget w.
+ \a force is true if this function is called from dispatchEnterLeave, it means that the
+ mouse is actually directly under this widget.
+ */
+void qt_x11_enforce_cursor(QWidget * w, bool force)
+{
+ if (!w->testAttribute(Qt::WA_WState_Created))
+ return;
+
+ static QPointer<QWidget> lastUnderMouse = 0;
+ if (force) {
+ lastUnderMouse = w;
+ } else if (lastUnderMouse && lastUnderMouse->effectiveWinId() == w->effectiveWinId()) {
+ w = lastUnderMouse;
+ } else if (!w->internalWinId()) {
+ return; //the mouse is not under this widget, and it's not native, so don't change it
+ }
+
+ while (!w->internalWinId() && w->parentWidget() && !w->isWindow() && !w->testAttribute(Qt::WA_SetCursor))
+ w = w->parentWidget();
+
+ QWidget *nativeParent = w;
+ if (!w->internalWinId())
+ nativeParent = w->nativeParentWidget();
+ // This does the same as effectiveWinId(), but since it is possible
+ // to not have a native parent widget due to a special hack in
+ // qwidget for reparenting widgets to a different X11 screen,
+ // added additional check to make sure native parent widget exists.
+ if (!nativeParent || !nativeParent->internalWinId())
+ return;
+ WId winid = nativeParent->internalWinId();
+
+ if (w->isWindow() || w->testAttribute(Qt::WA_SetCursor)) {
+#ifndef QT_NO_CURSOR
+ QCursor *oc = QApplication::overrideCursor();
+ if (oc) {
+ XDefineCursor(X11->display, winid, oc->handle());
+ } else if (w->isEnabled()) {
+ XDefineCursor(X11->display, winid, w->cursor().handle());
+ } else {
+ // enforce the windows behavior of clearing the cursor on
+ // disabled widgets
+ XDefineCursor(X11->display, winid, XNone);
+ }
+#endif
+ } else {
+ XDefineCursor(X11->display, winid, XNone);
+ }
+}
+
+Q_GUI_EXPORT void qt_x11_enforce_cursor(QWidget * w)
+{
+ qt_x11_enforce_cursor(w, false);
+}
+
+static Bool checkForConfigureAndExpose(Display *, XEvent *e, XPointer)
+{
+ return e->type == ConfigureNotify || e->type == Expose;
+}
+
+Q_GUI_EXPORT void qt_x11_wait_for_window_manager(QWidget* w)
+{
+ if (!w || (!w->isWindow() && !w->internalWinId()))
+ return;
+ QApplication::flush();
+ XEvent ev;
+ QTime t;
+ t.start();
+ static const int maximumWaitTime = 2000;
+ if (!w->testAttribute(Qt::WA_WState_Created))
+ return;
+
+ if (!(w->windowFlags() & Qt::X11BypassWindowManagerHint)) {
+ // if the window is not override-redirect, then the window manager
+ // will reparent us to the frame decoration window.
+ while (!XCheckTypedWindowEvent(X11->display, w->effectiveWinId(), ReparentNotify, &ev)) {
+ if (t.elapsed() > maximumWaitTime)
+ return;
+ qApp->syncX(); // non-busy wait
+ }
+ }
+
+ while (!XCheckTypedWindowEvent(X11->display, w->effectiveWinId(), MapNotify, &ev)) {
+ if (t.elapsed() > maximumWaitTime)
+ return;
+ qApp->syncX(); // non-busy wait
+ }
+
+ qApp->x11ProcessEvent(&ev);
+
+ // ok, seems like the window manager successfully reparented us, we'll wait
+ // for the first paint event to arrive, while handling ConfigureNotify in
+ // the arrival order
+ while(1)
+ {
+ if (XCheckIfEvent(X11->display, &ev, checkForConfigureAndExpose, 0)) {
+ qApp->x11ProcessEvent(&ev);
+ if (ev.type == Expose)
+ return;
+ }
+ if (t.elapsed() > maximumWaitTime)
+ return;
+ qApp->syncX(); // non-busy wait
+ }
+}
+
+void qt_change_net_wm_state(const QWidget* w, bool set, Atom one, Atom two = 0)
+{
+ if (!w->isVisible()) // not managed by the window manager
+ return;
+
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = ATOM(_NET_WM_STATE);
+ e.xclient.display = X11->display;
+ e.xclient.window = w->internalWinId();
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = set ? 1 : 0;
+ e.xclient.data.l[1] = one;
+ e.xclient.data.l[2] = two;
+ e.xclient.data.l[3] = 0;
+ e.xclient.data.l[4] = 0;
+ XSendEvent(X11->display, RootWindow(X11->display, w->x11Info().screen()),
+ false, (SubstructureNotifyMask | SubstructureRedirectMask), &e);
+}
+
+struct QX11WindowAttributes {
+ const XWindowAttributes *att;
+};
+
+void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const XWindowAttributes &a)
+{
+ QX11WindowAttributes att;
+ att.att = &a;
+ qt_x11_getX11InfoForWindow(xinfo,att);
+}
+
+
+static QVector<Atom> getNetWmState(QWidget *w)
+{
+ QVector<Atom> returnValue;
+
+ // Don't read anything, just get the size of the property data
+ Atom actualType;
+ int actualFormat;
+ ulong propertyLength;
+ ulong bytesLeft;
+ uchar *propertyData = 0;
+ if (XGetWindowProperty(X11->display, w->internalWinId(), ATOM(_NET_WM_STATE), 0, 0,
+ False, XA_ATOM, &actualType, &actualFormat,
+ &propertyLength, &bytesLeft, &propertyData) == Success
+ && actualType == XA_ATOM && actualFormat == 32) {
+ returnValue.resize(bytesLeft / 4);
+ XFree((char*) propertyData);
+
+ // fetch all data
+ if (XGetWindowProperty(X11->display, w->internalWinId(), ATOM(_NET_WM_STATE), 0,
+ returnValue.size(), False, XA_ATOM, &actualType, &actualFormat,
+ &propertyLength, &bytesLeft, &propertyData) != Success) {
+ returnValue.clear();
+ } else if (propertyLength != (ulong)returnValue.size()) {
+ returnValue.resize(propertyLength);
+ }
+
+ // put it into netWmState
+ if (!returnValue.isEmpty()) {
+ memcpy(returnValue.data(), propertyData, returnValue.size() * sizeof(Atom));
+ }
+ XFree((char*) propertyData);
+ }
+
+ return returnValue;
+}
+
+void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
+{
+ Q_Q(QWidget);
+ Qt::WindowType type = q->windowType();
+ Qt::WindowFlags &flags = data.window_flags;
+ QWidget *parentWidget = q->parentWidget();
+
+ if (type == Qt::ToolTip)
+ flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint;
+ if (type == Qt::Popup)
+ flags |= Qt::X11BypassWindowManagerHint;
+
+ bool topLevel = (flags & Qt::Window);
+ bool popup = (type == Qt::Popup);
+ bool dialog = (type == Qt::Dialog
+ || type == Qt::Sheet);
+ bool desktop = (type == Qt::Desktop);
+ bool tool = (type == Qt::Tool || type == Qt::SplashScreen
+ || type == Qt::ToolTip || type == Qt::Drawer);
+
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::create_sys START:" << q << "topLevel?" << topLevel << "WId:"
+ << window << "initializeWindow:" << initializeWindow << "destroyOldWindow" << destroyOldWindow;
+#endif
+ if (topLevel) {
+ if (parentWidget) { // if our parent stays on top, so must we
+ QWidget *ptl = parentWidget->window();
+ if(ptl && (ptl->windowFlags() & Qt::WindowStaysOnTopHint))
+ flags |= Qt::WindowStaysOnTopHint;
+ }
+
+ if (type == Qt::SplashScreen) {
+ if (X11->isSupportedByWM(ATOM(_NET_WM_WINDOW_TYPE_SPLASH))) {
+ flags &= ~Qt::X11BypassWindowManagerHint;
+ } else {
+ flags |= Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint;
+ }
+ }
+ // All these buttons depend on the system menu, so we enable it
+ if (flags & (Qt::WindowMinimizeButtonHint
+ | Qt::WindowMaximizeButtonHint
+ | Qt::WindowContextHelpButtonHint))
+ flags |= Qt::WindowSystemMenuHint;
+ }
+
+
+ Window parentw, destroyw = 0;
+ WId id = 0;
+
+ // always initialize
+ if (!window)
+ initializeWindow = true;
+
+ QX11Info *parentXinfo = parentWidget ? &parentWidget->d_func()->xinfo : 0;
+
+ if (desktop &&
+ qt_x11_create_desktop_on_screen >= 0 &&
+ qt_x11_create_desktop_on_screen != xinfo.screen()) {
+ // desktop on a certain screen other than the default requested
+ QX11InfoData *xd = &X11->screens[qt_x11_create_desktop_on_screen];
+ xinfo.setX11Data(xd);
+ } else if (parentXinfo && (parentXinfo->screen() != xinfo.screen()
+ || parentXinfo->visual() != xinfo.visual()))
+ {
+ xinfo = *parentXinfo;
+ }
+
+ //get display, screen number, root window and desktop geometry for
+ //the current screen
+ Display *dpy = X11->display;
+ int scr = xinfo.screen();
+ Window root_win = RootWindow(dpy, scr);
+ int sw = DisplayWidth(dpy,scr);
+ int sh = DisplayHeight(dpy,scr);
+
+ if (desktop) { // desktop widget
+ dialog = popup = false; // force these flags off
+ data.crect.setRect(0, 0, sw, sh);
+ } else if (topLevel && !q->testAttribute(Qt::WA_Resized)) {
+ QDesktopWidget *desktopWidget = qApp->desktop();
+ if (desktopWidget->isVirtualDesktop()) {
+ QRect r = desktopWidget->screenGeometry();
+ sw = r.width();
+ sh = r.height();
+ }
+
+ int width = sw / 2;
+ int height = 4 * sh / 10;
+ if (extra) {
+ width = qMax(qMin(width, extra->maxw), extra->minw);
+ height = qMax(qMin(height, extra->maxh), extra->minh);
+ }
+ data.crect.setSize(QSize(width, height));
+ }
+
+ parentw = topLevel ? root_win : parentWidget->effectiveWinId();
+
+ XSetWindowAttributes wsa;
+
+ if (window) { // override the old window
+ if (destroyOldWindow) {
+ if (topLevel)
+ X11->dndEnable(q, false);
+ destroyw = data.winid;
+ }
+ id = window;
+ setWinId(window);
+ XWindowAttributes a;
+ XGetWindowAttributes(dpy, window, &a);
+ data.crect.setRect(a.x, a.y, a.width, a.height);
+
+ if (a.map_state == IsUnmapped)
+ q->setAttribute(Qt::WA_WState_Visible, false);
+ else
+ q->setAttribute(Qt::WA_WState_Visible);
+
+ qt_x11_getX11InfoForWindow(&xinfo,a);
+
+ } else if (desktop) { // desktop widget
+#ifdef QWIDGET_EXTRA_DEBUG
+ qDebug() << "create desktop";
+#endif
+ id = (WId)parentw; // id = root window
+// QWidget *otherDesktop = find(id); // is there another desktop?
+// if (otherDesktop && otherDesktop->testWFlags(Qt::WPaintDesktop)) {
+// otherDesktop->d->setWinId(0); // remove id from widget mapper
+// d->setWinId(id); // make sure otherDesktop is
+// otherDesktop->d->setWinId(id); // found first
+// } else {
+ setWinId(id);
+// }
+ } else if (topLevel || q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) {
+#ifdef QWIDGET_EXTRA_DEBUG
+ static int topLevels = 0;
+ static int children = 0;
+ if (parentw == root_win)
+ qDebug() << "create toplevel" << ++topLevels;
+ else
+ qDebug() << "create child" << ++children;
+#endif
+ QRect safeRect = data.crect; //##### must handle huge sizes as well.... i.e. wrect
+ if (safeRect.width() < 1|| safeRect.height() < 1) {
+ if (topLevel) {
+ // top-levels must be at least 1x1
+ safeRect.setSize(safeRect.size().expandedTo(QSize(1, 1)));
+ } else {
+ // create it way off screen, and rely on
+ // setWSGeometry() to do the right thing with it later
+ safeRect = QRect(-1000,-1000,1,1);
+ }
+ }
+#ifndef QT_NO_XRENDER
+ int screen = xinfo.screen();
+ if (topLevel && X11->use_xrender
+ && xinfo.depth() != 32 && X11->argbVisuals[screen]
+ && q->testAttribute(Qt::WA_TranslucentBackground))
+ {
+ QX11InfoData *xd = xinfo.getX11Data(true);
+
+ xd->screen = screen;
+ xd->visual = X11->argbVisuals[screen];
+ xd->colormap = X11->argbColormaps[screen];
+ xd->depth = 32;
+ xd->defaultVisual = false;
+ xd->defaultColormap = false;
+ xd->cells = xd->visual->map_entries;
+ xinfo.setX11Data(xd);
+ }
+#endif
+ if (xinfo.defaultVisual() && xinfo.defaultColormap()) {
+ id = (WId)qt_XCreateSimpleWindow(q, dpy, parentw,
+ safeRect.left(), safeRect.top(),
+ safeRect.width(), safeRect.height(),
+ 0,
+ BlackPixel(dpy, xinfo.screen()),
+ WhitePixel(dpy, xinfo.screen()));
+ } else {
+ wsa.background_pixel = WhitePixel(dpy, xinfo.screen());
+ wsa.border_pixel = BlackPixel(dpy, xinfo.screen());
+ wsa.colormap = xinfo.colormap();
+ id = (WId)qt_XCreateWindow(q, dpy, parentw,
+ safeRect.left(), safeRect.top(),
+ safeRect.width(), safeRect.height(),
+ 0, xinfo.depth(), InputOutput,
+ (Visual *) xinfo.visual(),
+ CWBackPixel|CWBorderPixel|CWColormap,
+ &wsa);
+ }
+
+ setWinId(id); // set widget id/handle + hd
+ }
+
+#ifndef QT_NO_XRENDER
+ if (picture) {
+ XRenderFreePicture(X11->display, picture);
+ picture = 0;
+ }
+
+ if (X11->use_xrender && !desktop && q->internalWinId()) {
+ XRenderPictFormat *format = XRenderFindVisualFormat(dpy, (Visual *) xinfo.visual());
+ if (format)
+ picture = XRenderCreatePicture(dpy, id, format, 0, 0);
+ }
+#endif // QT_NO_XRENDER
+
+ QtMWMHints mwmhints;
+ mwmhints.flags = 0L;
+ mwmhints.functions = 0L;
+ mwmhints.decorations = 0;
+ mwmhints.input_mode = 0L;
+ mwmhints.status = 0L;
+
+ if (topLevel) {
+ ulong wsa_mask = 0;
+ if (type != Qt::SplashScreen) { // && customize) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+
+ bool customize = flags & Qt::CustomizeWindowHint;
+ if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) {
+ mwmhints.decorations |= MWM_DECOR_BORDER;
+ mwmhints.decorations |= MWM_DECOR_RESIZEH;
+
+ if (flags & Qt::WindowTitleHint)
+ mwmhints.decorations |= MWM_DECOR_TITLE;
+
+ if (flags & Qt::WindowSystemMenuHint)
+ mwmhints.decorations |= MWM_DECOR_MENU;
+
+ if (flags & Qt::WindowMinimizeButtonHint) {
+ mwmhints.decorations |= MWM_DECOR_MINIMIZE;
+ mwmhints.functions |= MWM_FUNC_MINIMIZE;
+ }
+
+ if (flags & Qt::WindowMaximizeButtonHint) {
+ mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
+ mwmhints.functions |= MWM_FUNC_MAXIMIZE;
+ }
+
+ if (flags & Qt::WindowCloseButtonHint)
+ mwmhints.functions |= MWM_FUNC_CLOSE;
+ }
+ } else {
+ // if type == Qt::SplashScreen
+ mwmhints.decorations = MWM_DECOR_ALL;
+ }
+
+ if (tool) {
+ wsa.save_under = True;
+ wsa_mask |= CWSaveUnder;
+ }
+
+ if (flags & Qt::X11BypassWindowManagerHint) {
+ wsa.override_redirect = True;
+ wsa_mask |= CWOverrideRedirect;
+ }
+
+ if (wsa_mask && initializeWindow) {
+ Q_ASSERT(id);
+ XChangeWindowAttributes(dpy, id, wsa_mask, &wsa);
+ }
+
+ if (mwmhints.functions != 0) {
+ mwmhints.flags |= MWM_HINTS_FUNCTIONS;
+ mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
+ } else {
+ mwmhints.functions = MWM_FUNC_ALL;
+ }
+
+ if (!(flags & Qt::FramelessWindowHint)
+ && flags & Qt::CustomizeWindowHint
+ && flags & Qt::WindowTitleHint
+ && !(flags &
+ (Qt::WindowMinimizeButtonHint
+ | Qt::WindowMaximizeButtonHint
+ | Qt::WindowCloseButtonHint))) {
+ // a special case - only the titlebar without any button
+ mwmhints.flags = MWM_HINTS_FUNCTIONS;
+ mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
+ mwmhints.decorations = 0;
+ }
+ }
+
+ if (!initializeWindow) {
+ // do no initialization
+ } else if (popup) { // popup widget
+ // set EWMH window types
+ setNetWmWindowTypes();
+
+ wsa.override_redirect = True;
+ wsa.save_under = True;
+ Q_ASSERT(id);
+ XChangeWindowAttributes(dpy, id, CWOverrideRedirect | CWSaveUnder,
+ &wsa);
+ } else if (topLevel && !desktop) { // top-level widget
+ if (!X11->wm_client_leader)
+ create_wm_client_leader();
+
+ // note: WM_TRANSIENT_FOR is set in QWidgetPrivate::show_sys()
+
+ XSizeHints size_hints;
+ size_hints.flags = USSize | PSize | PWinGravity;
+ size_hints.x = data.crect.left();
+ size_hints.y = data.crect.top();
+ size_hints.width = data.crect.width();
+ size_hints.height = data.crect.height();
+ size_hints.win_gravity =
+ QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
+
+ XWMHints wm_hints; // window manager hints
+ memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
+ wm_hints.flags = InputHint | StateHint | WindowGroupHint;
+ wm_hints.input = True;
+ wm_hints.initial_state = NormalState;
+ wm_hints.window_group = X11->wm_client_leader;
+
+ XClassHint class_hint;
+ QByteArray appName = qAppName().toLatin1();
+ class_hint.res_name = appName.data(); // application name
+ class_hint.res_class = const_cast<char *>(QX11Info::appClass()); // application class
+
+ XSetWMProperties(dpy, id, 0, 0,
+ qApp->d_func()->argv, qApp->d_func()->argc,
+ &size_hints, &wm_hints, &class_hint);
+
+ XResizeWindow(dpy, id,
+ qBound(1, data.crect.width(), XCOORD_MAX),
+ qBound(1, data.crect.height(), XCOORD_MAX));
+ XStoreName(dpy, id, appName.data());
+ Atom protocols[5];
+ int n = 0;
+ protocols[n++] = ATOM(WM_DELETE_WINDOW); // support del window protocol
+ protocols[n++] = ATOM(WM_TAKE_FOCUS); // support take focus window protocol
+ protocols[n++] = ATOM(_NET_WM_PING); // support _NET_WM_PING protocol
+#ifndef QT_NO_XSYNC
+ protocols[n++] = ATOM(_NET_WM_SYNC_REQUEST); // support _NET_WM_SYNC_REQUEST protocol
+#endif // QT_NO_XSYNC
+ if (flags & Qt::WindowContextHelpButtonHint)
+ protocols[n++] = ATOM(_NET_WM_CONTEXT_HELP);
+ XSetWMProtocols(dpy, id, protocols, n);
+
+ // set mwm hints
+ SetMWMHints(dpy, id, mwmhints);
+
+ // set EWMH window types
+ setNetWmWindowTypes();
+
+ // set _NET_WM_PID
+ long curr_pid = getpid();
+ XChangeProperty(dpy, id, ATOM(_NET_WM_PID), XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) &curr_pid, 1);
+
+ // when we create a toplevel widget, the frame strut should be dirty
+ data.fstrut_dirty = 1;
+
+ // declare the widget's window role
+ if (QTLWExtra *topData = maybeTopData()) {
+ if (!topData->role.isEmpty()) {
+ QByteArray windowRole = topData->role.toUtf8();
+ XChangeProperty(dpy, id,
+ ATOM(WM_WINDOW_ROLE), XA_STRING, 8, PropModeReplace,
+ (unsigned char *)windowRole.constData(), windowRole.length());
+ }
+ }
+
+ // set client leader property
+ XChangeProperty(dpy, id, ATOM(WM_CLIENT_LEADER),
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)&X11->wm_client_leader, 1);
+ } else {
+ // non-toplevel widgets don't have a frame, so no need to
+ // update the strut
+ data.fstrut_dirty = 0;
+ }
+
+ if (initializeWindow && q->internalWinId()) {
+ // don't erase when resizing
+ wsa.bit_gravity = QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
+ Q_ASSERT(id);
+ XChangeWindowAttributes(dpy, id, CWBitGravity, &wsa);
+ }
+
+ // set X11 event mask
+ if (desktop) {
+// QWidget* main_desktop = find(id);
+// if (main_desktop->testWFlags(Qt::WPaintDesktop))
+// XSelectInput(dpy, id, stdDesktopEventMask | ExposureMask);
+// else
+ XSelectInput(dpy, id, stdDesktopEventMask);
+ } else if (q->internalWinId()) {
+ XSelectInput(dpy, id, stdWidgetEventMask);
+#if !defined (QT_NO_TABLET)
+ QTabletDeviceDataList *tablet_list = qt_tablet_devices();
+ if (X11->ptrXSelectExtensionEvent) {
+ for (int i = 0; i < tablet_list->size(); ++i) {
+ QTabletDeviceData tablet = tablet_list->at(i);
+ X11->ptrXSelectExtensionEvent(dpy, id, reinterpret_cast<XEventClass*>(tablet.eventList),
+ tablet.eventCount);
+ }
+ }
+#endif
+ }
+
+ if (desktop) {
+ q->setAttribute(Qt::WA_WState_Visible);
+ } else if (topLevel) { // set X cursor
+ if (initializeWindow) {
+ qt_x11_enforce_cursor(q);
+
+ if (QTLWExtra *topData = maybeTopData())
+ if (!topData->caption.isEmpty())
+ setWindowTitle_helper(topData->caption);
+
+ //always enable dnd: it's not worth the effort to maintain the state
+ // NOTE: this always creates topData()
+ X11->dndEnable(q, true);
+
+ if (maybeTopData() && maybeTopData()->opacity != 255)
+ q->setWindowOpacity(maybeTopData()->opacity/255.);
+
+ }
+ } else if (q->testAttribute(Qt::WA_SetCursor) && q->internalWinId()) {
+ qt_x11_enforce_cursor(q);
+ }
+
+ if (extra && !extra->mask.isEmpty() && q->internalWinId())
+ XShapeCombineRegion(X11->display, q->internalWinId(), ShapeBounding, 0, 0,
+ extra->mask.handle(), ShapeSet);
+
+ if (q->hasFocus() && q->testAttribute(Qt::WA_InputMethodEnabled)) {
+ QInputContext *inputContext = q->inputContext();
+ if (inputContext)
+ inputContext->setFocusWidget(q);
+ }
+
+ if (destroyw)
+ qt_XDestroyWindow(q, dpy, destroyw);
+
+ // newly created windows are positioned at the window system's
+ // (0,0) position. If the parent uses wrect mapping to expand the
+ // coordinate system, we must also adjust this widget's window
+ // system position
+ if (!topLevel && !parentWidget->data->wrect.topLeft().isNull())
+ setWSGeometry();
+ else if (topLevel && (data.crect.width() == 0 || data.crect.height() == 0))
+ q->setAttribute(Qt::WA_OutsideWSRange, true);
+
+ if (!topLevel && q->testAttribute(Qt::WA_NativeWindow) && q->testAttribute(Qt::WA_Mapped)) {
+ Q_ASSERT(q->internalWinId());
+ XMapWindow(X11->display, q->internalWinId());
+ // Ensure that mapped alien widgets are flushed immediately when re-created as native widgets.
+ if (QWindowSurface *surface = q->windowSurface())
+ surface->flush(q, q->rect(), q->mapTo(surface->window(), QPoint()));
+ }
+
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::create_sys END:" << q;
+#endif
+}
+
+static void qt_x11_recreateWidget(QWidget *widget)
+{
+ if (widget->inherits("QGLWidget")) {
+ // We send QGLWidgets a ParentChange event which causes them to
+ // recreate their GL context, which in turn causes them to choose
+ // their visual again. Now that WA_TranslucentBackground is set,
+ // QGLContext::chooseVisual will select an ARGB visual.
+ QEvent e(QEvent::ParentChange);
+ QApplication::sendEvent(widget, &e);
+ } else {
+ // For regular widgets, reparent them with their parent which
+ // also triggers a recreation of the native window
+ QPoint pos = widget->pos();
+ bool visible = widget->isVisible();
+ if (visible)
+ widget->hide();
+
+ widget->setParent(widget->parentWidget(), widget->windowFlags());
+ widget->move(pos);
+ if (visible)
+ widget->show();
+ }
+}
+
+static void qt_x11_recreateNativeWidgetsRecursive(QWidget *widget)
+{
+ if (widget->internalWinId())
+ qt_x11_recreateWidget(widget);
+
+ const QObjectList &children = widget->children();
+ for (int i = 0; i < children.size(); ++i) {
+ QWidget *child = qobject_cast<QWidget*>(children.at(i));
+ if (child)
+ qt_x11_recreateNativeWidgetsRecursive(child);
+ }
+}
+
+void QWidgetPrivate::x11UpdateIsOpaque()
+{
+#ifndef QT_NO_XRENDER
+ Q_Q(QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
+ return;
+
+ bool topLevel = (data.window_flags & Qt::Window);
+ int screen = xinfo.screen();
+ if (topLevel && X11->use_xrender
+ && X11->argbVisuals[screen] && xinfo.depth() != 32)
+ {
+ qt_x11_recreateNativeWidgetsRecursive(q);
+ }
+#endif
+}
+
+/*
+ Returns true if the background is inherited; otherwise returns
+ false.
+
+ Mainly used in the paintOnScreen case.
+*/
+bool QWidgetPrivate::isBackgroundInherited() const
+{
+ Q_Q(const QWidget);
+
+ // windows do not inherit their background
+ if (q->isWindow() || q->windowType() == Qt::SubWindow)
+ return false;
+
+ if (q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_OpaquePaintEvent))
+ return false;
+
+ const QPalette &pal = q->palette();
+ QPalette::ColorRole bg = q->backgroundRole();
+ QBrush brush = pal.brush(bg);
+
+ // non opaque brushes leaves us no choice, we must inherit
+ if (!q->autoFillBackground() || !brush.isOpaque())
+ return true;
+
+ if (brush.style() == Qt::SolidPattern) {
+ // the background is just a solid color. If there is no
+ // propagated contents, then we claim as performance
+ // optimization that it was not inheritet. This is the normal
+ // case in standard Windows or Motif style.
+ const QWidget *w = q->parentWidget();
+ if (!w->d_func()->isBackgroundInherited())
+ return false;
+ }
+
+ return true;
+}
+
+void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
+{
+ Q_D(QWidget);
+ if (!isWindow() && parentWidget())
+ parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
+ d->deactivateWidgetCleanup();
+ if (testAttribute(Qt::WA_WState_Created)) {
+ setAttribute(Qt::WA_WState_Created, false);
+ QObjectList childList = children();
+ for (int i = 0; i < childList.size(); ++i) { // destroy all widget children
+ register QObject *obj = childList.at(i);
+ if (obj->isWidgetType())
+ static_cast<QWidget*>(obj)->destroy(destroySubWindows,
+ destroySubWindows);
+ }
+ if (QWidgetPrivate::mouseGrabber == this)
+ releaseMouse();
+ if (QWidgetPrivate::keyboardGrabber == this)
+ releaseKeyboard();
+ if (isWindow())
+ X11->deferred_map.removeAll(this);
+ if (isModal()) {
+ // just be sure we leave modal
+ QApplicationPrivate::leaveModal(this);
+ }
+ else if ((windowType() == Qt::Popup))
+ qApp->d_func()->closePopup(this);
+
+#ifndef QT_NO_XRENDER
+ if (d->picture) {
+ if (destroyWindow)
+ XRenderFreePicture(X11->display, d->picture);
+ d->picture = 0;
+ }
+#endif // QT_NO_XRENDER
+
+ // delete the _NET_WM_USER_TIME_WINDOW
+ qt_net_remove_user_time(this);
+
+ if ((windowType() == Qt::Desktop)) {
+ if (acceptDrops())
+ X11->dndEnable(this, false);
+ } else {
+ if (isWindow())
+ X11->dndEnable(this, false);
+ if (destroyWindow)
+ qt_XDestroyWindow(this, X11->display, data->winid);
+ }
+ QT_TRY {
+ d->setWinId(0);
+ } QT_CATCH (const std::bad_alloc &) {
+ // swallow - destructors must not throw
+ }
+
+ extern void qPRCleanup(QWidget *widget); // from qapplication_x11.cpp
+ if (testAttribute(Qt::WA_WState_Reparented))
+ qPRCleanup(this);
+
+ if(d->ic) {
+ delete d->ic;
+ } else {
+ // release previous focus information participating with
+ // preedit preservation of qic
+ QInputContext *qic = inputContext();
+ if (qic)
+ qic->widgetDestroyed(this);
+ }
+ }
+}
+
+void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
+{
+ Q_Q(QWidget);
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::setParent_sys START" << q << "parent:" << parent;
+#endif
+ QX11Info old_xinfo = xinfo;
+ if (parent && parent->windowType() == Qt::Desktop) {
+ // make sure the widget is created on the same screen as the
+ // programmer specified desktop widget
+ xinfo = parent->d_func()->xinfo;
+ parent = 0;
+ }
+
+ QTLWExtra *topData = maybeTopData();
+ bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
+ if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
+ extern void qPRCreate(const QWidget *, Window);
+#ifndef QT_NO_CURSOR
+ QCursor oldcurs;
+#endif
+
+ // dnd unregister (we will register again below)
+ if (q->testAttribute(Qt::WA_DropSiteRegistered))
+ q->setAttribute(Qt::WA_DropSiteRegistered, false);
+
+ // if we are a top then remove our dnd prop for now
+ // it will get rest later
+ if (q->isWindow() && wasCreated)
+ X11->dndEnable(q, false);
+
+ if (topData)
+ qt_net_remove_user_time(q);
+
+// QWidget *oldparent = q->parentWidget();
+ WId old_winid = wasCreated ? data.winid : 0;
+ if ((q->windowType() == Qt::Desktop))
+ old_winid = 0;
+ setWinId(0);
+
+#ifndef QT_NO_XRENDER
+ if (picture) {
+ XRenderFreePicture(X11->display, picture);
+ picture = 0;
+ }
+#endif
+
+ // hide and reparent our own window away. Otherwise we might get
+ // destroyed when emitting the child remove event below. See QWorkspace.
+ if (wasCreated && old_winid) {
+ XUnmapWindow(X11->display, old_winid);
+ if (!old_xinfo.screen() != xinfo.screen())
+ XReparentWindow(X11->display, old_winid, RootWindow(X11->display, xinfo.screen()), 0, 0);
+ }
+ if (topData) {
+ topData->parentWinId = 0;
+ // zero the frame strut and mark it dirty
+ topData->frameStrut.setCoords(0, 0, 0, 0);
+
+ // reparenting from top-level, make sure show() works again
+ topData->waitingForMapNotify = 0;
+ topData->validWMState = 0;
+ }
+ data.fstrut_dirty = (!parent || (f & Qt::Window)); // toplevels get a dirty framestrut
+
+ QObjectPrivate::setParent_helper(parent);
+ bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
+
+ data.window_flags = f;
+ q->setAttribute(Qt::WA_WState_Created, false);
+ q->setAttribute(Qt::WA_WState_Visible, false);
+ q->setAttribute(Qt::WA_WState_Hidden, false);
+ adjustFlags(data.window_flags, q);
+ // keep compatibility with previous versions, we need to preserve the created state
+ // (but we recreate the winId for the widget being reparented, again for compatibility)
+ if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created)))
+ createWinId();
+ if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
+ q->setAttribute(Qt::WA_WState_Hidden);
+ q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
+
+ if (wasCreated) {
+ QObjectList chlist = q->children();
+ for (int i = 0; i < chlist.size(); ++i) { // reparent children
+ QObject *obj = chlist.at(i);
+ if (obj->isWidgetType()) {
+ QWidget *w = (QWidget *)obj;
+ if (!w->testAttribute(Qt::WA_WState_Created))
+ continue;
+ if (xinfo.screen() != w->d_func()->xinfo.screen()) {
+ // ### force setParent() to not shortcut out (because
+ // ### we're setting the parent to the current parent)
+ // ### setParent will add child back to the list
+ // ### of children so we need to make sure the
+ // ### widget won't be added twice.
+ w->d_func()->parent = 0;
+ this->children.removeOne(w);
+ w->setParent(q);
+ } else if (!w->isWindow()) {
+ w->d_func()->invalidateBuffer(w->rect());
+ if (w->internalWinId()) {
+ if (w->testAttribute(Qt::WA_NativeWindow)) {
+ QWidget *nativeParentWidget = w->nativeParentWidget();
+ // Qt::WA_NativeWindow ensures that we always have a nativeParentWidget
+ Q_ASSERT(nativeParentWidget != 0);
+ QPoint p = w->mapTo(nativeParentWidget, QPoint());
+ XReparentWindow(X11->display,
+ w->internalWinId(),
+ nativeParentWidget->internalWinId(),
+ p.x(), p.y());
+ } else {
+ w->d_func()->setParent_sys(q, w->data->window_flags);
+ }
+ }
+ } else if (isTransient(w)) {
+ /*
+ when reparenting toplevel windows with toplevel-transient children,
+ we need to make sure that the window manager gets the updated
+ WM_TRANSIENT_FOR information... unfortunately, some window managers
+ don't handle changing WM_TRANSIENT_FOR before the toplevel window is
+ visible, so we unmap and remap all toplevel-transient children *after*
+ the toplevel parent has been mapped. thankfully, this is easy in Qt :)
+
+ note that the WM_TRANSIENT_FOR hint is actually updated in
+ QWidgetPrivate::show_sys()
+ */
+ if (w->internalWinId())
+ XUnmapWindow(X11->display, w->internalWinId());
+ QApplication::postEvent(w, new QEvent(QEvent::ShowWindowRequest));
+ }
+ }
+ }
+ qPRCreate(q, old_winid);
+ updateSystemBackground();
+
+ if (old_winid) {
+ Window *cmwret;
+ int count;
+ if (XGetWMColormapWindows(X11->display, old_winid, &cmwret, &count)) {
+ Window *cmw;
+ int cmw_size = sizeof(Window)*count;
+ cmw = new Window[count];
+ memcpy((char *)cmw, (char *)cmwret, cmw_size);
+ XFree((char *)cmwret);
+ int i;
+ for (i=0; i<count; i++) {
+ if (cmw[i] == old_winid) {
+ cmw[i] = q->internalWinId();
+ break;
+ }
+ }
+ int top_count;
+ if (XGetWMColormapWindows(X11->display, q->window()->internalWinId(),
+ &cmwret, &top_count))
+ {
+ Window *merged_cmw = new Window[count + top_count];
+ memcpy((char *)merged_cmw, (char *)cmw, cmw_size);
+ memcpy((char *)merged_cmw + cmw_size, (char *)cmwret, sizeof(Window)*top_count);
+ delete [] cmw;
+ XFree((char *)cmwret);
+ cmw = merged_cmw;
+ count += top_count;
+ }
+
+ XSetWMColormapWindows(X11->display, q->window()->internalWinId(), cmw, count);
+ delete [] cmw;
+ }
+
+ qt_XDestroyWindow(q, X11->display, old_winid);
+ }
+ }
+
+ // check if we need to register our dropsite
+ if (q->testAttribute(Qt::WA_AcceptDrops)
+ || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))) {
+ q->setAttribute(Qt::WA_DropSiteRegistered, true);
+ }
+#if !defined(QT_NO_IM)
+ ic = 0;
+#endif
+ invalidateBuffer(q->rect());
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::setParent_sys END" << q;
+#endif
+}
+
+
+QPoint QWidget::mapToGlobal(const QPoint &pos) const
+{
+ Q_D(const QWidget);
+ if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
+ QPoint p = pos + data->crect.topLeft();
+ //cannot trust that !isWindow() implies parentWidget() before create
+ return (isWindow() || !parentWidget()) ? p : parentWidget()->mapToGlobal(p);
+ }
+ int x, y;
+ Window child;
+ QPoint p = d->mapToWS(pos);
+ XTranslateCoordinates(X11->display, internalWinId(),
+ QApplication::desktop()->screen(d->xinfo.screen())->internalWinId(),
+ p.x(), p.y(), &x, &y, &child);
+ return QPoint(x, y);
+}
+
+
+QPoint QWidget::mapFromGlobal(const QPoint &pos) const
+{
+ Q_D(const QWidget);
+ if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
+ //cannot trust that !isWindow() implies parentWidget() before create
+ QPoint p = (isWindow() || !parentWidget()) ? pos : parentWidget()->mapFromGlobal(pos);
+ return p - data->crect.topLeft();
+ }
+ int x, y;
+ Window child;
+ XTranslateCoordinates(X11->display,
+ QApplication::desktop()->screen(d->xinfo.screen())->internalWinId(),
+ internalWinId(), pos.x(), pos.y(), &x, &y, &child);
+ return d->mapFromWS(QPoint(x, y));
+}
+
+void QWidgetPrivate::updateSystemBackground()
+{
+ Q_Q(QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created) || !q->internalWinId())
+ return;
+ QBrush brush = q->palette().brush(QPalette::Active, q->backgroundRole());
+ Qt::WindowType type = q->windowType();
+ if (brush.style() == Qt::NoBrush
+ || q->testAttribute(Qt::WA_NoSystemBackground)
+ || q->testAttribute(Qt::WA_UpdatesDisabled)
+ || type == Qt::Popup || type == Qt::ToolTip
+ )
+ XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), XNone);
+ else if (brush.style() == Qt::SolidPattern && brush.isOpaque())
+ XSetWindowBackground(X11->display, q->internalWinId(),
+ QColormap::instance(xinfo.screen()).pixel(brush.color()));
+ else if (isBackgroundInherited())
+ XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), ParentRelative);
+ else if (brush.style() == Qt::TexturePattern) {
+ extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap); // qpixmap_x11.cpp
+ XSetWindowBackgroundPixmap(X11->display, q->internalWinId(),
+ static_cast<QX11PixmapData*>(qt_toX11Pixmap(brush.texture()).data.data())->x11ConvertToDefaultDepth());
+ } else
+ XSetWindowBackground(X11->display, q->internalWinId(),
+ QColormap::instance(xinfo.screen()).pixel(brush.color()));
+}
+
+#ifndef QT_NO_CURSOR
+void QWidgetPrivate::setCursor_sys(const QCursor &)
+{
+ Q_Q(QWidget);
+ qt_x11_enforce_cursor(q);
+ XFlush(X11->display);
+}
+
+void QWidgetPrivate::unsetCursor_sys()
+{
+ Q_Q(QWidget);
+ qt_x11_enforce_cursor(q);
+ XFlush(X11->display);
+}
+#endif
+
+static XTextProperty*
+qstring_to_xtp(const QString& s)
+{
+ static XTextProperty tp = { 0, 0, 0, 0 };
+ static bool free_prop = true; // we can't free tp.value in case it references
+ // the data of the static QCString below.
+ if (tp.value) {
+ if (free_prop)
+ XFree(tp.value);
+ tp.value = 0;
+ free_prop = true;
+ }
+
+ static const QTextCodec* mapper = QTextCodec::codecForLocale();
+ int errCode = 0;
+ if (mapper) {
+ QByteArray mapped = mapper->fromUnicode(s);
+ char* tl[2];
+ tl[0] = mapped.data();
+ tl[1] = 0;
+ errCode = XmbTextListToTextProperty(X11->display, tl, 1, XStdICCTextStyle, &tp);
+#if defined(QT_DEBUG)
+ if (errCode < 0)
+ qDebug("qstring_to_xtp result code %d", errCode);
+#endif
+ }
+ if (!mapper || errCode < 0) {
+ static QByteArray qcs;
+ qcs = s.toAscii();
+ tp.value = (uchar*)qcs.data();
+ tp.encoding = XA_STRING;
+ tp.format = 8;
+ tp.nitems = qcs.length();
+ free_prop = false;
+ }
+
+ // ### If we knew WM could understand unicode, we could use
+ // ### a much simpler, cheaper encoding...
+ /*
+ tp.value = (XChar2b*)s.unicode();
+ tp.encoding = XA_UNICODE; // wish
+ tp.format = 16;
+ tp.nitems = s.length();
+ */
+
+ return &tp;
+}
+
+void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (!q->internalWinId())
+ return;
+ XSetWMName(X11->display, q->internalWinId(), qstring_to_xtp(caption));
+
+ QByteArray net_wm_name = caption.toUtf8();
+ XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_NAME), ATOM(UTF8_STRING), 8,
+ PropModeReplace, (unsigned char *)net_wm_name.data(), net_wm_name.size());
+}
+
+void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
+{
+ Q_Q(QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created))
+ return;
+ QTLWExtra *topData = this->topData();
+ if (topData->iconPixmap && !forceReset)
+ // already been set
+ return;
+
+ // preparing images to set the _NET_WM_ICON property
+ QIcon icon = q->windowIcon();
+ QVector<long> icon_data;
+ Qt::HANDLE pixmap_handle = 0;
+ if (!icon.isNull()) {
+ QList<QSize> availableSizes = icon.availableSizes();
+ if(availableSizes.isEmpty()) {
+ // try to use default sizes since the icon can be a scalable image like svg.
+ availableSizes.push_back(QSize(16,16));
+ availableSizes.push_back(QSize(32,32));
+ availableSizes.push_back(QSize(64,64));
+ availableSizes.push_back(QSize(128,128));
+ }
+ for(int i = 0; i < availableSizes.size(); ++i) {
+ QSize size = availableSizes.at(i);
+ QPixmap pixmap = icon.pixmap(size);
+ if (!pixmap.isNull()) {
+ QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ int pos = icon_data.size();
+ icon_data.resize(pos + 2 + image.width()*image.height());
+ icon_data[pos++] = image.width();
+ icon_data[pos++] = image.height();
+ if (sizeof(long) == sizeof(quint32)) {
+ memcpy(icon_data.data() + pos, image.scanLine(0), image.numBytes());
+ } else {
+ for (int y = 0; y < image.height(); ++y) {
+ uint *scanLine = reinterpret_cast<uint *>(image.scanLine(y));
+ for (int x = 0; x < image.width(); ++x)
+ icon_data[pos + y*image.width() + x] = scanLine[x];
+ }
+ }
+ }
+ }
+ if (!icon_data.isEmpty()) {
+ extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap);
+ /*
+ if the app is running on an unknown desktop, or it is not
+ using the default visual, convert the icon to 1bpp as stated
+ in the ICCCM section 4.1.2.4; otherwise, create the icon pixmap
+ in the default depth (even though this violates the ICCCM)
+ */
+ if (X11->desktopEnvironment == DE_UNKNOWN
+ || !QX11Info::appDefaultVisual(xinfo.screen())
+ || !QX11Info::appDefaultColormap(xinfo.screen())) {
+ // unknown DE or non-default visual/colormap, use 1bpp bitmap
+ if (!forceReset || !topData->iconPixmap)
+ topData->iconPixmap = new QBitmap(qt_toX11Pixmap(icon.pixmap(QSize(64,64))));
+ pixmap_handle = topData->iconPixmap->handle();
+ } else {
+ // default depth, use a normal pixmap (even though this
+ // violates the ICCCM), since this works on all DEs known to Qt
+ if (!forceReset || !topData->iconPixmap)
+ topData->iconPixmap = new QPixmap(qt_toX11Pixmap(icon.pixmap(QSize(64,64))));
+ pixmap_handle = static_cast<QX11PixmapData*>(topData->iconPixmap->data.data())->x11ConvertToDefaultDepth();
+ }
+ }
+ }
+
+ if (!q->internalWinId())
+ return;
+
+ if (!icon_data.isEmpty()) {
+ XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON), XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) icon_data.data(),
+ icon_data.size());
+ } else {
+ XDeleteProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON));
+ }
+
+ XWMHints *h = XGetWMHints(X11->display, q->internalWinId());
+ XWMHints wm_hints;
+ if (!h) {
+ memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
+ h = &wm_hints;
+ }
+
+ if (pixmap_handle) {
+ h->icon_pixmap = pixmap_handle;
+ h->flags |= IconPixmapHint;
+ } else {
+ h->icon_pixmap = 0;
+ h->flags &= ~(IconPixmapHint | IconMaskHint);
+ }
+
+ XSetWMHints(X11->display, q->internalWinId(), h);
+ if (h != &wm_hints)
+ XFree((char *)h);
+}
+
+void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
+{
+ Q_Q(QWidget);
+ if (!q->internalWinId())
+ return;
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ XSetWMIconName(X11->display, q->internalWinId(), qstring_to_xtp(iconText));
+
+ QByteArray icon_name = iconText.toUtf8();
+ XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON_NAME), ATOM(UTF8_STRING), 8,
+ PropModeReplace, (unsigned char *) icon_name.constData(), icon_name.size());
+}
+
+
+void QWidget::grabMouse()
+{
+ if (isVisible() && !qt_nograb()) {
+ if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
+ QWidgetPrivate::mouseGrabber->releaseMouse();
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+#ifndef QT_NO_DEBUG
+ int status =
+#endif
+ XGrabPointer(X11->display, effectiveWinId(), False,
+ (uint)(ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | EnterWindowMask |
+ LeaveWindowMask),
+ GrabModeAsync, GrabModeAsync,
+ XNone, XNone, X11->time);
+#ifndef QT_NO_DEBUG
+ if (status) {
+ const char *s =
+ status == GrabNotViewable ? "\"GrabNotViewable\"" :
+ status == AlreadyGrabbed ? "\"AlreadyGrabbed\"" :
+ status == GrabFrozen ? "\"GrabFrozen\"" :
+ status == GrabInvalidTime ? "\"GrabInvalidTime\"" :
+ "<?>";
+ qWarning("QWidget::grabMouse: Failed with %s", s);
+ }
+#endif
+ QWidgetPrivate::mouseGrabber = this;
+ }
+}
+
+
+#ifndef QT_NO_CURSOR
+void QWidget::grabMouse(const QCursor &cursor)
+{
+ if (!qt_nograb()) {
+ if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
+ QWidgetPrivate::mouseGrabber->releaseMouse();
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+#ifndef QT_NO_DEBUG
+ int status =
+#endif
+ XGrabPointer(X11->display, effectiveWinId(), False,
+ (uint)(ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | EnterWindowMask | LeaveWindowMask),
+ GrabModeAsync, GrabModeAsync,
+ XNone, cursor.handle(), X11->time);
+#ifndef QT_NO_DEBUG
+ if (status) {
+ const char *s =
+ status == GrabNotViewable ? "\"GrabNotViewable\"" :
+ status == AlreadyGrabbed ? "\"AlreadyGrabbed\"" :
+ status == GrabFrozen ? "\"GrabFrozen\"" :
+ status == GrabInvalidTime ? "\"GrabInvalidTime\"" :
+ "<?>";
+ qWarning("QWidget::grabMouse: Failed with %s", s);
+ }
+#endif
+ QWidgetPrivate::mouseGrabber = this;
+ }
+}
+#endif
+
+
+void QWidget::releaseMouse()
+{
+ if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) {
+ XUngrabPointer(X11->display, X11->time);
+ XFlush(X11->display);
+ QWidgetPrivate::mouseGrabber = 0;
+ }
+}
+
+
+void QWidget::grabKeyboard()
+{
+ if (!qt_nograb()) {
+ if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this)
+ QWidgetPrivate::keyboardGrabber->releaseKeyboard();
+ XGrabKeyboard(X11->display, effectiveWinId(), False, GrabModeAsync, GrabModeAsync,
+ X11->time);
+ QWidgetPrivate::keyboardGrabber = this;
+ }
+}
+
+
+void QWidget::releaseKeyboard()
+{
+ if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) {
+ XUngrabKeyboard(X11->display, X11->time);
+ QWidgetPrivate::keyboardGrabber = 0;
+ }
+}
+
+
+QWidget *QWidget::mouseGrabber()
+{
+ return QWidgetPrivate::mouseGrabber;
+}
+
+
+QWidget *QWidget::keyboardGrabber()
+{
+ return QWidgetPrivate::keyboardGrabber;
+}
+
+void QWidget::activateWindow()
+{
+ QWidget *tlw = window();
+ if (tlw->isVisible() && !tlw->d_func()->topData()->embedded && !X11->deferred_map.contains(tlw)) {
+ if (X11->userTime == 0)
+ X11->userTime = X11->time;
+ qt_net_update_user_time(tlw, X11->userTime);
+ XSetInputFocus(X11->display, tlw->internalWinId(), XRevertToParent, X11->time);
+ }
+}
+
+void QWidget::setWindowState(Qt::WindowStates newstate)
+{
+ Q_D(QWidget);
+ bool needShow = false;
+ Qt::WindowStates oldstate = windowState();
+ if (oldstate == newstate)
+ return;
+ if (isWindow()) {
+ // Ensure the initial size is valid, since we store it as normalGeometry below.
+ if (!testAttribute(Qt::WA_Resized) && !isVisible())
+ adjustSize();
+
+ QTLWExtra *top = d->topData();
+
+ if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) {
+ if (X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ))
+ && X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT))) {
+ if ((newstate & Qt::WindowMaximized) && !(oldstate & Qt::WindowFullScreen))
+ top->normalGeometry = geometry();
+ qt_change_net_wm_state(this, (newstate & Qt::WindowMaximized),
+ ATOM(_NET_WM_STATE_MAXIMIZED_HORZ),
+ ATOM(_NET_WM_STATE_MAXIMIZED_VERT));
+ } else if (! (newstate & Qt::WindowFullScreen)) {
+ if (newstate & Qt::WindowMaximized) {
+ // save original geometry
+ const QRect normalGeometry = geometry();
+
+ if (isVisible()) {
+ data->fstrut_dirty = true;
+ const QRect maxRect = QApplication::desktop()->availableGeometry(this);
+ const QRect r = top->normalGeometry;
+ const QRect fs = d->frameStrut();
+ setGeometry(maxRect.x() + fs.left(),
+ maxRect.y() + fs.top(),
+ maxRect.width() - fs.left() - fs.right(),
+ maxRect.height() - fs.top() - fs.bottom());
+ top->normalGeometry = r;
+ }
+
+ if (top->normalGeometry.width() < 0)
+ top->normalGeometry = normalGeometry;
+ } else {
+ // restore original geometry
+ setGeometry(top->normalGeometry);
+ }
+ }
+ }
+
+ if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) {
+ if (X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN))) {
+ if (newstate & Qt::WindowFullScreen) {
+ top->normalGeometry = geometry();
+ top->fullScreenOffset = d->frameStrut().topLeft();
+ }
+ qt_change_net_wm_state(this, (newstate & Qt::WindowFullScreen),
+ ATOM(_NET_WM_STATE_FULLSCREEN));
+ } else {
+ needShow = isVisible();
+
+ if (newstate & Qt::WindowFullScreen) {
+ data->fstrut_dirty = true;
+ const QRect normalGeometry = geometry();
+ const QPoint fullScreenOffset = d->frameStrut().topLeft();
+
+ top->savedFlags = windowFlags();
+ setParent(0, Qt::Window | Qt::FramelessWindowHint);
+ const QRect r = top->normalGeometry;
+ setGeometry(qApp->desktop()->screenGeometry(this));
+ top->normalGeometry = r;
+
+ if (top->normalGeometry.width() < 0) {
+ top->normalGeometry = normalGeometry;
+ top->fullScreenOffset = fullScreenOffset;
+ }
+ } else {
+ setParent(0, top->savedFlags);
+
+ if (newstate & Qt::WindowMaximized) {
+ // from fullscreen to maximized
+ data->fstrut_dirty = true;
+ const QRect maxRect = QApplication::desktop()->availableGeometry(this);
+ const QRect r = top->normalGeometry;
+ const QRect fs = d->frameStrut();
+ setGeometry(maxRect.x() + fs.left(),
+ maxRect.y() + fs.top(),
+ maxRect.width() - fs.left() - fs.right(),
+ maxRect.height() - fs.top() - fs.bottom());
+ top->normalGeometry = r;
+ } else {
+ // restore original geometry
+ setGeometry(top->normalGeometry.adjusted(-top->fullScreenOffset.x(),
+ -top->fullScreenOffset.y(),
+ -top->fullScreenOffset.x(),
+ -top->fullScreenOffset.y()));
+ }
+ }
+ }
+ }
+
+ createWinId();
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) {
+ if (isVisible()) {
+ if (newstate & Qt::WindowMinimized) {
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = ATOM(WM_CHANGE_STATE);
+ e.xclient.display = X11->display;
+ e.xclient.window = data->winid;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = IconicState;
+ e.xclient.data.l[1] = 0;
+ e.xclient.data.l[2] = 0;
+ e.xclient.data.l[3] = 0;
+ e.xclient.data.l[4] = 0;
+ XSendEvent(X11->display,
+ RootWindow(X11->display,d->xinfo.screen()),
+ False, (SubstructureNotifyMask|SubstructureRedirectMask), &e);
+ } else {
+ setAttribute(Qt::WA_Mapped);
+ XMapWindow(X11->display, effectiveWinId());
+ }
+ }
+
+ needShow = false;
+ }
+ }
+
+ data->window_state = newstate;
+
+ if (needShow)
+ show();
+
+ if (newstate & Qt::WindowActive)
+ activateWindow();
+
+ QWindowStateChangeEvent e(oldstate);
+ QApplication::sendEvent(this, &e);
+}
+
+/*!
+ \internal
+ Platform-specific part of QWidget::show().
+*/
+
+void QWidgetPrivate::show_sys()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+
+ if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
+ invalidateBuffer(q->rect());
+ q->setAttribute(Qt::WA_Mapped);
+ if (QTLWExtra *tlwExtra = maybeTopData())
+ tlwExtra->waitingForMapNotify = 0;
+ return;
+ }
+
+ if (q->isWindow()) {
+ XWMHints *h = XGetWMHints(X11->display, q->internalWinId());
+ XWMHints wm_hints;
+ bool got_hints = h != 0;
+ if (!got_hints) {
+ memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy
+ h = &wm_hints;
+ }
+ h->initial_state = q->isMinimized() ? IconicState : NormalState;
+ h->flags |= StateHint;
+ XSetWMHints(X11->display, q->internalWinId(), h);
+ if (got_hints)
+ XFree((char *)h);
+
+ // update WM_NORMAL_HINTS
+ do_size_hints(q, extra);
+
+ // udpate WM_TRANSIENT_FOR
+ if (isTransient(q)) {
+ QWidget *p = q->parentWidget();
+
+#ifndef QT_NO_MENU
+ // hackish ... try to find the main window related to this QMenu
+ if (qobject_cast<QMenu *>(q)) {
+ p = static_cast<QMenuPrivate*>(this)->causedPopup.widget;
+ if (!p)
+ p = q->parentWidget();
+ if (!p)
+ p = QApplication::widgetAt(q->pos());
+ if (!p)
+ p = qApp->activeWindow();
+ }
+#endif
+ if (p)
+ p = p->window();
+ if (p) {
+ // transient for window
+ XSetTransientForHint(X11->display, q->internalWinId(), p->internalWinId());
+ } else {
+ // transient for group
+ XSetTransientForHint(X11->display, q->internalWinId(), X11->wm_client_leader);
+ }
+ }
+
+ // update _MOTIF_WM_HINTS
+ QtMWMHints mwmhints = GetMWMHints(X11->display, q->internalWinId());
+
+ if (data.window_modality != Qt::NonModal) {
+ switch (data.window_modality) {
+ case Qt::WindowModal:
+ mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL;
+ break;
+ case Qt::ApplicationModal:
+ default:
+ mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL;
+ break;
+ }
+ mwmhints.flags |= MWM_HINTS_INPUT_MODE;
+ } else {
+ mwmhints.input_mode = MWM_INPUT_MODELESS;
+ mwmhints.flags &= ~MWM_HINTS_INPUT_MODE;
+ }
+
+ if (q->minimumSize() == q->maximumSize()) {
+ // fixed size, remove the resize handle (since mwm/dtwm
+ // isn't smart enough to do it itself)
+ mwmhints.flags |= MWM_HINTS_FUNCTIONS;
+ if (mwmhints.functions == MWM_FUNC_ALL) {
+ mwmhints.functions = MWM_FUNC_MOVE;
+ } else {
+ mwmhints.functions &= ~MWM_FUNC_RESIZE;
+ }
+
+ if (mwmhints.decorations == MWM_DECOR_ALL) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = (MWM_DECOR_BORDER
+ | MWM_DECOR_TITLE
+ | MWM_DECOR_MENU);
+ } else {
+ mwmhints.decorations &= ~MWM_DECOR_RESIZEH;
+ }
+
+ if (q->windowFlags() & Qt::WindowMinimizeButtonHint) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+ mwmhints.decorations |= MWM_DECOR_MINIMIZE;
+ mwmhints.functions |= MWM_FUNC_MINIMIZE;
+ }
+ if (q->windowFlags() & Qt::WindowMaximizeButtonHint) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+ mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
+ mwmhints.functions |= MWM_FUNC_MAXIMIZE;
+ }
+ if (q->windowFlags() & Qt::WindowCloseButtonHint)
+ mwmhints.functions |= MWM_FUNC_CLOSE;
+ }
+
+ SetMWMHints(X11->display, q->internalWinId(), mwmhints);
+
+ // update _NET_WM_STATE
+ QVector<Atom> netWmState = getNetWmState(q);
+
+ Qt::WindowFlags flags = q->windowFlags();
+ if (flags & Qt::WindowStaysOnTopHint) {
+ if (flags & Qt::WindowStaysOnBottomHint)
+ qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
+ netWmState.append(ATOM(_NET_WM_STATE_ABOVE));
+ netWmState.append(ATOM(_NET_WM_STATE_STAYS_ON_TOP));
+ } else if (flags & Qt::WindowStaysOnBottomHint) {
+ netWmState.append(ATOM(_NET_WM_STATE_BELOW));
+ }
+ if (q->isFullScreen()) {
+ netWmState.append(ATOM(_NET_WM_STATE_FULLSCREEN));
+ }
+ if (q->isMaximized()) {
+ netWmState.append(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ));
+ netWmState.append(ATOM(_NET_WM_STATE_MAXIMIZED_VERT));
+ }
+ if (data.window_modality != Qt::NonModal) {
+ netWmState.append(ATOM(_NET_WM_STATE_MODAL));
+ }
+
+ if (!netWmState.isEmpty()) {
+ XChangeProperty(X11->display, q->internalWinId(),
+ ATOM(_NET_WM_STATE), XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) netWmState.data(), netWmState.size());
+ } else {
+ XDeleteProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_STATE));
+ }
+
+ // set _NET_WM_USER_TIME
+ Time userTime = X11->userTime;
+ bool setUserTime = false;
+ if (q->testAttribute(Qt::WA_ShowWithoutActivating)) {
+ userTime = 0;
+ setUserTime = true;
+ } else if (userTime != CurrentTime) {
+ setUserTime = true;
+ }
+ if (setUserTime)
+ qt_net_update_user_time(q, userTime);
+
+#ifndef QT_NO_XSYNC
+ if (!topData()->syncUpdateCounter) {
+ XSyncValue value;
+ XSyncIntToValue(&value, 0);
+ topData()->syncUpdateCounter = XSyncCreateCounter(X11->display, value);
+
+ XChangeProperty(X11->display, q->internalWinId(),
+ ATOM(_NET_WM_SYNC_REQUEST_COUNTER),
+ XA_CARDINAL,
+ 32, PropModeReplace,
+ (uchar *) &topData()->syncUpdateCounter, 1);
+
+ topData()->newCounterValueHi = 0;
+ topData()->newCounterValueLo = 0;
+ }
+#endif
+
+ if (!topData()->embedded
+ && (topData()->validWMState || topData()->waitingForMapNotify)
+ && !q->isMinimized()) {
+ X11->deferred_map.append(q);
+ return;
+ }
+
+ if (q->isMaximized() && !q->isFullScreen()
+ && !(X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ))
+ && X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT)))) {
+ XMapWindow(X11->display, q->internalWinId());
+ data.fstrut_dirty = true;
+ qt_x11_wait_for_window_manager(q);
+
+ // if the wm was not smart enough to adjust our size, do that manually
+ QRect maxRect = QApplication::desktop()->availableGeometry(q);
+
+ QTLWExtra *top = topData();
+ QRect normalRect = top->normalGeometry;
+ const QRect fs = frameStrut();
+
+ q->setGeometry(maxRect.x() + fs.left(),
+ maxRect.y() + fs.top(),
+ maxRect.width() - fs.left() - fs.right(),
+ maxRect.height() - fs.top() - fs.bottom());
+
+ // restore the original normalGeometry
+ top->normalGeometry = normalRect;
+ // internalSetGeometry() clears the maximized flag... make sure we set it back
+ data.window_state = data.window_state | Qt::WindowMaximized;
+ q->setAttribute(Qt::WA_Mapped);
+ return;
+ }
+
+ if (q->isFullScreen() && !X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN))) {
+ XMapWindow(X11->display, q->internalWinId());
+ qt_x11_wait_for_window_manager(q);
+ q->setAttribute(Qt::WA_Mapped);
+ return;
+ }
+ }
+
+ invalidateBuffer(q->rect());
+
+ if (q->testAttribute(Qt::WA_OutsideWSRange))
+ return;
+ q->setAttribute(Qt::WA_Mapped);
+ if (q->isWindow())
+ topData()->waitingForMapNotify = 1;
+
+ if (!q->isWindow()
+ && (!q->autoFillBackground()
+ || q->palette().brush(q->backgroundRole()).style() == Qt::LinearGradientPattern)) {
+ if (q->internalWinId()) {
+ XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), XNone);
+ XMapWindow(X11->display, q->internalWinId());
+ updateSystemBackground();
+ }
+ return;
+ }
+
+ if (q->internalWinId())
+ XMapWindow(X11->display, q->internalWinId());
+
+ // Freedesktop.org Startup Notification
+ if (X11->startupId && q->isWindow()) {
+ QByteArray message("remove: ID=");
+ message.append(X11->startupId);
+ sendStartupMessage(message.constData());
+ X11->startupId = 0;
+ }
+}
+
+/*!
+ \internal
+ Platform-specific part of QWidget::show().
+*/
+
+void QWidgetPrivate::sendStartupMessage(const char *message) const
+{
+ Q_Q(const QWidget);
+
+ if (!message)
+ return;
+
+ XEvent xevent;
+ xevent.xclient.type = ClientMessage;
+ xevent.xclient.message_type = ATOM(_NET_STARTUP_INFO_BEGIN);
+ xevent.xclient.display = X11->display;
+ xevent.xclient.window = q->internalWinId();
+ xevent.xclient.format = 8;
+
+ Window rootWindow = RootWindow(X11->display, DefaultScreen(X11->display));
+ uint sent = 0;
+ uint length = strlen(message) + 1;
+ do {
+ if (sent == 20)
+ xevent.xclient.message_type = ATOM(_NET_STARTUP_INFO);
+
+ for (uint i = 0; i < 20 && i + sent <= length; i++)
+ xevent.xclient.data.b[i] = message[i + sent++];
+
+ XSendEvent(X11->display, rootWindow, false, PropertyChangeMask, &xevent);
+ } while (sent <= length);
+}
+
+void QWidgetPrivate::setNetWmWindowTypes()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+
+ if (!q->isWindow()) {
+ if (q->internalWinId())
+ XDeleteProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_WINDOW_TYPE));
+ return;
+ }
+
+ QVector<long> windowTypes;
+
+ // manual selection 1 (these are never set by Qt and take precedence)
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDesktop))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DESKTOP));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDock))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DOCK));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeNotification))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_NOTIFICATION));
+
+ // manual selection 2 (Qt uses these during auto selection);
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeUtility))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_UTILITY));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeSplash))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_SPLASH));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDialog))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DIALOG));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeToolTip))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_TOOLTIP));
+
+ // manual selection 3 (these can be set by Qt, but don't have a
+ // corresponding Qt::WindowType). note that order of the *MENU
+ // atoms is important
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeMenu))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_MENU));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypePopupMenu))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_POPUP_MENU));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeToolBar))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_TOOLBAR));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeCombo))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_COMBO));
+ if (q->testAttribute(Qt::WA_X11NetWmWindowTypeDND))
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DND));
+
+ // automatic selection
+ switch (q->windowType()) {
+ case Qt::Dialog:
+ case Qt::Sheet:
+ // dialog netwm type
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_DIALOG));
+ break;
+
+ case Qt::Tool:
+ case Qt::Drawer:
+ // utility netwm type
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_UTILITY));
+ break;
+
+ case Qt::ToolTip:
+ // tooltip netwm type
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_TOOLTIP));
+ break;
+
+ case Qt::SplashScreen:
+ // splash netwm type
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_SPLASH));
+ break;
+
+ default:
+ break;
+ }
+
+ if (q->windowFlags() & Qt::FramelessWindowHint) {
+ // override netwm type - quick and easy for KDE noborder
+ windowTypes.append(ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
+ }
+
+ // normal netwm type - default
+ windowTypes.append(ATOM(_NET_WM_WINDOW_TYPE_NORMAL));
+
+ if (!windowTypes.isEmpty()) {
+ XChangeProperty(X11->display, q->winId(), ATOM(_NET_WM_WINDOW_TYPE), XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) windowTypes.constData(),
+ windowTypes.count());
+ } else {
+ XDeleteProperty(X11->display, q->winId(), ATOM(_NET_WM_WINDOW_TYPE));
+ }
+}
+
+/*!
+ \internal
+ Platform-specific part of QWidget::hide().
+*/
+
+void QWidgetPrivate::hide_sys()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ deactivateWidgetCleanup();
+ if (q->isWindow()) {
+ X11->deferred_map.removeAll(q);
+ if (q->internalWinId()) // in nsplugin, may be 0
+ XWithdrawWindow(X11->display, q->internalWinId(), xinfo.screen());
+ XFlush(X11->display);
+ } else {
+ invalidateBuffer(q->rect());
+ if (q->internalWinId()) // in nsplugin, may be 0
+ XUnmapWindow(X11->display, q->internalWinId());
+ }
+ q->setAttribute(Qt::WA_Mapped, false);
+}
+
+void QWidgetPrivate::setFocus_sys()
+{
+
+}
+
+
+void QWidgetPrivate::raise_sys()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (q->internalWinId())
+ XRaiseWindow(X11->display, q->internalWinId());
+}
+
+void QWidgetPrivate::lower_sys()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (q->internalWinId())
+ XLowerWindow(X11->display, q->internalWinId());
+ if(!q->isWindow())
+ invalidateBuffer(q->rect());
+}
+
+void QWidgetPrivate::stackUnder_sys(QWidget* w)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (q->internalWinId() && w->internalWinId()) {
+ Window stack[2];
+ stack[0] = w->internalWinId();;
+ stack[1] = q->internalWinId();
+ XRestackWindows(X11->display, stack, 2);
+ }
+ if(!q->isWindow() || !w->internalWinId())
+ invalidateBuffer(q->rect());
+}
+
+
+static void do_size_hints(QWidget* widget, QWExtra *x)
+{
+ Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
+ XSizeHints s;
+ s.flags = 0;
+ if (x) {
+ QRect g = widget->geometry();
+ s.x = g.x();
+ s.y = g.y();
+ s.width = g.width();
+ s.height = g.height();
+ if (x->minw > 0 || x->minh > 0) {
+ // add minimum size hints
+ s.flags |= PMinSize;
+ s.min_width = qMin(XCOORD_MAX, x->minw);
+ s.min_height = qMin(XCOORD_MAX, x->minh);
+ }
+ if (x->maxw < QWIDGETSIZE_MAX || x->maxh < QWIDGETSIZE_MAX) {
+ // add maximum size hints
+ s.flags |= PMaxSize;
+ s.max_width = qMin(XCOORD_MAX, x->maxw);
+ s.max_height = qMin(XCOORD_MAX, x->maxh);
+ }
+ if (x->topextra &&
+ (x->topextra->incw > 0 || x->topextra->inch > 0)) {
+ // add resize increment hints
+ s.flags |= PResizeInc | PBaseSize;
+ s.width_inc = x->topextra->incw;
+ s.height_inc = x->topextra->inch;
+ s.base_width = x->topextra->basew;
+ s.base_height = x->topextra->baseh;
+ }
+ }
+ if (widget->testAttribute(Qt::WA_Moved)) {
+ // user (i.e. command-line) specified position
+ s.flags |= USPosition;
+ s.flags |= PPosition;
+ }
+ if (widget->testAttribute(Qt::WA_Resized)) {
+ // user (i.e. command-line) specified size
+ s.flags |= USSize;
+ s.flags |= PSize;
+ }
+ s.flags |= PWinGravity;
+ if (widget->testAttribute(Qt::WA_Moved) && x && x->topextra && !x->topextra->posFromMove) {
+ // position came from setGeometry(), tell the WM that we don't
+ // want our window gravity-shifted
+ s.win_gravity = StaticGravity;
+ } else {
+ // position came from move()
+ s.x = widget->x();
+ s.y = widget->y();
+ s.win_gravity = QApplication::isRightToLeft() ? NorthEastGravity : NorthWestGravity;
+ }
+ if (widget->internalWinId())
+ XSetWMNormalHints(X11->display, widget->internalWinId(), &s);
+}
+
+
+/*
+ Helper function for non-toplevel widgets. Helps to map Qt's 32bit
+ coordinate system to X11's 16bit coordinate system.
+
+ Sets the geometry of the widget to data.crect, but clipped to sizes
+ that X can handle. Unmaps widgets that are completely outside the
+ valid range.
+
+ Maintains data.wrect, which is the geometry of the X widget,
+ measured in this widget's coordinate system.
+
+ if the parent is not clipped, parentWRect is empty, otherwise
+ parentWRect is the geometry of the parent's X rect, measured in
+ parent's coord sys
+ */
+void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+
+ /*
+ There are up to four different coordinate systems here:
+ Qt coordinate system for this widget.
+ X coordinate system for this widget (relative to wrect).
+ Qt coordinate system for parent
+ X coordinate system for parent (relative to parent's wrect).
+ */
+ Display *dpy = xinfo.display();
+ QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
+ QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
+ QRect wrect;
+ //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)
+ QRect xrect = data.crect;
+
+ const QWidget *const parent = q->parentWidget();
+ QRect parentWRect = parent->data->wrect;
+
+ if (parentWRect.isValid()) {
+ // parent is clipped, and we have to clip to the same limit as parent
+ if (!parentWRect.contains(xrect)) {
+ xrect &= parentWRect;
+ wrect = xrect;
+ //translate from parent's to my Qt coord sys
+ wrect.translate(-data.crect.topLeft());
+ }
+ //translate from parent's Qt coords to parent's X coords
+ xrect.translate(-parentWRect.topLeft());
+
+ } else {
+ // parent is not clipped, we may or may not have to clip
+
+ if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
+ // This is where the main optimization is: we are already
+ // clipped, and if our clip is still valid, we can just
+ // move our window, and do not need to move or clip
+ // children
+
+ QRect vrect = xrect & parent->rect();
+ vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
+ if (data.wrect.contains(vrect)) {
+ xrect = data.wrect;
+ xrect.translate(data.crect.topLeft());
+ if (data.winid)
+ XMoveWindow(dpy, data.winid, xrect.x(), xrect.y());
+ return;
+ }
+ }
+
+ if (!validRange.contains(xrect)) {
+ // we are too big, and must clip
+ xrect &=wrectRange;
+ wrect = xrect;
+ wrect.translate(-data.crect.topLeft());
+ //parent's X coord system is equal to parent's Qt coord
+ //sys, so we don't need to map xrect.
+ }
+
+ }
+
+ // unmap if we are outside the valid window system coord system
+ bool outsideRange = !xrect.isValid();
+ bool mapWindow = false;
+ if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
+ q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
+ if (outsideRange) {
+ if (data.winid)
+ XUnmapWindow(dpy, data.winid);
+ q->setAttribute(Qt::WA_Mapped, false);
+ } else if (!q->isHidden()) {
+ mapWindow = true;
+ }
+ }
+
+ if (outsideRange)
+ return;
+
+ bool jump = (data.wrect != wrect);
+ data.wrect = wrect;
+
+
+ // and now recursively for all children...
+ // ### can be optimized
+ for (int i = 0; i < children.size(); ++i) {
+ QObject *object = children.at(i);
+ if (object->isWidgetType()) {
+ QWidget *w = static_cast<QWidget *>(object);
+ if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
+ w->d_func()->setWSGeometry(jump);
+ }
+ }
+
+ if (data.winid) {
+ // move ourselves to the new position and map (if necessary) after
+ // the movement. Rationale: moving unmapped windows is much faster
+ // than moving mapped windows
+ if (jump) //avoid flicker when jumping
+ XSetWindowBackgroundPixmap(dpy, data.winid, XNone);
+ if (!parent->internalWinId())
+ xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
+ XMoveResizeWindow(dpy, data.winid, xrect.x(), xrect.y(), xrect.width(), xrect.height());
+ }
+
+ //to avoid flicker, we have to show children after the helper widget has moved
+ if (jump) {
+ for (int i = 0; i < children.size(); ++i) {
+ QObject *object = children.at(i);
+ if (object->isWidgetType()) {
+ QWidget *w = static_cast<QWidget *>(object);
+ if (!w->testAttribute(Qt::WA_OutsideWSRange) && !w->testAttribute(Qt::WA_Mapped) && !w->isHidden()) {
+ w->setAttribute(Qt::WA_Mapped);
+ if (w->internalWinId())
+ XMapWindow(dpy, w->data->winid);
+ }
+ }
+ }
+ }
+
+
+ if (jump && data.winid)
+ XClearArea(dpy, data.winid, 0, 0, wrect.width(), wrect.height(), True);
+
+ if (mapWindow && !dontShow) {
+ q->setAttribute(Qt::WA_Mapped);
+ if (data.winid)
+ XMapWindow(dpy, data.winid);
+ }
+}
+
+void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ Display *dpy = X11->display;
+
+ if ((q->windowType() == Qt::Desktop))
+ return;
+ if (q->isWindow()) {
+ if (!X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_VERT))
+ && !X11->isSupportedByWM(ATOM(_NET_WM_STATE_MAXIMIZED_HORZ)))
+ data.window_state &= ~Qt::WindowMaximized;
+ if (!X11->isSupportedByWM(ATOM(_NET_WM_STATE_FULLSCREEN)))
+ data.window_state &= ~Qt::WindowFullScreen;
+ if (QTLWExtra *topData = maybeTopData())
+ topData->normalGeometry = QRect(0,0,-1,-1);
+ } else {
+ uint s = data.window_state;
+ s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen);
+ data.window_state = s;
+ }
+ if (extra) { // any size restrictions?
+ w = qMin(w,extra->maxw);
+ h = qMin(h,extra->maxh);
+ w = qMax(w,extra->minw);
+ h = qMax(h,extra->minh);
+ }
+ QPoint oldPos(q->pos());
+ QSize oldSize(q->size());
+ QRect oldGeom(data.crect);
+ QRect r(x, y, w, h);
+
+ // We only care about stuff that changes the geometry, or may
+ // cause the window manager to change its state
+ if (!q->isWindow() && oldGeom == r)
+ return;
+
+ data.crect = r;
+ bool isResize = q->size() != oldSize;
+
+ if (q->isWindow()) {
+ if (w == 0 || h == 0) {
+ q->setAttribute(Qt::WA_OutsideWSRange, true);
+ if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
+ hide_sys();
+ } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
+ q->setAttribute(Qt::WA_OutsideWSRange, false);
+
+ // put the window in its place and show it
+ if (data.winid)
+ XMoveResizeWindow(dpy, data.winid, x, y, w, h);
+ topData()->posFromMove = false; // force StaticGravity
+ do_size_hints(q, extra);
+ show_sys();
+ } else {
+ q->setAttribute(Qt::WA_OutsideWSRange, false);
+ if (!q->isVisible())
+ do_size_hints(q, extra);
+ if (isMove) {
+ if ((data.window_flags & Qt::X11BypassWindowManagerHint) == Qt::X11BypassWindowManagerHint
+ // work around 4Dwm's incompliance with ICCCM 4.1.5
+ || X11->desktopEnvironment == DE_4DWM) {
+ if (data.winid)
+ XMoveResizeWindow(dpy, data.winid, x, y, w, h);
+ } else if (q->isVisible()
+ && topData()->validWMState
+ && X11->isSupportedByWM(ATOM(_NET_MOVERESIZE_WINDOW))) {
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = ATOM(_NET_MOVERESIZE_WINDOW);
+ e.xclient.display = X11->display;
+ e.xclient.window = q->internalWinId();
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = StaticGravity | 1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12;
+ e.xclient.data.l[1] = x;
+ e.xclient.data.l[2] = y;
+ e.xclient.data.l[3] = w;
+ e.xclient.data.l[4] = h;
+ XSendEvent(X11->display, RootWindow(X11->display, q->x11Info().screen()),
+ false, (SubstructureNotifyMask | SubstructureRedirectMask), &e);
+ } else if (data.winid) {
+ // pos() is right according to ICCCM 4.1.5
+ XMoveResizeWindow(dpy, data.winid, q->pos().x(), q->pos().y(), w, h);
+ }
+ } else if (isResize && data.winid) {
+ if (!q->isVisible()
+ && topData()->validWMState
+ && !q->testAttribute(Qt::WA_PendingMoveEvent)) {
+ /*
+ even though we've not visible, we could be in a
+ race w/ the window manager, and it may ignore
+ our ConfigureRequest. setting posFromMove to
+ false makes sure that doDeferredMap() in
+ qapplication_x11.cpp keeps the window in the
+ right place
+ */
+ topData()->posFromMove = false;
+ }
+ XResizeWindow(dpy, data.winid, w, h);
+ }
+ }
+ if (isResize && !q->testAttribute(Qt::WA_DontShowOnScreen)) // set config pending only on resize, see qapplication_x11.cpp, translateConfigEvent()
+ q->setAttribute(Qt::WA_WState_ConfigPending);
+
+ } else {
+ QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
+ const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
+ const bool disableInTopLevelResize = inTopLevelResize && q->internalWinId();
+ if (disableInTopLevelResize) {
+ // Top-level resize optimization does not work for native child widgets;
+ // disable it for this particular widget.
+ tlwExtra->inTopLevelResize = false;
+ }
+
+ if (!isResize && (!inTopLevelResize || disableInTopLevelResize) && q->isVisible()) {
+ moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
+ }
+ if (q->testAttribute(Qt::WA_WState_Created))
+ setWSGeometry();
+
+ if (isResize && (!inTopLevelResize || disableInTopLevelResize) && q->isVisible())
+ invalidateBuffer_resizeHelper(oldPos, oldSize);
+
+ if (disableInTopLevelResize)
+ tlwExtra->inTopLevelResize = true;
+ }
+
+ if (q->isVisible()) {
+ if (isMove && q->pos() != oldPos) {
+ if (X11->desktopEnvironment != DE_4DWM) {
+ // pos() is right according to ICCCM 4.1.5
+ QMoveEvent e(q->pos(), oldPos);
+ QApplication::sendEvent(q, &e);
+ } else {
+ // work around 4Dwm's incompliance with ICCCM 4.1.5
+ QMoveEvent e(data.crect.topLeft(), oldGeom.topLeft());
+ QApplication::sendEvent(q, &e);
+ }
+ }
+ if (isResize) {
+ static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
+ // If we have a backing store with static contents, we have to disable the top-level
+ // resize optimization in order to get invalidated regions for resized widgets.
+ // The optimization discards all invalidateBuffer() calls since we're going to
+ // repaint everything anyways, but that's not the case with static contents.
+ const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
+ && !extra->topextra->inTopLevelResize
+ && (!extra->topextra->backingStore
+ || !extra->topextra->backingStore->hasStaticContents());
+ if (setTopLevelResize)
+ extra->topextra->inTopLevelResize = true;
+ QResizeEvent e(q->size(), oldSize);
+ QApplication::sendEvent(q, &e);
+ if (setTopLevelResize)
+ extra->topextra->inTopLevelResize = false;
+ }
+ } else {
+ if (isMove && q->pos() != oldPos)
+ q->setAttribute(Qt::WA_PendingMoveEvent, true);
+ if (isResize)
+ q->setAttribute(Qt::WA_PendingResizeEvent, true);
+ }
+}
+
+void QWidgetPrivate::setConstraints_sys()
+{
+ Q_Q(QWidget);
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::setConstraints_sys START" << q;
+#endif
+ if (q->testAttribute(Qt::WA_WState_Created))
+ do_size_hints(q, extra);
+#ifdef ALIEN_DEBUG
+ qDebug() << "QWidgetPrivate::setConstraints_sys END" << q;
+#endif
+}
+
+void QWidgetPrivate::scroll_sys(int dx, int dy)
+{
+ Q_Q(QWidget);
+
+ scrollChildren(dx, dy);
+ if (!paintOnScreen()) {
+ scrollRect(q->rect(), dx, dy);
+ } else {
+ scroll_sys(dx, dy, QRect());
+ }
+}
+
+void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
+{
+ Q_Q(QWidget);
+
+ if (!paintOnScreen()) {
+ scrollRect(r, dx, dy);
+ return;
+ }
+ bool valid_rect = r.isValid();
+ bool just_update = qAbs(dx) > q->width() || qAbs(dy) > q->height();
+ QRect sr = valid_rect ? r : clipRect();
+ if (just_update)
+ q->update();
+ else if (!valid_rect)
+ dirty.translate(dx, dy);
+
+ int x1, y1, x2, y2, w = sr.width(), h = sr.height();
+ if (dx > 0) {
+ x1 = sr.x();
+ x2 = x1+dx;
+ w -= dx;
+ } else {
+ x2 = sr.x();
+ x1 = x2-dx;
+ w += dx;
+ }
+ if (dy > 0) {
+ y1 = sr.y();
+ y2 = y1+dy;
+ h -= dy;
+ } else {
+ y2 = sr.y();
+ y1 = y2-dy;
+ h += dy;
+ }
+
+ if (dx == 0 && dy == 0)
+ return;
+
+ Display *dpy = X11->display;
+ // Want expose events
+ if (w > 0 && h > 0 && !just_update && q->internalWinId()) {
+ GC gc = XCreateGC(dpy, q->internalWinId(), 0, 0);
+ XSetGraphicsExposures(dpy, gc, True);
+ XCopyArea(dpy, q->internalWinId(), q->internalWinId(), gc, x1, y1, w, h, x2, y2);
+ XFreeGC(dpy, gc);
+ }
+
+ if (!valid_rect && !children.isEmpty()) { // scroll children
+ QPoint pd(dx, dy);
+ for (int i = 0; i < children.size(); ++i) { // move all children
+ register QObject *object = children.at(i);
+ if (object->isWidgetType()) {
+ QWidget *w = static_cast<QWidget *>(object);
+ if (!w->isWindow())
+ w->move(w->pos() + pd);
+ }
+ }
+ }
+
+ if (just_update)
+ return;
+
+ // Don't let the server be bogged-down with repaint events
+ bool repaint_immediately = (qt_sip_count(q) < 3 && !q->testAttribute(Qt::WA_WState_InPaintEvent));
+
+ if (dx) {
+ int x = x2 == sr.x() ? sr.x()+w : sr.x();
+ if (repaint_immediately)
+ q->repaint(x, sr.y(), qAbs(dx), sr.height());
+ else if (q->internalWinId())
+ XClearArea(dpy, data.winid, x, sr.y(), qAbs(dx), sr.height(), True);
+ }
+ if (dy) {
+ int y = y2 == sr.y() ? sr.y()+h : sr.y();
+ if (repaint_immediately)
+ q->repaint(sr.x(), y, sr.width(), qAbs(dy));
+ else if (q->internalWinId())
+ XClearArea(dpy, data.winid, sr.x(), y, sr.width(), qAbs(dy), True);
+ }
+
+ qt_insert_sip(q, dx, dy); // #### ignores r
+}
+
+int QWidget::metric(PaintDeviceMetric m) const
+{
+ Q_D(const QWidget);
+ int val;
+ if (m == PdmWidth) {
+ val = data->crect.width();
+ } else if (m == PdmHeight) {
+ val = data->crect.height();
+ } else {
+ Display *dpy = X11->display;
+ int scr = d->xinfo.screen();
+ switch (m) {
+ case PdmDpiX:
+ case PdmPhysicalDpiX:
+ if (d->extra && d->extra->customDpiX)
+ val = d->extra->customDpiX;
+ else if (d->parent)
+ val = static_cast<QWidget *>(d->parent)->metric(m);
+ else
+ val = QX11Info::appDpiX(scr);
+ break;
+ case PdmDpiY:
+ case PdmPhysicalDpiY:
+ if (d->extra && d->extra->customDpiY)
+ val = d->extra->customDpiY;
+ else if (d->parent)
+ val = static_cast<QWidget *>(d->parent)->metric(m);
+ else
+ val = QX11Info::appDpiY(scr);
+ break;
+ case PdmWidthMM:
+ val = (DisplayWidthMM(dpy,scr)*data->crect.width())/
+ DisplayWidth(dpy,scr);
+ break;
+ case PdmHeightMM:
+ val = (DisplayHeightMM(dpy,scr)*data->crect.height())/
+ DisplayHeight(dpy,scr);
+ break;
+ case PdmNumColors:
+ val = d->xinfo.cells();
+ break;
+ case PdmDepth:
+ val = d->xinfo.depth();
+ break;
+ default:
+ val = 0;
+ qWarning("QWidget::metric: Invalid metric command");
+ }
+ }
+ return val;
+}
+
+void QWidgetPrivate::createSysExtra()
+{
+ extra->compress_events = true;
+ extra->xDndProxy = 0;
+}
+
+void QWidgetPrivate::deleteSysExtra()
+{
+}
+
+void QWidgetPrivate::createTLSysExtra()
+{
+ extra->topextra->spont_unmapped = 0;
+ extra->topextra->dnd = 0;
+ extra->topextra->validWMState = 0;
+ extra->topextra->waitingForMapNotify = 0;
+ extra->topextra->parentWinId = 0;
+ extra->topextra->userTimeWindow = 0;
+#ifndef QT_NO_XSYNC
+ extra->topextra->syncUpdateCounter = 0;
+ extra->topextra->syncRequestTimestamp = 0;
+ extra->topextra->newCounterValueHi = 0;
+ extra->topextra->newCounterValueLo = 0;
+#endif
+}
+
+void QWidgetPrivate::deleteTLSysExtra()
+{
+ // don't destroy input context here. it will be destroyed in
+ // QWidget::destroy() destroyInputContext();
+}
+
+void QWidgetPrivate::registerDropSite(bool on)
+{
+ Q_UNUSED(on);
+}
+
+void QWidgetPrivate::setMask_sys(const QRegion ®ion)
+{
+ Q_Q(QWidget);
+ if (!q->internalWinId())
+ return;
+
+ if (region.isEmpty()) {
+ XShapeCombineMask(X11->display, q->internalWinId(), ShapeBounding, 0, 0,
+ XNone, ShapeSet);
+ } else {
+ XShapeCombineRegion(X11->display, q->internalWinId(), ShapeBounding, 0, 0,
+ region.handle(), ShapeSet);
+ }
+}
+
+/*!
+ \internal
+
+ Computes the frame rectangle when needed. This is an internal function, you
+ should never call this.
+*/
+
+void QWidgetPrivate::updateFrameStrut()
+{
+ Q_Q(QWidget);
+
+ QTLWExtra *top = topData();
+ if (!top->validWMState) {
+ return;
+ }
+ if (!q->isWindow() && !q->internalWinId()) {
+ data.fstrut_dirty = false;
+ return;
+ }
+
+ Atom type_ret;
+ Window l = q->effectiveWinId(), w = l, p, r; // target window, its parent, root
+ Window *c;
+ int i_unused;
+ unsigned int nc;
+ unsigned char *data_ret;
+ unsigned long l_unused;
+
+ while (XQueryTree(X11->display, w, &r, &p, &c, &nc)) {
+ if (c && nc > 0)
+ XFree(c);
+
+ if (! p) {
+ qWarning("QWidget::updateFrameStrut: No parent");
+ return;
+ }
+
+ // if the parent window is the root window, an Enlightenment virtual root or
+ // a NET WM virtual root window, stop here
+ data_ret = 0;
+ if (p == r ||
+ (XGetWindowProperty(X11->display, p,
+ ATOM(ENLIGHTENMENT_DESKTOP), 0, 1, False, XA_CARDINAL,
+ &type_ret, &i_unused, &l_unused, &l_unused,
+ &data_ret) == Success &&
+ type_ret == XA_CARDINAL)) {
+ if (data_ret)
+ XFree(data_ret);
+
+ break;
+ } else if (X11->isSupportedByWM(ATOM(_NET_VIRTUAL_ROOTS)) && X11->net_virtual_root_list) {
+ int i = 0;
+ while (X11->net_virtual_root_list[i] != 0) {
+ if (X11->net_virtual_root_list[i++] == p)
+ break;
+ }
+ }
+
+ l = w;
+ w = p;
+ }
+
+ // we have our window
+ int transx, transy;
+ XWindowAttributes wattr;
+ if (XTranslateCoordinates(X11->display, l, w,
+ 0, 0, &transx, &transy, &p) &&
+ XGetWindowAttributes(X11->display, w, &wattr)) {
+ top->frameStrut.setCoords(transx,
+ transy,
+ wattr.width - data.crect.width() - transx,
+ wattr.height - data.crect.height() - transy);
+
+ // add the border_width for the window managers frame... some window managers
+ // do not use a border_width of zero for their frames, and if we the left and
+ // top strut, we ensure that pos() is absolutely correct. frameGeometry()
+ // will still be incorrect though... perhaps i should have foffset as well, to
+ // indicate the frame offset (equal to the border_width on X).
+ // - Brad
+ top->frameStrut.adjust(wattr.border_width,
+ wattr.border_width,
+ wattr.border_width,
+ wattr.border_width);
+ }
+
+ data.fstrut_dirty = false;
+}
+
+void QWidgetPrivate::setWindowOpacity_sys(qreal opacity)
+{
+ Q_Q(QWidget);
+ ulong value = ulong(opacity * 0xffffffff);
+ XChangeProperty(QX11Info::display(), q->internalWinId(), ATOM(_NET_WM_WINDOW_OPACITY), XA_CARDINAL,
+ 32, PropModeReplace, (uchar*)&value, 1);
+}
+
+const QX11Info &QWidget::x11Info() const
+{
+ Q_D(const QWidget);
+ return d->xinfo;
+}
+
+void QWidgetPrivate::setWindowRole()
+{
+ Q_Q(QWidget);
+ if (!q->internalWinId())
+ return;
+ QByteArray windowRole = topData()->role.toUtf8();
+ XChangeProperty(X11->display, q->internalWinId(),
+ ATOM(WM_WINDOW_ROLE), XA_STRING, 8, PropModeReplace,
+ (unsigned char *)windowRole.constData(), windowRole.length());
+}
+
+Q_GLOBAL_STATIC(QX11PaintEngine, qt_widget_paintengine)
+QPaintEngine *QWidget::paintEngine() const
+{
+ Q_D(const QWidget);
+ if (qt_widget_paintengine()->isActive()) {
+ if (d->extraPaintEngine)
+ return d->extraPaintEngine;
+ QWidget *self = const_cast<QWidget *>(this);
+ self->d_func()->extraPaintEngine = new QX11PaintEngine();
+ return d->extraPaintEngine;
+ }
+ return qt_widget_paintengine();
+}
+
+QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
+{
+ return new QX11WindowSurface(q_func());
+}
+
+Qt::HANDLE QWidget::x11PictureHandle() const
+{
+#ifndef QT_NO_XRENDER
+ Q_D(const QWidget);
+ if (!internalWinId() && testAttribute(Qt::WA_WState_Created))
+ (void)winId(); // enforce native window
+ return d->picture;
+#else
+ return 0;
+#endif // QT_NO_XRENDER
+}
+
+#ifndef QT_NO_XRENDER
+XRenderColor QX11Data::preMultiply(const QColor &c)
+{
+ XRenderColor color;
+ const uint A = c.alpha(),
+ R = c.red(),
+ G = c.green(),
+ B = c.blue();
+ color.alpha = (A | A << 8);
+ color.red = (R | R << 8) * color.alpha / 0x10000;
+ color.green = (G | G << 8) * color.alpha / 0x10000;
+ color.blue = (B | B << 8) * color.alpha / 0x10000;
+ return color;
+}
+Picture QX11Data::getSolidFill(int screen, const QColor &c)
+{
+ if (!X11->use_xrender)
+ return XNone;
+
+ XRenderColor color = preMultiply(c);
+ for (int i = 0; i < X11->solid_fill_count; ++i) {
+ if (X11->solid_fills[i].screen == screen
+ && X11->solid_fills[i].color.alpha == color.alpha
+ && X11->solid_fills[i].color.red == color.red
+ && X11->solid_fills[i].color.green == color.green
+ && X11->solid_fills[i].color.blue == color.blue)
+ return X11->solid_fills[i].picture;
+ }
+ // none found, replace one
+ int i = rand() % 16;
+
+ if (X11->solid_fills[i].screen != screen && X11->solid_fills[i].picture) {
+ XRenderFreePicture (X11->display, X11->solid_fills[i].picture);
+ X11->solid_fills[i].picture = 0;
+ }
+
+ if (!X11->solid_fills[i].picture) {
+ Pixmap pixmap = XCreatePixmap (X11->display, RootWindow (X11->display, screen), 1, 1, 32);
+ XRenderPictureAttributes attrs;
+ attrs.repeat = True;
+ X11->solid_fills[i].picture = XRenderCreatePicture (X11->display, pixmap,
+ XRenderFindStandardFormat(X11->display, PictStandardARGB32),
+ CPRepeat, &attrs);
+ XFreePixmap (X11->display, pixmap);
+ }
+
+ X11->solid_fills[i].color = color;
+ X11->solid_fills[i].screen = screen;
+ XRenderFillRectangle (X11->display, PictOpSrc, X11->solid_fills[i].picture, &color, 0, 0, 1, 1);
+ return X11->solid_fills[i].picture;
+}
+#endif
+
+void QWidgetPrivate::setModal_sys()
+{
+}
+
+void qt_x11_getX11InfoForWindow(QX11Info * xinfo, const QX11WindowAttributes &att)
+{
+ QX11InfoData* xd = xinfo->getX11Data(true);
+ const XWindowAttributes &a = *(att.att);
+ // find which screen the window is on...
+ xd->screen = QX11Info::appScreen(); // by default, use the default :)
+ int i;
+ for (i = 0; i < ScreenCount(X11->display); i++) {
+ if (RootWindow(X11->display, i) == a.root) {
+ xd->screen = i;
+ break;
+ }
+ }
+
+ xd->depth = a.depth;
+ xd->cells = DisplayCells(X11->display, xd->screen);
+ xd->visual = a.visual;
+ xd->defaultVisual = (XVisualIDFromVisual((Visual *) a.visual) ==
+ XVisualIDFromVisual((Visual *) QX11Info::appVisual(xinfo->screen())));
+ xd->colormap = a.colormap;
+ xd->defaultColormap = (a.colormap == QX11Info::appColormap(xinfo->screen()));
+ xinfo->setX11Data(xd);
+}
+
+QT_END_NAMESPACE