File indexing completed on 2024-04-28 05:46:51

0001 /*****************************************************************************
0002  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0003  *                                                                           *
0004  *   This program is free software; you can redistribute it and/or modify    *
0005  *   it under the terms of the GNU Lesser General Public License as          *
0006  *   published by the Free Software Foundation; either version 2.1 of the    *
0007  *   License, or (at your option) version 3, or any later version accepted   *
0008  *   by the membership of KDE e.V. (or its successor approved by the         *
0009  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0010  *   Section 6 of version 3 of the license.                                  *
0011  *                                                                           *
0012  *   This program is distributed in the hope that it will be useful,         *
0013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0015  *   Lesser General Public License for more details.                         *
0016  *                                                                           *
0017  *   You should have received a copy of the GNU Lesser General Public        *
0018  *   License along with this library. If not,                                *
0019  *   see <http://www.gnu.org/licenses/>.                                     *
0020  *****************************************************************************/
0021 
0022 #include "config.h"
0023 
0024 #include "x11shadow_p.h"
0025 #include "x11wmmove.h"
0026 #include "x11blur.h"
0027 #include "x11qtc.h"
0028 #include "x11wrap.h"
0029 
0030 static int shadow_size = 30;
0031 
0032 #ifdef QTC_ENABLE_X11
0033 
0034 #include "log.h"
0035 #include "number.h"
0036 #include "shadow_p.h"
0037 #include "x11utils_p.h"
0038 #include <X11/Xlib.h>
0039 #include <X11/Xatom.h>
0040 
0041 /**
0042  * shadow atom and property specification available at
0043  * http://community.kde.org/KWin/Shadow
0044  **/
0045 
0046 static uint32_t shadow_xpixmaps[8];
0047 static uint32_t shadow_data_xcb[8 + 4];
0048 /**
0049  * Use XCB to set window property receives BadWindow errors for menus in
0050  * Qt4 kpartsplugin here, probably because of the order of some pending
0051  * event/requests in Xlib. Calling #XFlush before #xcb_change_property
0052  * doesn't solve the problem for unknown reason but using #XChangeProperty
0053  * works.
0054  * NOTE: #XChangeProperty want `unsigned long` for format 32. So we need
0055  * two separate data buffers.
0056  **/
0057 static unsigned long shadow_data_xlib[8 + 4];
0058 
0059 static xcb_pixmap_t
0060 qtcX11ShadowCreatePixmap(const QtCurve::Image *data)
0061 {
0062     xcb_pixmap_t pixmap = qtcX11GenerateId();
0063 
0064     // create X11 pixmap
0065     qtcX11CallVoid(create_pixmap, 32, pixmap, qtc_root_window,
0066                    data->width, data->height);
0067     xcb_gcontext_t cid = qtcX11GenerateId();
0068     qtcX11CallVoid(create_gc, cid, pixmap, 0, (const uint32_t*)0);
0069     qtcX11CallVoid(put_image, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, cid,
0070                    data->width, data->height, 0, 0, 0, 32, data->data.size(),
0071                    (unsigned char*)&data->data[0]);
0072     qtcX11CallVoid(free_gc, cid);
0073     qtcX11Flush();
0074     return pixmap;
0075 }
0076 
0077 void
0078 qtcX11ShadowInit()
0079 {
0080     int shadow_radius = 4;
0081     QtcColor c1 = {0.4, 0.4, 0.4};
0082     QtcColor c2 = {0.2, 0.2, 0.2};
0083     QtCurve::Image *shadow_images[8];
0084     qtcShadowCreate(shadow_size, &c1, &c2, shadow_radius, false,
0085                     QTC_PIXEL_XCB, shadow_images);
0086     for (int i = 0;i < 8;i++) {
0087         shadow_xpixmaps[i] = qtcX11ShadowCreatePixmap(shadow_images[i]);
0088         delete shadow_images[i];
0089     }
0090 
0091     memcpy(shadow_data_xcb, shadow_xpixmaps, sizeof(shadow_xpixmaps));
0092     for (int i = 0;i < 8;i++) {
0093         shadow_data_xlib[i] = shadow_xpixmaps[i];
0094     }
0095     for (int i = 8;i < 12;i++) {
0096         shadow_data_xlib[i] = shadow_data_xcb[i] = shadow_size - 1;
0097     }
0098 }
0099 
0100 // Necessary?
0101 void
0102 qtcX11ShadowDestroy()
0103 {
0104     QTC_RET_IF_FAIL(qtc_xcb_conn);
0105     for (unsigned int i = 0;
0106          i < sizeof(shadow_xpixmaps) / sizeof(shadow_xpixmaps[0]);i++) {
0107         qtcX11CallVoid(free_pixmap, shadow_xpixmaps[i]);
0108     }
0109     qtcX11Flush();
0110 }
0111 
0112 QTC_EXPORT void
0113 qtcX11ShadowInstall(xcb_window_t win, const int margins[4])
0114 {
0115     QTC_RET_IF_FAIL(win);
0116     if (qtcUnlikely(!margins)) {
0117         qtcX11ShadowInstall(win);
0118         return;
0119     }
0120     // In principle, I should check for _KDE_NET_WM_SHADOW in _NET_SUPPORTED.
0121     // However, it's complicated and we will gain nothing.
0122     xcb_atom_t atom = qtc_x11_kde_net_wm_shadow;
0123     if (qtc_disp) {
0124         unsigned long shadow_data[8 + 4];
0125         memcpy(shadow_data, shadow_data_xlib, 12 * sizeof(unsigned long));
0126         for (int i = 0;i < 4;i++) {
0127             shadow_data[i + 8] -= margins[i];
0128         }
0129         XChangeProperty((Display*)qtc_disp, win, atom, XA_CARDINAL, 32,
0130                         PropModeReplace, (unsigned char*)shadow_data, 12);
0131     } else {
0132         uint32_t shadow_data[8 + 4];
0133         memcpy(shadow_data, shadow_data_xcb, 12 * sizeof(uint32_t));
0134         for (int i = 0;i < 4;i++) {
0135             shadow_data[i + 8] -= margins[i];
0136         }
0137         qtcX11ChangeProperty(XCB_PROP_MODE_REPLACE, win, atom,
0138                              XCB_ATOM_CARDINAL, 32, 12, shadow_data);
0139         qtcX11Flush();
0140     }
0141 }
0142 
0143 QTC_EXPORT void
0144 qtcX11ShadowInstall(xcb_window_t win)
0145 {
0146     QTC_RET_IF_FAIL(win);
0147     // In principle, I should check for _KDE_NET_WM_SHADOW in _NET_SUPPORTED.
0148     // However, it's complicated and we will gain nothing.
0149     xcb_atom_t atom = qtc_x11_kde_net_wm_shadow;
0150     if (qtc_disp) {
0151         XChangeProperty((Display*)qtc_disp, win, atom, XA_CARDINAL, 32,
0152                         PropModeReplace, (unsigned char*)shadow_data_xlib, 12);
0153     } else {
0154         qtcX11ChangeProperty(XCB_PROP_MODE_REPLACE, win, atom,
0155                              XCB_ATOM_CARDINAL, 32, 12, shadow_data_xcb);
0156         qtcX11Flush();
0157     }
0158 }
0159 
0160 QTC_EXPORT void
0161 qtcX11ShadowUninstall(xcb_window_t win)
0162 {
0163     QTC_RET_IF_FAIL(win);
0164     qtcX11CallVoid(delete_property, win, qtc_x11_kde_net_wm_shadow);
0165     qtcX11Flush();
0166 }
0167 
0168 // WM Move
0169 QTC_EXPORT void
0170 qtcX11MoveTrigger(xcb_window_t wid, uint32_t x, uint32_t y)
0171 {
0172     QTC_RET_IF_FAIL(wid);
0173     qtcX11FlushXlib();
0174     qtcX11CallVoid(ungrab_pointer, XCB_TIME_CURRENT_TIME);
0175     union {
0176         char _buff[32];
0177         xcb_client_message_event_t ev;
0178     } buff;
0179     memset(&buff, 0, sizeof(buff));
0180     // ...Taken from bespin...
0181     // stolen... errr "adapted!" from QSizeGrip
0182     // Well now it is "ported"
0183     xcb_client_message_event_t *xev = &buff.ev;
0184     xev->response_type = XCB_CLIENT_MESSAGE;
0185     xev->format = 32;
0186     xev->window = wid;
0187     xev->type = qtc_x11_net_wm_moveresize;
0188     xev->data.data32[0] = x;
0189     xev->data.data32[1] = y;
0190     xev->data.data32[2] = 8; // NET::Move
0191     xev->data.data32[3] = XCB_KEY_BUT_MASK_BUTTON_1;
0192     qtcX11SendEvent(false, qtc_root_window,
0193                     XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
0194                     XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, xev);
0195     qtcX11Flush();
0196 }
0197 
0198 // Blur
0199 QTC_EXPORT void
0200 qtcX11BlurTrigger(xcb_window_t wid, bool enable, unsigned prop_num,
0201                   const uint32_t *props)
0202 {
0203     QTC_RET_IF_FAIL(wid);
0204     xcb_atom_t atom = qtc_x11_kde_net_wm_blur_behind_region;
0205     if (enable) {
0206         if (qtc_disp) {
0207             QtCurve::LocalBuff<unsigned long, 256> xlib_props(prop_num);
0208             for (unsigned i = 0;i < prop_num;i++) {
0209                 xlib_props[i] = props[i];
0210             }
0211             XChangeProperty((Display*)qtc_disp, wid, atom, XA_CARDINAL, 32,
0212                             PropModeReplace, (unsigned char*)xlib_props.get(),
0213                             prop_num);
0214         } else {
0215             qtcX11ChangeProperty(XCB_PROP_MODE_REPLACE, wid, atom,
0216                                  XCB_ATOM_CARDINAL, 32, prop_num, props);
0217         }
0218     } else {
0219         qtcX11CallVoid(delete_property, wid, atom);
0220     }
0221     qtcX11Flush();
0222 }
0223 
0224 QTC_EXPORT int32_t
0225 qtcX11GetShortProp(xcb_window_t win, xcb_atom_t atom)
0226 {
0227     QTC_RET_IF_FAIL(qtc_xcb_conn && win, -1);
0228     int32_t res = -1;
0229     xcb_get_property_reply_t *reply =
0230         qtcX11GetProperty(0, win, atom, XCB_ATOM_CARDINAL, 0, 1);
0231     QTC_RET_IF_FAIL(reply, -1);
0232     if (xcb_get_property_value_length(reply) > 0) {
0233         uint32_t val = *(int32_t*)xcb_get_property_value(reply);
0234         if (val < 512) {
0235             res = val;
0236         }
0237     }
0238     free(reply);
0239     return res;
0240 }
0241 
0242 static inline void
0243 qtcX11SetShortProp(xcb_window_t win, xcb_atom_t atom, unsigned short prop)
0244 {
0245     qtcX11ChangeProperty(XCB_PROP_MODE_REPLACE, win, atom,
0246                          XCB_ATOM_CARDINAL, 16, 1, &prop);
0247     qtcX11Flush();
0248 }
0249 
0250 QTC_EXPORT void
0251 qtcX11SetMenubarSize(xcb_window_t win, unsigned short s)
0252 {
0253     qtcX11SetShortProp(win, qtc_x11_qtc_menubar_size, s);
0254 }
0255 
0256 QTC_EXPORT void
0257 qtcX11SetStatusBar(xcb_window_t win)
0258 {
0259     qtcX11SetShortProp(win, qtc_x11_qtc_statusbar, 1);
0260 }
0261 
0262 QTC_EXPORT void
0263 qtcX11SetOpacity(xcb_window_t win, unsigned short o)
0264 {
0265     qtcX11SetShortProp(win, qtc_x11_qtc_opacity, o);
0266 }
0267 
0268 QTC_EXPORT void
0269 qtcX11SetBgnd(xcb_window_t win, uint32_t prop)
0270 {
0271     qtcX11ChangeProperty(XCB_PROP_MODE_REPLACE, win, qtc_x11_qtc_bgnd,
0272                          XCB_ATOM_CARDINAL, 32, 1, &prop);
0273     qtcX11Flush();
0274 }
0275 
0276 #else
0277 
0278 QTC_EXPORT void
0279 qtcX11ShadowInstall(xcb_window_t, const int[4])
0280 {
0281 }
0282 
0283 QTC_EXPORT void
0284 qtcX11ShadowInstall(xcb_window_t)
0285 {
0286 }
0287 
0288 QTC_EXPORT void
0289 qtcX11ShadowUninstall(xcb_window_t)
0290 {
0291 }
0292 
0293 // WM Move
0294 QTC_EXPORT void
0295 qtcX11MoveTrigger(xcb_window_t, uint32_t, uint32_t)
0296 {
0297 }
0298 
0299 // Blur
0300 QTC_EXPORT void
0301 qtcX11BlurTrigger(xcb_window_t, bool, unsigned, const uint32_t*)
0302 {
0303 }
0304 
0305 QTC_EXPORT int32_t
0306 qtcX11GetShortProp(xcb_window_t, xcb_atom_t)
0307 {
0308     return -1;
0309 }
0310 
0311 QTC_EXPORT void
0312 qtcX11SetMenubarSize(xcb_window_t, unsigned short)
0313 {
0314 }
0315 
0316 QTC_EXPORT void
0317 qtcX11SetStatusBar(xcb_window_t)
0318 {
0319 }
0320 
0321 QTC_EXPORT void
0322 qtcX11SetOpacity(xcb_window_t, unsigned short)
0323 {
0324 }
0325 
0326 QTC_EXPORT void
0327 qtcX11SetBgnd(xcb_window_t, uint32_t)
0328 {
0329 }
0330 
0331 #endif
0332 
0333 QTC_EXPORT void
0334 qtcX11SetShadowSize(int size)
0335 {
0336     if (size >= 0 && size != shadow_size) {
0337         shadow_size = size;
0338 #ifdef QTC_ENABLE_X11
0339         qtcX11ShadowDestroy();
0340         qtcX11ShadowInit();
0341 #endif
0342     }
0343 }
0344 
0345 QTC_EXPORT int
0346 qtcX11ShadowSize()
0347 {
0348     return shadow_size;
0349 }
0350