File indexing completed on 2024-11-10 10:57:02

0001 /*
0002     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 #include <cstdlib>
0007 #include <iostream>
0008 #include <xcb/xcb.h>
0009 #include <xcb/xcb_icccm.h>
0010 
0011 /*
0012  * This is a small test app to ensure that KWin calculates the size of a window correctly
0013  * according to ICCCM section 4.1.2.3
0014  *
0015  * The application creates a window and specifies the normal hints with:
0016  * * min size
0017  * * base size
0018  * * size increment
0019  *
0020  * With these normal flags the size should be calculated as:
0021  *     width = base_width + (i * width_inc)
0022  *     height = base_height + (j * height_inc)
0023  *
0024  * With i and j being non-negative integers!
0025  *
0026  * This application waits for configure notify events and calculates the i and j and
0027  * tries to calculate the size it expects. If it doesn't match it exits with a non-zero
0028  * exit code and prints the mismatching i and/or j value to stderr.
0029  *
0030  * To simply quit the application just click into the window. This will return with exit code 0.
0031  */
0032 int main(int, char **)
0033 {
0034     int screenNumber;
0035     xcb_connection_t *c = xcb_connect(nullptr, &screenNumber);
0036 
0037     auto getScreen = [=]() {
0038         const xcb_setup_t *setup = xcb_get_setup(c);
0039         auto it = xcb_setup_roots_iterator(setup);
0040         for (int i = 0; i < screenNumber; ++i) {
0041             xcb_screen_next(&it);
0042         }
0043         return it.data;
0044     };
0045     xcb_screen_t *screen = getScreen();
0046 
0047     xcb_window_t w = xcb_generate_id(c);
0048     const uint32_t values[2] = {
0049         screen->white_pixel,
0050         XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY};
0051 
0052     xcb_create_window(c, 0, w, screen->root, 0, 0, 365, 104, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
0053                       screen->root_visual, XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, values);
0054 
0055     // set the normal hints
0056     xcb_size_hints_t hints;
0057     hints.flags = XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_BASE_SIZE | XCB_ICCCM_SIZE_HINT_P_RESIZE_INC;
0058     hints.min_width = 365;
0059     hints.min_height = 104;
0060     hints.base_width = 15;
0061     hints.base_height = 64;
0062     hints.width_inc = 9;
0063     hints.height_inc = 18;
0064     xcb_icccm_set_wm_normal_hints(c, w, &hints);
0065 
0066     // and map the window
0067     xcb_map_window(c, w);
0068     xcb_flush(c);
0069 
0070     bool error = false;
0071     while (xcb_generic_event_t *event = xcb_wait_for_event(c)) {
0072         bool exit = false;
0073         if ((event->response_type & ~0x80) == XCB_BUTTON_RELEASE) {
0074             exit = true;
0075         } else if ((event->response_type & ~0x80) == XCB_CONFIGURE_NOTIFY) {
0076             auto *ce = reinterpret_cast<xcb_configure_notify_event_t *>(event);
0077             const double i = (ce->width - hints.base_width) / (double)hints.width_inc;
0078             const double j = (ce->height - hints.base_height) / (double)hints.height_inc;
0079             // according to ICCCM the size should be:
0080             // width = base_width + (i * width_inc)
0081             // height = base_height + (j * height_inc)
0082             // thus if the window manager configured correctly we get the same result
0083             if (hints.base_width + (int(i) * hints.width_inc) != ce->width) {
0084                 std::cerr << "Incorrect width - i factor is " << i << std::endl;
0085                 exit = true;
0086                 error = true;
0087             }
0088             if (hints.base_height + (int(j) * hints.height_inc) != ce->height) {
0089                 std::cerr << "Incorrect height - j factor is " << i << std::endl;
0090                 exit = true;
0091                 error = true;
0092             }
0093         }
0094         free(event);
0095         if (exit) {
0096             break;
0097         }
0098     }
0099 
0100     xcb_disconnect(c);
0101     return error ? 1 : 0;
0102 }