X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fplugins%2Fplatforms%2Fxcb%2Fqxcbwindow.cpp;h=7020e63b0efa70d07c4565dfeb3748dfcae05f24;hb=015a5e0dcad0bca55d10822f6300b77a95fb69d6;hp=6996c87f3fea7701a2846b63d1f81901b8b6de2f;hpb=9bd032355163d92cda5e7e59ecd21214b131f187;p=profile%2Fivi%2Fqtbase.git diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 6996c87..7020e63 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -43,14 +43,17 @@ #include #include +#include +#include #include "qxcbconnection.h" #include "qxcbscreen.h" #include "qxcbdrag.h" #include "qxcbkeyboard.h" #include "qxcbwmsupport.h" +#include "qxcbimage.h" -#include +#include #ifdef XCB_USE_DRI2 #include "qdri2context.h" @@ -61,6 +64,9 @@ #include #undef class #include +#ifndef QT_NO_SHAPE +# include +#endif // QT_NO_SHAPE // xcb-icccm 3.8 support #ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS @@ -87,8 +93,8 @@ #include #include -#include -#include +#include +#include #include @@ -97,7 +103,7 @@ #include #endif -#ifdef XCB_USE_XINPUT2_MAEMO +#if defined(XCB_USE_XINPUT2_MAEMO) || defined(XCB_USE_XINPUT2) #include #endif @@ -138,14 +144,21 @@ static inline QImage::Format imageFormatForDepth(int depth) } } +static inline bool positionIncludesFrame(QWindow *w) +{ + return qt_window_private(w)->positionPolicy == QWindowPrivate::WindowFrameInclusive; +} + QXcbWindow::QXcbWindow(QWindow *window) : QPlatformWindow(window) , m_window(0) , m_syncCounter(0) + , m_gravity(XCB_GRAVITY_STATIC) , m_mapped(false) , m_transparent(false) , m_deferredActivation(false) , m_netWmUserTimeWindow(XCB_NONE) + , m_dirtyFrameMargins(false) #if defined(XCB_USE_EGL) , m_eglSurface(0) #endif @@ -176,6 +189,11 @@ void QXcbWindow::create() return; } + // Determine gravity from initial position. Do not change + // later as it will cause the window to move uncontrollably. + m_gravity = positionIncludesFrame(window()) ? + XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC; + const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK; const quint32 values[] = { // XCB_CW_BACK_PIXMAP @@ -199,6 +217,9 @@ void QXcbWindow::create() | XCB_EVENT_MASK_FOCUS_CHANGE }; + // Parameters to XCreateWindow() are frame corner + inner size. + // This fits in case position policy is frame inclusive. There is + // currently no way to implement it for frame-exclusive geometries. QRect rect = window()->geometry(); QPlatformWindow::setGeometry(rect); @@ -217,7 +238,7 @@ void QXcbWindow::create() { #if defined(XCB_USE_GLX) XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), &m_format); - if (!visualInfo) + if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface) qFatal("Could not initialize GLX"); #elif defined(XCB_USE_EGL) EGLDisplay eglDisplay = connection()->egl_display(); @@ -233,26 +254,30 @@ void QXcbWindow::create() XVisualInfo *visualInfo; int matchingCount = 0; visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount); - if (!visualInfo) + if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface) qFatal("Could not initialize EGL"); #endif //XCB_USE_GLX - m_depth = visualInfo->depth; - m_imageFormat = imageFormatForDepth(m_depth); - Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone); + if (visualInfo) { + m_depth = visualInfo->depth; + m_imageFormat = imageFormatForDepth(m_depth); + Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone); - XSetWindowAttributes a; - a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); - a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); - a.colormap = cmap; + XSetWindowAttributes a; + a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); + a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); + a.colormap = cmap; - m_visualId = visualInfo->visualid; + m_visualId = visualInfo->visualid; - m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(), - 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWBackPixel|CWBorderPixel|CWColormap, &a); + m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(), + 0, visualInfo->depth, InputOutput, visualInfo->visual, + CWBackPixel|CWBorderPixel|CWColormap, &a); - XFree(visualInfo); - } else + XFree(visualInfo); + } + } + + if (!m_window) #endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL) { m_window = xcb_generate_id(xcb_connection()); @@ -338,7 +363,7 @@ void QXcbWindow::create() 1, &leader)); #ifdef XCB_USE_XINPUT2_MAEMO - if (connection()->isUsingXInput2()) { + if (connection()->isUsingXInput2Maemo()) { XIEventMask xieventmask; uchar bitmask[2] = { 0, 0 }; @@ -352,6 +377,8 @@ void QXcbWindow::create() XISelectEvents(DISPLAY_FROM_XCB(this), m_window, &xieventmask, 1); } +#elif defined(XCB_USE_XINPUT2) + connection()->xi2Select(m_window); #endif setWindowFlags(window()->windowFlags()); @@ -361,7 +388,9 @@ void QXcbWindow::create() if (window()->windowFlags() & Qt::WindowTransparentForInput) setTransparentForMouseEvents(true); +#ifndef QT_NO_DRAGANDDROP connection()->drag()->dndEnable(this, true); +#endif } QXcbWindow::~QXcbWindow() @@ -384,6 +413,7 @@ void QXcbWindow::destroy() } connection()->removeWindow(m_window); Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window)); + m_window = 0; } m_mapped = false; @@ -398,13 +428,14 @@ void QXcbWindow::setGeometry(const QRect &rect) QPlatformWindow::setGeometry(rect); propagateSizeHints(); + const QRect wmGeometry = windowToWmGeometry(rect); const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; const qint32 values[] = { - qBound(-XCOORD_MAX, rect.x(), XCOORD_MAX), - qBound(-XCOORD_MAX, rect.y(), XCOORD_MAX), - qBound(1, rect.width(), XCOORD_MAX), - qBound(1, rect.height(), XCOORD_MAX), + qBound(-XCOORD_MAX, wmGeometry.x(), XCOORD_MAX), + qBound(-XCOORD_MAX, wmGeometry.y(), XCOORD_MAX), + qBound(1, wmGeometry.width(), XCOORD_MAX), + qBound(1, wmGeometry.height(), XCOORD_MAX), }; Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast(values))); @@ -1104,6 +1135,49 @@ void QXcbWindow::setWindowTitle(const QString &title) ba.constData())); } +void QXcbWindow::setWindowIcon(const QIcon &icon) +{ + QVector icon_data; + + if (!icon.isNull()) { + QList availableSizes = icon.availableSizes(); + if (availableSizes.isEmpty()) { + // try to use default sizes since the icon can be a scalable image like svg. + availableSizes.push_back(QSize(16,16)); + availableSizes.push_back(QSize(32,32)); + availableSizes.push_back(QSize(64,64)); + availableSizes.push_back(QSize(128,128)); + } + for (int i = 0; i < availableSizes.size(); ++i) { + QSize size = availableSizes.at(i); + QPixmap pixmap = icon.pixmap(size); + if (!pixmap.isNull()) { + QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32); + int pos = icon_data.size(); + icon_data.resize(pos + 2 + image.width()*image.height()); + icon_data[pos++] = image.width(); + icon_data[pos++] = image.height(); + memcpy(icon_data.data() + pos, image.bits(), image.width()*image.height()*4); + } + } + } + + if (!icon_data.isEmpty()) { + Q_XCB_CALL(xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, + m_window, + atom(QXcbAtom::_NET_WM_ICON), + atom(QXcbAtom::CARDINAL), + 32, + icon_data.size(), + (unsigned char *) icon_data.data())); + } else { + Q_XCB_CALL(xcb_delete_property(xcb_connection(), + m_window, + atom(QXcbAtom::_NET_WM_ICON))); + } +} + void QXcbWindow::raise() { const quint32 mask = XCB_CONFIG_WINDOW_STACK_MODE; @@ -1118,20 +1192,36 @@ void QXcbWindow::lower() Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values)); } +// Adapt the geometry to match the WM expection with regards +// to gravity. +QRect QXcbWindow::windowToWmGeometry(QRect r) const +{ + if (m_dirtyFrameMargins || m_frameMargins.isNull()) + return r; + const bool frameInclusive = positionIncludesFrame(window()); + // XCB_GRAVITY_STATIC requires the inner geometry, whereas + // XCB_GRAVITY_NORTH_WEST requires the frame geometry + if (frameInclusive && m_gravity == XCB_GRAVITY_STATIC) { + r.translate(m_frameMargins.left(), m_frameMargins.top()); + } else if (!frameInclusive && m_gravity == XCB_GRAVITY_NORTH_WEST) { + r.translate(-m_frameMargins.left(), -m_frameMargins.top()); + } + return r; +} + void QXcbWindow::propagateSizeHints() { // update WM_NORMAL_HINTS xcb_size_hints_t hints; memset(&hints, 0, sizeof(hints)); - QRect rect = geometry(); + const QRect rect = windowToWmGeometry(geometry()); QWindow *win = window(); xcb_size_hints_set_position(&hints, true, rect.x(), rect.y()); xcb_size_hints_set_size(&hints, true, rect.width(), rect.height()); - xcb_size_hints_set_win_gravity(&hints, qt_window_private(win)->positionPolicy == QWindowPrivate::WindowFrameInclusive - ? XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC); + xcb_size_hints_set_win_gravity(&hints, m_gravity); QSize minimumSize = win->minimumSize(); QSize maximumSize = win->maximumSize(); @@ -1188,7 +1278,7 @@ void QXcbWindow::requestActivateWindow() } #if XCB_USE_MAEMO_WINDOW_PROPERTIES -void QXcbWindow::setOrientation(Qt::ScreenOrientation orientation) +void QXcbWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation) { int angle = 0; switch (orientation) { @@ -1266,6 +1356,7 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even } else { qWarning() << "QXcbWindow: Unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]); } +#ifndef QT_NO_DRAGANDDROP } else if (event->type == atom(QXcbAtom::XdndEnter)) { connection()->drag()->handleEnter(window(), event); } else if (event->type == atom(QXcbAtom::XdndPosition)) { @@ -1274,6 +1365,7 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even connection()->drag()->handleLeave(window(), event); } else if (event->type == atom(QXcbAtom::XdndDrop)) { connection()->drag()->handleDrop(window(), event); +#endif } else if (event->type == atom(QXcbAtom::_XEMBED)) { // QSystemTrayIcon } else { qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type); @@ -1589,4 +1681,63 @@ void QXcbWindow::setCursor(xcb_cursor_t cursor) xcb_flush(xcb_connection()); } +bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) +{ + const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); + if (!connection()->wmSupport()->isSupportedByWM(moveResize)) + return false; + xcb_client_message_event_t xev; + xev.response_type = XCB_CLIENT_MESSAGE; + xev.type = moveResize; + xev.window = xcb_window(); + xev.format = 32; + const QPoint globalPos = window()->mapToGlobal(pos); + xev.data.data32[0] = globalPos.x(); + xev.data.data32[1] = globalPos.y(); + const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner; + const bool left = corner == Qt::BottomLeftCorner || corner == Qt::TopLeftCorner; + if (bottom) + xev.data.data32[2] = left ? 6 : 4; // bottomleft/bottomright + else + xev.data.data32[2] = left ? 0 : 2; // topleft/topright + xev.data.data32[3] = XCB_BUTTON_INDEX_1; + xev.data.data32[4] = 0; + xcb_ungrab_pointer(connection()->xcb_connection(), XCB_CURRENT_TIME); + xcb_send_event(connection()->xcb_connection(), false, m_screen->root(), + XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, + (const char *)&xev); + return true; +} + +#if !defined(QT_NO_SHAPE) + +static inline xcb_rectangle_t qRectToXCBRectangle(const QRect &r) +{ + xcb_rectangle_t result; + result.x = qMax(SHRT_MIN, r.x()); + result.y = qMax(SHRT_MIN, r.y()); + result.width = qMin((int)USHRT_MAX, r.width()); + result.height = qMin((int)USHRT_MAX, r.height()); + return result; +} + +void QXcbWindow::setMask(const QRegion ®ion) +{ + if (!connection()->hasXShape()) + return; + if (region.isEmpty()) { + xcb_shape_mask(connection()->xcb_connection(), XCB_SHAPE_SO_SET, + XCB_SHAPE_SK_BOUNDING, xcb_window(), 0, 0, XCB_NONE); + } else { + QVector rects; + foreach (const QRect &r, region.rects()) + rects.push_back(qRectToXCBRectangle(r)); + xcb_shape_rectangles(connection()->xcb_connection(), XCB_SHAPE_SO_SET, + XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, + xcb_window(), 0, 0, rects.size(), &rects[0]); + } +} + +#endif // !QT_NO_SHAPE + QT_END_NAMESPACE