Qt 4.8
qxlibscreen.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qxlibscreen.h"
43 
44 #include <X11/extensions/Xfixes.h>
45 
46 #include "qxlibcursor.h"
47 #include "qxlibwindow.h"
48 #include "qxlibkeyboard.h"
49 #include "qxlibstatic.h"
50 #include "qxlibclipboard.h"
51 #include "qxlibdisplay.h"
52 
53 #include <QtCore/QDebug>
54 #include <QtCore/QSocketNotifier>
55 #include <QtCore/QElapsedTimer>
56 
57 #include <private/qapplication_p.h>
58 
60 
61 static int (*original_x_errhandler)(Display *dpy, XErrorEvent *);
62 static bool seen_badwindow;
63 
64 static int qt_x_errhandler(Display *dpy, XErrorEvent *err)
65 {
66 
67 qDebug() << "qt_x_errhandler" << err->error_code;
68 
69  switch (err->error_code) {
70  case BadAtom:
71 #if 0
72  if (err->request_code == 20 /* X_GetProperty */
73  && (err->resourceid == XA_RESOURCE_MANAGER
74  || err->resourceid == XA_RGB_DEFAULT_MAP
75  || err->resourceid == ATOM(_NET_SUPPORTED)
76  || err->resourceid == ATOM(_NET_SUPPORTING_WM_CHECK)
77  || err->resourceid == ATOM(KDE_FULL_SESSION)
78  || err->resourceid == ATOM(KWIN_RUNNING)
79  || err->resourceid == ATOM(XdndProxy)
80  || err->resourceid == ATOM(XdndAware))
81 
82 
83  ) {
84  // Perhaps we're running under SECURITY reduction? :/
85  return 0;
86  }
87 #endif
88  qDebug() << "BadAtom";
89  break;
90 
91  case BadWindow:
92  if (err->request_code == 2 /* X_ChangeWindowAttributes */
93  || err->request_code == 38 /* X_QueryPointer */) {
94  for (int i = 0; i < ScreenCount(dpy); ++i) {
95  if (err->resourceid == RootWindow(dpy, i)) {
96  // Perhaps we're running under SECURITY reduction? :/
97  return 0;
98  }
99  }
100  }
101  seen_badwindow = true;
102  if (err->request_code == 25 /* X_SendEvent */) {
103  for (int i = 0; i < ScreenCount(dpy); ++i) {
104  if (err->resourceid == RootWindow(dpy, i)) {
105  // Perhaps we're running under SECURITY reduction? :/
106  return 0;
107  }
108  }
109 #if 0
110  if (X11->xdndHandleBadwindow()) {
111  qDebug("xdndHandleBadwindow returned true");
112  return 0;
113  }
114 #endif
115  }
116 #if 0
117  if (X11->ignore_badwindow)
118  return 0;
119 #endif
120  break;
121 
122  case BadMatch:
123  if (err->request_code == 42 /* X_SetInputFocus */)
124  return 0;
125  break;
126 
127  default:
128 #if 0
129  if (err->request_code == X11->xinput_major
130  && err->error_code == (X11->xinput_errorbase + XI_BadDevice)
131  && err->minor_code == 3 /* X_OpenDevice */) {
132  return 0;
133  }
134 #endif
135  break;
136  }
137 
138  char errstr[256];
139  XGetErrorText( dpy, err->error_code, errstr, 256 );
140  char buffer[256];
141  char request_str[256];
142  qsnprintf(buffer, 256, "%d", err->request_code);
143  XGetErrorDatabaseText(dpy, "XRequest", buffer, "", request_str, 256);
144  if (err->request_code < 128) {
145  // X error for a normal protocol request
146  qWarning( "X Error: %s %d\n"
147  " Major opcode: %d (%s)\n"
148  " Resource id: 0x%lx",
149  errstr, err->error_code,
150  err->request_code,
151  request_str,
152  err->resourceid );
153  } else {
154  // X error for an extension request
155  const char *extensionName = 0;
156 #if 0
157  if (err->request_code == X11->xrender_major)
158  extensionName = "RENDER";
159  else if (err->request_code == X11->xrandr_major)
160  extensionName = "RANDR";
161  else if (err->request_code == X11->xinput_major)
162  extensionName = "XInputExtension";
163  else if (err->request_code == X11->mitshm_major)
164  extensionName = "MIT-SHM";
165 #endif
166  char minor_str[256];
167  if (extensionName) {
168  qsnprintf(buffer, 256, "%s.%d", extensionName, err->minor_code);
169  XGetErrorDatabaseText(dpy, "XRequest", buffer, "", minor_str, 256);
170  } else {
171  extensionName = "Uknown extension";
172  qsnprintf(minor_str, 256, "Unknown request");
173  }
174  qWarning( "X Error: %s %d\n"
175  " Extension: %d (%s)\n"
176  " Minor opcode: %d (%s)\n"
177  " Resource id: 0x%lx",
178  errstr, err->error_code,
179  err->request_code,
180  extensionName,
181  err->minor_code,
182  minor_str,
183  err->resourceid );
184  }
185 
186  // ### we really should distinguish between severe, non-severe and
187  // ### application specific errors
188 
189  return 0;
190 }
191 
193  : mFormat(QImage::Format_RGB32)
194 #if !defined(QT_NO_OPENGL) && defined(QT_OPENGL_ES_2)
195  , mEGLDisplay(0)
196 #endif
197 {
198  char *display_name = getenv("DISPLAY");
199  Display *display = XOpenDisplay(display_name);
200  mDisplay = new QXlibDisplay(display);
201 
202 
203 #ifndef DONT_USE_MIT_SHM
204  int MIT_SHM_extension_supported = XShmQueryExtension (mDisplay->nativeDisplay());
205  Q_ASSERT(MIT_SHM_extension_supported == True);
206 #endif
207  original_x_errhandler = XSetErrorHandler(qt_x_errhandler);
208 
209  if (qgetenv("DO_X_SYNCHRONIZE").toInt())
210  XSynchronize(mDisplay->nativeDisplay(), true);
211 
212  mScreen = DefaultScreen(mDisplay->nativeDisplay());
213  XSelectInput(mDisplay->nativeDisplay(),rootWindow(), KeymapStateMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask);
214  int width = DisplayWidth(mDisplay->nativeDisplay(), mScreen);
215  int height = DisplayHeight(mDisplay->nativeDisplay(), mScreen);
216  mGeometry = QRect(0,0,width,height);
217 
218  int physicalWidth = DisplayWidthMM(mDisplay->nativeDisplay(), mScreen);
219  int physicalHeight = DisplayHeightMM(mDisplay->nativeDisplay(), mScreen);
220  mPhysicalSize = QSize(physicalWidth,physicalHeight);
221 
222  int xSocketNumber = XConnectionNumber(mDisplay->nativeDisplay());
223 
224  mDepth = DefaultDepth(mDisplay->nativeDisplay(),mScreen);
225 #ifdef MYX11_DEBUG
226  qDebug() << "X socket:"<< xSocketNumber;
227 #endif
228  QSocketNotifier *sock = new QSocketNotifier(xSocketNumber, QSocketNotifier::Read, this);
229  connect(sock, SIGNAL(activated(int)), this, SLOT(eventDispatcher()));
230 
231  mCursor = new QXlibCursor(this);
232  mKeyboard = new QXlibKeyboard(this);
233 }
234 
236 {
237  delete mCursor;
238  delete mDisplay;
239 }
240 
242 {
243  return RootWindow(mDisplay->nativeDisplay(), mScreen);
244 }
245 
246 unsigned long QXlibScreen::blackPixel()
247 {
248  return BlackPixel(mDisplay->nativeDisplay(), mScreen);
249 }
250 
251 unsigned long QXlibScreen::whitePixel()
252 {
253  return WhitePixel(mDisplay->nativeDisplay(), mScreen);
254 }
255 
256 #ifdef KeyPress
257 #undef KeyPress
258 #endif
259 #ifdef KeyRelease
260 #undef KeyRelease
261 #endif
262 
264 {
265  int quit = false;
266  QXlibWindow *platformWindow = 0;
267  QWidget *widget = QWidget::find(xe->xany.window);
268  if (widget) {
269  platformWindow = static_cast<QXlibWindow *>(widget->platformWindow());
270  }
271 
274  switch (xe->type) {
275 
276  case ClientMessage:
277  if (xe->xclient.format == 32 && xe->xclient.message_type == wmProtocolsAtom) {
278  Atom a = xe->xclient.data.l[0];
279  if (a == wmDeleteWindowAtom)
280  platformWindow->handleCloseEvent();
281  }
282  break;
283 
284  case Expose:
285  if (platformWindow)
286  if (xe->xexpose.count == 0)
287  platformWindow->paintEvent();
288  break;
289  case ConfigureNotify:
290  if (platformWindow)
291  platformWindow->resizeEvent(&xe->xconfigure);
292  break;
293 
294  case ButtonPress:
295  if (platformWindow)
296  platformWindow->mousePressEvent(&xe->xbutton);
297  break;
298 
299  case ButtonRelease:
300  if (platformWindow)
301  platformWindow->handleMouseEvent(QEvent::MouseButtonRelease, &xe->xbutton);
302  break;
303 
304  case MotionNotify:
305  if (platformWindow)
306  platformWindow->handleMouseEvent(QEvent::MouseMove, &xe->xbutton);
307  break;
308 
309  case XKeyPress:
310  mKeyboard->handleKeyEvent(widget,QEvent::KeyPress, &xe->xkey);
311  break;
312 
313  case XKeyRelease:
314  mKeyboard->handleKeyEvent(widget,QEvent::KeyRelease, &xe->xkey);
315  break;
316 
317  case EnterNotify:
318  if (platformWindow)
319  platformWindow->handleEnterEvent();
320  break;
321 
322  case LeaveNotify:
323  if (platformWindow)
324  platformWindow->handleLeaveEvent();
325  break;
326 
327  case XFocusIn:
328  if (platformWindow)
329  platformWindow->handleFocusInEvent();
330  break;
331 
332  case XFocusOut:
333  if (platformWindow)
334  platformWindow->handleFocusOutEvent();
335  break;
336 
337  case PropertyNotify:
338  break;
339 
340  case SelectionClear:
341  qDebug() << "Selection Clear!!!";
342  break;
343  case SelectionRequest:
345  break;
346  case SelectionNotify:
347  qDebug() << "Selection Notify!!!!";
348 
349  break;
350 
351 
352  default:
353 #ifdef MYX11_DEBUG
354  qDebug() << hex << xe->xany.window << "Other X event" << xe->type;
355 #endif
356  break;
357  }
358 
359  return quit;
360 }
361 
363 {
365  return ((e->type == SelectionRequest && (e->xselectionrequest.selection == XA_PRIMARY
366  || e->xselectionrequest.selection == clipboard))
367  || (e->type == SelectionClear && (e->xselectionclear.selection == XA_PRIMARY
368  || e->xselectionclear.selection == clipboard)));
369 }
370 
372 {
374  timer.start();
375  do {
376  if (XCheckTypedWindowEvent(mDisplay->nativeDisplay(),win,type,event))
377  return true;
378 
379  // process other clipboard events, since someone is probably requesting data from us
380  XEvent e;
381  if (XCheckIfEvent(mDisplay->nativeDisplay(), &e, checkForClipboardEvents, 0))
382  handleEvent(&e);
383 
384  mDisplay->flush();
385 
386  // sleep 50 ms, so we don't use up CPU cycles all the time.
387  struct timeval usleep_tv;
388  usleep_tv.tv_sec = 0;
389  usleep_tv.tv_usec = 50000;
390  select(0, 0, 0, 0, &usleep_tv);
391  } while (timer.elapsed() < timeout);
392  return false;
393 }
394 
396 {
397  ulong marker = XNextRequest(mDisplay->nativeDisplay());
398  // int i = 0;
399  while (XPending(mDisplay->nativeDisplay())) {
400  XEvent event;
401  XNextEvent(mDisplay->nativeDisplay(), &event);
402  /* done = */
403  handleEvent(&event);
404 
405  if (event.xany.serial >= marker) {
406  #ifdef MYX11_DEBUG
407  qDebug() << "potential livelock averted";
408  #endif
409  #if 0
410  if (XEventsQueued(mDisplay->nativeDisplay(), QueuedAfterFlush)) {
411  qDebug() << " with events queued";
413  }
414  #endif
415  break;
416  }
417  }
418 }
419 
420 QImage QXlibScreen::grabWindow(Window window, int x, int y, int w, int h)
421 {
422  if (w == 0 || h ==0)
423  return QImage();
424 
425  //WinId 0 means the desktop widget
426  if (!window)
427  window = rootWindow();
428 
429  XWindowAttributes window_attr;
430  if (!XGetWindowAttributes(mDisplay->nativeDisplay(), window, &window_attr))
431  return QImage();
432 
433  if (w < 0)
434  w = window_attr.width - x;
435  if (h < 0)
436  h = window_attr.height - y;
437 
438  // Ideally, we should also limit ourselves to the screen area, but the Qt docs say
439  // that it's "unsafe" to go outside the screen, so we can ignore that problem.
440 
441  //We're definitely not optimizing for speed...
442  XImage *xi = XGetImage(mDisplay->nativeDisplay(), window, x, y, w, h, AllPlanes, ZPixmap);
443 
444  if (!xi)
445  return QImage();
446 
447  //taking a copy to make sure we have ownership -- not fast
448  QImage result = QImage( (uchar*) xi->data, xi->width, xi->height, xi->bytes_per_line, QImage::Format_RGB32 ).copy();
449 
450  XDestroyImage(xi);
451 
452  return result;
453 }
454 
456 {
457  QPlatformScreen *platformScreen = platformScreenForWidget(widget);
458  return static_cast<QXlibScreen *>(platformScreen);
459 }
460 
462 {
463  return mDisplay;
464 }
465 
467 {
468  return mScreen;
469 }
470 
472 {
473  return DefaultVisual(display()->nativeDisplay(), xScreenNumber());
474 }
475 
477 {
478  return mKeyboard;
479 }
480 
482 {
483  QPlatformIntegration *integration = QApplicationPrivate::platformIntegration();
484  QXlibClipboard *clipboard = static_cast<QXlibClipboard *>(integration->clipboard());
485  clipboard->handleSelectionRequest(event);
486 }
487 
unsigned long whitePixel()
static QWaylandClipboard * clipboard
void handleSelectionRequest(XEvent *event)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
QImage copy(const QRect &rect=QRect()) const
Returns a sub-area of the image as a new image.
Definition: qimage.cpp:1410
void eventDispatcher()
int type
Definition: qmetatype.cpp:239
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QPointer< QWidget > widget
The QPlatformScreen class provides an abstraction for visual displays.
void handleSelectionRequest(XEvent *event)
Window rootWindow()
void paintEvent()
Display * nativeDisplay() const
QImage grabWindow(Window window, int x, int y, int w, int h)
#define SLOT(a)
Definition: qobjectdefs.h:226
void handleMouseEvent(QEvent::Type, XButtonEvent *ev)
static int(* original_x_errhandler)(Display *dpy, XErrorEvent *)
Definition: qxlibscreen.cpp:61
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
int select(int, fd_set *, fd_set *, fd_set *, struct timeval *)
QXlibCursor * mCursor
Definition: qxlibscreen.h:100
QRect mGeometry
Definition: qxlibscreen.h:96
long ASN1_INTEGER_get ASN1_INTEGER * a
EventLoopTimerRef timer
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
virtual bool event(QEvent *)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition: qobject.cpp:1200
#define X11
Definition: qt_x11_p.h:724
void resizeEvent(XConfigureEvent *configure_event)
The QElapsedTimer class provides a fast way to calculate elapsed times.
Definition: qelapsedtimer.h:53
void handleLeaveEvent()
qint64 elapsed() const
Returns the number of milliseconds since this QElapsedTimer was last started.
void handleFocusInEvent()
Q_CORE_EXPORT QTextStream & hex(QTextStream &s)
QSize mPhysicalSize
Definition: qxlibscreen.h:97
The QSocketNotifier class provides support for monitoring activity on a file descriptor.
union _XEvent XEvent
Definition: qwindowdefs.h:116
#define ATOM(x)
Definition: qt_x11_p.h:723
void handleEnterEvent()
Q_CORE_EXPORT void qDebug(const char *,...)
#define SIGNAL(a)
Definition: qobjectdefs.h:227
virtual QPlatformClipboard * clipboard() const
Accessor for the platform integrations clipboard.
static QXlibScreen * testLiteScreenForWidget(QWidget *widget)
unsigned char uchar
Definition: qglobal.h:994
NSWindow * window
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QXlibDisplay * mDisplay
Definition: qxlibscreen.h:103
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
void handleFocusOutEvent()
bool waitForClipboardEvent(Window win, int type, XEvent *event, int timeout)
QXlibKeyboard * keyboard() const
static QWidget * find(WId)
Returns a pointer to the widget with window identifer/handle id.
Definition: qwidget.cpp:2517
static int toInt(const QByteArray &str)
Definition: generator.cpp:167
Q_CORE_EXPORT void qWarning(const char *,...)
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
static QPlatformScreen * platformScreenForWidget(const QWidget *widget)
unsigned long ulong
Definition: qglobal.h:997
The QPlatformIntegration class is the entry for WindowSystem specific functionality.
static Atom atom(X11Atom atom)
char * XPointer
Definition: qt_x11_p.h:180
struct _XDisplay Display
Definition: qwindowdefs.h:115
static int qt_x_errhandler(Display *dpy, XErrorEvent *err)
Definition: qxlibscreen.cpp:64
int xScreenNumber() const
Q_GUI_EXPORT EGLNativeDisplayType nativeDisplay()
Definition: qegl_qpa.cpp:55
void handleCloseEvent()
bool handleEvent(XEvent *xe)
bool singleShot
This static function calls a slot after a given time interval.
Definition: qtimer.h:59
Visual * defaultVisual() const
if(void) toggleToolbarShown
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
int qsnprintf(char *str, size_t n, const char *fmt,...)
A portable snprintf() function, calls qvsnprintf.
Definition: qvsnprintf.cpp:128
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
QXlibKeyboard * mKeyboard
Definition: qxlibscreen.h:101
static bool seen_badwindow
Definition: qxlibscreen.cpp:62
#define QT_OPENGL_ES_2
Definition: main.cpp:46
void handleKeyEvent(QWidget *widget, QEvent::Type type, XKeyEvent *ev)
QXlibDisplay * display() const
void flush() const
static Bool checkForClipboardEvents(Display *, XEvent *e, XPointer)
void start()
Starts this timer.
void mousePressEvent(XButtonEvent *)
unsigned long blackPixel()