static void weston_wm_send_selection_notify(struct weston_wm *wm, xcb_atom_t property) { xcb_selection_notify_event_t selection_notify; memset(&selection_notify, 0, sizeof selection_notify); selection_notify.response_type = XCB_SELECTION_NOTIFY; selection_notify.sequence = 0; selection_notify.time = wm->selection_request.time; selection_notify.requestor = wm->selection_request.requestor; selection_notify.selection = wm->selection_request.selection; selection_notify.target = wm->selection_request.target; selection_notify.property = property; xcb_send_event(wm->conn, 0, /* propagate */ wm->selection_request.requestor, XCB_EVENT_MASK_NO_EVENT, (char *) &selection_notify); }
void send_client_message(xcb_window_t destination, xcb_window_t window, xcb_atom_t message, const uint32_t data[]) { xcb_client_message_event_t event; event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; event.sequence = 0; event.window = window; event.type = message; int i; for (i = 0; i < 5; i++) { event.data.data32[i] = data[i]; } xcb_send_event(conn, 0, destination, mask, (const char *) &event); }
// === MinimizeWindow() === void LXCB::MinimizeWindow(WId win){ //request that the window be unmapped/minimized if(DEBUG){ qDebug() << "XCB: MinimizeWindow()"; } if(win==0){ return; } //Note: Fluxbox completely removes this window from the open list if unmapped manually // xcb_unmap_window(QX11Info::connection(), win); //xcb_flush(QX11Info::connection()); //make sure the command is sent out right away //Need to send a client message event for the window so the WM picks it up xcb_client_message_event_t event; event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; event.window = win; event.type = EWMH._NET_WM_STATE; event.data.data32[0] = 1; //set to toggle (switch back and forth) event.data.data32[1] = EWMH._NET_WM_STATE_HIDDEN; event.data.data32[2] = 0; event.data.data32[3] = 0; event.data.data32[4] = 0; xcb_send_event(QX11Info::connection(), 0, QX11Info::appRootWindow(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *) &event); }
// === SetAsSticky() === void LXCB::SetAsSticky(WId win){ if(DEBUG){ qDebug() << "XCB: SetAsSticky()"; } if(win==0){ return; } //Need to send a client message event for the window so the WM picks it up xcb_client_message_event_t event; event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; event.window = win; event.type = EWMH._NET_WM_STATE; event.data.data32[0] = 1; //set to enabled event.data.data32[1] = EWMH._NET_WM_STATE_STICKY; event.data.data32[2] = 0; event.data.data32[3] = 0; event.data.data32[4] = 0; xcb_send_event(QX11Info::connection(), 0, QX11Info::appRootWindow(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *) &event); //This method changes the property on the window directly - the WM is not aware of it /*xcb_change_property( QX11Info::connection(), XCB_PROP_MODE_APPEND, win, EWMH._NET_WM_STATE, XCB_ATOM_ATOM, 32, 1, &(EWMH._NET_WM_STATE_STICKY) ); xcb_flush(QX11Info::connection()); //apply it right away*/ }
/* window_configure {{{ * @window the window be changed * @new_geom the new geometry * @border border in pixels */ void window_configure(xcb_window_t window, uint16_t x, uint16_t y, uint16_t width, uint16_t height, int border) { xcb_configure_notify_event_t conf; /* Fill the struct */ conf.event = window; conf.window = window; conf.response_type = XCB_CONFIGURE_NOTIFY; conf.above_sibling = XCB_NONE; conf.override_redirect = false; conf.x = x; conf.y = y; conf.width = width; conf.height = width; /* Update */ xcb_send_event(rootconf.connection, false, window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &conf); } /* }}} */
void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *event) { if (event->format == 32 && event->type == atom(QXcbAtom::WM_PROTOCOLS)) { if (event->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW)) { QWindowSystemInterface::handleCloseEvent(widget()); } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) { xcb_client_message_event_t reply = *event; reply.response_type = XCB_CLIENT_MESSAGE; reply.window = m_screen->root(); xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply); xcb_flush(xcb_connection()); } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) { if (!m_hasReceivedSyncRequest) { m_hasReceivedSyncRequest = true; printf("Window manager supports _NET_WM_SYNC_REQUEST, syncing resizes\n"); } m_syncValue.lo = event->data.data32[2]; m_syncValue.hi = event->data.data32[3]; } } }
void QXcbScreen::sendStartupMessage(const QByteArray &message) const { xcb_window_t rootWindow = root(); xcb_client_message_event_t ev; ev.response_type = XCB_CLIENT_MESSAGE; ev.format = 8; ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO_BEGIN); ev.window = rootWindow; int sent = 0; int length = message.length() + 1; // include NUL byte const char *data = message.constData(); do { if (sent == 20) ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO); const int start = sent; const int numBytes = qMin(length - start, 20); memcpy(ev.data.data8, data + start, numBytes); xcb_send_event(connection()->xcb_connection(), false, rootWindow, XCB_EVENT_MASK_PROPERTY_CHANGE, (const char *) &ev); sent += numBytes; } while (sent < length); }
// ===== startSystemTray() ===== WId LXCB::startSystemTray(int screen){ qDebug() << "Starting System Tray:" << screen; //Setup the freedesktop standards compliance //Get the appropriate atom for this screen QString str = QString("_NET_SYSTEM_TRAY_S%1").arg(QString::number(screen)); //qDebug() << "Default Screen Atom Name:" << str; xcb_intern_atom_reply_t *treply = xcb_intern_atom_reply(QX11Info::connection(), \ xcb_intern_atom(QX11Info::connection(), 0, str.length(), str.toLocal8Bit()), NULL); xcb_intern_atom_reply_t *oreply = xcb_intern_atom_reply(QX11Info::connection(), \ xcb_intern_atom(QX11Info::connection(), 0, 28, "_NET_SYSTEM_TRAY_ORIENTATION"), NULL); xcb_intern_atom_reply_t *vreply = xcb_intern_atom_reply(QX11Info::connection(), \ xcb_intern_atom(QX11Info::connection(), 0, 23, "_NET_SYSTEM_TRAY_VISUAL"), NULL); if(treply==0){ qDebug() << " - ERROR: Could not initialize _NET_SYSTEM_TRAY_S<num> atom"; return 0; } if(oreply==0){ qDebug() << " - ERROR: Could not initialize _NET_SYSTEM_TRAY_ORIENTATION atom"; return 0; } if(vreply==0){ qDebug() << " - ERROR: Could not initialize _NET_SYSTEM_TRAY_VISUAL atom"; return 0; } xcb_atom_t _NET_SYSTEM_TRAY_S = treply->atom; xcb_atom_t _NET_SYSTEM_TRAY_ORIENTATION = oreply->atom; xcb_atom_t _NET_SYSTEM_TRAY_VISUAL = vreply->atom; free(treply); //done with atom generation free(oreply); free(vreply); //Make sure that there is no other system tray running xcb_get_selection_owner_reply_t *ownreply = xcb_get_selection_owner_reply(QX11Info::connection(), \ xcb_get_selection_owner_unchecked(QX11Info::connection(), _NET_SYSTEM_TRAY_S), NULL); if(ownreply==0){ qWarning() << " - Could not get owner selection reply"; return 0; } if(ownreply->owner != 0){ free(ownreply); qWarning() << " - An alternate system tray is currently in use"; return 0; } free(ownreply); //Create a simple window to register as the tray (not visible - just off the screen) xcb_screen_t *root_screen = xcb_aux_get_screen(QX11Info::connection(), QX11Info::appScreen()); uint32_t params[] = {1}; WId LuminaSessionTrayID = xcb_generate_id(QX11Info::connection()); //need a new ID xcb_create_window(QX11Info::connection(), root_screen->root_depth, \ LuminaSessionTrayID, root_screen->root, -1, -1, 1, 1, 0, \ XCB_WINDOW_CLASS_INPUT_OUTPUT, root_screen->root_visual, \ XCB_CW_OVERRIDE_REDIRECT, params); //Now register this widget as the system tray xcb_set_selection_owner(QX11Info::connection(), LuminaSessionTrayID, _NET_SYSTEM_TRAY_S, XCB_CURRENT_TIME); //Make sure that it was registered properly ownreply = xcb_get_selection_owner_reply(QX11Info::connection(), \ xcb_get_selection_owner_unchecked(QX11Info::connection(), _NET_SYSTEM_TRAY_S), NULL); if(ownreply==0 || ownreply->owner != LuminaSessionTrayID){ if(ownreply!=0){ free(ownreply); } qWarning() << " - Could not register the system tray"; xcb_destroy_window(QX11Info::connection(), LuminaSessionTrayID); return 0; } free(ownreply); //done with structure //Now register the orientation of the system tray uint32_t orient = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, LuminaSessionTrayID, \ _NET_SYSTEM_TRAY_ORIENTATION, XCB_ATOM_CARDINAL, 32, 1, &orient); //Now set the visual ID for the system tray (same as the root window, but TrueColor) xcb_visualtype_t *type = xcb_aux_find_visual_by_attrs(root_screen, XCB_VISUAL_CLASS_TRUE_COLOR, 32); if(type!=0){ xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, LuminaSessionTrayID, \ _NET_SYSTEM_TRAY_VISUAL, XCB_ATOM_VISUALID, 32, 1, &type->visual_id); }else{ qWarning() << " - Could not set TrueColor visual for system tray"; } //Finally, send out an X event letting others know that the system tray is up and running xcb_client_message_event_t event; event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; event.window = root_screen->root; event.type = EWMH.MANAGER; //MANAGER atom event.data.data32[0] = XCB_TIME_CURRENT_TIME; //CurrentTime; event.data.data32[1] = _NET_SYSTEM_TRAY_S; //_NET_SYSTEM_TRAY_S atom event.data.data32[2] = LuminaSessionTrayID; event.data.data32[3] = 0; event.data.data32[4] = 0; xcb_send_event(QX11Info::connection(), 0, root_screen->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *) &event); //Success return LuminaSessionTrayID; }
/** Changes the EWMH state of the window */ static void set_wm_state (vout_window_t *wnd, bool on, xcb_atom_t state) { vout_window_sys_t *sys = wnd->sys; /* From EWMH "_WM_STATE" */ xcb_client_message_event_t ev = { .response_type = XCB_CLIENT_MESSAGE, .format = 32, .window = wnd->handle.xid, .type = sys->wm_state, }; ev.data.data32[0] = on ? NET_WM_STATE_ADD : NET_WM_STATE_REMOVE; ev.data.data32[1] = state; ev.data.data32[2] = 0; ev.data.data32[3] = 1; /* From ICCCM "Changing Window State" */ xcb_send_event (sys->conn, 0, sys->root, XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&ev); } static int Control (vout_window_t *wnd, int cmd, va_list ap) { vout_window_sys_t *p_sys = wnd->sys; xcb_connection_t *conn = p_sys->conn; switch (cmd) { case VOUT_WINDOW_SET_SIZE: { if (p_sys->embedded) return VLC_EGENERIC; unsigned width = va_arg (ap, unsigned); unsigned height = va_arg (ap, unsigned); const uint32_t values[] = { width, height, }; xcb_configure_window (conn, wnd->handle.xid, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); break; } case VOUT_WINDOW_SET_STATE: { unsigned state = va_arg (ap, unsigned); bool above = (state & VOUT_WINDOW_STATE_ABOVE) != 0; bool below = (state & VOUT_WINDOW_STATE_BELOW) != 0; set_wm_state (wnd, above, p_sys->wm_state_above); set_wm_state (wnd, below, p_sys->wm_state_below); break; } case VOUT_WINDOW_SET_FULLSCREEN: { bool fs = va_arg (ap, int); if (!fs && var_GetBool (wnd, "video-wallpaper")) return VLC_EGENERIC; set_wm_state (wnd, fs, p_sys->wm_state_fullscreen); break; } default: msg_Err (wnd, "request %d not implemented", cmd); return VLC_EGENERIC; } xcb_flush (p_sys->conn); return VLC_SUCCESS; }
void configure_request(xcb_generic_event_t *evt) { xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt; PRINTF("configure request %X\n", e->window); coordinates_t loc; bool is_managed = locate_window(e->window, &loc); client_t *c = (is_managed ? loc.node->client : NULL); int w = 0, h = 0; if (is_managed && !is_floating(c)) { if (e->value_mask & XCB_CONFIG_WINDOW_X) c->floating_rectangle.x = e->x; if (e->value_mask & XCB_CONFIG_WINDOW_Y) c->floating_rectangle.y = e->y; if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) w = e->width; if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) h = e->height; if (w != 0) { restrain_floating_width(c, &w); c->floating_rectangle.width = w; } if (h != 0) { restrain_floating_height(c, &h); c->floating_rectangle.height = h; } xcb_configure_notify_event_t evt; xcb_rectangle_t rect; xcb_window_t win = c->window; unsigned int bw = c->border_width; if (c->fullscreen) rect = loc.monitor->rectangle; else rect = c->tiled_rectangle; evt.response_type = XCB_CONFIGURE_NOTIFY; evt.event = win; evt.window = win; evt.above_sibling = XCB_NONE; evt.x = rect.x; evt.y = rect.y; evt.width = rect.width; evt.height = rect.height; evt.border_width = bw; evt.override_redirect = false; xcb_send_event(dpy, false, win, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt); if (c->pseudo_tiled) arrange(loc.monitor, loc.desktop); } else { uint16_t mask = 0; uint32_t values[7]; unsigned short i = 0; if (e->value_mask & XCB_CONFIG_WINDOW_X) { mask |= XCB_CONFIG_WINDOW_X; values[i++] = e->x; if (is_managed) c->floating_rectangle.x = e->x; } if (e->value_mask & XCB_CONFIG_WINDOW_Y) { mask |= XCB_CONFIG_WINDOW_Y; values[i++] = e->y; if (is_managed) c->floating_rectangle.y = e->y; } if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) { mask |= XCB_CONFIG_WINDOW_WIDTH; w = e->width; if (is_managed) { restrain_floating_width(c, &w); c->floating_rectangle.width = w; } values[i++] = w; } if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) { mask |= XCB_CONFIG_WINDOW_HEIGHT; h = e->height; if (is_managed) { restrain_floating_height(c, &h); c->floating_rectangle.height = h; } values[i++] = h; } if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) { mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH; values[i++] = e->border_width; } if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) { mask |= XCB_CONFIG_WINDOW_SIBLING; values[i++] = e->sibling; } if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) { mask |= XCB_CONFIG_WINDOW_STACK_MODE; values[i++] = e->stack_mode; } xcb_configure_window(dpy, e->window, mask, values); } if (is_managed) translate_client(monitor_from_client(c), loc.monitor, c); }
void QXcbDrag::move(const QMouseEvent *me) { // The mouse event is in the coordinate system of the window that started the drag. // We do not know which window that was at this point, so we just use the device pixel ratio // of the QGuiApplication. This will break once we support screens with different DPR. Fixing // this properly requires some redesign of the drag and drop architecture. static const int dpr = int(qApp->devicePixelRatio()); QBasicDrag::move(me); QPoint globalPos = me->globalPos(); if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid()) return; const QList<QXcbScreen *> &screens = connection()->screens(); QXcbScreen *screen = connection()->primaryScreen(); for (int i = 0; i < screens.size(); ++i) { if (screens.at(i)->geometry().contains(globalPos)) { screen = screens.at(i); break; } } if (screen != current_screen) { // ### need to recreate the shaped pixmap window? // int screen = QCursor::x11Screen(); // if ((qt_xdnd_current_screen == -1 && screen != X11->defaultScreen) || (screen != qt_xdnd_current_screen)) { // // recreate the pixmap on the new screen... // delete xdnd_data.deco; // QWidget* parent = object->source()->window()->x11Info().screen() == screen // ? object->source()->window() : QApplication::desktop()->screen(screen); // xdnd_data.deco = new QShapedPixmapWidget(parent); // if (!QWidget::mouseGrabber()) { // updatePixmap(); // xdnd_data.deco->grabMouse(); // } // } // xdnd_data.deco->move(QCursor::pos() - xdnd_data.deco->pm_hot); current_screen = screen; } // qt_xdnd_current_screen = screen; xcb_window_t rootwin = current_screen->root(); xcb_translate_coordinates_reply_t *translate = ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x() * dpr, globalPos.y() * dpr); if (!translate) return; xcb_window_t target = translate->child; int lx = translate->dst_x; int ly = translate->dst_y; free (translate); if (target && target != rootwin) { xcb_window_t src = rootwin; while (target != 0) { DNDDEBUG << "checking target for XdndAware" << target << lx << ly; // translate coordinates translate = ::translateCoordinates(connection(), src, target, lx, ly); if (!translate) { target = 0; break; } lx = translate->dst_x; ly = translate->dst_y; src = target; xcb_window_t child = translate->child; free(translate); // check if it has XdndAware xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, target, atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0)); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); bool aware = reply && reply->type != XCB_NONE; free(reply); if (aware) { DNDDEBUG << "Found XdndAware on " << target; break; } target = child; } if (!target || target == shapedPixmapWindow()->handle()->winId()) { DNDDEBUG << "need to find real window"; target = findRealWindow(globalPos, rootwin, 6, true); if (target == 0) target = findRealWindow(globalPos, rootwin, 6, false); DNDDEBUG << "real window found" << target; } } QXcbWindow *w = 0; if (target) { w = connection()->platformWindowFromId(target); if (w && (w->window()->type() == Qt::Desktop) /*&& !w->acceptDrops()*/) w = 0; } else { w = 0; target = rootwin; } xcb_window_t proxy_target = xdndProxy(connection(), target); if (!proxy_target) proxy_target = target; int target_version = 1; if (proxy_target) { xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, proxy_target, atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 1); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); if (!reply || reply->type == XCB_NONE) target = 0; target_version = *(uint32_t *)xcb_get_property_value(reply); target_version = qMin(xdnd_version, target_version ? target_version : 1); free(reply); } if (target != current_target) { if (current_target) send_leave(); current_target = target; current_proxy_target = proxy_target; if (target) { int flags = target_version << 24; if (drag_types.size() > 3) flags |= 0x0001; xcb_client_message_event_t enter; enter.response_type = XCB_CLIENT_MESSAGE; enter.window = target; enter.format = 32; enter.type = atom(QXcbAtom::XdndEnter); enter.data.data32[0] = connection()->clipboard()->owner(); enter.data.data32[1] = flags; enter.data.data32[2] = drag_types.size()>0 ? drag_types.at(0) : 0; enter.data.data32[3] = drag_types.size()>1 ? drag_types.at(1) : 0; enter.data.data32[4] = drag_types.size()>2 ? drag_types.at(2) : 0; // provisionally set the rectangle to 5x5 pixels... source_sameanswer = QRect(globalPos.x() - 2, globalPos.y() -2 , 5, 5); DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0]; if (w) handleEnter(w->window(), &enter); else if (target) xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&enter); waiting_for_status = false; } } if (waiting_for_status) return; if (target) { waiting_for_status = true; xcb_client_message_event_t move; move.response_type = XCB_CLIENT_MESSAGE; move.window = target; move.format = 32; move.type = atom(QXcbAtom::XdndPosition); move.data.data32[0] = connection()->clipboard()->owner(); move.data.data32[1] = 0; // flags move.data.data32[2] = (globalPos.x() * dpr << 16) + globalPos.y() * dpr; move.data.data32[3] = connection()->time(); move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), QGuiApplication::keyboardModifiers())); DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window; source_time = connection()->time(); if (w) handle_xdnd_position(w->window(), &move); else xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move); } }
//_____________________________________________ void SizeGrip::sendMoveResizeEvent( QPoint position ) { #if OXYGEN_HAVE_X11 if( !QX11Info::isPlatformX11() ) return; // pointer to connection auto connection( QX11Info::connection() ); // client auto c = m_decoration.data()->client().data(); /* get root position matching position need to use xcb because the embedding of the widget breaks QT's mapToGlobal and other methods */ QPoint rootPosition( position ); xcb_get_geometry_cookie_t cookie( xcb_get_geometry( connection, winId() ) ); ScopedPointer<xcb_get_geometry_reply_t> reply( xcb_get_geometry_reply( connection, cookie, 0x0 ) ); if( reply ) { // translate coordinates xcb_translate_coordinates_cookie_t coordCookie( xcb_translate_coordinates( connection, winId(), reply.data()->root, -reply.data()->border_width, -reply.data()->border_width ) ); ScopedPointer< xcb_translate_coordinates_reply_t> coordReply( xcb_translate_coordinates_reply( connection, coordCookie, 0x0 ) ); if( coordReply ) { rootPosition.rx() += coordReply.data()->dst_x; rootPosition.ry() += coordReply.data()->dst_y; } } // move/resize atom if( !m_moveResizeAtom ) { // create atom if not found const QString atomName( "_NET_WM_MOVERESIZE" ); xcb_intern_atom_cookie_t cookie( xcb_intern_atom( connection, false, atomName.size(), qPrintable( atomName ) ) ); ScopedPointer<xcb_intern_atom_reply_t> reply( xcb_intern_atom_reply( connection, cookie, 0x0 ) ); m_moveResizeAtom = reply ? reply->atom:0; } if( !m_moveResizeAtom ) return; // button release event xcb_button_release_event_t releaseEvent; memset(&releaseEvent, 0, sizeof(releaseEvent)); releaseEvent.response_type = XCB_BUTTON_RELEASE; releaseEvent.event = winId(); releaseEvent.child = XCB_WINDOW_NONE; releaseEvent.root = QX11Info::appRootWindow(); releaseEvent.event_x = position.x(); releaseEvent.event_y = position.y(); releaseEvent.root_x = rootPosition.x(); releaseEvent.root_y = rootPosition.y(); releaseEvent.detail = XCB_BUTTON_INDEX_1; releaseEvent.state = XCB_BUTTON_MASK_1; releaseEvent.time = XCB_CURRENT_TIME; releaseEvent.same_screen = true; xcb_send_event( connection, false, winId(), XCB_EVENT_MASK_BUTTON_RELEASE, reinterpret_cast<const char*>(&releaseEvent)); xcb_ungrab_pointer( connection, XCB_TIME_CURRENT_TIME ); // move resize event xcb_client_message_event_t clientMessageEvent; memset(&clientMessageEvent, 0, sizeof(clientMessageEvent)); clientMessageEvent.response_type = XCB_CLIENT_MESSAGE; clientMessageEvent.type = m_moveResizeAtom; clientMessageEvent.format = 32; clientMessageEvent.window = c->windowId(); clientMessageEvent.data.data32[0] = rootPosition.x(); clientMessageEvent.data.data32[1] = rootPosition.y(); clientMessageEvent.data.data32[2] = 4; // bottom right clientMessageEvent.data.data32[3] = Qt::LeftButton; clientMessageEvent.data.data32[4] = 0; xcb_send_event( connection, false, QX11Info::appRootWindow(), XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, reinterpret_cast<const char*>(&clientMessageEvent) ); xcb_flush( connection ); #endif }
static void forwardMouseEventToRoot(QMouseEvent* event) { xcb_ungrab_pointer(QX11Info::connection(), event->timestamp()); // forward the event to the root window xcb_button_press_event_t xcb_event; uint32_t mask = 0; xcb_event.state = 0; switch(event->type()) { case QEvent::MouseButtonPress: xcb_event.response_type = XCB_BUTTON_PRESS; mask = XCB_EVENT_MASK_BUTTON_PRESS; break; case QEvent::MouseButtonRelease: xcb_event.response_type = XCB_BUTTON_RELEASE; mask = XCB_EVENT_MASK_BUTTON_RELEASE; break; default: return; } // convert Qt button to XCB button switch(event->button()) { case Qt::LeftButton: xcb_event.detail = 1; xcb_event.state |= XCB_BUTTON_MASK_1; break; case Qt::MiddleButton: xcb_event.detail = 2; xcb_event.state |= XCB_BUTTON_MASK_2; break; case Qt::RightButton: xcb_event.detail = 3; xcb_event.state |= XCB_BUTTON_MASK_3; break; default: xcb_event.detail = 0; } // convert Qt modifiers to XCB states if(event->modifiers() & Qt::ShiftModifier) { xcb_event.state |= XCB_MOD_MASK_SHIFT; } if(event->modifiers() & Qt::ControlModifier) { xcb_event.state |= XCB_MOD_MASK_SHIFT; } if(event->modifiers() & Qt::AltModifier) { xcb_event.state |= XCB_MOD_MASK_1; } xcb_event.sequence = 0; xcb_event.time = event->timestamp(); WId root = QX11Info::appRootWindow(QX11Info::appScreen()); xcb_event.event = root; xcb_event.root = root; xcb_event.child = 0; xcb_event.root_x = event->globalX(); xcb_event.root_y = event->globalY(); xcb_event.event_x = event->x(); xcb_event.event_y = event->y(); xcb_event.same_screen = 1; xcb_send_event(QX11Info::connection(), 0, root, mask, (char*)&xcb_event); xcb_flush(QX11Info::connection()); }
void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) { //it's best not to look at this code //GTK doesn't like send_events and double checks the mouse position matches where the window is and is top level //in order to solve this we move the embed container over to where the mouse is then replay the event using send_event //if patching, test with xchat + xchat context menus //note x,y are not actually where the mouse is, but the plasmoid //ideally we should make this match the plasmoid hit area qCDebug(SNIPROXY) << "Sending click " << mouseButton << "to" << x << y; auto c = QX11Info::connection(); //set our window so the middle is where the mouse is const uint32_t stackAboveData[] = {XCB_STACK_MODE_ABOVE}; xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackAboveData); const uint32_t config_vals[4] = {x, y, s_embedSize, s_embedSize }; xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, config_vals); //mouse down { xcb_button_press_event_t* event = new xcb_button_press_event_t; memset(event, 0x00, sizeof(xcb_button_press_event_t)); event->response_type = XCB_BUTTON_PRESS; event->event = m_windowId; event->time = QX11Info::getTimestamp(); event->same_screen = 1; event->root = QX11Info::appRootWindow(); event->root_x = x; event->root_y = y; event->event_x = 0; event->event_y = 0; event->child = 0; event->state = 0; event->detail = mouseButton; xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_BUTTON_PRESS, (char *) event); free(event); } //mouse up { xcb_button_release_event_t* event = new xcb_button_release_event_t; memset(event, 0x00, sizeof(xcb_button_release_event_t)); event->response_type = XCB_BUTTON_RELEASE; event->event = m_windowId; event->time = QX11Info::getTimestamp(); event->same_screen = 1; event->root = QX11Info::appRootWindow(); event->root_x = x; event->root_y = y; event->event_x = 0; event->event_y = 0; event->child = 0; event->state = 0; event->detail = mouseButton; xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_BUTTON_RELEASE, (char *) event); free(event); } #ifndef VISUAL_DEBUG const uint32_t stackBelowData[] = {XCB_STACK_MODE_BELOW}; xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackBelowData); #endif }
void configure_request(xcb_generic_event_t *evt) { xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt; coordinates_t loc; bool is_managed = locate_window(e->window, &loc); client_t *c = (is_managed ? loc.node->client : NULL); int w = 0, h = 0; if (is_managed && !IS_FLOATING(c)) { if (e->value_mask & XCB_CONFIG_WINDOW_X) { c->floating_rectangle.x = e->x; } if (e->value_mask & XCB_CONFIG_WINDOW_Y) { c->floating_rectangle.y = e->y; } if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) { w = e->width; } if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) { h = e->height; } if (w != 0) { restrain_floating_width(c, &w); c->floating_rectangle.width = w; } if (h != 0) { restrain_floating_height(c, &h); c->floating_rectangle.height = h; } xcb_configure_notify_event_t evt; unsigned int bw = c->border_width; xcb_rectangle_t rect = get_rectangle(loc.desktop, loc.node); evt.response_type = XCB_CONFIGURE_NOTIFY; evt.event = e->window; evt.window = e->window; evt.above_sibling = XCB_NONE; evt.x = rect.x; evt.y = rect.y; evt.width = rect.width; evt.height = rect.height; evt.border_width = bw; evt.override_redirect = false; xcb_send_event(dpy, false, e->window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt); if (c->state == STATE_PSEUDO_TILED) { arrange(loc.monitor, loc.desktop); } } else { uint16_t mask = 0; uint32_t values[7]; unsigned short i = 0; if (e->value_mask & XCB_CONFIG_WINDOW_X) { mask |= XCB_CONFIG_WINDOW_X; values[i++] = e->x; if (is_managed) { c->floating_rectangle.x = e->x; } } if (e->value_mask & XCB_CONFIG_WINDOW_Y) { mask |= XCB_CONFIG_WINDOW_Y; values[i++] = e->y; if (is_managed) { c->floating_rectangle.y = e->y; } } if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) { mask |= XCB_CONFIG_WINDOW_WIDTH; w = e->width; if (is_managed) { restrain_floating_width(c, &w); c->floating_rectangle.width = w; } values[i++] = w; } if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) { mask |= XCB_CONFIG_WINDOW_HEIGHT; h = e->height; if (is_managed) { restrain_floating_height(c, &h); c->floating_rectangle.height = h; } values[i++] = h; } if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) { mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH; values[i++] = e->border_width; } if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_SIBLING) { mask |= XCB_CONFIG_WINDOW_SIBLING; values[i++] = e->sibling; } if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) { mask |= XCB_CONFIG_WINDOW_STACK_MODE; values[i++] = e->stack_mode; } xcb_configure_window(dpy, e->window, mask, values); if (is_managed && mask & XCB_CONFIG_WINDOW_X_Y_WIDTH_HEIGHT) { xcb_rectangle_t r = c->floating_rectangle; put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%X 0x%X 0x%X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, e->window, r.width, r.height, r.x, r.y); } } if (is_managed) { monitor_t *m = monitor_from_client(c); adapt_geometry(&m->rectangle, &loc.monitor->rectangle, loc.node); } }