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 // TODO multi screen?
0023 
0024 #include "config.h"
0025 #include "x11utils.h"
0026 
0027 QTC_EXPORT xcb_atom_t qtc_x11_qtc_menubar_size;
0028 QTC_EXPORT xcb_atom_t qtc_x11_qtc_statusbar;
0029 QTC_EXPORT xcb_atom_t qtc_x11_qtc_titlebar_size;
0030 QTC_EXPORT xcb_atom_t qtc_x11_qtc_active_window;
0031 QTC_EXPORT xcb_atom_t qtc_x11_qtc_toggle_menubar;
0032 QTC_EXPORT xcb_atom_t qtc_x11_qtc_toggle_statusbar;
0033 QTC_EXPORT xcb_atom_t qtc_x11_qtc_opacity;
0034 QTC_EXPORT xcb_atom_t qtc_x11_qtc_bgnd;
0035 
0036 #ifdef QTC_ENABLE_X11
0037 
0038 #include "x11shadow_p.h"
0039 #include "x11wrap.h"
0040 #include "log.h"
0041 #include "x11utils_p.h"
0042 #include <X11/Xlib-xcb.h>
0043 // #include <X11/Xutil.h>
0044 // #include <X11/extensions/Xrender.h>
0045 
0046 void *qtc_disp = nullptr;
0047 xcb_connection_t *qtc_xcb_conn = nullptr;
0048 int qtc_default_screen_no = -1;
0049 xcb_window_t qtc_root_window = {0};
0050 xcb_screen_t *qtc_default_screen = nullptr;
0051 static char wm_cm_s_atom_name[100] = "_NET_WM_CM_S";
0052 
0053 xcb_atom_t qtc_x11_net_wm_moveresize;
0054 xcb_atom_t qtc_x11_net_wm_cm_s_default;
0055 xcb_atom_t qtc_x11_kde_net_wm_shadow;
0056 xcb_atom_t qtc_x11_kde_net_wm_blur_behind_region;
0057 static xcb_atom_t qtc_x11_xembed_info;
0058 
0059 static const struct {
0060     xcb_atom_t *atom;
0061     const char *name;
0062 } qtc_x11_atoms[] = {
0063     {&qtc_x11_net_wm_moveresize, "_NET_WM_MOVERESIZE"},
0064     {&qtc_x11_net_wm_cm_s_default, wm_cm_s_atom_name},
0065     {&qtc_x11_kde_net_wm_shadow, "_KDE_NET_WM_SHADOW"},
0066     {&qtc_x11_kde_net_wm_blur_behind_region, "_KDE_NET_WM_BLUR_BEHIND_REGION"},
0067     {&qtc_x11_qtc_menubar_size, "_QTCURVE_MENUBAR_SIZE_"},
0068     {&qtc_x11_qtc_statusbar, "_QTCURVE_STATUSBAR_"},
0069     {&qtc_x11_qtc_titlebar_size, "_QTCURVE_TITLEBAR_SIZE_"},
0070     {&qtc_x11_qtc_active_window, "_QTCURVE_ACTIVE_WINDOW_"},
0071     {&qtc_x11_qtc_toggle_menubar, "_QTCURVE_TOGGLE_MENUBAR_"},
0072     {&qtc_x11_qtc_toggle_statusbar, "_QTCURVE_TOGGLE_STATUSBAR_"},
0073     {&qtc_x11_qtc_opacity, "_QTCURVE_OPACITY_"},
0074     {&qtc_x11_qtc_bgnd, "_QTCURVE_BGND_"},
0075     {&qtc_x11_xembed_info, "_XEMBED_INFO"}
0076 };
0077 #define QTC_X11_ATOM_N (sizeof(qtc_x11_atoms) / sizeof(qtc_x11_atoms[0]))
0078 
0079 QTC_EXPORT bool
0080 qtcX11Enabled()
0081 {
0082     return qtc_xcb_conn != nullptr;
0083 }
0084 
0085 QTC_EXPORT xcb_window_t
0086 qtcX11RootWindow(int scrn_no)
0087 {
0088     if (scrn_no < 0 || scrn_no == qtc_default_screen_no) {
0089         return qtc_root_window;
0090     }
0091     return qtcX11GetScreen(scrn_no)->root;
0092 }
0093 
0094 QTC_EXPORT int
0095 qtcX11DefaultScreenNo()
0096 {
0097     return qtc_default_screen_no;
0098 }
0099 
0100 QTC_EXPORT xcb_screen_t*
0101 qtcX11DefaultScreen()
0102 {
0103     return qtc_default_screen;
0104 }
0105 
0106 static xcb_screen_t*
0107 screen_of_display(xcb_connection_t *c, int screen)
0108 {
0109     xcb_screen_iterator_t iter;
0110 
0111     iter = xcb_setup_roots_iterator(xcb_get_setup(c));
0112     for (;iter.rem;--screen, xcb_screen_next(&iter)) {
0113         if (screen == 0) {
0114             return iter.data;
0115         }
0116     }
0117     return nullptr;
0118 }
0119 
0120 static void
0121 qtcX11AtomsInit()
0122 {
0123     xcb_connection_t *conn = qtc_xcb_conn;
0124     xcb_intern_atom_cookie_t cookies[QTC_X11_ATOM_N];
0125     for (size_t i = 0;i < QTC_X11_ATOM_N;i++) {
0126         cookies[i] = xcb_intern_atom(conn, 0, strlen(qtc_x11_atoms[i].name),
0127                                      qtc_x11_atoms[i].name);
0128     }
0129     for (size_t i = 0;i < QTC_X11_ATOM_N;i++) {
0130         xcb_intern_atom_reply_t *r =
0131             xcb_intern_atom_reply(conn, cookies[i], nullptr);
0132         if (qtcLikely(r)) {
0133             *qtc_x11_atoms[i].atom = r->atom;
0134             free(r);
0135         } else {
0136             *qtc_x11_atoms[i].atom = 0;
0137         }
0138     }
0139 }
0140 
0141 QTC_EXPORT xcb_screen_t*
0142 qtcX11GetScreen(int screen_no)
0143 {
0144     QTC_RET_IF_FAIL(qtc_xcb_conn, nullptr);
0145     if (screen_no == -1 || screen_no == qtc_default_screen_no) {
0146         return qtc_default_screen;
0147     }
0148     return screen_of_display(qtc_xcb_conn, screen_no);
0149 }
0150 
0151 QTC_EXPORT void
0152 qtcX11InitXcb(xcb_connection_t *conn, int screen_no)
0153 {
0154     QTC_RET_IF_FAIL(!qtc_xcb_conn && conn);
0155     if (screen_no < 0) {
0156         screen_no = 0;
0157     }
0158     qtc_xcb_conn = conn;
0159     qtc_default_screen_no = screen_no;
0160     qtc_default_screen = screen_of_display(conn, screen_no);
0161     if (qtc_default_screen) {
0162         qtc_root_window = qtc_default_screen->root;
0163     }
0164     const size_t base_len = strlen("_NET_WM_CM_S");
0165     sprintf(wm_cm_s_atom_name + base_len, "%d", screen_no);
0166     qtcX11AtomsInit();
0167     qtcX11ShadowInit();
0168 }
0169 
0170 QTC_EXPORT void
0171 qtcX11InitXlib(void *disp)
0172 {
0173     QTC_RET_IF_FAIL(!qtc_xcb_conn && disp);
0174     qtc_disp = disp;
0175     qtcX11InitXcb(XGetXCBConnection((Display*)disp), DefaultScreen(disp));
0176 }
0177 
0178 QTC_EXPORT xcb_connection_t*
0179 qtcX11GetConn()
0180 {
0181     return qtc_xcb_conn;
0182 }
0183 
0184 QTC_EXPORT void*
0185 qtcX11GetDisp()
0186 {
0187     return qtc_disp;
0188 }
0189 
0190 QTC_EXPORT void
0191 qtcX11MapRaised(xcb_window_t win)
0192 {
0193     QTC_RET_IF_FAIL(qtc_xcb_conn && win);
0194     static const uint32_t val = XCB_STACK_MODE_ABOVE;
0195     qtcX11CallVoid(configure_window, win, XCB_CONFIG_WINDOW_STACK_MODE, &val);
0196     qtcX11CallVoid(map_window, win);
0197 }
0198 
0199 QTC_EXPORT bool
0200 qtcX11CompositingActive()
0201 {
0202     QTC_RET_IF_FAIL(qtc_xcb_conn, false);
0203     xcb_get_selection_owner_reply_t *reply =
0204         qtcX11Call(get_selection_owner, qtc_x11_net_wm_cm_s_default);
0205     QTC_RET_IF_FAIL(reply, false);
0206     bool res = (reply->owner != 0);
0207     free(reply);
0208     return res;
0209 }
0210 
0211 QTC_EXPORT bool
0212 qtcX11HasAlpha(xcb_window_t win)
0213 {
0214     QTC_RET_IF_FAIL(qtc_xcb_conn && win, false);
0215     if (!qtcX11CompositingActive()) {
0216         return false;
0217     }
0218     xcb_get_geometry_reply_t *reply = qtcX11Call(get_geometry, win);
0219     QTC_RET_IF_FAIL(reply, false);
0220     bool res = (reply->depth == 32);
0221     free(reply);
0222     return res;
0223 }
0224 
0225 QTC_EXPORT bool
0226 qtcX11IsEmbed(xcb_window_t win)
0227 {
0228     QTC_RET_IF_FAIL(qtc_xcb_conn && win, false);
0229     xcb_get_property_reply_t *reply =
0230         qtcX11GetProperty(0, win, qtc_x11_xembed_info,
0231                           qtc_x11_xembed_info, 0, 1);
0232     QTC_RET_IF_FAIL(reply, false);
0233     bool res = xcb_get_property_value_length(reply) > 0;
0234     free(reply);
0235     return res;
0236 }
0237 
0238 #if 0
0239 QTC_EXPORT void*
0240 qtcX11RgbaVisual(unsigned long *colormap, int *map_entries, int screen)
0241 {
0242     QTC_RET_IF_FAIL(qtc_disp, nullptr);
0243     if (screen < 0) {
0244         screen = qtc_default_screen_no;
0245     }
0246     // Copied from Qt4
0247     Visual *argbVisual = nullptr;
0248     int nvi;
0249     XVisualInfo templ;
0250     templ.screen = screen;
0251     templ.depth = 32;
0252     templ.class = TrueColor;
0253     XVisualInfo *xvi = XGetVisualInfo(qtc_disp, VisualScreenMask |
0254                                       VisualDepthMask | VisualClassMask,
0255                                       &templ, &nvi);
0256     for (int idx = 0; idx < nvi; ++idx) {
0257         XRenderPictFormat *format = XRenderFindVisualFormat(qtc_disp,
0258                                                             xvi[idx].visual);
0259         if (format->type == PictTypeDirect && format->direct.alphaMask) {
0260             argbVisual = xvi[idx].visual;
0261             break;
0262         }
0263     }
0264     XFree(xvi);
0265     QTC_RET_IF_FAIL(argbVisual, nullptr);
0266     qtcAssign(colormap, XCreateColormap(qtc_disp, RootWindow(qtc_disp, screen),
0267                                         argbVisual, AllocNone));
0268     qtcAssign(map_entries, argbVisual->map_entries);
0269     return argbVisual;
0270 }
0271 #endif
0272 
0273 #else
0274 
0275 QTC_EXPORT bool
0276 qtcX11Enabled()
0277 {
0278     return false;
0279 }
0280 
0281 QTC_EXPORT xcb_window_t
0282 qtcX11RootWindow(int)
0283 {
0284     return 0;
0285 }
0286 
0287 QTC_EXPORT int
0288 qtcX11DefaultScreenNo()
0289 {
0290     return -1;
0291 }
0292 
0293 QTC_EXPORT xcb_screen_t*
0294 qtcX11DefaultScreen()
0295 {
0296     return nullptr;
0297 }
0298 
0299 QTC_EXPORT xcb_screen_t*
0300 qtcX11GetScreen(int)
0301 {
0302     return nullptr;
0303 }
0304 
0305 QTC_EXPORT void
0306 qtcX11InitXcb(xcb_connection_t*, int)
0307 {
0308 }
0309 
0310 QTC_EXPORT void
0311 qtcX11InitXlib(void*)
0312 {
0313 }
0314 
0315 QTC_EXPORT xcb_connection_t*
0316 qtcX11GetConn()
0317 {
0318     return nullptr;
0319 }
0320 
0321 QTC_EXPORT void*
0322 qtcX11GetDisp()
0323 {
0324     return nullptr;
0325 }
0326 
0327 QTC_EXPORT void
0328 qtcX11MapRaised(xcb_window_t)
0329 {
0330 }
0331 
0332 QTC_EXPORT bool
0333 qtcX11CompositingActive()
0334 {
0335     return false;
0336 }
0337 
0338 QTC_EXPORT bool
0339 qtcX11HasAlpha(xcb_window_t)
0340 {
0341     return false;
0342 }
0343 
0344 QTC_EXPORT bool
0345 qtcX11IsEmbed(xcb_window_t)
0346 {
0347     return false;
0348 }
0349 
0350 #if 0
0351 QTC_EXPORT void*
0352 qtcX11RgbaVisual(unsigned long*, int*, int)
0353 {
0354     return nullptr;
0355 }
0356 #endif
0357 
0358 #endif