x11windowlesscontainer.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2009 Girish Ramakrishnan (girish@forwardbias.in)
  4. ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
  5. **
  6. ** Use, modification and distribution is allowed without limitation,
  7. ** warranty, liability or support of any kind.
  8. **
  9. ****************************************************************************/
  10. #include "x11windowlesscontainer.h"
  11. #include <QX11Info>
  12. #include <X11/Xlib.h>
  13. #ifndef Q_WS_MAEMO_6
  14. #include <X11/extensions/Xrender.h>
  15. #endif
  16. #include "stream.h"
  17. #ifndef Q_WS_MAEMO_6
  18. #include <gdk/gdk.h>
  19. #include <gdk/gdkx.h>
  20. #endif
  21. static int x11ErrorHandler(Display *, XErrorEvent *)
  22. {
  23. return 0;
  24. }
  25. X11WindowlessContainer::X11WindowlessContainer(Instance *instance, QWidget *parent)
  26. : QWidget(parent), m_instance(instance)
  27. {
  28. memset(&m_ws_info, 0, sizeof(NPSetWindowCallbackStruct));
  29. XSetErrorHandler(x11ErrorHandler); // ###: Why?
  30. setMouseTracking(true);
  31. QTimer::singleShot(0, this, SLOT(startStream()));
  32. setFocusPolicy(Qt::ClickFocus);
  33. setAttribute(Qt::WA_OpaquePaintEvent);
  34. }
  35. void X11WindowlessContainer::setWindowIfNeeded()
  36. {
  37. memset(&m_npWindow, 0, sizeof(NPWindow));
  38. m_ws_info.type = 0; // ??
  39. m_ws_info.display = QX11Info::display();
  40. #ifdef GRAB_BS
  41. m_ws_info.visual = (Visual *) m_pixmap.x11Info().visual();
  42. m_ws_info.colormap = m_pixmap.x11Info().colormap();
  43. m_ws_info.depth = m_pixmap.x11Info().depth();
  44. #else
  45. m_ws_info.visual = (Visual *) QX11Info::appVisual();
  46. m_ws_info.colormap = QX11Info::appColormap();
  47. m_ws_info.depth = QX11Info::appDepth();
  48. #endif
  49. m_npWindow.ws_info = &m_ws_info; // needed, whether windowless or not!
  50. m_npWindow.type = NPWindowTypeDrawable;
  51. m_npWindow.window = 0; // Not used?
  52. QPoint windowPos = mapTo(window(), QPoint(0, 0));
  53. #ifdef GRAB_BS
  54. m_npWindow.x = 0;
  55. m_npWindow.y = 0;
  56. #else
  57. m_npWindow.x = windowPos.x();
  58. m_npWindow.y = windowPos.y();
  59. #endif
  60. m_npWindow.width = size().width();
  61. m_npWindow.height = size().height();
  62. Plugin *plugin = m_instance->plugin();
  63. NPError error = plugin->funcs()->setwindow(m_instance->npInstance(), &m_npWindow);
  64. if (error != NPERR_NO_ERROR) {
  65. qDebug() << "X11WindowlessContainer: Failed to setwindow";
  66. }
  67. }
  68. void X11WindowlessContainer::resizeEvent(QResizeEvent *event)
  69. {
  70. #ifdef GRAB_BS
  71. m_pixmap = QPixmap(event->size());
  72. #endif
  73. setWindowIfNeeded();
  74. }
  75. void X11WindowlessContainer::moveEvent(QMoveEvent *event)
  76. {
  77. Q_UNUSED(event);
  78. setWindowIfNeeded();
  79. }
  80. void X11WindowlessContainer::paintUsingImageSurface(QPaintEvent *event)
  81. {
  82. NPImageExpose imageExpose;
  83. QPoint offset;
  84. QPaintDevice* surface = QPainter::redirected(this, &offset);
  85. offset = -offset; // negating the offset gives us the offset of the view within the surface
  86. if (!surface || surface->devType() != QInternal::Image) {
  87. qDebug() << "Not implemented : local rendering is implemented only for raster graphicssystem";
  88. return;
  89. }
  90. QVector<QRect> rects = event->region().rects();
  91. Plugin *plugin = m_instance->plugin();
  92. for (int i = 0; i < rects.count(); i++) {
  93. QRect exposedRect = rects[i];
  94. QImage* image = static_cast<QImage*>(surface);
  95. imageExpose.data = reinterpret_cast<char*>(image->bits());
  96. imageExpose.dataSize.width = image->width();
  97. imageExpose.dataSize.height = image->height();
  98. imageExpose.stride = image->bytesPerLine();
  99. imageExpose.depth = image->depth(); // this is guaranteed to be 16 on Maemo5
  100. imageExpose.translateX = offset.x();
  101. imageExpose.translateY = offset.y();
  102. imageExpose.scaleX = 1;
  103. imageExpose.scaleY = 1;
  104. imageExpose.x = exposedRect.x();
  105. imageExpose.y = exposedRect.y();
  106. imageExpose.width = exposedRect.width();
  107. imageExpose.height = exposedRect.height();
  108. XEvent xevent;
  109. memset(&xevent, 0, sizeof(XEvent));
  110. XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
  111. exposeEvent.type = GraphicsExpose;
  112. exposeEvent.display = 0;
  113. exposeEvent.drawable = reinterpret_cast<XID>(&imageExpose);
  114. exposeEvent.x = exposedRect.x();
  115. exposeEvent.y = exposedRect.y();
  116. exposeEvent.width = exposedRect.width();
  117. exposeEvent.height = exposedRect.height();
  118. plugin->funcs()->event(m_instance->npInstance(), &xevent);
  119. }
  120. }
  121. void X11WindowlessContainer::paintEvent(QPaintEvent *event)
  122. {
  123. if (m_instance->isLocalRendering()) {
  124. paintUsingImageSurface(event); // maemo5 only
  125. return;
  126. }
  127. QPoint offset;
  128. QPaintDevice *backingStore = QPainter::redirected(this, &offset);
  129. offset = -offset;
  130. if (backingStore->devType() != QInternal::Pixmap) {
  131. qDebug() << "Windowless mode implemented only for x11 graphicssystem";
  132. return;
  133. }
  134. QPixmap *pixmap = static_cast<QPixmap *>(backingStore);
  135. #ifndef Q_WS_MAEMO_6
  136. Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
  137. const bool flush = gdkDisplay != QX11Info::display();
  138. #endif
  139. #ifdef GRAB_BS
  140. GC gc = XCreateGC(QX11Info::display(), m_pixmap.handle(), None, 0); // QX11Info::appScreen());
  141. XCopyArea(QX11Info::display(), pixmap->handle(), m_pixmap.handle(), gc,
  142. offset.x() + event->rect().x(), offset.y() + event->rect().y(),
  143. event->rect().width(), event->rect().height(), event->rect().x(), event->rect().y());
  144. #endif
  145. #ifndef Q_WS_MAEMO_6
  146. if (flush) {
  147. qApp->syncX(); // flush any changes to backing store
  148. }
  149. #endif
  150. XEvent xevent;
  151. memset(&xevent, 0, sizeof(XEvent));
  152. xevent.xgraphicsexpose.type = GraphicsExpose;
  153. xevent.xgraphicsexpose.display = QX11Info::display();
  154. #ifdef GRAB_BS
  155. xevent.xgraphicsexpose.drawable = m_pixmap.handle();
  156. xevent.xgraphicsexpose.x = event->rect().x();
  157. xevent.xgraphicsexpose.y = event->rect().y();
  158. xevent.xgraphicsexpose.width = event->rect().x() + event->rect().width(); // flash bug? event->rect().x() is not correct.
  159. xevent.xgraphicsexpose.height = event->rect().y() + event->rect().height();
  160. #else
  161. xevent.xgraphicsexpose.drawable = pixmap->handle();
  162. xevent.xgraphicsexpose.x = offset.x() + event->rect().x();
  163. xevent.xgraphicsexpose.y = offset.y() + event->rect().y();
  164. xevent.xgraphicsexpose.width = event->rect().width();
  165. xevent.xgraphicsexpose.height = event->rect().height();
  166. #endif
  167. Plugin *plugin = m_instance->plugin();
  168. plugin->funcs()->event(m_instance->npInstance(), &xevent);
  169. #ifndef Q_WS_MAEMO_6
  170. if (flush) {
  171. XSync(gdkDisplay, False);
  172. }
  173. #endif
  174. #ifdef GRAB_BS
  175. XCopyArea(QX11Info::display(), m_pixmap.handle(), pixmap->handle(), gc,
  176. event->rect().x(), event->rect().y(),
  177. event->rect().width(), event->rect().height(),
  178. offset.x() + event->rect().x(), offset.y() + event->rect().y());
  179. XFreeGC(QX11Info::display(), gc);
  180. #endif
  181. #if 0 // simple X11
  182. XDrawLine(QX11Info::display(), pixmap->handle(), DefaultGC(QX11Info::display(), QX11Info::appScreen()),
  183. 50, 50, 100, 100);
  184. #elif 0 // XRender
  185. XRenderPictFormat *fmt = XRenderFindStandardFormat(QX11Info::display(), PictStandardRGB24);
  186. XRenderPictureAttributes pict_attr;
  187. pict_attr.poly_edge=PolyEdgeSmooth;
  188. pict_attr.poly_mode=PolyModeImprecise;
  189. Picture picture = XRenderCreatePicture(QX11Info::display(), pixmap->handle(), fmt, CPPolyEdge|CPPolyMode, &pict_attr);
  190. XRenderColor red;
  191. red.red=0xffff;
  192. red.green=0x0;
  193. red.blue=0x0;
  194. red.alpha=0x1234;
  195. XRenderFillRectangle(QX11Info::display(), PictOpOver, picture, &red,
  196. xevent.xgraphicsexpose.x, xevent.xgraphicsexpose.y,
  197. xevent.xgraphicsexpose.width, xevent.xgraphicsexpose.height);
  198. XRenderFreePicture(QX11Info::display(), picture);
  199. #elif 0 // different connection
  200. Display *d = XOpenDisplay(NULL);
  201. XDrawLine(d, pixmap->handle(), DefaultGC(d, DefaultScreen(d)),
  202. event->rect().x(), event->rect().y(), event->rect().width(), event->rect().height());
  203. XSync(d, False);
  204. XCloseDisplay(d);
  205. #endif
  206. }
  207. bool X11WindowlessContainer::event(QEvent *event)
  208. {
  209. XEvent xevent;
  210. memset(&xevent, 0, sizeof(XEvent));
  211. xevent.xany.display = QX11Info::display();
  212. xevent.xany.window = window()->winId(); // ??
  213. switch (event->type()) {
  214. case QEvent::MouseButtonRelease:
  215. case QEvent::MouseButtonPress: {
  216. QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
  217. xevent.xbutton.type = event->type() == QEvent::MouseButtonPress ? ButtonPress : ButtonRelease;
  218. xevent.xbutton.root = QX11Info::appRootWindow();
  219. xevent.xbutton.subwindow = None;
  220. xevent.xbutton.x = mouseEvent->x();
  221. xevent.xbutton.y = mouseEvent->y();
  222. xevent.xbutton.x_root = mouseEvent->globalX();
  223. xevent.xbutton.y_root = mouseEvent->globalY();
  224. xevent.xbutton.state = 0; // ## convert mouseEvent->modifiers()
  225. xevent.xbutton.button = mouseEvent->button() == Qt::LeftButton ? Button1 : Button3; // ##
  226. break;
  227. }
  228. case QEvent::MouseMove: {
  229. QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
  230. xevent.xmotion.type = MotionNotify;
  231. xevent.xmotion.root = QX11Info::appRootWindow();
  232. xevent.xmotion.subwindow = None;
  233. xevent.xmotion.x = mouseEvent->x();
  234. xevent.xmotion.y = mouseEvent->y();
  235. xevent.xmotion.x_root = mouseEvent->globalX();
  236. xevent.xmotion.y_root = mouseEvent->globalY();
  237. xevent.xmotion.state = 0; // ## convert mouseEvent->modifiers() & buttons()
  238. break;
  239. }
  240. #undef KeyRelease
  241. #undef KeyPress
  242. case QEvent::KeyRelease:
  243. case QEvent::KeyPress: {
  244. QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
  245. xevent.xkey.type = event->type() == QEvent::KeyPress ? 2 : 3;
  246. xevent.xkey.root = QX11Info::appRootWindow();
  247. xevent.xkey.subwindow = None;
  248. xevent.xkey.time = 0; // event->timeStamp();
  249. xevent.xkey.state = keyEvent->nativeModifiers();
  250. xevent.xkey.keycode = keyEvent->nativeScanCode();
  251. xevent.xkey.same_screen = true;
  252. xevent.xkey.x = 0;
  253. xevent.xkey.y = 0;
  254. xevent.xkey.x_root = 0;
  255. xevent.xkey.y_root = 0;
  256. break;
  257. }
  258. default:
  259. return QWidget::event(event);
  260. }
  261. // To make mouse propagation work to underlying siblings, we need a new Qt attribute.
  262. Plugin *plugin = m_instance->plugin();
  263. bool handled = plugin->funcs()->event(m_instance->npInstance(), &xevent);
  264. event->setAccepted(handled);
  265. return true;
  266. }
  267. void X11WindowlessContainer::startStream()
  268. {
  269. Stream stream;
  270. stream.write(m_instance);
  271. }