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