/****************************************************************************
**
** Copyright (C) 2010 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);
}
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;
WId winid = w->internalWinId();
// first deliver events that are already in the local queue
QApplication::sendPostedEvents();
// the normal sequence is:
// ... ConfigureNotify ... ReparentNotify ... MapNotify ... Expose
// with X11BypassWindowManagerHint:
// ConfigureNotify ... MapNotify ... Expose
enum State {
Initial, Mapped
} state = Initial;
do {
if (XEventsQueued(X11->display, QueuedAlready)) {
XNextEvent(X11->display, &ev);
qApp->x11ProcessEvent(&ev);
switch (state) {
case Initial:
if (ev.type == MapNotify && ev.xany.window == winid)
state = Mapped;
break;
case Mapped:
if (ev.type == Expose && ev.xany.window == winid)
return;
break;
}
} else {
if (!XEventsQueued(X11->display, QueuedAfterFlush))
qApp->syncX(); // non-busy wait
}
if (t.elapsed() > maximumWaitTime)
return;
} while(1);
}
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()
&& !q->inherits("QGLWidget"))))
{
// QGLWidgets have to be excluded here as they have a
// specially crafted QX11Info structure which can't be swapped
// out with the parent widgets QX11Info. The parent visual,
// for instance, might not even be GL capable.
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 = QApplicationPrivate::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.byteCount());
} 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