Changeset View
Changeset View
Standalone View
Standalone View
xembed-sni-proxy/sniproxy.cpp
Show First 20 Lines • Show All 86 Lines • ▼ Show 20 Line(s) | 81 | { | |||
---|---|---|---|---|---|
87 | auto reply = statusNotifierWatcher->RegisterStatusNotifierItem(m_dbus.baseService()); | 87 | auto reply = statusNotifierWatcher->RegisterStatusNotifierItem(m_dbus.baseService()); | ||
88 | reply.waitForFinished(); | 88 | reply.waitForFinished(); | ||
89 | if (reply.isError()) { | 89 | if (reply.isError()) { | ||
90 | qCWarning(SNIPROXY) << "could not register SNI:" << reply.error().message(); | 90 | qCWarning(SNIPROXY) << "could not register SNI:" << reply.error().message(); | ||
91 | } | 91 | } | ||
92 | 92 | | |||
93 | auto c = QX11Info::connection(); | 93 | auto c = QX11Info::connection(); | ||
94 | 94 | | |||
95 | auto cookie = xcb_get_geometry(c, m_windowId); | | |||
96 | QScopedPointer<xcb_get_geometry_reply_t, QScopedPointerPodDeleter> | | |||
97 | clientGeom(xcb_get_geometry_reply(c, cookie, nullptr)); | | |||
98 | | ||||
99 | //create a container window | 95 | //create a container window | ||
100 | auto screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data; | 96 | auto screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data; | ||
101 | m_containerWid = xcb_generate_id(c); | 97 | m_containerWid = xcb_generate_id(c); | ||
102 | uint32_t values[2]; | 98 | uint32_t values[2]; | ||
103 | auto mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT; | 99 | auto mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT; | ||
104 | values[0] = screen->black_pixel; //draw a solid background so the embedded icon doesn't get garbage in it | 100 | values[0] = screen->black_pixel; //draw a solid background so the embedded icon doesn't get garbage in it | ||
105 | values[1] = true; //bypass wM | 101 | values[1] = true; //bypass wM | ||
106 | xcb_create_window (c, /* connection */ | 102 | xcb_create_window (c, /* connection */ | ||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Line(s) | 130 | #endif | |||
157 | 153 | | |||
158 | //move window we're embedding | 154 | //move window we're embedding | ||
159 | const uint32_t windowMoveConfigVals[2] = { 0, 0 }; | 155 | const uint32_t windowMoveConfigVals[2] = { 0, 0 }; | ||
160 | 156 | | |||
161 | xcb_configure_window(c, wid, | 157 | xcb_configure_window(c, wid, | ||
162 | XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, | 158 | XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, | ||
163 | windowMoveConfigVals); | 159 | windowMoveConfigVals); | ||
164 | 160 | | |||
165 | 161 | QSize clientWindowSize = calculateClientWindowSize(); | |||
166 | QSize clientWindowSize; | | |||
167 | | ||||
168 | if (clientGeom) { | | |||
169 | clientWindowSize = QSize(clientGeom->width, clientGeom->height); | | |||
170 | } | | |||
171 | //if the window is a clearly stupid size resize to be something sensible | | |||
172 | //this is needed as chormium and such when resized just fill the icon with transparent space and only draw in the middle | | |||
173 | //however spotify does need this as by default the window size is 900px wide. | | |||
174 | //use an artbitrary heuristic to make sure icons are always sensible | | |||
175 | if (clientWindowSize.isEmpty() || clientWindowSize.width() > s_embedSize || clientWindowSize.height() > s_embedSize ) | | |||
176 | { | | |||
177 | qCDebug(SNIPROXY) << "Resizing window" << wid << Title() << "from w*h" << clientWindowSize; | | |||
178 | | ||||
179 | xcb_configure_notify_event_t event; | | |||
180 | memset(&event, 0x00, sizeof(xcb_configure_notify_event_t)); | | |||
181 | event.response_type = XCB_CONFIGURE_NOTIFY; | | |||
182 | event.event = wid; | | |||
183 | event.window = wid; | | |||
184 | event.width = s_embedSize; | | |||
185 | event.height = s_embedSize; | | |||
186 | xcb_send_event(c, false, wid, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char *) &event); | | |||
187 | | ||||
188 | const uint32_t windowMoveConfigVals[2] = { s_embedSize, s_embedSize }; | | |||
189 | xcb_configure_window(c, wid, | | |||
190 | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, | | |||
191 | windowMoveConfigVals); | | |||
192 | | ||||
193 | clientWindowSize = QSize(s_embedSize, s_embedSize); | | |||
194 | } | | |||
195 | 162 | | |||
196 | //show the embedded window otherwise nothing happens | 163 | //show the embedded window otherwise nothing happens | ||
197 | xcb_map_window(c, wid); | 164 | xcb_map_window(c, wid); | ||
198 | 165 | | |||
199 | xcb_clear_area(c, 0, wid, 0, 0, clientWindowSize.width(), clientWindowSize.height()); | 166 | xcb_clear_area(c, 0, wid, 0, 0, clientWindowSize.width(), clientWindowSize.height()); | ||
200 | 167 | | |||
201 | xcb_flush(c); | 168 | xcb_flush(c); | ||
202 | 169 | | |||
Show All 39 Lines | 198 | { | |||
242 | if (w != s_embedSize || h != s_embedSize) { | 209 | if (w != s_embedSize || h != s_embedSize) { | ||
243 | qCDebug(SNIPROXY) << "Scaling pixmap of window" << m_windowId << Title() << "from w*h" << w << h; | 210 | qCDebug(SNIPROXY) << "Scaling pixmap of window" << m_windowId << Title() << "from w*h" << w << h; | ||
244 | m_pixmap = m_pixmap.scaled(s_embedSize, s_embedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); | 211 | m_pixmap = m_pixmap.scaled(s_embedSize, s_embedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); | ||
245 | } | 212 | } | ||
246 | emit NewIcon(); | 213 | emit NewIcon(); | ||
247 | emit NewToolTip(); | 214 | emit NewToolTip(); | ||
248 | } | 215 | } | ||
249 | 216 | | |||
217 | QSize SNIProxy::calculateClientWindowSize() const | ||||
davidedmundson: It's a bit weird to have a method called "getSomething" that changes the state of things
| |||||
kmaterka: True, get* should not have side effect. I will change it. | |||||
218 | { | ||||
219 | auto c = QX11Info::connection(); | ||||
220 | | ||||
221 | auto cookie = xcb_get_geometry(c, m_windowId); | ||||
222 | QScopedPointer<xcb_get_geometry_reply_t, QScopedPointerPodDeleter> | ||||
223 | clientGeom(xcb_get_geometry_reply(c, cookie, nullptr)); | ||||
224 | | ||||
225 | QSize clientWindowSize; | ||||
226 | if (clientGeom) { | ||||
227 | clientWindowSize = QSize(clientGeom->width, clientGeom->height); | ||||
228 | } | ||||
229 | //if the window is a clearly stupid size resize to be something sensible | ||||
230 | //this is needed as chromium and such when resized just fill the icon with transparent space and only draw in the middle | ||||
231 | //however KeePass2 does need this as by default the window size is 273px wide and is not transparent | ||||
232 | //use an artbitrary heuristic to make sure icons are always sensible | ||||
233 | if (clientWindowSize.isEmpty() || clientWindowSize.width() > s_embedSize || clientWindowSize.height() > s_embedSize) { | ||||
234 | qCDebug(SNIPROXY) << "Resizing window" << m_windowId << Title() << "from w*h" << clientWindowSize; | ||||
235 | | ||||
236 | xcb_configure_notify_event_t event; | ||||
237 | memset(&event, 0x00, sizeof(xcb_configure_notify_event_t)); | ||||
238 | event.response_type = XCB_CONFIGURE_NOTIFY; | ||||
239 | event.event = m_windowId; | ||||
240 | event.window = m_windowId; | ||||
241 | event.width = s_embedSize; | ||||
242 | event.height = s_embedSize; | ||||
243 | xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char *) &event); | ||||
244 | | ||||
245 | const uint32_t windowMoveConfigVals[2] = { s_embedSize, s_embedSize }; | ||||
246 | xcb_configure_window(c, m_windowId, | ||||
247 | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, | ||||
248 | windowMoveConfigVals); | ||||
249 | | ||||
250 | clientWindowSize = QSize(s_embedSize, s_embedSize); | ||||
251 | } | ||||
252 | | ||||
253 | return clientWindowSize; | ||||
254 | } | ||||
255 | | ||||
250 | void sni_cleanup_xcb_image(void *data) { | 256 | void sni_cleanup_xcb_image(void *data) { | ||
251 | xcb_image_destroy(static_cast<xcb_image_t*>(data)); | 257 | xcb_image_destroy(static_cast<xcb_image_t*>(data)); | ||
252 | } | 258 | } | ||
253 | 259 | | |||
254 | bool SNIProxy::isTransparentImage(const QImage& image) const | 260 | bool SNIProxy::isTransparentImage(const QImage& image) const | ||
255 | { | 261 | { | ||
256 | int w = image.width(); | 262 | int w = image.width(); | ||
257 | int h = image.height(); | 263 | int h = image.height(); | ||
Show All 14 Lines | |||||
272 | } | 278 | } | ||
273 | 279 | | |||
274 | return true; | 280 | return true; | ||
275 | } | 281 | } | ||
276 | 282 | | |||
277 | QImage SNIProxy::getImageNonComposite() const | 283 | QImage SNIProxy::getImageNonComposite() const | ||
278 | { | 284 | { | ||
279 | auto c = QX11Info::connection(); | 285 | auto c = QX11Info::connection(); | ||
280 | auto cookie = xcb_get_geometry(c, m_windowId); | | |||
281 | QScopedPointer<xcb_get_geometry_reply_t, QScopedPointerPodDeleter> | | |||
282 | geom(xcb_get_geometry_reply(c, cookie, nullptr)); | | |||
283 | 286 | | |||
284 | if (!geom) { | 287 | QSize clientWindowSize = calculateClientWindowSize(); | ||
285 | return QImage(); | | |||
286 | } | | |||
287 | 288 | | |||
288 | xcb_image_t *image = xcb_image_get(c, m_windowId, 0, 0, geom->width, geom->height, 0xFFFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP); | 289 | xcb_image_t *image = xcb_image_get(c, m_windowId, 0, 0, clientWindowSize.width(), clientWindowSize.height(), 0xFFFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP); | ||
289 | 290 | | |||
290 | // Don't hook up cleanup yet, we may use a different QImage after all | 291 | // Don't hook up cleanup yet, we may use a different QImage after all | ||
291 | QImage naiveConversion; | 292 | QImage naiveConversion; | ||
292 | if (image) { | 293 | if (image) { | ||
293 | naiveConversion = QImage(image->data, image->width, image->height, QImage::Format_ARGB32); | 294 | naiveConversion = QImage(image->data, image->width, image->height, QImage::Format_ARGB32); | ||
294 | } else { | 295 | } else { | ||
295 | qCDebug(SNIPROXY) << "Skip NULL image returned from xcb_image_get() for" << m_windowId << Title(); | 296 | qCDebug(SNIPROXY) << "Skip NULL image returned from xcb_image_get() for" << m_windowId << Title(); | ||
296 | return QImage(); | 297 | return QImage(); | ||
▲ Show 20 Lines • Show All 298 Lines • Show Last 20 Lines |
It's a bit weird to have a method called "getSomething" that changes the state of things