void Client::close() { WindowManager *wm = WindowManager::instance(); if (mOwned) { EventLoop::eventLoop()->callLater([this, wm] { delete this; xcb_flush(wm->connection()); }); } else { if (mProtocols.contains(Atoms::WM_DELETE_WINDOW)) { // delete xcb_client_message_event_t event; memset(&event, '\0', sizeof(event)); event.response_type = XCB_CLIENT_MESSAGE; event.window = mWindow; event.format = 32; event.type = Atoms::WM_PROTOCOLS; event.data.data32[0] = Atoms::WM_DELETE_WINDOW; event.data.data32[1] = wm->timestamp(); xcb_send_event(wm->connection(), false, mWindow, XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<char*>(&event)); } else { xcb_kill_client(wm->connection(), mWindow); } } }
void Client::focus() { const bool takeFocus = mProtocols.count(Atoms::WM_TAKE_FOCUS) > 0; if (mNoFocus && !takeFocus) return; WindowManager *wm = WindowManager::instance(); if (takeFocus) { xcb_client_message_event_t event; memset(&event, '\0', sizeof(event)); event.response_type = XCB_CLIENT_MESSAGE; event.window = mWindow; event.format = 32; event.type = Atoms::WM_PROTOCOLS; event.data.data32[0] = Atoms::WM_TAKE_FOCUS; event.data.data32[1] = wm->timestamp(); xcb_send_event(wm->connection(), false, mWindow, XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<char*>(&event)); } xcb_set_input_focus(wm->connection(), XCB_INPUT_FOCUS_PARENT, mWindow, wm->timestamp()); //error() << "Setting input focus to client" << mWindow << mClass.className; xcb_ewmh_set_active_window(wm->ewmhConnection(), mScreenNumber, mWindow); wm->setFocusedClient(this); if (mWorkspace) mWorkspace->updateFocus(this); }
Client *Client::create(const Rect& rect, int screenNumber, const String &clazz, const String &instance, bool movable) { WindowManager *wm = WindowManager::instance(); xcb_connection_t* conn = wm->connection(); xcb_screen_t* scr = wm->screens().at(screenNumber); xcb_window_t window = xcb_generate_id(conn); const uint32_t values[] = { scr->black_pixel, XCB_GRAVITY_NORTH_WEST, XCB_GRAVITY_NORTH_WEST, 1, (XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE) }; warning() << "creating client window" << rect; xcb_create_window(conn, XCB_COPY_FROM_PARENT, window, scr->root, rect.x, rect.y, rect.width, rect.height, 0, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT, XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY | XCB_CW_WIN_GRAVITY | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, values); xcb_icccm_wm_hints_t wmHints; xcb_icccm_wm_hints_set_none(&wmHints); xcb_icccm_wm_hints_set_input(&wmHints, 0); xcb_icccm_set_wm_hints(conn, window, &wmHints); xcb_size_hints_t wmNormalHints; memset(&wmNormalHints, 0, sizeof(wmNormalHints)); xcb_icccm_size_hints_set_position(&wmNormalHints, 1, rect.x, rect.y); xcb_icccm_size_hints_set_size(&wmNormalHints, 1, rect.width, rect.height); xcb_icccm_set_wm_normal_hints(conn, window, &wmNormalHints); String className = clazz + ' ' + instance; className[clazz.size()] = '\0'; xcb_icccm_set_wm_class(conn, window, className.size(), className.constData()); Client *ptr = new Client(window); ptr->mMovable = movable; ptr->mRect = rect; ptr->mOwned = true; ptr->mScreenNumber = screenNumber; ptr->init(); ptr->mNoFocus = true; Workspace *ws = wm->activeWorkspace(screenNumber); assert(ws); ptr->mWorkspace = ws; ws->addClient(ptr); wm->js().onClient(ptr); ptr->complete(); sClients[window] = ptr; return ptr; }
void Client::complete() { WindowManager *wm = WindowManager::instance(); xcb_connection_t* conn = wm->connection(); xcb_ewmh_connection_t* ewmhConn = wm->ewmhConnection(); if (mEwmhState.contains(ewmhConn->_NET_WM_STATE_STICKY)) { // don't put in layout #warning support strut windows in layouts (reserved space) #warning support partial struts Rect rect = wm->rect(mScreenNumber); if (mStrut.left) { if (mRect.width != static_cast<int>(mStrut.left)) mRect.width = mStrut.left; mRect.x = rect.x; rect.x += mRect.width; rect.width -= mRect.width; } else if (mStrut.right) { if (mRect.width != static_cast<int>(mStrut.right)) mRect.width = mStrut.right; mRect.x = rect.x + rect.width - mStrut.right; rect.width -= mStrut.right; } else if (mStrut.top) { if (mRect.height != static_cast<int>(mStrut.top)) mRect.height = mStrut.top; mRect.y = rect.y; rect.y += mRect.height; rect.height -= mRect.height; } else if (mStrut.bottom) { if (mRect.height != static_cast<int>(mStrut.bottom)) mRect.height = mStrut.bottom; mRect.y = rect.y + rect.height - mStrut.bottom; rect.height -= mStrut.bottom; } wm->setRect(rect, mScreenNumber); warning() << "fixed at" << mRect; } else { if (shouldLayout()) { wm->js().onLayout(this); warning() << "laid out at" << mRect; } } #warning do startup-notification stuff here if (!mOwned) xcb_change_save_set(conn, XCB_SET_MODE_INSERT, mWindow); xcb_screen_t* scr = screen(); mFrame = xcb_generate_id(conn); const uint32_t values[] = { scr->black_pixel, XCB_GRAVITY_NORTH_WEST, XCB_GRAVITY_NORTH_WEST, 1, (XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE) }; warning() << "creating frame window" << mRect; xcb_create_window(conn, XCB_COPY_FROM_PARENT, mFrame, scr->root, mRect.x, mRect.y, mRect.width, mRect.height, 0, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT, XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY | XCB_CW_WIN_GRAVITY | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, values); { ServerGrabScope grabScope(conn); const uint32_t noValue[] = { 0 }; xcb_change_window_attributes(conn, scr->root, XCB_CW_EVENT_MASK, noValue); xcb_reparent_window(conn, mWindow, mFrame, 0, 0); const uint32_t rootEvent[] = { Types::RootEventMask }; xcb_change_window_attributes(conn, scr->root, XCB_CW_EVENT_MASK, rootEvent); xcb_grab_button(conn, false, mWindow, XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, scr->root, XCB_NONE, 1, XCB_BUTTON_MASK_ANY); const uint32_t windowEvent[] = { Types::ClientInputMask }; xcb_change_window_attributes(conn, mWindow, XCB_CW_EVENT_MASK, windowEvent); } { uint16_t windowMask = XCB_CONFIG_WINDOW_WIDTH|XCB_CONFIG_WINDOW_HEIGHT|XCB_CONFIG_WINDOW_BORDER_WIDTH; uint32_t windowValues[3]; int i = 0; windowValues[i++] = mRect.width; windowValues[i++] = mRect.height; windowValues[i++] = 0; xcb_configure_window(conn, mWindow, windowMask, windowValues); } #warning do xinerama placement const uint32_t stateMode[] = { XCB_ICCCM_WM_STATE_NORMAL, XCB_NONE }; xcb_change_property(conn, XCB_PROP_MODE_REPLACE, mWindow, Atoms::WM_STATE, Atoms::WM_STATE, 32, 2, stateMode); map(); raise(); warning() << "created and mapped parent client for frame" << mFrame << "with window" << mWindow; }