pax_global_header00006660000000000000000000000064132553470740014524gustar00rootroot0000000000000052 comment=7840fe5b3fdde44c6e18d9cdf96d36673a3a47fc deepin-qt5dxcb-plugin-1.1.8.4+ds/000077500000000000000000000000001325534707400164075ustar00rootroot00000000000000deepin-qt5dxcb-plugin-1.1.8.4+ds/.clog.toml000066400000000000000000000002261325534707400203060ustar00rootroot00000000000000[clog] repository = "https://github.com/linuxdeepin/qt5dxcb-plugin" from-latest-tag = true changelog = "CHANGELOG.md" [sections] Others = ["chore"] deepin-qt5dxcb-plugin-1.1.8.4+ds/.gitignore000066400000000000000000000005461325534707400204040ustar00rootroot00000000000000*.pro.user* build*/ bin/ # C++ objects and libs *.slo *.lo *.o *.a *.la *.lai *.so *.dll *.dylib # Qt-es /.qmake.cache /.qmake.stash *.pro.user *.pro.user.* *.qbs.user *.qbs.user.* *.moc moc_*.cpp qrc_*.cpp ui_*.h Makefile* *build-* # QtCreator *.autosave # QtCtreator Qml *.qmlproject.user *.qmlproject.user.* # QtCtreator CMake CMakeLists.txt.user deepin-qt5dxcb-plugin-1.1.8.4+ds/.qmake.conf000066400000000000000000000000561325534707400204330ustar00rootroot00000000000000isEmpty(DXCB_VERSION): DXCB_VERSION = 1.1.8.3 deepin-qt5dxcb-plugin-1.1.8.4+ds/CHANGELOG.md000066400000000000000000000364451325534707400202340ustar00rootroot00000000000000 ## (2018-03-22) #### Bug Fixes * window setting Qt::WindowTransparentForInput flag is invalid ([475bc708](1.1.8.4/commit/475bc70832591da3ef9ca06ccbd328c033baefa3)) * clear the window blur areas when the window unmap ([482d26e1](1.1.8.4/commit/482d26e1854d27c055d97c5e223f29991f8efccd)) ## (2018-03-16) #### Bug Fixes * crash in DPlatformBackingStoreHelper::flush ([38d9dad0](1.1.8.3/commit/38d9dad077e127a64fbcf847a9c7cc1e31541473)) ## (2018-03-15) #### Bug Fixes * dframewindow timerEvent ([5afacaec](1.1.8.2/commit/5afacaec9839c898eebf4f120c9e44a9bae098b3)) * request active window is invalid ([ea8e7a13](1.1.8.2/commit/ea8e7a132aa603b9cf88b64d7fbc78d1c91249a3)) * window not receive Leave event when the window is covered by other windows ([2348e1c3](1.1.8.2/commit/2348e1c3ea1138850181a84571437690f48c9a25)) ## 1.1.8.1 (2018-03-08) #### Features * support disable change window cursor ([0fbb6f1c](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/0fbb6f1cd56d8514f512f533893f115af93cca78)) #### Bug Fixes * crash on handlePropertyNotifyEvent ([ebb2b1a3](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/ebb2b1a32f53b2a6d888835ada88a4c98d5de537)) * window can not maximize ([da161585](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/da161585468526e8a821933d08e97b94c76d3e36)) * no leave event when window hide ([a2bd2498](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/a2bd24989a077dc058928bf58d0aefea4dc98f13)) * the window "_d_netWmStates" property is invalid ([f48df4c1](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/f48df4c139cc058cd6a8ac05d10245cdba715121)) * window fillet anti-aliasing ([ed29cca5](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/ed29cca57544f2678bbc594fd7d7203d0d9ed933)) * blurred window sometimes does not take effect ([3aa09aa3](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/3aa09aa3502e422395cc60acaa2797a15f0105c5)) * carsh on arm platform ([92d20f72](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/92d20f720331542891b04a738e42bc586064a322)) * optimize the effect of the window fillet ([40d298a7](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/40d298a7beeb7cad7e2f6bb5cadcfc79b8fdbbc2)) * window exists property on non-kwin windows _KDE_NET_WM_BLUR_BEHIND_REGION ([4cc89fcc](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/4cc89fccb8b7791bb349bdbfd0c08f744ab143e6)) ## 1.1.8 (2018-02-09) #### Bug Fixes * shadow image not repaint ([8cde9879](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/8cde9879cc74944c111e23a7c99634b0ab545e15)) * content window no clip ([359647c3](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/359647c39c6220ecb6c44471b953d9bd248ce392)) ## 1.1.7 (2018-02-07) #### Features * set window radius to 0 when window maximzed ([35ef919c](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/35ef919cb5dd6a50deff1e2f466bb141a4fc3424)) #### Bug Fixes * crash in DPlatformBackingStoreHelper::flush ([dbab1dc3](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/dbab1dc31e6a3129d2b688ede676679102c099f8)) * update copyright year ([422c0d2d](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/422c0d2d53a1452ff9b80f31c166a38db95daa38)) * shadow image size is wrong ([e537bcea](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/e537bceab205b45f4f7dd5080213ab33ec0bd5bd)) * window radius not visible ([671b8894](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/671b8894667877e0b263234d2e91edecdcafab75)) * window can not get focus on Qt 5.9+ ([3c0a44bf](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/3c0a44bf9f8522ad820287d28d7b49bbeea32350)) * QGuiApplicationPrivate::lastCursorPosition on hiDPI window ([08755140](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/0875514090cf19e8129f1c6f08a42ac8c219bb3c)) * remove debug output in DPlatformBackingStoreHelper::flush ([c68032d9](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/c68032d9cfe0e4e2fc6ef508908f53eec1f2a704)) * can not resize window by bottom/right ([e4c58d76](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/e4c58d767d6e5b9fdd8805cec2449d3ddb2b5e0a)) * can not reisze window on openbox ([218df1e2](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/218df1e28708dbea9926eb0f94896d959744f7c3)) * content window position ([2439d675](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/2439d6753fdd3c6449b43c844f4191d0b60aa12b)) * set miniumu/maximum size inoperative for window ([0ad7e599](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/0ad7e59901db5d167227a6026623ffae678dab02)) * crash at VtableHook::overrideVfptrFun ([1a8e03cf](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/1a8e03cfb8574ac8df2e1f406b12568307943af1)) ## 1.1.6 (2017-12-28) #### Bug Fixes * send resize event to content window on frame window size changed ([fc88f619](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/fc88f6198c3273acc49f566f95efc459b5a357ba)) * the content window frame margins is invalid ([bb069366](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/bb069366555c07d1750f376677b20b19fa09e8d3)) * content window position is wrong at show ([2f74cd2c](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/2f74cd2ce4db37009141d181f9752f3b124dee09)) * add break for switch/case ([ca84b062](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/ca84b0622ebee89d7454401d261f99f577850f36)) * fcitx input method can not work in QTextEdit ([cbd74f2a](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/cbd74f2a6a9f137d0081848a53a40bd50d350ca6)) * window blur area is a rounded rect if set clip path ([a89e7d0c](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/a89e7d0c035137bf1f85c7993eb14cb190f98ce0)) * LICENSE ([f8013823](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/f801382355dd62618fa0548c87cf6752b53673e8)) * after moving the window release the mouse and then move the mouse will receive a mouse release event ([10a73727](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/10a73727fe067bbe395d38c46890508ddd1ef559)) * Adapt lintian ([1f862c11](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/1f862c1175a2342520a3340621cb122e4478f88a)) * also search for libqt5xcbqpa private headers in system ([e47d510f](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/e47d510f9c2d371f59c33a290d27347840318f44)) * do not paint shadow on window maximized ([b1483de1](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/b1483de187d26ac360aa6b6f08469fad61b32077)) #### Features * eat focus event on grab/ungrab ([936da4ca](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/936da4ca99900ee4256ede4ca33b8767f189e5a2)) * support for Qt 5.10.0 ([247cabb7](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/247cabb70d2f97de4e6cec062e1106c9678d97a5)) ## 1.1.5 (2017-12-07) #### Bug Fixes * visable black border when maximize window ([9a25eccc](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/9a25eccc5e50ccd2cf196671d898ca83ed468f19)) * output "QPainter::begin: Paint device returned engine == 0, type: 3" ([d424dd61](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/d424dd61e2adc6cb4f96315354128751a2ac60cf)) ## 1.1.4 (2017-12-06) #### Features * support for Qt 5.9.3 ([32ec6503](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/32ec650304f12e3107c7dd13677c0cbb0afb1023)) #### Bug Fixes * compiling failed in Qt5.7.0 and above ([790377a5](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/790377a5ecadbcd86a0bb62bc71cf71144873984)) ## 1.1.3.1 (2017-12-06) #### Features * not clean when begin paint on opaque window ([635a8252](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/635a8252efe0500e2a299b0f336bab6b0362da1e)) #### Bug Fixes * visible lines at bottom/right on frame window ([40f53663](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/40f536630fac0222f6e2ae29d0cfcd604f9e6b77)) * content window area path on window maximized/fullscreen ([4dd1dc20](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/4dd1dc204125a62137ad735bc8e387ef0150314b)) * mouse position error on automatic adsorption ([196e34cb](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/196e34cbade9e665b4b766e9c62332930cb34f54)) ## 1.1.3 (2017-11-28) #### Features * add native function: popupSystemWindowMenu ([0e741b1e](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/0e741b1ef87e77df108c9cccd3fb24e5a9010a88)) * add showWindowSystemMenu function ([915c6d3f](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/915c6d3f75723c4574c00a786511ea098345d0d8)) * support for Qt 5.9.2 ([715bb1e4](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/715bb1e411ebf5283a4aec5416c9b7d19d09a55d)) #### Bug Fixes * window vaild path is empty ([c2b1a1b5](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/c2b1a1b52324f668a45213bebf1282aeec2c64e2)) * blur area overstep the content window area ([69f5edef](https://github.com/linuxdeepin/qt5dxcb-plugin/commit/69f5edef4453780c1566bc000b63307a5417b14d)) ## 1.1.2 (2017-11-16) #### Features * support set the window radius for QOpenGLWindow ([431fa688](https://github.com/linuxdeepin/qt5integration/commit/431fa688a6fad3a5057c89396342dfcc53987b04)) * use fake platform name when set DXCB_FAKE_PLATFORM_NAME_XCB ([471216b2](https://github.com/linuxdeepin/qt5integration/commit/471216b22d3ab08129d6d6e5c9e47696947adaaa)) #### Bug Fixes * the drag window position when dragging from one screen to another ([3905a0a0](https://github.com/linuxdeepin/qt5integration/commit/3905a0a02e1f17092b6c324516ae130172e247c9)) * the DFrameWindow's border path is wrong ([4882b916](https://github.com/linuxdeepin/qt5integration/commit/4882b91676593eadb8dcc98fb2a86ae82d0fe87a)) * the content window screen is wrong ([20f7695f](https://github.com/linuxdeepin/qt5integration/commit/20f7695f59a3a07981fc9bc5dde874385e215328)) * update screen for content window when the frame window screen changed ([f40a66ab](https://github.com/linuxdeepin/qt5integration/commit/f40a66abdaea1af1d8c00079717dc8d8c2622748)) * can not move window on openbox wm ([af64d84d](https://github.com/linuxdeepin/qt5integration/commit/af64d84dfc7d98e2bf5b8ea5a11507e200111431)) ## 1.1.1 (2017-11-10) #### Bug Fixes * crash on use the QWebEngineView ([c13bdeee](https://github.com/linuxdeepin/qt5integration/commit/c13bdeee242b0cbfebef78df925028f285913f2c)) * mouse enter of the window to receive the mouse to release the event ([7a6989e5](https://github.com/linuxdeepin/qt5integration/commit/7a6989e5cf8a2be0cc84644c9289e647704b06c6)) * mouse over the right border of the window to receive the mouse to leave the event ([cad2e037](https://github.com/linuxdeepin/qt5integration/commit/cad2e0379abf745e5d59fbca5902a1008edfff4f)) ## 1.1 (2017-11-06) #### Features * print info on create new window ([b68d0371](https://github.com/linuxdeepin/qt5integration/commit/b68d03713feb1d77640b35891e38e05736becba9)) #### Bug Fixes * update the content window clip path by it size ([070e3bc4](https://github.com/linuxdeepin/qt5integration/commit/070e3bc4d9c715d1c8c4e1531077286c43658815)) * the content window position is wrong when content margins hint changed ([9b1a28e6](https://github.com/linuxdeepin/qt5integration/commit/9b1a28e65d60e7286687943511a58485e0937bf5)) * window focus out when mouse leave ([14c14df2](https://github.com/linuxdeepin/qt5integration/commit/14c14df2c7a92be746d5479558ae2c61765052a9)) * the DFrameWindow's shadow and border ([e35a87a9](https://github.com/linuxdeepin/qt5integration/commit/e35a87a93872acde909383b6f5b4ca3baf63bfe5)) * the chile window is blocked by modal window ([db20016c](https://github.com/linuxdeepin/qt5integration/commit/db20016c6baa38ea561cddb9a3676252a19d8af6)) * warning: "W: Ignoring Provides line with non-equal DepCompareOp for package dde-qt5integration" for apt-get ([a074941e](https://github.com/linuxdeepin/qt5integration/commit/a074941e238476cf5e93fe2400e72d0901474d64)) * disable update frame mask ([5d136679](https://github.com/linuxdeepin/qt5integration/commit/5d136679f4886523dc3bc779ac8d0347611028bc)) * can not install ([1ac9975a](https://github.com/linuxdeepin/qt5integration/commit/1ac9975a9169b47f185ef5e33d79e3e2de2dbc50)) ## 1.0 (2017-11-02) #### Others * setup .clog.toml ([d5d065d4](https://github.com/linuxdeepin/qt5integration/commit/d5d065d4099973a2d82aca0e16acd26c99621bd9)) #### Features * keep the window border is 1px for hiDPI ([da8040c4](https://github.com/linuxdeepin/qt5integration/commit/da8040c42df0cbde97e21693f472a288ef46a9d8)) * QMenu hiDPI support ([a045b17e](https://github.com/linuxdeepin/qt5integration/commit/a045b17e86735779b48ea734bd18f2b2e25b4251)) * **style:** override drawItemPixmap ([a580b9bf](https://github.com/linuxdeepin/qt5integration/commit/a580b9bf2024cc5e9564283f4880229bac1d780a)) * **theme plugin:** read settings from config file ([aacc2995](https://github.com/linuxdeepin/qt5integration/commit/aacc299512f4006ff174c5700d471d344d7155d0)) * **theme style:** auto update the widgets font when theme config file changed ([d478074e](https://github.com/linuxdeepin/qt5integration/commit/d478074e73d8e22e2d70080ad1430c565261d9af)) #### Bug Fixes * set cursor is invaild ([a2e235be](https://github.com/linuxdeepin/qt5integration/commit/a2e235bed7873d35030be380e8cd73acc0192e89)) * menu can not hide on dde-dock ([ecae595e](https://github.com/linuxdeepin/qt5integration/commit/ecae595e29f1da24654c3128f13321c22412a7bd)) * compatibility with Qt 5.7.1+ ([774ffb89](https://github.com/linuxdeepin/qt5integration/commit/774ffb89733232b8728b897b58db3eab6c7a6e05)) * **dxcb:** * crash when screen changed ([7e1627c2](https://github.com/linuxdeepin/qt5integration/commit/7e1627c20fd92d7b4c1d7a69c55b4de5869cf6b6)) * the window border size is wrong ([83d6ac50](https://github.com/linuxdeepin/qt5integration/commit/83d6ac500b7e070f5c97ff220da16736229fd060)) * draw shadow area ([284cae9d](https://github.com/linuxdeepin/qt5integration/commit/284cae9dd90e9b9d7af92480e3a0e217a7c5f478)) * the DFrameWindow shadow area ([6e9c8274](https://github.com/linuxdeepin/qt5integration/commit/6e9c8274ef871fe3fa48a60a0861a96b6880dbf0)) * update the DFrameWindow's positionAutomatic value ([f6331ee3](https://github.com/linuxdeepin/qt5integration/commit/f6331ee32809d7e548b7d538beefc7ea5582f111)) * update the content window motif hints on propagateSizeHints/setVisible ([4e490995](https://github.com/linuxdeepin/qt5integration/commit/4e490995f5cfb564dbec705af114467c0ed374f0)) * the DFrameWindow's transientParent is self ([d5d93dba](https://github.com/linuxdeepin/qt5integration/commit/d5d93dbae8cdc21e887da17b8d710b0403f3b0aa)) * **style:** * update all widgets on font changed ([0e28f244](https://github.com/linuxdeepin/qt5integration/commit/0e28f244217f57d454424cc7dfba488ee6be93e3)) * update all widgets on font changed ([d4a65deb](https://github.com/linuxdeepin/qt5integration/commit/d4a65deb9e21e18390447c8b26eb429843333be4)) * **theme:** * "DFileSystemWatcherPrivate::addPaths: inotify_add_watch failed" ([a0322a68](https://github.com/linuxdeepin/qt5integration/commit/a0322a68447b7d918af49fbba23ebe1d5f53da25)) * set ini codec to "utf8" for QSettings ([3a4f7d76](https://github.com/linuxdeepin/qt5integration/commit/3a4f7d7651f6c433ef9735426d936289ac04d6c9)) deepin-qt5dxcb-plugin-1.1.8.4+ds/LICENSE000066400000000000000000001045141325534707400174210ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . deepin-qt5dxcb-plugin-1.1.8.4+ds/README.md000066400000000000000000000026361325534707400176750ustar00rootroot00000000000000# qt5dxcb-plugin qt5dxcb-plugin is the Qt platform integration plugin for Deepin Desktop Environment. ## Dependencies ### Build dependencies * pkg-config * mtdev * xcb-xkb * xcb-render-util * xcb-image * xcb-icccm4 * xcb-keysyms1-dev * egl1-mesa * xkbcommon-x11 * dbus-1 * udev * xrender * xi * sm * xcb-xinerama * fontconfig * freetype6 * glib2.0 * xcb-damage * xcb-composite * cairo2 * Qt5 (>= 5.6) * Qt5-Core * Qt5-Gui * Qt5-OpenGL * Qt5-X11extras * Qt5-Core-Private ## Installation ### Build from source code 1. Make sure you have installed all dependencies. 2. Build: ``` $ cd qt5dxcb-plugin $ mkdir build $ cd build $ qmake .. $ make ``` 3. Install: ``` $ sudo make install ``` ## Usage To be done. ## Getting help You may also find these channels useful if you encounter any other issues: * [Gitter](https://gitter.im/orgs/linuxdeepin/rooms) * [IRC Channel](https://webchat.freenode.net/?channels=deepin) * [Official Forum](https://bbs.deepin.org/) * [Wiki](https://wiki.deepin.org/) ## Getting involved We encourage you to report issues and contribute changes * [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en). (English) * [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) (中文) ## License qt5dxcb-plugin is licensed under [GPLv3](LICENSE). deepin-qt5dxcb-plugin-1.1.8.4+ds/clog.toml000066400000000000000000000001661325534707400202330ustar00rootroot00000000000000[clog] repository = "https://github.com/linuxdeepin/qt5dxcb-plugin" from-latest-tag = true changelog = "CHANGELOG.md" deepin-qt5dxcb-plugin-1.1.8.4+ds/debian/000077500000000000000000000000001325534707400176315ustar00rootroot00000000000000deepin-qt5dxcb-plugin-1.1.8.4+ds/debian/changelog000066400000000000000000000002331325534707400215010ustar00rootroot00000000000000qt5dxcb-plugin (1.0.0-1) unstable; urgency=medium * Initial release -- Deepin Packages Builder Tue, 08 Nov 2016 15:10:02 +0800 deepin-qt5dxcb-plugin-1.1.8.4+ds/debian/compat000066400000000000000000000000021325534707400210270ustar00rootroot000000000000009 deepin-qt5dxcb-plugin-1.1.8.4+ds/debian/control000066400000000000000000000015401325534707400212340ustar00rootroot00000000000000Source: qt5dxcb-plugin Section: devel Priority: optional Maintainer: Deepin Packages Builder Build-Depends: debhelper (>=9), qtbase5-dev, qtbase5-private-dev, pkg-config, libqt5x11extras5-dev, libxcb-xkb-dev, libxcb-render-util0-dev, libxcb-image0-dev, libxcb-icccm4-dev, libxcb-keysyms1-dev, libegl1-mesa-dev, libmtdev-dev, libxkbcommon-x11-dev, libdbus-1-dev, libqt5opengl5-dev, libudev-dev, libxrender-dev,libxi-dev, libsm-dev, libxcb-xinerama0-dev, libfontconfig1-dev, libfreetype6-dev, libglib2.0-dev, libxcb-damage0-dev, libxcb-composite0-dev, libcairo2-dev Standards-Version: 3.9.8 Package: qt5dxcb-plugin Architecture: any Provides: libqt5dxcb-plugin Conflicts: libqt5dxcb-plugin Breaks:dde-qt5integration (<< 0.2.8.1) Depends: ${shlibs:Depends}, ${misc:Depends} Description: Qt platform plugins Qt platform plugins for DDE. deepin-qt5dxcb-plugin-1.1.8.4+ds/debian/copyright000066400000000000000000000017441325534707400215720ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: qt5integration Source: https://github.com/linuxdeepin/qt5integration Files: * Copyright: 2017 Deepin.Inc License: GPL-3+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". deepin-qt5dxcb-plugin-1.1.8.4+ds/debian/rules000077500000000000000000000017601325534707400207150ustar00rootroot00000000000000#!/usr/bin/make -f # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. #export DH_VERBOSE = 1 # see FEATURE AREAS in dpkg-buildflags(1) #export DEB_BUILD_MAINT_OPTIONS = hardening=+all # see ENVIRONMENT in dpkg-buildflags(1) # package maintainers to append CFLAGS #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic # package maintainers to append LDFLAGS #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed export QT_SELECT=5 %: dh $@ override_dh_auto_configure: qmake "QMAKE_CFLAGS_RELEASE=-g -O2 " "QMAKE_CFLAGS_DEBUG=-g -O2 " "QMAKE_CXXFLAGS_RELEASE=-g -O2 " "QMAKE_CXXFLAGS_DEBUG=-g -O2 " QMAKE_STRIP=: PREFIX=/usr LIB_INSTALL_DIR=/usr/lib/x86_64-linux-gnu override_dh_shlibdeps: dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info # dh_make generated override targets # This is example for Cmake (See https://bugs.debian.org/641051 ) #override_dh_auto_configure: # dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) deepin-qt5dxcb-plugin-1.1.8.4+ds/debian/source/000077500000000000000000000000001325534707400211315ustar00rootroot00000000000000deepin-qt5dxcb-plugin-1.1.8.4+ds/debian/source/format000066400000000000000000000000151325534707400223400ustar00rootroot000000000000003.0 (native) deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/000077500000000000000000000000001325534707400214525ustar00rootroot00000000000000deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/README.md000066400000000000000000000000521325534707400227260ustar00rootroot00000000000000# qt5dxcb-plugin The Qt5 platforms plugin deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/000077500000000000000000000000001325534707400231525ustar00rootroot00000000000000deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/README000066400000000000000000000002131325534707400240260ustar00rootroot00000000000000All images under this directory are made by Wuhan Deepin Technology Co., Ltd. Licensed under GNU GENERAL PUBLIC LICENSE Version 3 or later.deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/all-scroll.png000066400000000000000000000047701325534707400257340ustar00rootroot00000000000000PNG  IHDR00W IDATx͚h?νq1V̭k6@]Юѡ,4:)t&:e &p+i)!6Tt-Kf)hVk:#B?6&Zrss<9ωp  Ξ=[ f͚ ֧>X4x<7++3o,?L ! !R.t( Bhdd@5ѕk%XyGGZ4M)ܿܿFFFla߾}սvZOPs2 c:uW^y) @Agg'< iNy: IJ* o[MNNpD:.P رcz#vM* bL@Ç9D~$m3gv[WXAyfwʕ+st巅oʕ=z766v3@C0bػ?sLf~v9[>/JE΁9m۶ӧOSQQam%XLar(;\YYR!,c x_$gi1%`dSAHQ<֦ը|?-yWAh5_AH~<BO? aLRp^$~@=g?phYi,&o g9Lxڵkg#o{,Agp'l4.RA/ա5}JCT{n6Cr6 QƋGIENDB`deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/bottom_side.png000066400000000000000000000034551325534707400261770ustar00rootroot00000000000000PNG  IHDR00WIDATx_hT?ޙtd[jdDҕc}Pc[(+O EԇJEć6  >ԇVDCԭbL$3ׇ2I͝;|;Ek2& 4[%ҖϽ"S門hSi oݻ=Z T+cUiy bVmqi `JWm+++–esܔ|s #xp0իoANXQ`6*wRzttTN l4]6 ?|pBk׮a1<<,\0xǎ ސcۚjO;ywe?~L2<l… y^6de '|@W>uݞl6˞={H%#DQ`IoD=Y\q^x=dT*3 q-u;3 \nݺq<#y g8q]]]}'ӫ5w@ۡCvOW299&OLLpevGgjQ r~RA;33Wٶ8*) }:hsii?fYvE&IyEH7oAsAXrTQo _!JrNٷoP/_U3RJ :jMMM,ZE<=UZ-pMк rJN;wP,3*F%tU\i!]+?S\y)|%`b0WZ74UTyofm7nEЕ{%@*%r>ʩBܩ$вv"J.,|TPRn&ʂՅS_M˛7o.yӧV]Ƶf-]PUٌ]y AlJ(]=n"VQM^*̀LVDllKt @e$ۇͽM=1Wj`QU^+˲W瀔ZX?_w50Ҫt0K(ZR+zYjE^:pyu̙yZ]tZ2'! _=DY[N7]gvv뮮? 133Ӑz{{{.sss7E7`M9Baaa.(b1B_@9]mKY6O=F"nܸmU;-bbbX,yP( Ou|WOxDc!غu+Oy?|)ݻwrZ\   ?sGp"2 ZzQΕO^`p``WB]Ƅm¶mqY9^" 1 91"|=Cࣱ/dR$Ux)ȑ Z3JAmv9io7T*m4X\\3ͫהn7I`)|>  SD(. @#[JSr###)mb)]N 33}s|=VSr̦^}3M\#-RwTMn~`IENDB`deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/crossed_circle.png000066400000000000000000000036171325534707400266520ustar00rootroot00000000000000PNG  IHDR00WVIDATxY]hW6l͊imMTtUbF(Ah#X)hM/>IcTPOeנM6&3aޙBvf9w9wνE4+-qNL,FD!_=$K@8e ]%" ~!Ewm4 hQ %E, X(0@ӧPhDDIIg^ﮦr|mqGNH |p{OO`0+IdRc`0xv sIɓu`Ydbb3gj96 =x+7<ɓ'dY~A"D7nۻڵĊUU۰!,O<|p;1L|>B΁DTDt(ŋ#hU1pr_$M!?qOlJZ_O481~H)߿!f^Q]38 %rf$Ȍ`hiiqIZuq*15}ZDn---.DrƱdD(HbxEv"Wun(Ly|ΝJ I"bWtZM>\vQ&tDȴZ%CC< %&úH>P&0Q8K5扈z{3k@9y$"/h&Q rPT}f҇OPE7MI LIu4 0 hdjjjh\ :_SSS# h^>֩_~cP`QZ6n|?u?~ oLW`%[li`I|: V^;czmSX+*HjllѢ.CO@(P jX O񊹶6Ȉ@5"CY(BN^bV'&xf .N8@%@lE HՁbņ$ZbDOn~@b?bb(0={|#I[;IJӫNE!{W5/Iқ;v| `90&i}YLrAM &ImtM-h0,P`eWW/^/1+Lcg+EÌKJQPLc\#cDĖ.MnpADD}}}%HrQ/l)mmmp-饻؁֯'VQA gMMD==17>Ij[E$r"2)$\۶mvhh3M:nݺ| )nl$bՈiÇ|mBdY?znZ&㱉Y#29Xihh(޽{ñ`~VV$䋱? bottom_side.png all-scroll.png crossed_circle.png dnd-copy.png dnd-link.png dnd-move.png grabbing.png hand1.png left_ptr_watch_0001.png question_arrow.png sb_h_double_arrow.png sb_v_double_arrow.png deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/dnd-copy.png000066400000000000000000000052501325534707400253770ustar00rootroot00000000000000PNG  IHDR00W oIDATx{lS?~8&)xt(PvTU[N-+mĖB: )c*tR[$n@i ai< %'`4v|{=IO>s~s~scap~edhI ~EAn,mLm :R8+`8tv9~y$g$$U\\~iZⶦi_+r>- ܦ/yݧ(5a"Mb>?zȑ=<g3*»\ ?AӴBMWUBtuu5kֈjq9!XL⋢R̛7O|gB!ҥKo477/7"Oߜ%$UwYb~9SUUE(J X?O?Mghhhn7;MBgϞ̙31 N} HfȤ'N555,Zʕ+0&q8ӧQU5ɱX+W7|C(J4;vFc7n~tCLqBh4ڝCaa!|ׯ/dSH5v`a[ȤB`0PQQi}XQEI5܅')J+={6e޻ad$1iҤL>!BU2e~@A2{GG}>KWa '`}[cc|)s=Gss3999\.h G0r3߬`d5k@$!R`pXA RU(E}ND>4ܤ[wL'0~h&7J=k2V/)bd,FIG`,~R2HTUl>k׮0VP($ $'lfhDY0`ٲeCXA|A֯_ϡCr pٺΝϟ_}IQz'1Ɉ;D4bŊ*--漼$?ә { (!C*K?([ncǎ{<xDIIػw4mH| ]&I9$jb`Pv%z(Ennv -ƍ'S$q{bC˓3ON"o.ŶK]E\SRƄBe@!uf*sturw&LիL:՘Af%!Ncǎ1{dC>\[X`wS(M˗CBTyD;f̘9tA9!۶m^K<|۠l~6a#ܺud ^H^<:D"Huuŗ,YΝ;X,zJn}=|<'߯|z/:thJ͙Hsu !˖-/`!IUUbIxƯS1}O|.X-9dYzuֽzf̘ŋQh4J8ܼyOUUm] /k c>V[[[f0)ټy_pa,dyq:Ʌ>@ zunF… $s! FH$>[ZLw S𒚺?Ɫx;dNt:˫@) b9Phϗwr\d8)$3;ovʍlf?ٔp]d,Aϋ2@62;'#a#rQ)j;E"YK624[?w7 oFv}<=RK@NI|K*r&ۊB́>pdL*/#bގd09wB J#Hr@, B8:&9QHɋZ[[OJ '"mB;*>R4>ה ?.)|2|2 $^oٲjgg G I۰[MֆH"w PvgSH3<] lZ >?<---5eeeOC"~m-n3&nJ---B@dB$*%7[RRܹzr#ԵNsMᕉ[R SNeGGm]07M1wq."#4uT;3%w&s p6#P0M__*kqXD"ZZZuttt`Z3̙Sm۶q݅X3gnسgϟ'y饗~zzPU-ZDEE˗/aÆWtFͤ:ÑP__(DhmmMS7oTUe߾}BX۷#փd~,BP(t=%%TUMh|̙uW^8ݎIh٩D9z`a]H&BvPTT4@,:::%+pp8PFsڹ +$w :`Qy(HƽNF2O{[[ 'O9YB m-Q2t& wvv6?? M6n0b2qmgϞ]$Gp)))Ɗ9|> f9x`֭[9w``08Kq?~ʉA%o~3YYYQ߉I.r cn@fxd eX,cɬP(fG'a(3(6-;??+W9V/$'G62n3<'xA32)5kFi+2[rqZ[[%;;MMM+++EKd&w$7 -K~2*((YYY.l2Q__,QKJ}}}gjkkēD@0pooWB/qƍ\.rD^^8tPUuH~(F S $/z4e˖;vXFH|ff&,X -S 0. 2B(-nn޼y}gnQ@M>W{{'N̘1A t2o޼X \NO1s̟~~ PqD:v?ݻw3 Qo}:,Z[ - VH<):TU\cX<ϧ,63s5Rnv?q7+O$+++BD׬Yg}Ɣ)SB H'EE[S_ѳï05 bŋh`Kvt(uAR^˧o۶UÑ%t8h4JAAQ~'8횒W»{޽>l3/Eh]Kp׮]YYY777D"tK(N36FJCrؾ S:O|.]#L; |"a܉4+tڤzE'NP:-i2 s5P7n4''gtG>"vz0 L'^qƵ2ڵcLǜϑ8Z?9axʺuYzCSNriii@w]tÇ~}.\}L/ۧylU2[EQ,34Y5/1c+Pͦv3&7 x\4 <ۣ迢h*///4mDDjx<~ԩSu5n>,俳<@!P *6nܸ,M4MKnjG},0S x R d(4M+"(DDn߾-{_|Q.]$""DBm&ׯ7J__(2W_u?)c"JəL'Y]'2/..j?YQ{1~ѣG9}t<ٳgq&NӴŋW^}H 1c ߻ϝ;⭚ϳn:ZZZ?f||M4 UUypBrL4׮]# yyyE'O>$gϞpڵkP$V4if/PU5D1UU 1Mxwbk:@aal92vrb;24MK9̙3icCCCrN9wttTżb@x5L \j V\###ic4SE>,iLx<]UUsldc^d{tݺusҥXj"Ȭʖ$)dwWUU `TUUrrO7~iΟ?D tR.\&{ H.^k֬9o>>3(ht,X O~~>^nRJKK+3JFZh8'2̸ pyf!p8fFSYqKU1YZUU\`(G"Ywd@?=\N+mxx<)c"b kx饗ziLUQE77H~7 =R`5@{wGU2&ȶ6:::ضmhN5M˳1 (+_{QꤨhZXX((q(f eٲe5Li 06_[/ny& 2' Ohhh'x+W0|n71`1-4u5WK ""x$???guHKK H0(PT$3Pqm&DD=*G\.WN!""HDڤIM"\~ca`zm1a<&ch>| f… R[[+NSGVmjjP($"">OR-_2XrحPh~+{NH$$I4`0(oߖQ jZs^UU8wܟQ `f2F7osAAK.uOLL' -I$Iodll,ScNlVWWwX޽+ 5- #WU%Uzx y{{+~퐈H44555RSS6ꫯ&cbbbbnlRNmLmED% "?Z' #(e˖-R]]:xkk\zUDD4M^~}lfZic&fgC쪭} ĉtuuͺ z߿g}P(#G. 6ECjv\d-"g6jJ@DPކϩ`@>z@C9A__E˦M2U*++oذA\""zVxx5r f; k5 Xڽ{w p8,;wLZQQ!i;wp8,Ƶ^}D.Eyɒ%~嗧RVV&eee~7no >d &LE f{5@ɓ'lUJJJ$ (޿3\11z`q;%YH,GOktvv`رcGZc|jEڸitd%aګ Ǐ?$MMMzI'O| }a4/Gwp! kvH˗TJKK""oxsM3*%fCLY-|G޽; "r19v예+Vh~o'H!/BQ%h{5ӻ ^Iz>mHdZ/k|GFFȃ>C3t@/S!EfP 'wp?3p9?d.$[Ns᳾jRmN),aQA:,e|d>BIENDB`deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/grabbing.png000066400000000000000000000040751325534707400254410ustar00rootroot00000000000000PNG  IHDR00WIDATxZol]ǗCQr-j֧P"rҥYB!_@Hp-J $ Em(H "@|r@*DI#4 Ŗ]M?xy^:NBHGٞݷo~3γ#h>3#*YDL1"s֊z^aA [Sߓ !B [2 fb)@qVm**K/8::mgg87(cDD`nݺE3ʲLΝzxI xKUlذawډ(ś1'"z)m޼jkk۷DDt̙\ׯQ8o tU2#DLE-|p8|YQq\YlY#Q*\M5p>|u]]gb׮]r *++!l&ַ=z V׋v?:p8F{Ul0tسgϷeC[[[f@0 @V엖n&J-""Q5!> e@8NIU2;bn滮!%HXYEQ@*;@H&B2k.xɗFg"R`6nܸ(|?zzz MMM E@!\ڽ{D"1^YY[.E){T,?~|>ѽ 5 xh/S*vqMFSSӢx@C}) {^˖-5o7z@@ ߜx\VVK.b~hBHQYz(Jȑ#T*ݴi:w8l`%~Y2+B+VxcSDD QmFDDHT ݃-t%CǷ?A)5~/N"'O$IdZ?(Z? ӭF Nq:uvv~yA;Nx<444Y@jH'=Z1ӽ"%j(UFoLZH$2sίqEQ(9@VWWok0O2 WT* B޽r~>R >-fZ)Vit[k>nyR"w@@BzMd3Qg?:ƐN @{w99ev^qɢ||<(#ki1y`6')>mQtٕMR![tc dR ن,h"}Ԣc!\̎\t{s }W#b6 91;7Fb(\U7=>@{FIENDB`deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/hand1.png000066400000000000000000000053431325534707400246600ustar00rootroot00000000000000PNG  IHDR00W IDATxŚlTU?󳝁"[X]()!e,Iݤj7ՀXqY~H6qaٸDXqe-b6ֶ3MڲimrJί73ox:S*R&'o=s}& 8jŨm"BsTtGi *UJ+5b)%Owvvn9u@9&:u*28FDK'!&ԴJʩJ؁)T fo BC"_gΜzkE4, {hn d(u֌_'E ,̮,PҥKRTWW!@+ yU{{{EOOQ$~>%%% HyK ہԪ^(>y%I~7  !DUU((("??__^tttDojj6l^|aϜ9HB07憆7~eKqݘ{~o8v,( v9x`t:$_j0]-M y^0E6 /000IMM5 F1\oχcKRR TBD2xl,&)^vimm%777QEQ^okv;ӧO~n26m]v5a޽ܠq0]t ??fԄdxx2/--w6?<oUXr%P(r zghhh+a0doΒ%KVXq% &⁨َ=z;LBNNN---7n ֊lbDWݻX,?%L#5H.驇0F>Ux%'btttLzz:@?xR/^z8P+V088Dd]HM[*kTEZx1)))1\.~-P!˗/ŋDĀ BB---#nd2`0 0B~?.$IrSǏoV0$ x(((c .>EQR?oѢEv|>ߕw}׭0^ݯ8w*Ty@FCCC>>}}}N4I8ꃊТ_$i8339sX%nT- x< DomPZ1Q\}pΟ?WWW޺p$&/^(,,H$書JvZ{챸V5nM ϮӦM&##chrL˗/Wڵj֭kJJJ~wY***bpvm…rZ۲&l~r?:r}}}̚5YYY[{_h)+<@kkk+W```IQ is[[&Q.I/Q.]ʓO>IqqqRNNN1@jj*999477v5ܠOM Dk{w'޽{9q,Gt:k֬I6o<;wNHRjjJ kjjxᇩLxwߍ,>ZGvxxꩧZڵk|r'x+$X_P?~zZZW glْppIxg9y$SNsڵk]u}^y-[Ų,cz{{'B3g`dd_O4+Zm?4֭tX,;v3f$RvIZZ`УW^蔗Q`tofϞÇ'-P Ö(ɲ-..xRe(IMMPR@DCݖΝ;(T&ɠ5 BqAȲ?t!!Dh۶mdee11i4n,_x1Ȳ `0GF^PAD7%I.**bݺuw@ l11RIB8VPzڎDܼys󩨨t P(t144;y^x222Vj<'xs)))9rdR=(KJJO6T*n۶OyIf(24YS>^j |gϞ=paIPPP@oo;nڴ.t  R7o0MʄBH)**w޹L&?!f;S o},fggv !իWEiiHNN%33Sٳ'w|…WsIBx65b@6P~b,l6V z*2#ɵlկ KDvo7xi`ydD J>8XDnǼOՍcQe}GF/&Ԛ\2X=]/]h|}2(.򌽛N(mIENDB`deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/left_ptr_watch_0001.png000066400000000000000000000045031325534707400273270ustar00rootroot00000000000000PNG  IHDR00W IDATx͚mlSױ_``LCҌl-C mxѪih6v$V-VU;DetR&hJBSJ`t6lf'og|bkyG׾>>\+7uUr)pS~xJ&UsZ k5HBʕ+?Tk@_'#Fd9@,U6sWɈԉ}f-DprS8sf`֨>2cnʻl`&b.L`,U/Yā,K裏6JrQm1u@phmmnm``q v+@@=p;@8i[l!sNZ4줧EQ|mmmcj ȼn*D)܂n4y9pmmm8v "rZ \0رc> ԰\)H۷˖,_wYA6pCHJʿa H[~+W~СYO6@[b!DAnߺu+o&eWZ!BMnR"0< Mxg8x ׮]յn.U1DIJiv!21MB"?ҥKb444*i.]zݸq 4@L- o*2m᳀fEuNE]]C={Vk n#҇[иpDy7HR"H$"/^,kTW_}u]I3( b.ڙ3RǺ3w\xO4uL$8q'OryFGGF477˩q1M/-[Wv).U/ 5McÆ |>4`޽$ɒ5ٰaׯ +V8N(0 ([l%dΜ9@%x՛6m:SlRXWW>(/_HX,޽{={6Th4:JM NS3<^Nyꩧxbѕy:駟&N Z?{lg΅r{#SNaY smii5QlEl*^X x+ 9_/o\/jZ M(߳T/1x b0X=emB )I,ӊ,D&U(1H+6ݟ-MM9~S-`ŝϚRⓓ` sA4T$UPCԠ_Cx<^G!8ih,jR[[m-~_VLB/xC \?\_:2_-/iRn9r=ܳ `o'x7|iXv{^P ^>oիW BMS5K9$:&DRU(n*L]G&o%3QfD dsRDU~o4f'v޽'H\[䛚ۀ;E?;}*cccx~oy]F/H*>'r דyt]ۻڵk/۷o; Xbuw]<~,)ՔT]J =֭[6o޼EP> KRWΝ;7t^z0i{ǍABH* :+: Aw v `p1 ap+%iMwy_@1)V*t\6][xY4MlIENDB`deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/question_arrow.png000066400000000000000000000043121325534707400267410ustar00rootroot00000000000000PNG  IHDR00WIDATxՙkhT+:3Č> (5H)4T[PZV ^"_CVQ Ԉ^5DČ3~9ə3L`q{Xkm)b">h>e{2c&37h|%m"FJA @Օ iHz`r,T=0W :&0 XzRfZV$I!D$088}wwUV]okk N5"zۀ GrMmoou(j)J$SRR L&T? ,:Qcǎ}aÆ9?۷o>ͼ|nYt)>p8޽{.\xaF[C?D xիWZxYŒ 9y$/_FQ#RTTDuu5>!D7>ƈDR%*9 طm6VufSS;w?)pXVXnں#֑0R)Ѓ؁ߟu\I8p!<ϒG}?$"`c@`Ǐաrsof׮]dee5rii*ֶ0pL~[-[J$IS08q `PU5r(//暶vSLElD'455N5kְi&{v͛7Oٽ{iۖ8|mY`\Sh3iҤ/=z7YYYl߾UѣGbŊ?+*..fڴiqE$[EEEn bfn><B}3fjMM>|ԩ<ed蕦BBhɌ ݼyWB)^>}zVUU OӧO?':ub}b'dv ], ϙ3g9@mm-CCCqy< KٸqMZ8(͒6De@vׯ_7=֯_! >Xr? CJ YM ,[ +W# |Zif׈ȲlWUsСC@kj>@\ $f͊k 2!>X\MmÇ+K,w2X'0^hūϞ=3m1Oꦴh2ٳgVS1<qC'f;ARh")T@Ւ&! 4Lw_&ye,4N+ko6:::(B[GP2D3VȲ3 _/c'6FkѓjʈA?"#w :w-6֒_cN!}E蜑V_!J@sƝy-b=? >4Mt5a7_IoIENDB`deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/cursors/sb_h_double_arrow.png000066400000000000000000000037171325534707400273470ustar00rootroot00000000000000PNG  IHDR00WIDATx[hT;%$17DOxLOĞR-}lDPb$oyhDJ BT Z%PKИX0bl@qfrìgΞɭp^򇏙Y a kX÷ /Vw9Y(\㻎\qp}2BnC2raI,eK!|/0L9 Tjt+ƛ7o~_WW ݻ>})i@;~EB*(ʕ+:u ɑ3`yDŽ-Lz@z8}?f۶P\MM(**҇g$VE>v+"QYY)YO<3!{P ӒrTsN˲L!H$"[$&Ig[]/D"ӗ/_JGJ>}::8VRA bw@5 >Mէ*XB i&gϞ#My2AҝPʔJr'''P]]VL)RY:W !^(wWoE.$`ђ fTMMMz_H(EȔ)]p7E)]pwHI/6M'njm;2m? | |LWY ^' |$ֶE>_GfB ɔbPmP{O4GRvsyA:j_J;zDQLQ~S 8cK.-6<bPۢonJ`adRۭI7v=sis7^BŮJs. PbPY>Ԫ=z44MnܸAgg ߒ6EuN_~ 'N`vA+m'OA-PЕJ|8r kZH$8|0ɯȮH%F7&Xʴ$qRo#U(CVǎL8|,'[f䝍|t,ZHg}/U0d3oX&:/+dYnht!ORqhϼ{+.]ْˉB=R"壜XD~'0}ڵ`r]LYBQZfbMźb#ey֭9gggեh-]P]yu^+2ɝ@Yz@YkTJ[EYZ7{Rg+՘zzΡRRjxQC6 R1 ?o+30dsaͺ-x^U-! kIudey]N*mp:s*5Zabbb8RN߻wt[NW\f@LJvqx<^۹>SSSg;::n[.XUNx⯑H޽cϗ|CCa^|9DHt-嚫Akk'{.i'6 q0Db2|MShՖloڴWdrNDիR____|YDDVVVm 2[R$: [Ϝ9sqȩS./gܹs_ݮ\ zk`j-eΝ;3Ν;w|:ݽ zn,..JKKBnnnoߊ||*Z bys`'onn""=˲$ J0˲""277lseTc-Wj!|ϓ[a1MSLӔK.H2\زeo;xISӧO:J4ٳgS+C,_<| t{Ɔ{1שׂB66W=333J=3jɬDJȼ}!ҖTJ$$ۉPV/[Ζo. */ #ifndef DFOREIGNPLATFORMWINDOW_H #define DFOREIGNPLATFORMWINDOW_H #include "global.h" #include #ifdef Q_OS_LINUX #define private public #include "qxcbwindow.h" typedef QXcbWindow QNativeWindow; #undef private #elif defined(Q_OS_WIN) #include "qwindowswindow.h" typedef QWindowsWindow QNativeWindow; #endif DPP_BEGIN_NAMESPACE class DForeignPlatformWindow : public QNativeWindow { public: explicit DForeignPlatformWindow(QWindow *window); ~DForeignPlatformWindow(); QRect geometry() const Q_DECL_OVERRIDE; #ifdef Q_OS_LINUX void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *); void handlePropertyNotifyEvent(const xcb_property_notify_event_t *); #endif private: void create() override; void updateTitle(); void updateWmClass(); void updateWmDesktop(); void updateWindowState(); void updateWindowTypes(); void updateProcessId(); void init(); }; DPP_END_NAMESPACE #endif // DFOREIGNPLATFORMWINDOW_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dforeignplatformwindow_x11.cpp000066400000000000000000000300561325534707400274450ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dforeignplatformwindow.h" #include "dplatformintegration.h" #include "global.h" #include "utility.h" #include "qxcbconnection.h" #include "qxcbscreen.h" #include #include #include DPP_BEGIN_NAMESPACE enum { baseEventMask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE, defaultEventMask = baseEventMask | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_POINTER_MOTION, transparentForInputEventMask = baseEventMask | XCB_EVENT_MASK_VISIBILITY_CHANGE | XCB_EVENT_MASK_RESIZE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_COLOR_MAP_CHANGE | XCB_EVENT_MASK_OWNER_GRAB_BUTTON }; DForeignPlatformWindow::DForeignPlatformWindow(QWindow *window) : QXcbWindow(window) { // init window id QNativeWindow::create(); m_dirtyFrameMargins = true; init(); create(); } DForeignPlatformWindow::~DForeignPlatformWindow() { qt_window_private(window())->windowFlags = Qt::ForeignWindow; } QRect DForeignPlatformWindow::geometry() const { xcb_connection_t *conn = DPlatformIntegration::xcbConnection()->xcb_connection(); xcb_get_geometry_reply_t *geomReply = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, m_window), 0); if (!geomReply) return QRect(); xcb_translate_coordinates_reply_t *translateReply = xcb_translate_coordinates_reply(conn, xcb_translate_coordinates(conn, m_window, DPlatformIntegration::xcbConnection()->rootWindow(), 0, 0), 0); if (!translateReply) { free(geomReply); return QRect(); } const QRect result(QPoint(translateReply->dst_x, translateReply->dst_y), QSize(geomReply->width, geomReply->height)); free(translateReply); // auto remove _GTK_FRAME_EXTENTS xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, m_window, Utility::internAtom("_GTK_FRAME_EXTENTS"), XCB_ATOM_CARDINAL, 0, 4); QScopedPointer reply( xcb_get_property_reply(xcb_connection(), cookie, NULL)); if (reply && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 && reply->value_len == 4) { quint32 *data = (quint32 *)xcb_get_property_value(reply.data()); // _NET_FRAME_EXTENTS format is left, right, top, bottom return result.marginsRemoved(QMargins(data[0], data[2], data[1], data[3])); } return result; } void DForeignPlatformWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event) { bool fromSendEvent = (event->response_type & 0x80); QPoint pos(event->x, event->y); if (!parent() && !fromSendEvent) { // Do not trust the position, query it instead. xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcb_window(), xcbScreen()->root(), 0, 0); xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL); if (reply) { pos.setX(reply->dst_x); pos.setY(reply->dst_y); free(reply); } } QRect actualGeometry = QRect(pos, QSize(event->width, event->height)); QPlatformScreen *newScreen = parent() ? parent()->screen() : screenForGeometry(actualGeometry); if (!newScreen) return; // auto remove _GTK_FRAME_EXTENTS xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, m_window, Utility::internAtom("_GTK_FRAME_EXTENTS"), XCB_ATOM_CARDINAL, 0, 4); QScopedPointer reply( xcb_get_property_reply(xcb_connection(), cookie, NULL)); if (reply && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 && reply->value_len == 4) { quint32 *data = (quint32 *)xcb_get_property_value(reply.data()); // _NET_FRAME_EXTENTS format is left, right, top, bottom actualGeometry = actualGeometry.marginsRemoved(QMargins(data[0], data[2], data[1], data[3])); } // Persist the actual geometry so that QWindow::geometry() can // be queried in the resize event. QPlatformWindow::setGeometry(actualGeometry); // FIXME: In the case of the requestedGeometry not matching the actualGeometry due // to e.g. the window manager applying restrictions to the geometry, the application // will never see a move/resize event if the actualGeometry is the same as the current // geometry, and may think the requested geometry was fulfilled. QWindowSystemInterface::handleGeometryChange(window(), actualGeometry); // QPlatformScreen::screen() is updated asynchronously, so we can't compare it // with the newScreen. Just send the WindowScreenChanged event and QGuiApplication // will make the comparison later. QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); if (m_usingSyncProtocol && m_syncState == SyncReceived) m_syncState = SyncAndConfigureReceived; m_dirtyFrameMargins = true; } void DForeignPlatformWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) { connection()->setTime(event->time); const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE; if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) { if (propertyDeleted) return; return updateWindowState(); } else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) { m_dirtyFrameMargins = true; } else if (event->atom == atom(QXcbAtom::_NET_WM_WINDOW_TYPE)) { return updateWindowTypes(); } else if (event->atom == Utility::internAtom("_NET_WM_DESKTOP")) { return updateWmDesktop(); } else if (event->atom == QXcbAtom::_NET_WM_NAME) { return updateTitle(); } else if (event->atom == QXcbAtom::WM_CLASS) { return updateWmClass(); } } void DForeignPlatformWindow::create() { const quint32 mask = XCB_CW_EVENT_MASK; const quint32 values[] = { // XCB_CW_EVENT_MASK baseEventMask }; connection()->addWindowEventListener(m_window, this); xcb_change_window_attributes(xcb_connection(), m_window, mask, values); } void DForeignPlatformWindow::updateTitle() { xcb_get_property_reply_t *wm_name = xcb_get_property_reply(xcb_connection(), xcb_get_property_unchecked(xcb_connection(), false, m_window, atom(QXcbAtom::_NET_WM_NAME), atom(QXcbAtom::UTF8_STRING), 0, 1024), NULL); if (wm_name && wm_name->format == 8 && wm_name->type == atom(QXcbAtom::UTF8_STRING)) { const QString &title = QString::fromUtf8((const char *)xcb_get_property_value(wm_name), xcb_get_property_value_length(wm_name)); if (title != qt_window_private(window())->windowTitle) { qt_window_private(window())->windowTitle = title; emit window()->windowTitleChanged(title); } } free(wm_name); } void DForeignPlatformWindow::updateWmClass() { xcb_get_property_reply_t *wm_class = xcb_get_property_reply(xcb_connection(), xcb_get_property(xcb_connection(), 0, m_window, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0L, 2048L), NULL); if (wm_class && wm_class->format == 8 && wm_class->type == XCB_ATOM_STRING) { const QByteArray wm_class_name((const char *)xcb_get_property_value(wm_class), xcb_get_property_value_length(wm_class)); const QList wm_class_name_list = wm_class_name.split('\0'); if (!wm_class_name_list.isEmpty()) window()->setProperty(WmClass, QString::fromLocal8Bit(wm_class_name_list.first())); } free(wm_class); } void DForeignPlatformWindow::updateWmDesktop() { window()->setProperty(WmNetDesktop, Utility::getWorkspaceForWindow(m_window)); } void DForeignPlatformWindow::updateWindowState() { Qt::WindowState newState = Qt::WindowNoState; const xcb_get_property_cookie_t get_cookie = xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::WM_STATE), XCB_ATOM_ANY, 0, 1024); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), get_cookie, NULL); if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) { const quint32 *data = (const quint32 *)xcb_get_property_value(reply); if (reply->length != 0 && XCB_ICCCM_WM_STATE_ICONIC == data[0]) newState = Qt::WindowMinimized; } free(reply); if (newState != Qt::WindowMinimized) { // Something else changed, get _NET_WM_STATE. const NetWmStates states = netWmStates(); if (states & NetWmStateFullScreen) newState = Qt::WindowFullScreen; else if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert)) newState = Qt::WindowMaximized; } if (m_windowState == newState) return; m_windowState = newState; qt_window_private(window())->windowState = newState; emit window()->windowStateChanged(newState); qt_window_private(window())->updateVisibility(); } void DForeignPlatformWindow::updateWindowTypes() { QXcbWindowFunctions::WmWindowTypes window_types = wmWindowTypes(); Qt::WindowFlags window_flags = 0; if (window_types & QXcbWindowFunctions::Normal) window_flags |= Qt::Window; else if (window_types & QXcbWindowFunctions::Desktop) window_flags |= Qt::Desktop; else if (window_types & QXcbWindowFunctions::Dialog) window_flags |= Qt::Dialog; else if (window_types & QXcbWindowFunctions::Utility) window_flags |= Qt::Tool; else if (window_types & QXcbWindowFunctions::Tooltip) window_flags |= Qt::ToolTip; else if (window_types & QXcbWindowFunctions::Splash) window_flags |= Qt::SplashScreen; else window_flags |= Qt::Widget; if (window_types & QXcbWindowFunctions::KdeOverride) window_flags |= Qt::FramelessWindowHint; qt_window_private(window())->windowFlags = window_flags; window()->setProperty(WmWindowTypes, (quint32)window_types); } void DForeignPlatformWindow::updateProcessId() { xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, m_window, atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 0, 1); QScopedPointer reply( xcb_get_property_reply(xcb_connection(), cookie, NULL)); if (reply && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 && reply->value_len == 1) { window()->setProperty(ProcessId, *(quint32 *)xcb_get_property_value(reply.data())); } } void DForeignPlatformWindow::init() { updateTitle(); updateWindowState(); updateWindowTypes(); updateWmClass(); updateWmDesktop(); updateProcessId(); // m_mapped = Utility::getWindows().contains(m_window); // qt_window_private(window())->visible = m_mapped; } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dframewindow.cpp000066400000000000000000000742561325534707400246620ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dframewindow.h" #include "dplatformwindowhelper.h" #include "dplatformintegration.h" #ifdef Q_OS_LINUX #include "dwmsupport.h" #include "qxcbwindow.h" #include "qxcbscreen.h" #include #include #endif #include #include #include #include #include #include #include #include #include #ifdef Q_OS_LINUX #include #endif DPP_BEGIN_NAMESPACE class DFrameWindowPrivate : public QPaintDeviceWindowPrivate { Q_DECLARE_PUBLIC(DFrameWindow) public: void resize(const QSize &size) { Q_Q(DFrameWindow); if (this->size == size) return; this->size = size; q->platformBackingStore->resize(size, QRegion()); q->update(); q->drawNativeWindowXPixmap(); } void beginPaint(const QRegion ®ion) Q_DECL_OVERRIDE { Q_Q(DFrameWindow); if (!q->m_redirectContent) { if (size != q->handle()->QPlatformWindow::geometry().size()) { size = q->handle()->QPlatformWindow::geometry().size(); q->platformBackingStore->resize(size, QRegion()); markWindowAsDirty(); } q->platformBackingStore->beginPaint(region * q->devicePixelRatio()); } } void endPaint() Q_DECL_OVERRIDE { Q_Q(DFrameWindow); if (!q->m_redirectContent) q->platformBackingStore->endPaint(); } void flush(const QRegion ®ion) Q_DECL_OVERRIDE { Q_Q(DFrameWindow); if (!q->m_redirectContent) { return q->platformBackingStore->flush(q, region * q->devicePixelRatio(), QPoint(0, 0)); } flushArea += region * q->devicePixelRatio(); if (flushTimer > 0) { return; } flushTimer = q->startTimer(8, Qt::PreciseTimer); } QSize size; int flushTimer = 0; QRegion flushArea; }; QList DFrameWindow::frameWindowList; DFrameWindow::DFrameWindow(QWindow *content) : QPaintDeviceWindow(*new DFrameWindowPrivate(), 0) , platformBackingStore(QGuiApplicationPrivate::platformIntegration()->createPlatformBackingStore(this)) , m_redirectContent(DPlatformWindowHelper::windowRedirectContent(content)) #ifdef Q_OS_LINUX , m_contentWindow(content) , nativeWindowXPixmap(XCB_PIXMAP_NONE) #endif { setSurfaceType(QSurface::RasterSurface); QSurfaceFormat f = this->format(); f.setAlphaBufferSize(8); setFormat(f); m_cursorAnimation.setDuration(50); m_cursorAnimation.setEasingCurve(QEasingCurve::InExpo); connect(&m_cursorAnimation, &QVariantAnimation::valueChanged, this, [this] (const QVariant &value) { qApp->primaryScreen()->handle()->cursor()->setPos(value.toPoint()); }); m_startAnimationTimer.setSingleShot(true); m_startAnimationTimer.setInterval(300); m_updateShadowTimer.setInterval(100); m_updateShadowTimer.setSingleShot(true); connect(&m_startAnimationTimer, &QTimer::timeout, this, &DFrameWindow::startCursorAnimation); updateContentMarginsHint(); frameWindowList.append(this); connect(this, &DFrameWindow::windowStateChanged, this, &DFrameWindow::updateMask); connect(&m_updateShadowTimer, &QTimer::timeout, this, &DFrameWindow::updateShadow); } DFrameWindow::~DFrameWindow() { frameWindowList.removeOne(this); #ifdef Q_OS_LINUX if (nativeWindowXSurface) cairo_surface_destroy(nativeWindowXSurface); if (nativeWindowXPixmap != XCB_PIXMAP_NONE) xcb_free_pixmap(DPlatformIntegration::xcbConnection()->xcb_connection(), nativeWindowXPixmap); #endif } QWindow *DFrameWindow::contentWindow() const { return m_contentWindow.data(); } int DFrameWindow::shadowRadius() const { return m_shadowRadius; } void DFrameWindow::setShadowRadius(int radius) { if (m_shadowRadius == radius) return; m_shadowRadius = radius; updateContentMarginsHint(); } QPoint DFrameWindow::shadowOffset() const { return m_shadowOffset; } void DFrameWindow::setShadowOffset(const QPoint &offset) { if (m_shadowOffset == offset) return; m_shadowOffset = offset; updateContentMarginsHint(); } QColor DFrameWindow::shadowColor() const { return m_shadowColor; } void DFrameWindow::setShadowColor(const QColor &color) { if (m_shadowColor == color) return; m_shadowColor = color; updateShadowAsync(); } int DFrameWindow::borderWidth() const { return m_borderWidth; } void DFrameWindow::setBorderWidth(int width) { if (m_borderWidth == width) return; m_borderWidth = width; updateContentMarginsHint(); } QColor DFrameWindow::borderColor() const { return m_borderColor; } void DFrameWindow::setBorderColor(const QColor &color) { if (m_borderColor == color) return; m_borderColor = color; updateShadowAsync(); } QPainterPath DFrameWindow::contentPath() const { return m_clipPathOfContent; } inline static QSize margins2Size(const QMargins &margins) { return QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); } void DFrameWindow::setContentPath(const QPainterPath &path) { setContentPath(path, false); } void DFrameWindow::setContentRoundedRect(const QRect &rect, int radius) { QPainterPath path; path.addRoundedRect(rect, radius, radius); m_contentGeometry = rect.translated(contentOffsetHint()); setContentPath(path, true, radius); // force update shadow // m_contentGeometry may changed, but clipPath is not change. updateShadowAsync(0); } QMargins DFrameWindow::contentMarginsHint() const { return m_contentMarginsHint; } QPoint DFrameWindow::contentOffsetHint() const { return QPoint(m_contentMarginsHint.left(), m_contentMarginsHint.top()); } bool DFrameWindow::isClearContentAreaForShadowPixmap() const { return m_clearContent; } void DFrameWindow::setClearContentAreaForShadowPixmap(bool clear) { if (m_clearContent == clear) return; m_clearContent = clear; if (clear && !m_shadowImage.isNull()) { QPainter pa(&m_shadowImage); pa.setCompositionMode(QPainter::CompositionMode_Clear); pa.setRenderHint(QPainter::Antialiasing); pa.fillPath(m_clipPathOfContent.translated(QPoint(m_shadowRadius, m_shadowRadius) - m_shadowOffset) * devicePixelRatio(), Qt::transparent); pa.end(); } } bool DFrameWindow::isEnableSystemResize() const { return m_enableSystemResize; } void DFrameWindow::setEnableSystemResize(bool enable) { m_enableSystemResize = enable; if (!m_enableSystemResize) Utility::cancelWindowMoveResize(Utility::getNativeTopLevelWindow(winId())); } bool DFrameWindow::isEnableSystemMove() const { #ifdef Q_OS_LINUX if (!m_enableSystemMove) return false; quint32 hints = DXcbWMSupport::getMWMFunctions(Utility::getNativeTopLevelWindow(winId())); return (hints == DXcbWMSupport::MWM_FUNC_ALL || hints & DXcbWMSupport::MWM_FUNC_MOVE); #endif return m_enableSystemMove; } void DFrameWindow::setEnableSystemMove(bool enable) { m_enableSystemMove = enable; if (!m_enableSystemMove) { setCursor(Qt::ArrowCursor); cancelAdsorbCursor(); m_canAdsorbCursor = false; Utility::cancelWindowMoveResize(Utility::getNativeTopLevelWindow(winId())); } } void DFrameWindow::disableRepaintShadow() { m_canUpdateShadow = false; } void DFrameWindow::enableRepaintShadow() { m_canUpdateShadow = true; } void DFrameWindow::paintEvent(QPaintEvent *) { if (m_redirectContent) { #ifdef Q_OS_LINUX drawNativeWindowXPixmap(); #endif } else { drawShadowTo(this); } } void DFrameWindow::showEvent(QShowEvent *event) { // Set frame extents Utility::setFrameExtents(winId(), contentMarginsHint() * devicePixelRatio()); QPaintDeviceWindow::showEvent(event); } void DFrameWindow::mouseMoveEvent(QMouseEvent *event) { if (event->source() == Qt::MouseEventSynthesizedByQt && qApp->mouseButtons() == Qt::LeftButton && m_clipPathOfContent.contains(event->pos() - contentOffsetHint())) { if (!isEnableSystemMove()) return; ///TODO: Warning: System move finished no mouse release event Utility::startWindowSystemMove(Utility::getNativeTopLevelWindow(winId())); m_isSystemMoveResizeState = true; return; } unsetCursor(); if (!canResize()) return; if (qApp->mouseButtons() != Qt::LeftButton && m_contentGeometry.contains(event->pos())) { return; } bool isFixedWidth = minimumWidth() == maximumWidth(); bool isFixedHeight = minimumHeight() == maximumHeight(); Utility::CornerEdge mouseCorner; QRect cornerRect; const QRect window_real_geometry = m_contentGeometry + QMargins(MOUSE_MARGINS, MOUSE_MARGINS, MOUSE_MARGINS, MOUSE_MARGINS); if (isFixedWidth || isFixedHeight) goto set_edge; /// begin set cursor corner type cornerRect.setSize(QSize(MOUSE_MARGINS * 2, MOUSE_MARGINS * 2)); cornerRect.moveTopLeft(window_real_geometry.topLeft()); if (cornerRect.contains(event->pos())) { mouseCorner = Utility::TopLeftCorner; goto set_cursor; } cornerRect.moveTopRight(window_real_geometry.topRight()); if (cornerRect.contains(event->pos())) { mouseCorner = Utility::TopRightCorner; goto set_cursor; } cornerRect.moveBottomRight(window_real_geometry.bottomRight()); if (cornerRect.contains(event->pos())) { mouseCorner = Utility::BottomRightCorner; goto set_cursor; } cornerRect.moveBottomLeft(window_real_geometry.bottomLeft()); if (cornerRect.contains(event->pos())) { mouseCorner = Utility::BottomLeftCorner; goto set_cursor; } set_edge: /// begin set cursor edge type if (event->x() <= m_contentGeometry.x()) { if (isFixedWidth) goto skip_set_cursor; mouseCorner = Utility::LeftEdge; } else if (event->x() < m_contentGeometry.right()) { if (isFixedHeight) goto skip_set_cursor; if (event->y() <= m_contentGeometry.y()) { mouseCorner = Utility::TopEdge; } else if (!isFixedWidth || event->y() >= m_contentGeometry.bottom()) { mouseCorner = Utility::BottomEdge; } else { goto skip_set_cursor; } } else if (!isFixedWidth && (!isFixedHeight || event->x() >= m_contentGeometry.right())) { mouseCorner = Utility::RightEdge; } else { goto skip_set_cursor; } set_cursor: Utility::setWindowCursor(winId(), mouseCorner); if (qApp->mouseButtons() == Qt::LeftButton) { Utility::startWindowSystemResize(Utility::getNativeTopLevelWindow(winId()), mouseCorner); m_isSystemMoveResizeState = true; cancelAdsorbCursor(); } else { adsorbCursor(mouseCorner); } return; skip_set_cursor: setCursor(Qt::ArrowCursor); cancelAdsorbCursor(); m_canAdsorbCursor = canResize(); } void DFrameWindow::mouseReleaseEvent(QMouseEvent *event) { if (m_isSystemMoveResizeState) { Utility::cancelWindowMoveResize(Utility::getNativeTopLevelWindow(winId())); m_isSystemMoveResizeState = false; } return QPaintDeviceWindow::mouseReleaseEvent(event); } void DFrameWindow::resizeEvent(QResizeEvent *event) { updateFrameMask(); return QPaintDeviceWindow::resizeEvent(event); } bool DFrameWindow::event(QEvent *event) { switch (event->type()) { case QEvent::Enter: m_canAdsorbCursor = canResize(); break; case QEvent::Leave: m_canAdsorbCursor = false; cancelAdsorbCursor(); break; default: break; } return QPaintDeviceWindow::event(event); } void DFrameWindow::timerEvent(QTimerEvent *event) { Q_D(DFrameWindow); if (event->timerId() == d->flushTimer) { killTimer(d->flushTimer); d->flushTimer = 0; if (!d->flushArea.isEmpty()) { platformBackingStore->flush(this, d->flushArea, QPoint(0, 0)); d->flushArea = QRegion(); } } else if (event->timerId() == m_paintShadowOnContentTimerId) { killTimer(m_paintShadowOnContentTimerId); m_paintShadowOnContentTimerId = -1; if (!m_contentWindow || !m_contentWindow->handle()) return QPaintDeviceWindow::timerEvent(event); QRect rect = m_contentWindow->handle()->geometry(); rect.setTopLeft(QPoint(0, 0)); m_contentBackingStore->flush(m_contentWindow, rect, QPoint(0, 0)); } else { return QPaintDeviceWindow::timerEvent(event); } } #ifdef Q_OS_LINUX static cairo_format_t cairo_format_from_qimage_format (QImage::Format fmt) { switch (fmt) { case QImage::Format_ARGB32_Premultiplied: return CAIRO_FORMAT_ARGB32; case QImage::Format_RGB32: return CAIRO_FORMAT_RGB24; case QImage::Format_Indexed8: // XXX not quite return CAIRO_FORMAT_A8; case QImage::Format_Mono: case QImage::Format_MonoLSB: return CAIRO_FORMAT_A1; case QImage::Format_Invalid: case QImage::Format_ARGB32: case QImage::Format_RGB16: case QImage::Format_ARGB8565_Premultiplied: case QImage::Format_RGB666: case QImage::Format_ARGB6666_Premultiplied: case QImage::Format_RGB555: case QImage::Format_ARGB8555_Premultiplied: case QImage::Format_RGB888: case QImage::Format_RGB444: case QImage::Format_ARGB4444_Premultiplied: case QImage::NImageFormats: default: return (cairo_format_t) -1; } } #endif void DFrameWindow::updateFromContents(void *ev) { #ifdef Q_OS_LINUX if (Q_UNLIKELY(nativeWindowXPixmap == XCB_PIXMAP_NONE && xsurfaceDirtySize.isEmpty())) { return; } xcb_connection_t *connect = DPlatformIntegration::xcbConnection()->xcb_connection(); xcb_damage_notify_event_t *event = reinterpret_cast(ev); xcb_xfixes_region_t parts = xcb_generate_id(connect); xcb_xfixes_create_region(connect, parts, 0, 0); xcb_damage_subtract(connect, event->damage, XCB_NONE, parts); xcb_xfixes_fetch_region_cookie_t cookie = xcb_xfixes_fetch_region(connect, parts); xcb_xfixes_fetch_region_reply_t *reply = xcb_xfixes_fetch_region_reply(connect, cookie, 0); if (Q_UNLIKELY(!reply)) return; xcb_rectangle_t *rectangles = xcb_xfixes_fetch_region_rectangles(reply); int length = xcb_xfixes_fetch_region_rectangles_length(reply); if (!xsurfaceDirtySize.isEmpty()) updateNativeWindowXPixmap(xsurfaceDirtySize.width(), xsurfaceDirtySize.height()); drawNativeWindowXPixmap(rectangles, length); free(reply); #endif } void DFrameWindow::drawShadowTo(QPaintDevice *device) { const QPoint &offset = m_contentGeometry.topLeft() - contentOffsetHint(); qreal device_pixel_ratio = devicePixelRatio(); const QSize &size = handle()->geometry().size(); QPainter pa(device); if (m_redirectContent) { QPainterPath clip_path; clip_path.addRect(QRect(QPoint(0, 0), size)); clip_path -= m_clipPath; pa.setRenderHint(QPainter::Antialiasing); pa.setClipPath(clip_path); } pa.setCompositionMode(QPainter::CompositionMode_Source); if (!disableFrame() && Q_LIKELY(DXcbWMSupport::instance()->hasComposite()) && !m_shadowImage.isNull()) { pa.drawImage(offset * device_pixel_ratio, m_shadowImage); } if (m_borderWidth > 0 && m_borderColor != Qt::transparent) { if (Q_LIKELY(DXcbWMSupport::instance()->hasComposite())) { pa.setRenderHint(QPainter::Antialiasing); pa.fillPath(m_borderPath, m_borderColor); } else { pa.fillRect(QRect(QPoint(0, 0), size), m_borderColor); } } pa.end(); } QPaintDevice *DFrameWindow::redirected(QPoint *) const { return platformBackingStore->paintDevice(); } void DFrameWindow::setContentPath(const QPainterPath &path, bool isRoundedRect, int radius) { if (m_clipPathOfContent == path) return; if (!isRoundedRect) m_contentGeometry = path.boundingRect().toRect().translated(contentOffsetHint()); qreal device_pixel_ratio = devicePixelRatio(); m_clipPathOfContent = path; m_clipPath = path.translated(contentOffsetHint()) * device_pixel_ratio; if (isRoundedRect && m_pathIsRoundedRect == isRoundedRect && m_roundedRectRadius == radius && !m_shadowImage.isNull()) { const QMargins margins(qMax(m_shadowRadius + radius + qAbs(m_shadowOffset.x()), m_borderWidth), qMax(m_shadowRadius + radius + qAbs(m_shadowOffset.y()), m_borderWidth), qMax(m_shadowRadius + radius + qAbs(m_shadowOffset.x()), m_borderWidth), qMax(m_shadowRadius + radius + qAbs(m_shadowOffset.y()), m_borderWidth)); const QSize &margins_size = margins2Size(margins); const QSize &shadow_size = m_shadowImage.size() / device_pixel_ratio; if (margins_size.width() > m_contentGeometry.width() || margins_size.height() > m_contentGeometry.height() || margins_size.width() >= shadow_size.width() || margins_size.height() >= shadow_size.height()) { updateShadowAsync(); } else if (m_canUpdateShadow && !m_contentGeometry.isEmpty() && isVisible() && !disableFrame()) { m_shadowImage = Utility::borderImage(QPixmap::fromImage(m_shadowImage), margins * device_pixel_ratio, (m_contentGeometry + contentMarginsHint()).size() * device_pixel_ratio); } } else { m_pathIsRoundedRect = isRoundedRect; m_roundedRectRadius = radius; updateShadowAsync(); } updateMask(); } #ifdef Q_OS_LINUX void DFrameWindow::drawNativeWindowXPixmap(xcb_rectangle_t *rects, int length) { if (Q_UNLIKELY(!nativeWindowXSurface)) return; const QPoint offset(m_contentMarginsHint.left() * devicePixelRatio(), m_contentMarginsHint.top() * devicePixelRatio()); const QImage &source_image = platformBackingStore->toImage(); QImage image(const_cast(source_image.bits()), source_image.width(), source_image.height(), source_image.bytesPerLine(), source_image.format()); const cairo_format_t format = cairo_format_from_qimage_format(image.format()); cairo_surface_t *surface = cairo_image_surface_create_for_data(image.bits(), format, image.width(), image.height(), image.bytesPerLine()); cairo_t *cr = cairo_create(surface); cairo_surface_mark_dirty(nativeWindowXSurface); cairo_set_source_rgb(cr, 0, 255, 0); cairo_set_source_surface(cr, nativeWindowXSurface, offset.x(), offset.y()); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); bool clip = false; for (int i = 0; i < m_clipPath.elementCount(); ++i) { const QPainterPath::Element &e = m_clipPath.elementAt(i); switch (e.type) { case QPainterPath::MoveToElement: clip = true; cairo_move_to(cr, e.x, e.y); break; case QPainterPath::LineToElement: clip = true; cairo_line_to(cr, e.x, e.y); break; case QPainterPath::CurveToElement: { clip = true; const QPainterPath::Element &p2 = m_clipPath.elementAt(++i); const QPainterPath::Element &p3 = m_clipPath.elementAt(++i); cairo_curve_to(cr, e.x, e.y, p2.x, p2.y, p3.x, p3.y); break; } default: break; } } if (clip) { cairo_clip(cr); } if (rects) { for (int i = 0; i < length; ++i) { const xcb_rectangle_t &rect = rects[i]; d_func()->flushArea += QRect(rect.x + offset.x(), rect.y + offset.y(), rect.width, rect.height); cairo_rectangle(cr, rect.x + offset.x(), rect.y + offset.y(), rect.width, rect.height); cairo_fill(cr); } } else { cairo_paint(cr); // draw shadow drawShadowTo(&image); d_func()->flushArea = QRect(QPoint(0, 0), d_func()->size); } cairo_destroy(cr); cairo_surface_destroy(surface); d_func()->flush(QRegion()); } bool DFrameWindow::updateNativeWindowXPixmap(int width, int height) { if (Q_UNLIKELY(!m_contentWindow->handle()->isExposed())) return false; WId winId = static_cast(m_contentWindow->handle())->QXcbWindow::winId(); qreal width_extra = (m_contentMarginsHint.left() + m_contentMarginsHint.right()) * devicePixelRatio(); qreal height_extra = (m_contentMarginsHint.top() + m_contentMarginsHint.bottom()) * devicePixelRatio(); d_func()->resize(QSize(width + qRound(width_extra), height + qRound(height_extra))); xcb_connection_t *connect = DPlatformIntegration::xcbConnection()->xcb_connection(); if (Q_LIKELY(nativeWindowXPixmap != XCB_PIXMAP_NONE)) { xcb_free_pixmap(connect, nativeWindowXPixmap); } else { nativeWindowXPixmap = xcb_generate_id(connect); } xcb_void_cookie_t cookie = xcb_composite_name_window_pixmap_checked(connect, winId, nativeWindowXPixmap); QScopedPointer error(xcb_request_check(connect, cookie)); if (error) { nativeWindowXPixmap = XCB_PIXMAP_NONE; return false; } if (Q_LIKELY(nativeWindowXSurface)) { cairo_xlib_surface_set_drawable(nativeWindowXSurface, nativeWindowXPixmap, width, height); } else { Display *display = (Display*)DPlatformIntegration::xcbConnection()->xlib_display(); XWindowAttributes attr; XGetWindowAttributes(display, winId, &attr); //###(zccrs): 只能使用cairo的xlib接口,使用xcb接口会导致从创建的surface中读取内容时不正确 nativeWindowXSurface = cairo_xlib_surface_create(display, nativeWindowXPixmap, attr.visual, attr.width, attr.height); } return true; } void DFrameWindow::markXPixmapToDirty(int width, int height) { if (Q_UNLIKELY(width < 0 || height < 0)) { WId winId = static_cast(m_contentWindow->handle())->QXcbWindow::winId(); const QRect rect = Utility::windowGeometry(winId); width = rect.width(); height = rect.height(); } xsurfaceDirtySize.setWidth(width); xsurfaceDirtySize.setHeight(height); } #endif void DFrameWindow::updateShadow() { if (!m_canUpdateShadow || m_contentGeometry.isEmpty() || disableFrame()) return; qreal device_pixel_ratio = devicePixelRatio(); QPixmap pixmap(m_contentGeometry.size() * device_pixel_ratio); if (pixmap.isNull()) return; pixmap.fill(Qt::transparent); QPainter pa(&pixmap); pa.fillPath(m_clipPath.translated(-m_contentGeometry.topLeft() * device_pixel_ratio), m_shadowColor); pa.end(); m_shadowImage = Utility::dropShadow(pixmap, m_shadowRadius * device_pixel_ratio, m_shadowColor); update(); // 阴影更新后尝试刷新内部窗口 if (m_contentBackingStore) m_paintShadowOnContentTimerId = startTimer(300, Qt::PreciseTimer); } void DFrameWindow::updateShadowAsync(int delaye) { if (m_updateShadowTimer.isActive()) { return; } m_updateShadowTimer.start(delaye); } void DFrameWindow::updateContentMarginsHint() { QMargins margins; margins = QMargins(qMax(m_shadowRadius - m_shadowOffset.x(), m_borderWidth), qMax(m_shadowRadius - m_shadowOffset.y(), m_borderWidth), qMax(m_shadowRadius + m_shadowOffset.x(), m_borderWidth), qMax(m_shadowRadius + m_shadowOffset.y(), m_borderWidth)); if (margins == m_contentMarginsHint) return; qreal device_pixel_ratio = devicePixelRatio(); Utility::setFrameExtents(winId(), margins * device_pixel_ratio); const QMargins old_margins = m_contentMarginsHint; m_contentMarginsHint = margins; m_contentGeometry.translate(m_contentMarginsHint.left() - old_margins.left(), m_contentMarginsHint.top() - old_margins.top()); m_clipPath = m_clipPathOfContent.translated(contentOffsetHint()) * device_pixel_ratio; qreal width_extra = (m_contentMarginsHint.left() + m_contentMarginsHint.right()) * device_pixel_ratio; qreal height_extra = (m_contentMarginsHint.top() + m_contentMarginsHint.bottom()) * device_pixel_ratio; #ifdef Q_OS_LINUX if (nativeWindowXSurface) { int width = cairo_xlib_surface_get_width(nativeWindowXSurface); int height = cairo_xlib_surface_get_height(nativeWindowXSurface); d_func()->resize(QSize(width + qRound(width_extra), height + qRound(height_extra))); } #endif updateShadow(); updateMask(); emit contentMarginsHintChanged(old_margins); } void DFrameWindow::updateMask() { if (windowState() == Qt::WindowMinimized) return; if (disableFrame()) { QRegion region(m_contentGeometry * devicePixelRatio()); Utility::setShapeRectangles(winId(), region, DWMSupport::instance()->hasComposite(), flags().testFlag(Qt::WindowTransparentForInput)); return; } // Set window clip mask int mouse_margins; if (DWMSupport::instance()->hasComposite()) mouse_margins = canResize() ? MOUSE_MARGINS : 0; else mouse_margins = qRound(m_borderWidth * devicePixelRatio()); const QPainterPath &path = m_clipPath; if (m_enableAutoInputMaskByContentPath && (!m_pathIsRoundedRect || m_roundedRectRadius > 0)) { QPainterPath p; if (Q_LIKELY(mouse_margins > 0)) { QPainterPathStroker stroker; stroker.setJoinStyle(Qt::MiterJoin); stroker.setWidth(mouse_margins * 2); p = stroker.createStroke(path); p = p.united(path); } else { p = path; } Utility::setShapePath(winId(), p, DWMSupport::instance()->hasComposite(), flags().testFlag(Qt::WindowTransparentForInput)); } else { QRegion region((m_contentGeometry * devicePixelRatio()).adjusted(-mouse_margins, -mouse_margins, mouse_margins, mouse_margins)); Utility::setShapeRectangles(winId(), region, DWMSupport::instance()->hasComposite(), flags().testFlag(Qt::WindowTransparentForInput)); } QPainterPathStroker stroker; stroker.setJoinStyle(Qt::MiterJoin); stroker.setWidth(m_borderWidth); m_borderPath = stroker.createStroke(path); updateFrameMask(); update(); } void DFrameWindow::updateFrameMask() { #ifdef Q_OS_LINUX // QXcbWindow *xw = static_cast(handle()); // if (!xw || !xw->wmWindowTypes().testFlag(QXcbWindowFunctions::Dock)) // return; // if (!m_enableAutoFrameMask || !DWMSupport::instance()->hasComposite()) // return; // const QRect rect(QRect(QPoint(0, 0), size())); // QRegion region(rect.united((m_contentGeometry + contentMarginsHint())) * devicePixelRatio()); // ###(zccrs): xfwm4 window manager会自动给dock类型的窗口加上阴影, 所以在此裁掉窗口之外的内容 // setMask(region); #endif } bool DFrameWindow::canResize() const { bool ok = m_enableSystemResize && !flags().testFlag(Qt::Popup) && !flags().testFlag(Qt::BypassWindowManagerHint) && minimumSize() != maximumSize() && !disableFrame(); #ifdef Q_OS_LINUX if (!ok) return false; quint32 hints = DXcbWMSupport::getMWMFunctions(Utility::getNativeTopLevelWindow(winId())); return (hints == DXcbWMSupport::MWM_FUNC_ALL || hints & DXcbWMSupport::MWM_FUNC_RESIZE); #endif return ok; } void DFrameWindow::cancelAdsorbCursor() { QSignalBlocker blocker(&m_startAnimationTimer); Q_UNUSED(blocker) m_startAnimationTimer.stop(); m_cursorAnimation.stop(); } void DFrameWindow::adsorbCursor(Utility::CornerEdge cornerEdge) { m_lastCornerEdge = cornerEdge; if (!m_canAdsorbCursor) return; if (m_cursorAnimation.state() == QVariantAnimation::Running) return; m_startAnimationTimer.start(); } void DFrameWindow::startCursorAnimation() { const QPoint &cursorPos = qApp->primaryScreen()->handle()->cursor()->pos(); QPoint toPos = cursorPos - handle()->geometry().topLeft(); const QRect geometry = (m_contentGeometry * devicePixelRatioF()).adjusted(-1, -1, 1, 1); switch (m_lastCornerEdge) { case Utility::TopLeftCorner: toPos = geometry.topLeft(); break; case Utility::TopEdge: toPos.setY(geometry.y()); break; case Utility::TopRightCorner: toPos = geometry.topRight(); break; case Utility::RightEdge: toPos.setX(geometry.right()); break; case Utility::BottomRightCorner: toPos = geometry.bottomRight(); break; case Utility::BottomEdge: toPos.setY(geometry.bottom()); break; case Utility::BottomLeftCorner: toPos = geometry.bottomLeft(); break; case Utility::LeftEdge: toPos.setX(geometry.x()); break; default: break; } toPos += handle()->geometry().topLeft(); const QPoint &tmp = toPos - cursorPos; if (qAbs(tmp.x()) < 3 && qAbs(tmp.y()) < 3) return; m_canAdsorbCursor = false; m_cursorAnimation.setStartValue(cursorPos); m_cursorAnimation.setEndValue(toPos); m_cursorAnimation.start(); } bool DFrameWindow::disableFrame() const { return windowState() == Qt::WindowFullScreen || windowState() == Qt::WindowMaximized || windowState() == Qt::WindowMinimized; } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dframewindow.h000066400000000000000000000121711325534707400243130ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DFRAMEWINDOW_H #define DFRAMEWINDOW_H #include "global.h" #include "utility.h" #include #include #include #include #ifdef Q_OS_LINUX #include struct xcb_rectangle_t; #endif QT_BEGIN_NAMESPACE class QPlatformBackingStore; QT_END_NAMESPACE DPP_BEGIN_NAMESPACE class DFrameWindowPrivate; class DFrameWindow : public QPaintDeviceWindow { Q_OBJECT Q_DECLARE_PRIVATE(DFrameWindow) public: explicit DFrameWindow(QWindow *content); ~DFrameWindow(); QWindow *contentWindow() const; int shadowRadius() const; void setShadowRadius(int radius); QPoint shadowOffset() const; void setShadowOffset(const QPoint &offset); QColor shadowColor() const; void setShadowColor(const QColor &color); int borderWidth() const; void setBorderWidth(int width); QColor borderColor() const; void setBorderColor(const QColor &color); QPainterPath contentPath() const; void setContentPath(const QPainterPath &path); void setContentRoundedRect(const QRect &rect, int radius = 0); QMargins contentMarginsHint() const; QPoint contentOffsetHint() const; bool isClearContentAreaForShadowPixmap() const; void setClearContentAreaForShadowPixmap(bool clear); bool isEnableSystemResize() const; void setEnableSystemResize(bool enable); bool isEnableSystemMove() const; void setEnableSystemMove(bool enable); void disableRepaintShadow(); void enableRepaintShadow(); signals: void contentMarginsHintChanged(const QMargins &oldMargins) const; protected: void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE; void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; bool event(QEvent *event) Q_DECL_OVERRIDE; void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; void updateFromContents(void *); void drawShadowTo(QPaintDevice *device); private: QPaintDevice *redirected(QPoint *) const Q_DECL_OVERRIDE; void setContentPath(const QPainterPath &path, bool isRoundedRect, int radius = 0); #ifdef Q_OS_LINUX void drawNativeWindowXPixmap(xcb_rectangle_t *rects = 0, int length = 0); bool updateNativeWindowXPixmap(int width, int height); void markXPixmapToDirty(int width = -1, int height = -1); #endif void updateShadow(); void updateShadowAsync(int delaye = 30); void updateContentMarginsHint(); void updateMask(); void updateFrameMask(); bool canResize() const; void cancelAdsorbCursor(); void adsorbCursor(Utility::CornerEdge cornerEdge); void startCursorAnimation(); bool disableFrame() const; static QList frameWindowList; QPlatformBackingStore *platformBackingStore; QImage m_shadowImage; bool m_clearContent = false; bool m_redirectContent = false; int m_shadowRadius = 60; QPoint m_shadowOffset = QPoint(0, 16); QColor m_shadowColor = QColor(0, 0, 0, 255 * 0.6); int m_borderWidth = 1; QColor m_borderColor = QColor(0, 0, 0, 255 * 0.15); QPainterPath m_clipPathOfContent; QPainterPath m_clipPath; QPainterPath m_borderPath; QRect m_contentGeometry; QMargins m_contentMarginsHint; bool m_pathIsRoundedRect = true; int m_roundedRectRadius = 0; bool m_enableSystemResize = true; bool m_enableSystemMove = true; bool m_enableAutoInputMaskByContentPath = true; bool m_enableAutoFrameMask = true; bool m_canUpdateShadow = true; bool m_canAdsorbCursor = false; bool m_isSystemMoveResizeState = false; Utility::CornerEdge m_lastCornerEdge; QTimer m_startAnimationTimer; QVariantAnimation m_cursorAnimation; QPointer m_contentWindow; QPlatformBackingStore *m_contentBackingStore = nullptr; QTimer m_updateShadowTimer; int m_paintShadowOnContentTimerId = -1; #ifdef Q_OS_LINUX uint32_t nativeWindowXPixmap = 0; cairo_surface_t *nativeWindowXSurface = 0; QSize xsurfaceDirtySize; #endif friend class DPlatformWindowHelper; friend class DPlatformBackingStoreHelper; friend class DPlatformOpenGLContextHelper; friend class DPlatformIntegration; friend class WindowEventHook; friend class DXcbWMSupport; friend class DFrameWindowPrivate; friend class XcbNativeEventFilter; }; DPP_END_NAMESPACE #endif // DFRAMEWINDOW_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dhighdpi.cpp000066400000000000000000000017431325534707400237430ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * Author: zccrs * * Maintainer: zccrs * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dhighdpi.h" #include QPointF DHighDpi::fromNativePixels(const QPointF &pixelPoint, const QWindow *window) { return QHighDpi::fromNativePixels(pixelPoint, window); } deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dhighdpi.h000066400000000000000000000020101325534707400233740ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * Author: zccrs * * Maintainer: zccrs * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DHIGHDPI_H #define DHIGHDPI_H #include QT_BEGIN_NAMESPACE class QWindow; QT_END_NAMESPACE class DHighDpi { public: static QPointF fromNativePixels(const QPointF &pixelPoint, const QWindow *window); }; #endif // DHIGHDPI_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformbackingstore.cpp000066400000000000000000001502141325534707400265450ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dplatformbackingstore.h" #include "dplatformwindowhook.h" #include "vtablehook.h" #ifdef Q_OS_LINUX #include "dxcbwmsupport.h" #endif #include "qxcbbackingstore.h" #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) #include #else #include #endif #ifndef QT_NO_OPENGL #include #include #include #include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 8, 0) #include #else #include #endif #include #include #endif #include #include #include DPP_BEGIN_NAMESPACE PUBLIC_CLASS(QMouseEvent, WindowEventListener); PUBLIC_CLASS(QWheelEvent, WindowEventListener); PUBLIC_CLASS(QResizeEvent, WindowEventListener); PUBLIC_CLASS(QWidget, WindowEventListener); PUBLIC_CLASS(QWindow, WindowEventListener); PUBLIC_CLASS(QXcbWindow, DPlatformBackingStore); class WindowEventListener : public QObject { Q_OBJECT public: explicit WindowEventListener(DPlatformBackingStore *store) : QObject(0) , m_store(store) { cursorAnimation.setDuration(50); cursorAnimation.setEasingCurve(QEasingCurve::InExpo); connect(&cursorAnimation, &QVariantAnimation::valueChanged, this, &WindowEventListener::onAnimationValueChanged); startAnimationTimer.setSingleShot(true); startAnimationTimer.setInterval(300); connect(&startAnimationTimer, &QTimer::timeout, this, &WindowEventListener::startAnimation); } ~WindowEventListener() { const QWidgetWindow *widgetWindow = m_store->widgetWindow(); QWidget *widget = widgetWindow->widget(); if (widget) { VtableHook::clearGhostVtable(widget); } else { VtableHook::clearGhostVtable(m_store->window()); } } public slots: void updateWindowBlurAreasForWM() { m_store->updateWindowBlurAreasForWM(); } protected: bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE { QWindow *window = qobject_cast(obj); if (!window) return false; const QRect &window_geometry = window->geometry(); // qDebug() << obj << event->type() << window_geometry; switch ((int)event->type()) { case QEvent::Wheel: { DQWheelEvent *e = static_cast(event); if (!window_geometry.contains(e->globalPos())) return true; e->p -= m_store->windowOffset() / window->devicePixelRatio(); break; } case QEvent::MouseMove: case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: { DQMouseEvent *e = static_cast(event); if (Q_LIKELY(e->source() != Qt::MouseEventSynthesizedByQt)) { e->l -= m_store->windowOffset() / window->devicePixelRatio(); e->w -= m_store->windowOffset() / window->devicePixelRatio(); } if (window->flags().testFlag(Qt::Popup) || window->flags().testFlag(Qt::BypassWindowManagerHint)) break; const QRect &window_visible_rect = QRect(m_store->windowValidRect.topLeft() + window_geometry.topLeft(), m_store->windowValidRect.size() / window->devicePixelRatio()); if (window->minimumSize() == window->maximumSize() || !m_store->m_enableSystemResize) goto skip_set_cursor; if (!leftButtonPressed && (!window_visible_rect.contains(e->globalPos()) || !m_store->m_clipPath.contains(e->windowPos() * window->devicePixelRatio()))) { if (event->type() == QEvent::MouseMove) { bool isFixedWidth = window->minimumWidth() == window->maximumWidth(); bool isFixedHeight = window->minimumHeight() == window->maximumHeight(); Utility::CornerEdge mouseCorner; QRect cornerRect; const QRect window_real_geometry = window_visible_rect + QMargins(MOUSE_MARGINS, MOUSE_MARGINS, MOUSE_MARGINS, MOUSE_MARGINS); if (isFixedWidth || isFixedHeight) goto set_edge; /// begin set cursor corner type cornerRect.setSize(QSize(MOUSE_MARGINS * 2, MOUSE_MARGINS * 2)); cornerRect.moveTopLeft(window_real_geometry.topLeft()); if (cornerRect.contains(e->globalPos())) { mouseCorner = Utility::TopLeftCorner; goto set_cursor; } cornerRect.moveTopRight(window_real_geometry.topRight()); if (cornerRect.contains(e->globalPos())) { mouseCorner = Utility::TopRightCorner; goto set_cursor; } cornerRect.moveBottomRight(window_real_geometry.bottomRight()); if (cornerRect.contains(e->globalPos())) { mouseCorner = Utility::BottomRightCorner; goto set_cursor; } cornerRect.moveBottomLeft(window_real_geometry.bottomLeft()); if (cornerRect.contains(e->globalPos())) { mouseCorner = Utility::BottomLeftCorner; goto set_cursor; } set_edge: /// begin set cursor edge type if (e->globalX() <= window_visible_rect.x()) { if (isFixedWidth) goto skip_set_cursor; mouseCorner = Utility::LeftEdge; } else if (e->globalX() < window_visible_rect.right()) { if (isFixedHeight) goto skip_set_cursor; if (e->globalY() <= window_visible_rect.y()) { mouseCorner = Utility::TopEdge; } else if (!isFixedWidth || e->globalY() >= window_visible_rect.bottom()) { mouseCorner = Utility::BottomEdge; } else { goto skip_set_cursor; } } else if (!isFixedWidth && (!isFixedHeight || e->globalX() >= window_visible_rect.right())) { mouseCorner = Utility::RightEdge; } else { goto skip_set_cursor; } set_cursor: Utility::setWindowCursor(window->winId(), mouseCorner); if (qApp->mouseButtons() == Qt::LeftButton) { Utility::startWindowSystemResize(window->winId(), mouseCorner); cancelAdsorbCursor(); } else { adsorbCursor(mouseCorner); } } else if (event->type() == QEvent::MouseButtonRelease) { Utility::cancelWindowMoveResize(window->winId()); } return true; } skip_set_cursor: if (e->buttons() == Qt::LeftButton) { if (e->type() == QEvent::MouseButtonPress) setLeftButtonPressed(true); else if (e->type() == QEvent::MouseButtonRelease) setLeftButtonPressed(false); } else { setLeftButtonPressed(false); } qApp->setOverrideCursor(window->cursor()); cancelAdsorbCursor(); canAdsorbCursor = m_store->m_enableSystemResize; break; } case QEvent::Resize: { const QSize &old_size = window->property("_dxcb_window_old_size").toSize(); const QSize &new_size = window->handle()->geometry().size(); if (old_size == new_size) return true; window->setProperty("_dxcb_window_old_size", new_size); DQResizeEvent *e = static_cast(event); e->s = window->size(); break; } case QEvent::Enter: canAdsorbCursor = m_store->m_enableSystemResize; break; case QEvent::Leave: canAdsorbCursor = false; cancelAdsorbCursor(); break; case QEvent::DynamicPropertyChange: { QDynamicPropertyChangeEvent *e = static_cast(event); if (e->propertyName() == netWmStates) { m_store->onWindowStateChanged(); } else if (e->propertyName() == windowRadius) { m_store->updateWindowRadius(); } else if (e->propertyName() == borderWidth) { m_store->updateBorderWidth(); } else if (e->propertyName() == borderColor) { m_store->updateBorderColor(); } else if (e->propertyName() == shadowRadius) { m_store->updateShadowRadius(); } else if (e->propertyName() == shadowOffset) { m_store->updateShadowOffset(); } else if (e->propertyName() == shadowColor) { m_store->updateShadowColor(); } else if (e->propertyName() == clipPath) { m_store->updateUserClipPath(); } else if (e->propertyName() == frameMask) { m_store->updateFrameMask(); } else if (e->propertyName() == translucentBackground) { m_store->updateTranslucentBackground(); } else if (e->propertyName() == enableSystemResize) { m_store->updateEnableSystemResize(); if (!m_store->m_enableSystemMove) { qApp->setOverrideCursor(window->cursor()); cancelAdsorbCursor(); canAdsorbCursor = false; Utility::cancelWindowMoveResize(window->winId()); } } else if (e->propertyName() == enableSystemMove) { m_store->updateEnableSystemMove(); if (!m_store->m_enableSystemMove) Utility::cancelWindowMoveResize(window->winId()); updateStealMoveEvent(); } else if (e->propertyName() == enableBlurWindow) { m_store->updateEnableBlurWindow(); } else if (e->propertyName() == windowBlurAreas) { m_store->updateWindowBlurAreas(); } else if (e->propertyName() == windowBlurPaths) { m_store->updateWindowBlurPaths(); } else if (e->propertyName() == autoInputMaskByClipPath) { m_store->updateAutoInputMaskByClipPath(); } break; } default: break; } return false; } void mouseMoveEvent(QMouseEvent *event) { Q_UNUSED(event); ///TODO: Warning: System move finished no mouse release event Utility::startWindowSystemMove(reinterpret_cast(this)->winId()); } void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE { if (event->timerId() == m_store->updateShadowTimer.timerId()) { m_store->repaintWindowShadow(); } } private: void setLeftButtonPressed(bool pressed) { if (leftButtonPressed == pressed) return; if (!pressed) Utility::cancelWindowMoveResize(m_store->window()->winId()); leftButtonPressed = pressed; updateStealMoveEvent(); } void updateStealMoveEvent() { const QWidgetWindow *widgetWindow = m_store->widgetWindow(); QWidget *widget = widgetWindow->widget(); if (widget) { if (leftButtonPressed && m_store->m_enableSystemMove) { VtableHook::overrideVfptrFun(static_cast(widget), &DQWidget::mouseMoveEvent, this, &WindowEventListener::mouseMoveEvent); } else { VtableHook::resetVfptrFun(static_cast(widget), &DQWidget::mouseMoveEvent); } } else { QWindow *window = m_store->window(); if (leftButtonPressed && m_store->m_enableSystemMove) { VtableHook::overrideVfptrFun(static_cast(window), &DQWindow::mouseMoveEvent, this, &WindowEventListener::mouseMoveEvent); } else { VtableHook::resetVfptrFun(static_cast(window), &DQWindow::mouseMoveEvent); } } } void adsorbCursor(Utility::CornerEdge cornerEdge) { lastCornerEdge = cornerEdge; if (!canAdsorbCursor) return; if (cursorAnimation.state() == QVariantAnimation::Running) return; startAnimationTimer.start(); } void cancelAdsorbCursor() { QSignalBlocker blocker(&startAnimationTimer); Q_UNUSED(blocker) startAnimationTimer.stop(); cursorAnimation.stop(); } void onAnimationValueChanged(const QVariant &value) { QCursor::setPos(value.toPoint()); } void startAnimation() { QPoint cursorPos = QCursor::pos(); QPoint toPos = cursorPos; const QRect geometry = QRect(m_store->windowValidRect.topLeft() + m_store->window()->position(), m_store->windowValidRect.size() / m_store->window()->devicePixelRatio()).adjusted(-1, -1, 1, 1); switch (lastCornerEdge) { case Utility::TopLeftCorner: toPos = geometry.topLeft(); break; case Utility::TopEdge: toPos.setY(geometry.y()); break; case Utility::TopRightCorner: toPos = geometry.topRight(); break; case Utility::RightEdge: toPos.setX(geometry.right()); break; case Utility::BottomRightCorner: toPos = geometry.bottomRight(); break; case Utility::BottomEdge: toPos.setY(geometry.bottom()); break; case Utility::BottomLeftCorner: toPos = geometry.bottomLeft(); break; case Utility::LeftEdge: toPos.setX(geometry.x()); break; default: break; } const QPoint &tmp = toPos - cursorPos; if (qAbs(tmp.x()) < 3 && qAbs(tmp.y()) < 3) return; canAdsorbCursor = false; cursorAnimation.setStartValue(cursorPos); cursorAnimation.setEndValue(toPos); cursorAnimation.start(); } /// mouse left button is pressed in window vaild geometry bool leftButtonPressed = false; bool canAdsorbCursor = false; Utility::CornerEdge lastCornerEdge; QTimer startAnimationTimer; QVariantAnimation cursorAnimation; DPlatformBackingStore *m_store; }; //class DXcbShmGraphicsBuffer : public QPlatformGraphicsBuffer //{ //public: // DXcbShmGraphicsBuffer(QImage *image) // : QPlatformGraphicsBuffer(image->size(), QImage::toPixelFormat(image->format())) // , m_access_lock(QPlatformGraphicsBuffer::None) // , m_image(image) // { } // bool doLock(AccessTypes access, const QRect &rect) Q_DECL_OVERRIDE // { // Q_UNUSED(rect); // if (access & ~(QPlatformGraphicsBuffer::SWReadAccess | QPlatformGraphicsBuffer::SWWriteAccess)) // return false; // m_access_lock |= access; // return true; // } // void doUnlock() Q_DECL_OVERRIDE { m_access_lock = None; } // const uchar *data() const Q_DECL_OVERRIDE { return m_image.bits(); } // uchar *data() Q_DECL_OVERRIDE { return m_image.bits(); } // int bytesPerLine() const Q_DECL_OVERRIDE { return m_image.bytesPerLine(); } // Origin origin() const Q_DECL_OVERRIDE { return QPlatformGraphicsBuffer::OriginTopLeft; } //private: // AccessTypes m_access_lock; // QImage *m_image; //}; DPlatformBackingStore::DPlatformBackingStore(QWindow *window, QXcbBackingStore *proxy) : QPlatformBackingStore(window) , m_proxy(proxy), #ifndef QT_NO_OPENGL m_textureId(0), m_blitter(0) #endif { m_eventListener = new WindowEventListener(this); m_windowHook = DPlatformWindowHook::getHookByWindow(window->handle()); shadowPixmap.fill(Qt::transparent); #ifdef Q_OS_LINUX m_enableShadow = DXcbWMSupport::instance()->hasComposite(); QObject::connect(DXcbWMSupport::instance(), &DXcbWMSupport::hasCompositeChanged, m_eventListener, [this, window] (bool hasComposite) { m_enableShadow = hasComposite; updateWindowMargins(); updateClipPath(); doDelayedUpdateWindowShadow(); }); #endif initUserProperties(); //! Warning: At this point you must be initialized window Margins and window Extents updateWindowMargins(); // updateFrameExtents(); VtableHook::overrideVfptrFun(static_cast(window->handle()), &QXcbWindowEventListener::handlePropertyNotifyEvent, this, &DPlatformBackingStore::handlePropertyNotifyEvent); QObject::connect(window, &QWindow::windowStateChanged, m_eventListener, [this] { updateWindowMargins(false); }); window->installEventFilter(m_eventListener); } DPlatformBackingStore::~DPlatformBackingStore() { delete m_proxy; delete m_eventListener; // if (m_graphicsBuffer) // delete m_graphicsBuffer; VtableHook::clearGhostVtable(static_cast(static_cast(window()->handle()))); } QPaintDevice *DPlatformBackingStore::paintDevice() { return &m_image; } static QColor colorBlend(const QColor &color1, const QColor &color2) { QColor c2 = color2.toRgb(); if (c2.alpha() >= 255) return c2; QColor c1 = color1.toRgb(); qreal c1_weight = 1 - c2.alphaF(); int r = c1_weight * c1.red() + c2.alphaF() * c2.red(); int g = c1_weight * c1.green() + c2.alphaF() * c2.green(); int b = c1_weight * c1.blue() + c2.alphaF() * c2.blue(); return QColor(r, g, b); } void DPlatformBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { Q_UNUSED(region) if (!m_proxy->paintDevice()) return; const QPoint &windowOffset = this->windowOffset(); QRegion tmp_region; QPainter pa(m_proxy->paintDevice()); pa.setCompositionMode(QPainter::CompositionMode_Source); #ifdef Q_OS_LINUX if (DXcbWMSupport::instance()->hasComposite()) #endif pa.setRenderHint(QPainter::Antialiasing); if (m_enableShadow) { pa.setClipPath(m_windowClipPath); for (const QRect &rect : region.rects()) { const QRect &tmp_rect = rect.translated(windowOffset); pa.drawImage(tmp_rect, m_image, rect); if (tmp_rect.size() == m_size) { tmp_region += QRect(QPoint(0, 0), m_size); } else { tmp_region += tmp_rect.united(QRect(windowOffset, m_image.size())); } } } else { pa.setPen(m_borderColor); QColor border_color = m_borderColor; #ifdef Q_OS_LINUX if (!DXcbWMSupport::instance()->hasComposite()) border_color = colorBlend(QColor("#e0e0e0"), m_borderColor); #endif tmp_region += QRect(QPoint(0, 0), m_size); if (m_borderWidth > 0) { QPainterPath path; path.addRect(tmp_region.rects().first()); path -= m_windowClipPath; pa.fillPath(path, border_color); pa.setClipPath(m_windowClipPath); } pa.drawImage(windowOffset, m_image); } pa.end(); // qDebug() << "flush" << window << tmp_region << offset; DPlatformWindowHook *window_hook = m_windowHook; if (window_hook) window_hook->setWindowMargins(QMargins(0, 0, 0, 0)); m_proxy->flush(window, tmp_region, offset); if (window_hook) window_hook->setWindowMargins(windowMargins); } #ifndef QT_NO_OPENGL static inline QRect deviceRect(const QRect &rect, QWindow *window) { QRect deviceRect(rect.topLeft() * window->devicePixelRatio(), rect.size() * window->devicePixelRatio()); return deviceRect; } static QRegion deviceRegion(const QRegion ®ion, QWindow *window, const QPoint &offset) { if (offset.isNull() && window->devicePixelRatio() <= 1) return region; QVector rects; const QVector regionRects = region.rects(); rects.reserve(regionRects.count()); foreach (const QRect &rect, regionRects) rects.append(deviceRect(rect.translated(offset), window)); QRegion deviceRegion; deviceRegion.setRects(rects.constData(), rects.count()); return deviceRegion; } static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight) { return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1, topLeftRect.width(), topLeftRect.height()); } static void blitTextureForWidget(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect, QOpenGLTextureBlitter *blitter, const QPoint &offset) { Q_UNUSED(deviceWindowRect) //orignal clipRect is wrong because of frame margins //const QRect clipRect = textures->clipRect(idx); QRect rectInWindow = textures->geometry(idx); const QRect clipRect = QRect(QPoint(), rectInWindow.size()); if (clipRect.isEmpty()) return; // relative to the TLW, not necessarily our window (if the flush is for a native child widget), have to adjust rectInWindow.translate(-offset); const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft()); const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height()); const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform( deviceRect(clippedRectInWindow, window), clippedRectInWindow); //deviceWindowRect); const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(deviceRect(srcRect, window), deviceRect(rectInWindow, window).size(), QOpenGLTextureBlitter::OriginBottomLeft); blitter->blit(textures->textureId(idx), target, source); } #if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) void DPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, QOpenGLContext *context) { Q_UNUSED(textures); Q_UNUSED(context); flush(window, region, offset); } #else void DPlatformBackingStore::composeAndFlushHelper(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, QOpenGLContext *context, bool translucentBackground) { Q_UNUSED(region) //if (!qt_window_private(window)->receivedExpose) //return; if (!context->makeCurrent(window)) { qWarning("composeAndFlush: makeCurrent() failed"); return; } //QWindowPrivate::get(window)->lastComposeTime.start(); QPoint reversedOrigin(windowMargins.left(), windowMargins.bottom()); // reversed QOpenGLFunctions *funcs = context->functions(); funcs->glViewport(reversedOrigin.x(), reversedOrigin.y(), m_windowSize.width() * window->devicePixelRatio(), m_windowSize.height() * window->devicePixelRatio()); funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1); funcs->glClear(GL_COLOR_BUFFER_BIT); if (!m_blitter) { m_blitter = new QOpenGLTextureBlitter; m_blitter->create(); } m_blitter->bind(); const QRect deviceWindowRect = deviceRect(QRect(windowOffset(), m_windowSize), window); // Textures for renderToTexture widgets. for (int i = 0; i < textures->count(); ++i) { if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) blitTextureForWidget(textures, i, window, deviceWindowRect, m_blitter, offset); } // Backingstore texture with the normal widgets. GLuint textureId = 0; QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft; #if 0 if (QPlatformGraphicsBuffer *graphicsBuffer = this->graphicsBuffer()) { if (graphicsBuffer->size() != m_textureSize) { if (m_textureId) funcs->glDeleteTextures(1, &m_textureId); funcs->glGenTextures(1, &m_textureId); funcs->glBindTexture(GL_TEXTURE_2D, m_textureId); QOpenGLContext *ctx = QOpenGLContext::currentContext(); if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) { funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); } funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &m_needsSwizzle, &m_premultiplied)) { m_textureSize = graphicsBuffer->size(); } else { m_textureSize = QSize(0,0); } graphicsBuffer->unlock(); } else if (!region.isEmpty()){ funcs->glBindTexture(GL_TEXTURE_2D, m_textureId); QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &m_needsSwizzle, &m_premultiplied); } if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft) origin = QOpenGLTextureBlitter::OriginBottomLeft; textureId = m_textureId; } else #endif { TextureFlags flags = 0; //I don't know why region is empty //textureId = toTexture(deviceRegion(region, window, offset + windowOffset()), &m_textureSize, &flags); QRegion region(0, 0, m_windowSize.width(), m_windowSize.height()); #if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) textureId = toTexture(deviceRegion(region, window, offset), &m_textureSize, false); #else textureId = toTexture(deviceRegion(region, window, offset), &m_textureSize, &flags); #endif m_needsSwizzle = (flags & TextureSwizzle) != 0; m_premultiplied = (flags & TexturePremultiplied) != 0; if (flags & TextureFlip) origin = QOpenGLTextureBlitter::OriginBottomLeft; } funcs->glEnable(GL_BLEND); if (m_premultiplied) funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); else funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); if (textureId) { if (m_needsSwizzle) #if QT_VERSION < QT_VERSION_CHECK(5, 8, 0) m_blitter->setSwizzleRB(true); #else m_blitter->setRedBlueSwizzle(true); #endif // The backingstore is for the entire tlw. // In case of native children offset tells the position relative to the tlw. // reverse translate backward for widgets const QRect srcRect = toBottomLeftRect(deviceWindowRect.translated(offset-windowOffset()), m_textureSize.height()); const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect, m_textureSize, origin); m_blitter->blit(textureId, QMatrix4x4(), source); if (m_needsSwizzle) #if QT_VERSION < QT_VERSION_CHECK(5, 8, 0) m_blitter->setSwizzleRB(false); #else m_blitter->setRedBlueSwizzle(false); #endif } // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. for (int i = 0; i < textures->count(); ++i) { if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) blitTextureForWidget(textures, i, window, deviceWindowRect, m_blitter, offset); } funcs->glDisable(GL_BLEND); m_blitter->release(); context->swapBuffers(window); } void DPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, QOpenGLContext *context, bool translucentBackground) { if (textures != nullptr) { composeAndFlushHelper(window, region, offset, textures, context, translucentBackground); } } #endif QImage DPlatformBackingStore::toImage() const { return m_image; } #if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) GLuint DPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize) const { return m_proxy->toTexture(dirtyRegion, textureSize); } #elif QT_VERSION < QT_VERSION_CHECK(5, 5, 0) GLuint DPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, bool *needsSwizzle) const { return QPlatformBackingStore::toTexture(dirtyRegion, textureSize, needsSwizzle); } #else GLuint DPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const { return QPlatformBackingStore::toTexture(dirtyRegion, textureSize, flags); } #endif #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) QPlatformGraphicsBuffer *DPlatformBackingStore::graphicsBuffer() const { // return m_graphicsBuffer; return m_proxy->graphicsBuffer(); } #endif void DPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents) { // qDebug() << "resize" << size << staticContents; #if QT_VERSION > QT_VERSION_CHECK(5, 5, 1) if (size == m_image.size()) return; m_image = QImage(size, QImage::Format_ARGB32_Premultiplied); #else const int dpr = int(window()->devicePixelRatio()); const QSize xSize = size * dpr; if (xSize == m_image.size() && dpr == m_image.devicePixelRatio()) return; m_image = QImage(xSize, QImage::Format_ARGB32_Premultiplied); m_image.setDevicePixelRatio(dpr); #endif // if (m_graphicsBuffer) // delete m_graphicsBuffer; // m_graphicsBuffer = new DXcbShmGraphicsBuffer(&m_image); m_windowSize = size; m_size = QSize(size.width() + windowMargins.left() + windowMargins.right(), size.height() + windowMargins.top() + windowMargins.bottom()); m_proxy->resize(m_size, staticContents); updateClipPath(); //! TODO: update window margins // updateWindowMargins(); if (isUserSetClipPath) { if (shadowPixmap.isNull()) { updateWindowShadow(); } if (!m_windowClipPath.isEmpty()) updateWindowBlurAreasForWM(); } else { updateWindowShadow(); if (!m_blurAreaList.isEmpty() || !m_blurPathList.isEmpty() || m_enableBlurWindow) updateWindowBlurAreasForWM(); } updateInputShapeRegion(); paintWindowShadow(); } void DPlatformBackingStore::beginPaint(const QRegion ®ion) { if (m_translucentBackground) { QPainter p(paintDevice()); p.setCompositionMode(QPainter::CompositionMode_Source); const QVector rects = region.rects(); const QColor blank = Qt::transparent; for (QVector::const_iterator it = rects.begin(); it != rects.end(); ++it) { const QRect &rect = *it; p.fillRect(rect, blank); } } } void DPlatformBackingStore::endPaint() { // m_proxy->endPaint(); // qDebug() << "end paint"; } void DPlatformBackingStore::initUserProperties() { updateWindowRadius(); updateBorderWidth(); updateBorderColor(); updateUserClipPath(); updateFrameMask(); updateShadowRadius(); updateShadowOffset(); updateShadowColor(); updateTranslucentBackground(); updateEnableSystemMove(); updateEnableSystemResize(); updateEnableBlurWindow(); updateWindowBlurAreas(); updateWindowBlurPaths(); updateAutoInputMaskByClipPath(); } bool DPlatformBackingStore::updateWindowMargins(bool repaintShadow) { Qt::WindowState state = window()->windowState(); const QMargins old_margins = windowMargins; const QRect &window_geometry = window()->handle()->geometry(); if (state == Qt::WindowMaximized || state == Qt::WindowFullScreen) { setWindowMargins(QMargins(0, 0, 0, 0)); } else if (state != Qt::WindowMinimized) { setWindowMargins(QMargins(qMax(getShadowRadius() - getShadowOffset().x(), m_borderWidth), qMax(getShadowRadius() - getShadowOffset().y(), m_borderWidth), qMax(getShadowRadius() + getShadowOffset().x(), m_borderWidth), qMax(getShadowRadius() + getShadowOffset().y(), m_borderWidth))); } if (repaintShadow && old_margins != windowMargins) { window()->handle()->setGeometry(window_geometry); repaintWindowShadow(); return true; } return false; } void DPlatformBackingStore::updateFrameExtents() { QMargins extentsMargins = windowMargins; if (canUseClipPath() && !isUserSetClipPath) { extentsMargins -= m_borderWidth; } Utility::setFrameExtents(window()->winId(), extentsMargins); } void DPlatformBackingStore::updateInputShapeRegion() { if (!windowGeometry().isValid()) return; int mouse_margins; if (m_enableShadow) mouse_margins = canResize() ? MOUSE_MARGINS : 0; else mouse_margins = m_borderWidth; // clear old state Utility::setShapeRectangles(window()->winId(), QRegion(), true); Utility::setShapeRectangles(window()->winId(), QRegion(), false); if (m_autoInputMaskByClipPath && (isUserSetClipPath || getWindowRadius() > 0)) { QPainterPath p; if (Q_LIKELY(mouse_margins > 0)) { QPainterPathStroker stroker; stroker.setJoinStyle(Qt::MiterJoin); stroker.setWidth(mouse_margins * 2); p = stroker.createStroke(m_windowClipPath); p = p.united(m_windowClipPath); p.translate(-0.5, -0.5); } else { p = m_windowClipPath; } Utility::setShapePath(window()->winId(), p #ifdef Q_OS_LINUX , DXcbWMSupport::instance()->hasComposite() #endif ); } else { QRegion region(windowGeometry().adjusted(-mouse_margins, -mouse_margins, mouse_margins, mouse_margins)); Utility::setShapeRectangles(window()->winId(), region #ifdef Q_OS_LINUX , DXcbWMSupport::instance()->hasComposite() #endif ); } } void DPlatformBackingStore::updateWindowRadius() { const QVariant &v = window()->property(windowRadius); if (!v.isValid()) { window()->setProperty(windowRadius, m_windowRadius); return; } bool ok; int radius = v.toInt(&ok); if (ok && radius != m_windowRadius) { m_windowRadius = radius; isUserSetWindowRadius = true; updateClipPath(); } } void DPlatformBackingStore::updateBorderWidth() { const QVariant &v = window()->property(borderWidth); if (!v.isValid()) { window()->setProperty(borderWidth, m_borderWidth); return; } bool ok; int width = v.toInt(&ok); if (ok && width != m_borderWidth) { m_borderWidth = width; updateFrameExtents(); if (!updateWindowMargins()) doDelayedUpdateWindowShadow(); } } void DPlatformBackingStore::updateBorderColor() { const QVariant &v = window()->property(borderColor); if (!v.isValid()) { window()->setProperty(borderColor, m_borderColor); return; } const QColor &color = qvariant_cast(v); if (color.isValid() && m_borderColor != color) { m_borderColor = color; doDelayedUpdateWindowShadow(); } } void DPlatformBackingStore::updateUserClipPath() { const QVariant &v = window()->property(clipPath); if (!v.isValid()) { return; } QPainterPath path; path = qvariant_cast(v); if (!isUserSetClipPath && path.isEmpty()) return; isUserSetClipPath = !path.isEmpty(); if (path.isEmpty()) updateClipPath(); else setClipPah(path * window()->devicePixelRatio()); } void DPlatformBackingStore::updateClipPath() { if (!isUserSetClipPath) { QPainterPath path; if (canUseClipPath()) path.addRoundedRect(QRect(QPoint(0, 0), m_windowSize), getWindowRadius(), getWindowRadius()); else path.addRect(0, 0, m_windowSize.width(), m_windowSize.height()); setClipPah(path); } } void DPlatformBackingStore::updateFrameMask() { const QVariant &v = window()->property(frameMask); if (!v.isValid()) { return; } QRegion region = qvariant_cast(v); static_cast(window()->handle())->QXcbWindow::setMask(region * window()->devicePixelRatio()); isUserSetFrameMask = !region.isEmpty(); } void DPlatformBackingStore::updateShadowRadius() { const QVariant &v = window()->property(shadowRadius); if (!v.isValid()) { window()->setProperty(shadowRadius, m_shadowRadius); return; } bool ok; int radius = qMax(v.toInt(&ok), 0); if (ok && radius != m_shadowRadius) { m_shadowRadius = radius; updateWindowMargins(); if (m_enableShadow) doDelayedUpdateWindowShadow(); } } void DPlatformBackingStore::updateShadowOffset() { const QVariant &v = window()->property(shadowOffset); if (!v.isValid()) { window()->setProperty(shadowOffset, m_shadowOffset); return; } const QPoint &offset = v.toPoint(); if (offset != m_shadowOffset) { m_shadowOffset = offset; updateWindowMargins(); if (m_enableShadow) doDelayedUpdateWindowShadow(); } } void DPlatformBackingStore::updateShadowColor() { const QVariant &v = window()->property(shadowColor); if (!v.isValid()) { window()->setProperty(shadowColor, m_shadowColor); return; } const QColor &color = qvariant_cast(v); if (color.isValid() && m_shadowColor != color) { m_shadowColor = color; if (m_enableShadow) doDelayedUpdateWindowShadow(); } } void DPlatformBackingStore::updateTranslucentBackground() { const QVariant &v = window()->property(translucentBackground); if (!v.isValid()) { window()->setProperty(translucentBackground, m_translucentBackground); return; } m_translucentBackground = v.toBool(); } void DPlatformBackingStore::updateEnableSystemResize() { const QVariant &v = window()->property(enableSystemResize); if (!v.isValid()) { window()->setProperty(enableSystemResize, m_enableSystemResize); return; } if (m_enableSystemResize == v.toBool()) return; m_enableSystemResize = v.toBool(); updateInputShapeRegion(); } void DPlatformBackingStore::updateEnableSystemMove() { const QVariant &v = window()->property(enableSystemMove); if (!v.isValid()) { window()->setProperty(enableSystemMove, m_enableSystemMove); return; } m_enableSystemMove = v.toBool(); } void DPlatformBackingStore::updateEnableBlurWindow() { const QVariant &v = window()->property(enableBlurWindow); if (!v.isValid()) { window()->setProperty(enableBlurWindow, m_enableBlurWindow); return; } if (m_enableBlurWindow != v.toBool()) { m_enableBlurWindow = v.toBool(); #ifdef Q_OS_LINUX if (m_enableBlurWindow) { QObject::connect(DXcbWMSupport::instance(), &DXcbWMSupport::windowManagerChanged, m_eventListener, &WindowEventListener::updateWindowBlurAreasForWM); } else { QObject::disconnect(DXcbWMSupport::instance(), &DXcbWMSupport::windowManagerChanged, m_eventListener, &WindowEventListener::updateWindowBlurAreasForWM); } #endif updateWindowBlurAreasForWM(); } } void DPlatformBackingStore::updateWindowBlurAreas() { const QVariant &v = window()->property(windowBlurAreas); const QVector &tmpV = qvariant_cast>(v); const QVector &a = *(reinterpret_cast*>(&tmpV)); if (a.isEmpty() && m_blurAreaList.isEmpty()) return; m_blurAreaList = a; updateWindowBlurAreasForWM(); } void DPlatformBackingStore::updateWindowBlurPaths() { const QVariant &v = window()->property(windowBlurPaths); const QList paths = qvariant_cast>(v); if (paths.isEmpty() && m_blurPathList.isEmpty()) return; m_blurPathList = paths; updateWindowBlurAreasForWM(); } void DPlatformBackingStore::updateAutoInputMaskByClipPath() { const QVariant &v = window()->property(autoInputMaskByClipPath); if (!v.isValid()) { window()->setProperty(autoInputMaskByClipPath, m_autoInputMaskByClipPath); return; } if (m_autoInputMaskByClipPath != v.toBool()) { m_autoInputMaskByClipPath = v.toBool(); } } void DPlatformBackingStore::setWindowMargins(const QMargins &margins) { if (windowMargins == margins) return; windowMargins = margins; m_windowClipPath = m_clipPath.translated(windowOffset()); DPlatformWindowHook *hook = m_windowHook; if (hook) { hook->setWindowMargins(margins, true); } const QSize &tmp_size = windowGeometry().size(); m_size = QSize(tmp_size.width() + windowMargins.left() + windowMargins.right(), tmp_size.height() + windowMargins.top() + windowMargins.bottom()); if (m_size.isValid()) { m_proxy->resize(m_size, QRegion()); } updateInputShapeRegion(); updateFrameExtents(); if (!m_blurAreaList.isEmpty() || !m_blurPathList.isEmpty() || m_enableBlurWindow) updateWindowBlurAreasForWM(); window()->setProperty(frameMargins, QVariant::fromValue(windowMargins)); } void DPlatformBackingStore::setClipPah(const QPainterPath &path) { if (m_clipPath != path) { m_clipPath = path; m_windowClipPath = m_clipPath.translated(windowOffset()); windowValidRect = m_clipPath.boundingRect().toRect(); updateInputShapeRegion(); if (isUserSetClipPath) { updateWindowBlurAreasForWM(); doDelayedUpdateWindowShadow(); } } } void DPlatformBackingStore::paintWindowShadow(QRegion region) { if (!m_proxy->paintDevice() || shadowPixmap.isNull()) return; QPainter pa; /// begin paint window drop shadow pa.begin(m_proxy->paintDevice()); pa.setCompositionMode(QPainter::CompositionMode_Source); pa.drawPixmap(0, 0, shadowPixmap); pa.end(); DPlatformWindowHook *window_hook = m_windowHook; if (window_hook) window_hook->setWindowMargins(QMargins(0, 0, 0, 0)); if (region.isEmpty()) { region += QRect(windowMargins.left(), 0, m_windowSize.width(), windowMargins.top()); region += QRect(windowMargins.left(), windowMargins.top() + m_windowSize.height(), m_windowSize.width(), windowMargins.bottom()); region += QRect(0, 0, windowMargins.left(), m_size.height()); region += QRect(windowMargins.left() + m_windowSize.width(), 0, windowMargins.right(), m_size.height()); } m_proxy->flush(window(), region, QPoint(0, 0)); if (window_hook) window_hook->setWindowMargins(windowMargins); /// end } void DPlatformBackingStore::repaintWindowShadow() { updateShadowTimer.stop(); shadowPixmap = QPixmap(); if (windowMargins.isNull()) return; updateWindowShadow(); paintWindowShadow(QRegion(0, 0, m_size.width(), m_size.height())); if (!shadowPixmap.isNull()) flush(window(), QRect(QPoint(0, 0), m_windowSize), QPoint(0, 0)); } inline QSize margins2Size(const QMargins &margins) { return QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); } void DPlatformBackingStore::updateWindowShadow() { if (m_image.isNull() || !m_enableShadow) return; bool paintShadow = isUserSetClipPath || shadowPixmap.isNull(); if (!paintShadow) { QSize margins_size = margins2Size(windowMargins + getWindowRadius() + m_borderWidth); if (margins_size.width() > qMin(m_size.width(), shadowPixmap.width()) || margins_size.height() > qMin(m_size.height(), shadowPixmap.height())) { paintShadow = true; } } if (paintShadow) { int shadow_radius = qMax(getShadowRadius(), m_borderWidth); QImage image; if (shadow_radius > m_borderWidth) { QPixmap pixmap(m_size - QSize(2 * shadow_radius, 2 * shadow_radius)); if (pixmap.isNull()) return; pixmap.fill(Qt::transparent); QPainter pa(&pixmap); pa.fillPath(m_clipPath, m_shadowColor); pa.end(); image = Utility::dropShadow(pixmap, shadow_radius, m_shadowColor); } else { image = QImage(m_size, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); } /// begin paint window border; QPainter pa; pa.begin(&image); if (m_borderWidth > 0) { QPainterPathStroker pathStroker; pathStroker.setWidth(m_borderWidth * 2); QTransform transform = pa.transform(); const QRectF &clipRect = m_clipPath.boundingRect(); transform.translate(windowMargins.left() + 2, windowMargins.top() + 2); transform.scale((clipRect.width() - 4) / clipRect.width(), (clipRect.height() - 4) / clipRect.height()); pa.setRenderHint(QPainter::Antialiasing); pa.fillPath(pathStroker.createStroke(m_windowClipPath), m_borderColor); pa.setCompositionMode(QPainter::CompositionMode_Clear); pa.setRenderHint(QPainter::Antialiasing, false); pa.setTransform(transform); } pa.fillPath(m_clipPath, Qt::transparent); pa.end(); /// end shadowPixmap = QPixmap::fromImage(image); } else { shadowPixmap = QPixmap::fromImage(Utility::borderImage(shadowPixmap, windowMargins + getWindowRadius(), m_size)); } } bool DPlatformBackingStore::updateWindowBlurAreasForWM() { const QRect &windowValidRect = windowGeometry(); if (windowValidRect.isEmpty()) return false; xcb_window_t top_level_w = Utility::getNativeTopLevelWindow(window()->winId()); QPoint offset; if (top_level_w != window()->winId()) { offset = Utility::translateCoordinates(QPoint(0, 0), window()->winId(), top_level_w); } QVector newAreas; qreal device_pixel_ratio = window()->devicePixelRatio(); if (m_enableBlurWindow) { Utility::BlurArea area; area.x = windowValidRect.x() << offset.x(); area.y = windowValidRect.y() << offset.y(); area.width = windowValidRect.width(); area.height = windowValidRect.height(); area.xRadius = getWindowRadius(); area.yRaduis = getWindowRadius(); newAreas.append(std::move(area)); } else { newAreas.reserve(m_blurAreaList.size()); foreach (Utility::BlurArea area, m_blurAreaList) { area *= device_pixel_ratio; if (area.x < 0) { area.width += area.x; area.x = 0; } if (area.y < 0) { area.height += area.y; area.y = 0; } area.x += windowValidRect.x(); area.y += windowValidRect.y(); area.width = qMin(area.x + area.width, windowValidRect.right() + 1) - area.x; area.height = qMin(area.y + area.height, windowValidRect.bottom() + 1) - area.y; area.x += offset.x(); area.y += offset.y(); newAreas.append(std::move(area)); } } if ((isUserSetClipPath && !m_windowClipPath.isEmpty()) || !m_blurPathList.isEmpty()) { QList newPathList; newPathList.reserve(m_blurPathList.size()); foreach (QPainterPath path, m_blurPathList) { path *= device_pixel_ratio; if (m_windowClipPath.isEmpty()) newPathList << path.translated(windowValidRect.topLeft() + offset); else newPathList << path.translated(windowValidRect.topLeft()).intersected(m_windowClipPath).translated(offset); } foreach (const Utility::BlurArea &area, newAreas) { QPainterPath path; path.addRoundedRect(area.x, area.y, area.width, area.height, area.xRadius, area.yRaduis); if (m_windowClipPath.isEmpty()) newPathList << path; else newPathList << path.intersected(m_windowClipPath.translated(offset)); } return Utility::blurWindowBackgroundByPaths(top_level_w, newPathList); } return Utility::blurWindowBackground(top_level_w, newAreas); } void DPlatformBackingStore::doDelayedUpdateWindowShadow(int delaye) { if (m_eventListener) updateShadowTimer.start(delaye, m_eventListener); } bool DPlatformBackingStore::isWidgetWindow(const QWindow *window) { return window->metaObject()->className() == QStringLiteral("QWidgetWindow"); } QWidgetWindow *DPlatformBackingStore::widgetWindow() const { return static_cast(window()); } int DPlatformBackingStore::getWindowRadius() const { #ifdef Q_OS_LINUX return (isUserSetWindowRadius || DXcbWMSupport::instance()->hasComposite()) ? m_windowRadius : 0; #else return m_windowRadius; #endif } bool DPlatformBackingStore::canUseClipPath() const { QXcbWindow::NetWmStates states = (QXcbWindow::NetWmStates)window()->property(netWmStates).toInt(); if (states & (QXcbWindow::NetWmStateFullScreen | QXcbWindow::NetWmStateMaximizedHorz | QXcbWindow::NetWmStateMaximizedVert)) { return false; } return true; } bool DPlatformBackingStore::canResize() const { return m_enableSystemResize && !window()->flags().testFlag(Qt::Popup) && window()->minimumSize() != window()->maximumSize(); } void DPlatformBackingStore::onWindowStateChanged() { updateClipPath(); updateFrameExtents(); doDelayedUpdateWindowShadow(); } void DPlatformBackingStore::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) { DQXcbWindow *window = static_cast(reinterpret_cast(this)); QWindow *ww = window->window(); Qt::WindowState oldState = ww->windowState(); window->QXcbWindow::handlePropertyNotifyEvent(event); if (window->m_windowState != oldState) { ww->setWindowState(window->m_windowState); } if (event->window == window->xcb_window() && event->atom == window->atom(QXcbAtom::_NET_WM_STATE)) { QXcbWindow::NetWmStates states = window->netWmStates(); ww->setProperty(netWmStates, (int)states); } } DPP_END_NAMESPACE #include "dplatformbackingstore.moc" deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformbackingstore.h000066400000000000000000000144431325534707400262150ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DXCBBACKINGSTORE_H #define DXCBBACKINGSTORE_H #define private public #include #undef private #include #include #include "global.h" #include "utility.h" QT_BEGIN_NAMESPACE class QXcbBackingStore; class QWidgetWindow; class QOpenGLTextureBlitter; QT_END_NAMESPACE struct xcb_property_notify_event_t; DPP_BEGIN_NAMESPACE class DXcbShmGraphicsBuffer; class WindowEventListener; class DPlatformWindowHook; class DPlatformBackingStore : public QPlatformBackingStore { public: DPlatformBackingStore(QWindow *window, QXcbBackingStore *proxy); ~DPlatformBackingStore(); QPaintDevice *paintDevice() Q_DECL_OVERRIDE; // 'window' can be a child window, in which case 'region' is in child window coordinates and // offset is the (child) window's offset in relation to the window surface. void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; #ifndef QT_NO_OPENGL #if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, QOpenGLContext *context) Q_DECL_OVERRIDE; #else void composeAndFlushHelper(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, QOpenGLContext *context, bool translucentBackground); void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, QOpenGLContext *context, bool translucentBackground) Q_DECL_OVERRIDE; #endif QImage toImage() const Q_DECL_OVERRIDE; #if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize) const Q_DECL_OVERRIDE; #elif QT_VERSION < QT_VERSION_CHECK(5, 5, 0) GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, bool *needsSwizzle) const Q_DECL_OVERRIDE; #else GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const Q_DECL_OVERRIDE; #endif #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) QPlatformGraphicsBuffer *graphicsBuffer() const Q_DECL_OVERRIDE; #endif void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE; void beginPaint(const QRegion ®ion) Q_DECL_OVERRIDE; void endPaint() Q_DECL_OVERRIDE; static bool isWidgetWindow(const QWindow *window); private: void initUserProperties(); bool updateWindowMargins(bool repaintShadow = true); void updateFrameExtents(); void updateInputShapeRegion(); void updateClipPath(); void updateWindowShadow(); bool updateWindowBlurAreasForWM(); void doDelayedUpdateWindowShadow(int delaye = 30); /// update of user properties void updateWindowRadius(); void updateBorderWidth(); void updateBorderColor(); void updateUserClipPath(); void updateFrameMask(); void updateShadowRadius(); void updateShadowOffset(); void updateShadowColor(); void updateTranslucentBackground(); void updateEnableSystemResize(); void updateEnableSystemMove(); void updateEnableBlurWindow(); void updateWindowBlurAreas(); void updateWindowBlurPaths(); void updateAutoInputMaskByClipPath(); void setWindowMargins(const QMargins &margins); void setClipPah(const QPainterPath &path); void setWindowBlurArea(const QVector &area); void paintWindowShadow(QRegion region = QRegion()); void repaintWindowShadow(); inline bool isWidgetWindow() const { return isWidgetWindow(window());} QWidgetWindow *widgetWindow() const; inline QPoint windowOffset() const { return QPoint(windowMargins.left(), windowMargins.top());} inline QRect windowGeometry() const { return QRect(windowOffset(), m_windowSize);} inline int getShadowRadius() const { return m_enableShadow ? m_shadowRadius : 0;} inline QPoint getShadowOffset() const { return m_shadowOffset;} inline int getWindowRadius() const; bool canUseClipPath() const; bool canResize() const; void onWindowStateChanged(); void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event); QSize m_size; QSize m_windowSize; QImage m_image; QXcbBackingStore *m_proxy; WindowEventListener *m_eventListener = Q_NULLPTR; // DXcbShmGraphicsBuffer *m_graphicsBuffer = Q_NULLPTR; DPlatformWindowHook *m_windowHook = Q_NULLPTR; int m_windowRadius = 4; bool isUserSetWindowRadius = false; int m_borderWidth = 1; bool isUserSetClipPath = false; QPainterPath m_clipPath; QPainterPath m_windowClipPath; QColor m_borderColor = QColor(0, 0, 0, 255 * 0.15); int m_shadowRadius = 60; QPoint m_shadowOffset = QPoint(0, 16); QColor m_shadowColor = QColor(0, 0, 0, 255 * 0.6); QPixmap shadowPixmap; bool m_translucentBackground = false; bool m_enableSystemResize = true; bool m_enableSystemMove = true; bool m_enableBlurWindow = false; bool m_autoInputMaskByClipPath = true; bool m_enableShadow = true; QVector m_blurAreaList; QList m_blurPathList; QRect windowValidRect; QMargins windowMargins; bool isUserSetFrameMask = false; QBasicTimer updateShadowTimer; friend class WindowEventListener; #ifndef QT_NO_OPENGL GLuint m_textureId; QSize m_textureSize; bool m_needsSwizzle; bool m_premultiplied; QOpenGLTextureBlitter *m_blitter; #endif }; DPP_END_NAMESPACE Q_DECLARE_METATYPE(QMargins) #endif // DXCBBACKINGSTORE_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformbackingstorehelper.cpp000066400000000000000000000127611325534707400277510ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dplatformbackingstorehelper.h" #include "vtablehook.h" #include "dplatformwindowhelper.h" #include "dframewindow.h" #include "dwmsupport.h" #ifdef Q_OS_LINUX #define private public #include "qxcbbackingstore.h" #undef private #endif #include #include #include #include DPP_BEGIN_NAMESPACE DPlatformBackingStoreHelper::DPlatformBackingStoreHelper() { } bool DPlatformBackingStoreHelper::addBackingStore(QPlatformBackingStore *store) { VtableHook::overrideVfptrFun(store, &QPlatformBackingStore::beginPaint, this, &DPlatformBackingStoreHelper::beginPaint); VtableHook::overrideVfptrFun(store, &QPlatformBackingStore::paintDevice, this, &DPlatformBackingStoreHelper::paintDevice); return VtableHook::overrideVfptrFun(store, &QPlatformBackingStore::flush, this, &DPlatformBackingStoreHelper::flush); } static QThreadStorage _d_dxcb_overridePaintDevice; QPaintDevice *DPlatformBackingStoreHelper::paintDevice() { QPlatformBackingStore *store = backingStore(); if (_d_dxcb_overridePaintDevice.hasLocalData() && _d_dxcb_overridePaintDevice.localData()) { static thread_local QImage device(1, 1, QImage::Format_Alpha8); return &device; } return VtableHook::callOriginalFun(store, &QPlatformBackingStore::paintDevice); } void DPlatformBackingStoreHelper::beginPaint(const QRegion ®ion) { QPlatformBackingStore *store = backingStore(); bool has_alpha = store->window()->property("_d_dxcb_TransparentBackground").toBool(); if (!has_alpha) _d_dxcb_overridePaintDevice.setLocalData(true); VtableHook::callOriginalFun(store, &QPlatformBackingStore::beginPaint, region); _d_dxcb_overridePaintDevice.setLocalData(false); } void DPlatformBackingStoreHelper::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { if (!backingStore()->paintDevice()) return; if (Q_LIKELY(DWMSupport::instance()->hasComposite())) { DPlatformWindowHelper *window_helper = DPlatformWindowHelper::mapped.value(window->handle()); if (!window_helper) goto end; qreal device_pixel_ratio = window_helper->m_nativeWindow->window()->devicePixelRatio(); int window_radius = qRound(window_helper->getWindowRadius() * device_pixel_ratio); // 停止触发内部窗口更新的定时器 if (window_helper->m_frameWindow->m_paintShadowOnContentTimerId > 0) { window_helper->m_frameWindow->killTimer(window_helper->m_frameWindow->m_paintShadowOnContentTimerId); window_helper->m_frameWindow->m_paintShadowOnContentTimerId = -1; } if (window_helper && (window_helper->m_isUserSetClipPath || window_radius > 0)) { QPainterPath path; QRegion new_region = region; // if (!window_helper->m_isUserSetClipPath) { // QRect window_rect(QPoint(0, 0), window_helper->m_nativeWindow->geometry().size()); // new_region += QRect(0, 0, window_radius, window_radius); // new_region += QRect(window_rect.width() - window_radius, // window_rect.height() - window_radius, // window_radius, window_radius); // new_region += QRect(0, window_rect.height() - window_radius, // window_radius, window_radius); // new_region += QRect(window_rect.width() - window_radius, 0, // window_radius, window_radius); // } path.addRegion(new_region); path -= window_helper->m_clipPath * device_pixel_ratio; if (path.isEmpty()) goto end; QPainter pa(backingStore()->paintDevice()); if (!pa.isActive()) goto end; QBrush border_brush(window_helper->m_frameWindow->m_shadowImage); const QPoint &offset = window_helper->m_frameWindow->m_contentGeometry.topLeft() * device_pixel_ratio; border_brush.setMatrix(QMatrix(1, 0, 0, 1, -offset.x(), -offset.y())); pa.setRenderHint(QPainter::Antialiasing); pa.setCompositionMode(QPainter::CompositionMode_Source); pa.fillPath(path, border_brush); if (window_helper->m_borderWidth > 0 && window_helper->m_borderColor != Qt::transparent) { pa.setClipPath(path); pa.setPen(QPen(window_helper->m_borderColor, window_helper->m_borderWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); pa.drawPath(window_helper->m_clipPath); } pa.end(); } } end: return VtableHook::callOriginalFun(this->backingStore(), &QPlatformBackingStore::flush, window, region, offset); } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformbackingstorehelper.h000066400000000000000000000026751325534707400274210ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DPLATFORMBACKINGSTOREHELPER_H #define DPLATFORMBACKINGSTOREHELPER_H #include #include "global.h" QT_BEGIN_NAMESPACE class QPlatformBackingStore; class QWindow; class QRegion; class QPoint; class QPaintDevice; QT_END_NAMESPACE DPP_BEGIN_NAMESPACE class DPlatformBackingStoreHelper { public: DPlatformBackingStoreHelper(); bool addBackingStore(QPlatformBackingStore *store); QPlatformBackingStore *backingStore() const { return reinterpret_cast(const_cast(this));} QPaintDevice *paintDevice(); void beginPaint(const QRegion &); void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); }; DPP_END_NAMESPACE #endif // DPLATFORMBACKINGSTOREHELPER_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformintegration.cpp000066400000000000000000000533731325534707400264250ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dplatformintegration.h" #include "global.h" #include "dforeignplatformwindow.h" #include "vtablehook.h" #ifdef USE_NEW_IMPLEMENTING #include "dplatformwindowhelper.h" #include "dplatformbackingstorehelper.h" #include "dplatformopenglcontexthelper.h" #include "dframewindow.h" #else #include "dplatformbackingstore.h" #include "dplatformwindowhook.h" #endif #ifdef Q_OS_LINUX #define private public #include "qxcbcursor.h" #undef private #include "windoweventhook.h" #include "xcbnativeeventfilter.h" #include "dplatformnativeinterfacehook.h" #include "qxcbscreen.h" #include "qxcbbackingstore.h" #include #include #include #endif #if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) #include #else #include #endif #include #include #include #include #define protected public #include #undef protected #include DPP_BEGIN_NAMESPACE #ifdef Q_OS_LINUX #if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) DPlatformIntegration *DPlatformIntegration::m_instance = Q_NULLPTR; #endif #endif DPlatformIntegration::DPlatformIntegration(const QStringList ¶meters, int &argc, char **argv) : DPlatformIntegrationParent(parameters, argc, argv) #ifdef USE_NEW_IMPLEMENTING , m_storeHelper(new DPlatformBackingStoreHelper) , m_contextHelper(new DPlatformOpenGLContextHelper) #endif { #ifdef Q_OS_LINUX #if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) m_instance = this; #endif #endif VtableHook::overrideVfptrFun(nativeInterface(), &QPlatformNativeInterface::platformFunction, &DPlatformNativeInterfaceHook::platformFunction); } DPlatformIntegration::~DPlatformIntegration() { #ifdef Q_OS_LINUX if (!m_eventFilter) return; qApp->removeNativeEventFilter(m_eventFilter); delete m_eventFilter; #endif #ifdef USE_NEW_IMPLEMENTING delete m_storeHelper; delete m_contextHelper; #endif } QPlatformWindow *DPlatformIntegration::createPlatformWindow(QWindow *window) const { qDebug() << __FUNCTION__ << window << window->type() << window->parent(); if (qEnvironmentVariableIsSet("DXCB_PRINT_WINDOW_CREATE")) { printf("New Window: %s(0x%llx, name: \"%s\")\n", window->metaObject()->className(), (quintptr)window, qPrintable(window->objectName())); } // handle foreign native window if (window->type() == Qt::ForeignWindow && window->property("_q_foreignWinId").isValid()) { return new DForeignPlatformWindow(window); } bool isUseDxcb = window->type() != Qt::Desktop && window->property(useDxcb).toBool(); if (isUseDxcb) { QSurfaceFormat format = window->format(); const int oldAlpha = format.alphaBufferSize(); const int newAlpha = 8; window->setProperty("_d_dxcb_TransparentBackground", format.hasAlpha()); if (!DPlatformWindowHelper::windowRedirectContent(window)) { if (oldAlpha != newAlpha) { format.setAlphaBufferSize(newAlpha); window->setFormat(format); } } } QPlatformWindow *w = DPlatformIntegrationParent::createPlatformWindow(window); QNativeWindow *xw = static_cast(w); if (isUseDxcb) { #ifdef USE_NEW_IMPLEMENTING Q_UNUSED(new DPlatformWindowHelper(xw)) #else Q_UNUSED(new DPlatformWindowHook(xw)) #endif } #ifdef Q_OS_LINUX const DFrameWindow *frame_window = qobject_cast(window); bool rc = frame_window ? DPlatformWindowHelper::windowRedirectContent(frame_window->m_contentWindow) : DPlatformWindowHelper::windowRedirectContent(window); Q_UNUSED(new WindowEventHook(xw, rc)) #endif // QWindow *tp_for_window = window->transientParent(); // if (tp_for_window) { // // reset transient parent // if (DPlatformWindowHelper *helper = DPlatformWindowHelper::mapped.value(tp_for_window->handle())) { // window->setTransientParent(helper->m_frameWindow); // } // } return xw; } QPlatformBackingStore *DPlatformIntegration::createPlatformBackingStore(QWindow *window) const { qDebug() << __FUNCTION__ << window << window->type() << window->parent(); QPlatformBackingStore *store = DPlatformIntegrationParent::createPlatformBackingStore(window); if (window->type() != Qt::Desktop && window->property(useDxcb).toBool()) #ifdef USE_NEW_IMPLEMENTING if (!DPlatformWindowHelper::windowRedirectContent(window)) { m_storeHelper->addBackingStore(store); if (DPlatformWindowHelper *helper = DPlatformWindowHelper::mapped.value(window->handle())) { helper->m_frameWindow->m_contentBackingStore = store; } } #else return new DPlatformBackingStore(window, static_cast(store)); #endif return store; } QPlatformOpenGLContext *DPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { QPlatformOpenGLContext *p_context = DPlatformIntegrationParent::createPlatformOpenGLContext(context); // m_contextHelper->addOpenGLContext(context, p_context); return p_context; } QStringList DPlatformIntegration::themeNames() const { QStringList list = DPlatformIntegrationParent::themeNames(); list.prepend("deepin"); return list; } #ifdef Q_OS_LINUX typedef int (*PtrXcursorLibraryLoadCursor)(void *, const char *); typedef char *(*PtrXcursorLibraryGetTheme)(void *); typedef int (*PtrXcursorLibrarySetTheme)(void *, const char *); typedef int (*PtrXcursorLibraryGetDefaultSize)(void *); #if defined(XCB_USE_XLIB) && !defined(QT_NO_LIBRARY) #include enum { XCursorShape = CursorShape }; #undef CursorShape static PtrXcursorLibraryLoadCursor ptrXcursorLibraryLoadCursor = 0; static PtrXcursorLibraryGetTheme ptrXcursorLibraryGetTheme = 0; static PtrXcursorLibrarySetTheme ptrXcursorLibrarySetTheme = 0; static PtrXcursorLibraryGetDefaultSize ptrXcursorLibraryGetDefaultSize = 0; static xcb_font_t cursorFont = 0; #endif static int cursorIdForShape(int cshape) { int cursorId = 0; switch (cshape) { case Qt::ArrowCursor: cursorId = XC_left_ptr; break; case Qt::UpArrowCursor: cursorId = XC_center_ptr; break; case Qt::CrossCursor: cursorId = XC_crosshair; break; case Qt::WaitCursor: cursorId = XC_watch; break; case Qt::IBeamCursor: cursorId = XC_xterm; break; case Qt::SizeAllCursor: cursorId = XC_fleur; break; case Qt::PointingHandCursor: cursorId = XC_hand2; break; case Qt::SizeBDiagCursor: cursorId = XC_top_right_corner; break; case Qt::SizeFDiagCursor: cursorId = XC_bottom_right_corner; break; case Qt::SizeVerCursor: case Qt::SplitVCursor: cursorId = XC_sb_v_double_arrow; break; case Qt::SizeHorCursor: case Qt::SplitHCursor: cursorId = XC_sb_h_double_arrow; break; case Qt::WhatsThisCursor: cursorId = XC_question_arrow; break; case Qt::ForbiddenCursor: cursorId = XC_circle; break; case Qt::BusyCursor: cursorId = XC_watch; break; default: break; } return cursorId; } static const char * const cursorNames[] = { "left_ptr", "up_arrow", "cross", "wait", "ibeam", "size_ver", "size_hor", "size_bdiag", "size_fdiag", "size_all", "blank", "split_v", "split_h", "pointing_hand", "forbidden", "whats_this", "left_ptr_watch", "openhand", "closedhand", "copy", "move", "link" }; static xcb_cursor_t loadCursor(void *dpy, int cshape) { xcb_cursor_t cursor = XCB_NONE; if (!ptrXcursorLibraryLoadCursor || !dpy) return cursor; switch (cshape) { case Qt::DragCopyCursor: cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-copy"); break; case Qt::DragMoveCursor: cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-move"); break; case Qt::DragLinkCursor: cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-link"); break; default: break; } if (!cursor) { cursor = ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]); } return cursor; } static xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, const QPoint &spot) { #ifdef XCB_USE_RENDER xcb_connection_t *conn = screen->xcb_connection(); const int w = image.width(); const int h = image.height(); xcb_generic_error_t *error = 0; xcb_render_query_pict_formats_cookie_t formatsCookie = xcb_render_query_pict_formats(conn); xcb_render_query_pict_formats_reply_t *formatsReply = xcb_render_query_pict_formats_reply(conn, formatsCookie, &error); if (!formatsReply || error) { qWarning("qt_xcb_createCursorXRender: query_pict_formats failed"); free(formatsReply); free(error); return XCB_NONE; } xcb_render_pictforminfo_t *fmt = xcb_render_util_find_standard_format(formatsReply, XCB_PICT_STANDARD_ARGB_32); if (!fmt) { qWarning("qt_xcb_createCursorXRender: Failed to find format PICT_STANDARD_ARGB_32"); free(formatsReply); return XCB_NONE; } QImage img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); xcb_image_t *xi = xcb_image_create(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP, 32, 32, 32, 32, QSysInfo::ByteOrder == QSysInfo::BigEndian ? XCB_IMAGE_ORDER_MSB_FIRST : XCB_IMAGE_ORDER_LSB_FIRST, XCB_IMAGE_ORDER_MSB_FIRST, 0, 0, 0); if (!xi) { qWarning("qt_xcb_createCursorXRender: xcb_image_create failed"); free(formatsReply); return XCB_NONE; } xi->data = (uint8_t *) malloc(xi->stride * h); if (!xi->data) { qWarning("qt_xcb_createCursorXRender: Failed to malloc() image data"); xcb_image_destroy(xi); free(formatsReply); return XCB_NONE; } memcpy(xi->data, img.constBits(), img.byteCount()); xcb_pixmap_t pix = xcb_generate_id(conn); xcb_create_pixmap(conn, 32, pix, screen->root(), w, h); xcb_render_picture_t pic = xcb_generate_id(conn); xcb_render_create_picture(conn, pic, pix, fmt->id, 0, 0); xcb_gcontext_t gc = xcb_generate_id(conn); xcb_create_gc(conn, gc, pix, 0, 0); xcb_image_put(conn, pix, gc, xi, 0, 0, 0); xcb_free_gc(conn, gc); xcb_cursor_t cursor = xcb_generate_id(conn); xcb_render_create_cursor(conn, cursor, pic, spot.x(), spot.y()); free(xi->data); xcb_image_destroy(xi); xcb_render_free_picture(conn, pic); xcb_free_pixmap(conn, pix); free(formatsReply); return cursor; #else Q_UNUSED(screen); Q_UNUSED(image); Q_UNUSED(spot); return XCB_NONE; #endif } static uint8_t cur_blank_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static xcb_cursor_t overrideCreateNonStandardCursor(QXcbCursor *xcb_cursor, Qt::CursorShape cshape, QWindow *window) { xcb_cursor_t cursor = 0; xcb_connection_t *conn = xcb_cursor->xcb_connection(); QImage image; switch (cshape) { case Qt::BlankCursor: { xcb_pixmap_t cp = xcb_create_pixmap_from_bitmap_data(conn, xcb_cursor->m_screen->root(), cur_blank_bits, 16, 16, 1, 0, 0, 0); xcb_pixmap_t mp = xcb_create_pixmap_from_bitmap_data(conn, xcb_cursor->m_screen->root(), cur_blank_bits, 16, 16, 1, 0, 0, 0); cursor = xcb_generate_id(conn); xcb_create_cursor(conn, cursor, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8); return cursor; } case Qt::SizeVerCursor: image.load(":/bottom_side.png"); break; case Qt::SizeAllCursor: image.load(":/all-scroll.png"); break; case Qt::SplitVCursor: image.load(":/sb_v_double_arrow.png"); break; case Qt::SplitHCursor: image.load(":/sb_h_double_arrow.png"); break; case Qt::WhatsThisCursor: image.load(":/question_arrow.png"); break; case Qt::BusyCursor: image.load(":/left_ptr_watch_0001.png"); break; case Qt::ForbiddenCursor: image.load(":/crossed_circle.png"); break; case Qt::OpenHandCursor: image.load(":/hand1.png"); break; case Qt::ClosedHandCursor: image.load(":/grabbing.png"); break; case Qt::DragCopyCursor: image.load(":/dnd-copy.png"); break; case Qt::DragMoveCursor: image.load(":/dnd-move.png"); break; case Qt::DragLinkCursor: image.load(":/dnd-link.png"); break; default: break; } if (!image.isNull()) { image = image.scaledToWidth(24 * window->devicePixelRatio()); cursor = qt_xcb_createCursorXRender(xcb_cursor->m_screen, image, QPoint(8, 8) * window->devicePixelRatio()); } return cursor; } static bool updateCursorTheme(void *dpy) { if (!ptrXcursorLibraryGetTheme || !ptrXcursorLibrarySetTheme) return false; QByteArray theme = ptrXcursorLibraryGetTheme(dpy); int setTheme = ptrXcursorLibrarySetTheme(dpy,theme.constData()); return setTheme; } static xcb_cursor_t overrideCreateFontCursor(QXcbCursor *xcb_cursor, QCursor *c, QWindow *window) { const Qt::CursorShape cshape = c->shape(); xcb_connection_t *conn = xcb_cursor->xcb_connection(); int cursorId = cursorIdForShape(cshape); xcb_cursor_t cursor = XCB_NONE; // Try Xcursor first #if defined(XCB_USE_XLIB) && !defined(QT_NO_LIBRARY) if (cshape >= 0 && cshape <= Qt::LastCursor) { void *dpy = xcb_cursor->connection()->xlib_display(); // special case for non-standard dnd-* cursors cursor = loadCursor(dpy, cshape); if (!cursor && !xcb_cursor->m_gtkCursorThemeInitialized) { VtableHook::callOriginalFun(xcb_cursor, &QPlatformCursor::changeCursor, c, window); if (updateCursorTheme(dpy)) { cursor = loadCursor(dpy, cshape); } } } if (cursor) return cursor; if (!cursor && cursorId) { #ifdef DISPLAY_FROM_XCB cursor = XCreateFontCursor(DISPLAY_FROM_XCB(xcb_cursor), cursorId); #else cursor = XCreateFontCursor(static_cast(xcb_cursor->connection()->xlib_display()), cursorId); #endif if (cursor) return cursor; } #endif // Non-standard X11 cursors are created from bitmaps cursor = overrideCreateNonStandardCursor(xcb_cursor, cshape, window); // Create a glpyh cursor if everything else failed if (!cursor && cursorId) { cursor = xcb_generate_id(conn); xcb_create_glyph_cursor(conn, cursor, cursorFont, cursorFont, cursorId, cursorId + 1, 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0); } if (cursor && cshape >= 0 && cshape < Qt::LastCursor && xcb_cursor->connection()->hasXFixes()) { const char *name = cursorNames[cshape]; xcb_xfixes_set_cursor_name(conn, cursor, strlen(name), name); } return cursor; } static void overrideChangeCursor(QPlatformCursor *cursorHandle, QCursor * cursor, QWindow * widget) { QXcbWindow *w = 0; if (widget && widget->handle()) w = static_cast(widget->handle()); else // No X11 cursor control when there is no widget under the cursor return; if (widget->property(disableOverrideCursor).toBool()) return; // set cursor size scale static bool xcursrSizeIsSet = qEnvironmentVariableIsSet("XCURSOR_SIZE"); if (!xcursrSizeIsSet) qputenv("XCURSOR_SIZE", QByteArray::number(24 * widget->devicePixelRatio())); QXcbCursor *xcb_cursor = static_cast(cursorHandle); xcb_cursor_t c = XCB_CURSOR_NONE; if (cursor && cursor->shape() != Qt::BitmapCursor) { const QXcbCursorCacheKey key(cursor->shape()); QXcbCursor::CursorHash::iterator it = xcb_cursor->m_cursorHash.find(key); if (it == xcb_cursor->m_cursorHash.end()) { it = xcb_cursor->m_cursorHash.insert(key, overrideCreateFontCursor(xcb_cursor, cursor, widget)); } c = it.value(); #if QT_VERSION < QT_VERSION_CHECK(5, 7, 1) w->setCursor(c); #else w->setCursor(c, false); #endif } VtableHook::callOriginalFun(cursorHandle, &QPlatformCursor::changeCursor, cursor, widget); } static void hookXcbCursor(QScreen *screen) { if (screen && screen->handle()) VtableHook::overrideVfptrFun(screen->handle()->cursor(), &QPlatformCursor::changeCursor, &overrideChangeCursor); } #endif static bool hookDragObjectEventFilter(QObject *drag, QObject *o, QEvent *e) { if (e->type() == QEvent::MouseMove) { return static_cast(drag)->QBasicDrag::eventFilter(o, e); } return VtableHook::callOriginalFun(drag, &QObject::eventFilter, o, e); } #ifdef Q_OS_LINUX typedef QXcbScreen QNativeScreen; #elif defined(Q_OS_WIN) typedef QWindowsScreen QNativeScreen; #endif QWindow *overrideTopLevelAt(QPlatformScreen *s, const QPoint &point) { QWindow *window = static_cast(s)->QNativeScreen::topLevelAt(point); if (DFrameWindow *fw = qobject_cast(window)) { return fw->contentWindow(); } return window; } static void hookScreenGetWindow(QScreen *screen) { if (screen && screen->handle()) VtableHook::overrideVfptrFun(screen->handle(), &QPlatformScreen::topLevelAt, &overrideTopLevelAt); } void DPlatformIntegration::initialize() { // 由于Qt很多代码中写死了是xcb,所以只能伪装成是xcb // FIXME: set platform_name to xcb to avoid webengine crash // It need dtk update tag, make it default when dtk udate if (qEnvironmentVariableIsSet("DXCB_FAKE_PLATFORM_NAME_XCB")) { *QGuiApplicationPrivate::platform_name = "xcb"; } qApp->setProperty("_d_isDxcb", true); QXcbIntegration::initialize(); #ifdef Q_OS_LINUX m_eventFilter = new XcbNativeEventFilter(defaultConnection()); qApp->installNativeEventFilter(m_eventFilter); if (!qEnvironmentVariableIsSet("DXCB_DISABLE_HOOK_CURSOR")) { #if defined(XCB_USE_XLIB) && !defined(QT_NO_LIBRARY) static bool function_ptrs_not_initialized = true; if (function_ptrs_not_initialized) { QLibrary xcursorLib(QLatin1String("Xcursor"), 1); bool xcursorFound = xcursorLib.load(); if (!xcursorFound) { // try without the version number xcursorLib.setFileName(QLatin1String("Xcursor")); xcursorFound = xcursorLib.load(); } if (xcursorFound) { ptrXcursorLibraryLoadCursor = (PtrXcursorLibraryLoadCursor) xcursorLib.resolve("XcursorLibraryLoadCursor"); ptrXcursorLibraryGetTheme = (PtrXcursorLibraryGetTheme) xcursorLib.resolve("XcursorGetTheme"); ptrXcursorLibrarySetTheme = (PtrXcursorLibrarySetTheme) xcursorLib.resolve("XcursorSetTheme"); ptrXcursorLibraryGetDefaultSize = (PtrXcursorLibraryGetDefaultSize) xcursorLib.resolve("XcursorGetDefaultSize"); } function_ptrs_not_initialized = false; } #endif for (QScreen *s : qApp->screens()) { hookXcbCursor(s); } QObject::connect(qApp, &QGuiApplication::screenAdded, qApp, &hookXcbCursor); } #endif VtableHook::overrideVfptrFun(qApp->d_func(), &QGuiApplicationPrivate::isWindowBlocked, this, &DPlatformIntegration::isWindowBlockedHandle); // FIXME(zccrs): 修复启动drag后鼠标从一块屏幕移动到另一块后图标窗口位置不对 VtableHook::overrideVfptrFun(static_cast(drag()), &QObject::eventFilter, &hookDragObjectEventFilter); for (QScreen *s : qApp->screens()) { hookScreenGetWindow(s); } QObject::connect(qApp, &QGuiApplication::screenAdded, qApp, &hookScreenGetWindow); } bool DPlatformIntegration::isWindowBlockedHandle(QWindow *window, QWindow **blockingWindow) { if (DFrameWindow *frame = qobject_cast(window)) { return VtableHook::callOriginalFun(qApp->d_func(), &QGuiApplicationPrivate::isWindowBlocked, frame->m_contentWindow, blockingWindow); } return VtableHook::callOriginalFun(qApp->d_func(), &QGuiApplicationPrivate::isWindowBlocked, window, blockingWindow); } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformintegration.h000066400000000000000000000044731325534707400260670ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GENERICPLUGIN_H #define GENERICPLUGIN_H #include "global.h" #include #ifdef Q_OS_LINUX #include "qxcbintegration.h" typedef QXcbIntegration DPlatformIntegrationParent; #elif defined(Q_OS_WIN) #include "qwindowsgdiintegration.h" typedef QWindowsGdiIntegration DPlatformIntegrationParent; #endif DPP_BEGIN_NAMESPACE class DPlatformWindowHook; class XcbNativeEventFilter; class DPlatformBackingStoreHelper; class DPlatformOpenGLContextHelper; class DPlatformIntegration : public DPlatformIntegrationParent { public: DPlatformIntegration(const QStringList ¶meters, int &argc, char **argv); ~DPlatformIntegration(); QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; QStringList themeNames() const Q_DECL_OVERRIDE; void initialize() Q_DECL_OVERRIDE; #ifdef Q_OS_LINUX #if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) static DPlatformIntegration *instance() { return m_instance; } private: static DPlatformIntegration *m_instance; #endif inline static QXcbConnection *xcbConnection() { return instance()->defaultConnection();} private: XcbNativeEventFilter *m_eventFilter = Q_NULLPTR; #endif private: // handle the DFrameWindow modal blocked state bool isWindowBlockedHandle(QWindow *window, QWindow **blockingWindow); DPlatformBackingStoreHelper *m_storeHelper; DPlatformOpenGLContextHelper *m_contextHelper; }; DPP_END_NAMESPACE #endif // GENERICPLUGIN_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformnativeinterfacehook.cpp000066400000000000000000000100351325534707400301160ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dplatformnativeinterfacehook.h" #include "global.h" #include "utility.h" #include "dplatformwindowhelper.h" #include "dwmsupport.h" #ifdef Q_OS_LINUX #include "qxcbnativeinterface.h" typedef QXcbNativeInterface DPlatformNativeInterface; #elif defined(Q_OS_WIN) #include "qwindowsgdinativeinterface.h" typedef QWindowsGdiNativeInterface DPlatformNativeInterface; #endif DPP_BEGIN_NAMESPACE static QString version() { return QStringLiteral(DXCB_VERSION); } QFunctionPointer DPlatformNativeInterfaceHook::platformFunction(QPlatformNativeInterface *interface, const QByteArray &function) { if (function == setWmBlurWindowBackgroundArea) { return reinterpret_cast(&Utility::blurWindowBackground); } else if (function == setWmBlurWindowBackgroundPathList) { return reinterpret_cast(&Utility::blurWindowBackgroundByPaths); } else if (function == setWmBlurWindowBackgroundMaskImage) { return reinterpret_cast(&Utility::blurWindowBackgroundByImage); } else if (function == hasBlurWindow) { return reinterpret_cast(&Utility::hasBlurWindow); } else if (function == hasComposite) { return reinterpret_cast(&Utility::hasComposite); } else if (function == connectWindowManagerChangedSignal) { return reinterpret_cast(&DWMSupport::connectWindowManagerChangedSignal); } else if (function == connectHasBlurWindowChanged) { return reinterpret_cast(&DWMSupport::connectHasBlurWindowChanged); } else if (function == connectHasCompositeChanged) { return reinterpret_cast(&DWMSupport::connectHasCompositeChanged); } else if (function == getWindows) { return reinterpret_cast(&Utility::getWindows); } else if (function == getCurrentWorkspaceWindows) { return reinterpret_cast(&Utility::getCurrentWorkspaceWindows); } else if (function == connectWindowListChanged) { return reinterpret_cast(&DWMSupport::connectWindowListChanged); } else if (function == setMWMFunctions) { return reinterpret_cast(&DWMSupport::setMWMFunctions); } else if (function == getMWMFunctions) { return reinterpret_cast(&DWMSupport::getMWMFunctions); } else if (function == setMWMDecorations) { return reinterpret_cast(&DWMSupport::setMWMDecorations); } else if (function == getMWMDecorations) { return reinterpret_cast(&DWMSupport::getMWMDecorations); } else if (function == connectWindowMotifWMHintsChanged) { return reinterpret_cast(&DWMSupport::connectWindowMotifWMHintsChanged); } else if (function == popupSystemWindowMenu) { return reinterpret_cast(&DWMSupport::popupSystemWindowMenu); } else if (function == setWindowProperty) { return reinterpret_cast(&DPlatformWindowHelper::setWindowProperty); } else if (function == pluginVersion) { return reinterpret_cast(&version); } #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) return static_cast(interface)->DPlatformNativeInterface::platformFunction(function); #endif return 0; } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformnativeinterfacehook.h000066400000000000000000000021341325534707400275640ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DPLATFORMNATIVEINTERFACE_H #define DPLATFORMNATIVEINTERFACE_H #include #include "global.h" QT_BEGIN_NAMESPACE class QPlatformNativeInterface; QT_END_NAMESPACE DPP_BEGIN_NAMESPACE class DPlatformNativeInterfaceHook { public: static QFunctionPointer platformFunction(QPlatformNativeInterface *interface, const QByteArray &function); }; DPP_END_NAMESPACE #endif // DPLATFORMNATIVEINTERFACE_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformopenglcontexthelper.cpp000066400000000000000000000132361325534707400301650ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dplatformopenglcontexthelper.h" #include "vtablehook.h" #include "dplatformwindowhelper.h" #include "dframewindow.h" #include "dwmsupport.h" #include #include #include #include #include #include #include #include DPP_BEGIN_NAMESPACE DPlatformOpenGLContextHelper::DPlatformOpenGLContextHelper() { } bool DPlatformOpenGLContextHelper::addOpenGLContext(QOpenGLContext *object, QPlatformOpenGLContext *context) { Q_UNUSED(object) return VtableHook::overrideVfptrFun(context, &QPlatformOpenGLContext::swapBuffers, this, &DPlatformOpenGLContextHelper::swapBuffers); } static void drawCornerImage(const QImage &source, const QPoint &source_offset, QPainter *dest, const QPainterPath &dest_path, QOpenGLFunctions *glf) { if (source.isNull()) return; const QRectF &br = dest_path.boundingRect(); if (br.isEmpty()) return; int height = dest->device()->height(); QBrush brush(source); QImage tmp_image(br.size().toSize(), QImage::Format_RGBA8888); glf->glReadPixels(br.x(), height - br.y() - tmp_image.height(), tmp_image.width(), tmp_image.height(), GL_RGBA, GL_UNSIGNED_BYTE, tmp_image.bits()); tmp_image = tmp_image.mirrored(); brush.setMatrix(QMatrix(1, 0, 0, 1, -source_offset.x() - br.x(), -source_offset.y() - br.y())); QPainter pa(&tmp_image); pa.setRenderHint(QPainter::Antialiasing); pa.setCompositionMode(QPainter::CompositionMode_Source); pa.fillPath(dest_path.translated(-br.topLeft()), brush); pa.end(); dest->drawImage(br.topLeft(), tmp_image); } void DPlatformOpenGLContextHelper::swapBuffers(QPlatformSurface *surface) { if (!DWMSupport::instance()->hasComposite()) goto end; if (surface->surface()->surfaceClass() == QSurface::Window) { QWindow *window = static_cast(surface->surface()); DPlatformWindowHelper *window_helper = DPlatformWindowHelper::mapped.value(window->handle()); if (!window_helper) goto end; if (!window_helper->m_isUserSetClipPath && window_helper->getWindowRadius() <= 0) goto end; qreal device_pixel_ratio = window_helper->m_nativeWindow->window()->devicePixelRatio(); QPainterPath path; const QPainterPath &real_clip_path = window_helper->m_clipPath * device_pixel_ratio; const QSize &window_size = window->handle()->geometry().size(); path.addRect(QRect(QPoint(0, 0), window_size)); path -= real_clip_path; if (path.isEmpty()) goto end; QOpenGLPaintDevice device(window_size); QPainter pa_device(&device); pa_device.setCompositionMode(QPainter::CompositionMode_Source); if (window_helper->m_isUserSetClipPath) { const QRect &content_rect = QRect(window_helper->m_frameWindow->contentOffsetHint() * device_pixel_ratio, window_size); QBrush border_brush(window_helper->m_frameWindow->platformBackingStore->toImage()); border_brush.setMatrix(QMatrix(1, 0, 0, 1, -content_rect.x(), -content_rect.y())); pa_device.fillPath(path, border_brush); } else { const QImage &frame_image = window_helper->m_frameWindow->platformBackingStore->toImage(); const QRect background_rect(QPoint(0, 0), window_size); const QPoint offset = window_helper->m_frameWindow->contentOffsetHint() * device_pixel_ratio; QRect corner_rect(0, 0, window_helper->m_windowRadius * device_pixel_ratio, window_helper->m_windowRadius * device_pixel_ratio); QPainterPath corner_path; QOpenGLFunctions *gl_funcs = QOpenGLContext::currentContext()->functions(); // draw top-left corner_path.addRect(corner_rect); drawCornerImage(frame_image, offset, &pa_device, corner_path - real_clip_path, gl_funcs); // draw top-right corner_rect.moveTopRight(background_rect.topRight()); corner_path = QPainterPath(); corner_path.addRect(corner_rect); drawCornerImage(frame_image, offset, &pa_device, corner_path - real_clip_path, gl_funcs); // draw bottom-left corner_rect.moveBottomLeft(background_rect.bottomLeft()); corner_path = QPainterPath(); corner_path.addRect(corner_rect); drawCornerImage(frame_image, offset, &pa_device, corner_path - real_clip_path, gl_funcs); // draw bottom-right corner_rect.moveBottomRight(background_rect.bottomRight()); corner_path = QPainterPath(); corner_path.addRect(corner_rect); drawCornerImage(frame_image, offset, &pa_device, corner_path - real_clip_path, gl_funcs); } pa_device.end(); } end: VtableHook::callOriginalFun(this->context(), &QPlatformOpenGLContext::swapBuffers, surface); } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformopenglcontexthelper.h000066400000000000000000000025761325534707400276370ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DPLATFORMOPENGLCONTEXTHELPER_H #define DPLATFORMOPENGLCONTEXTHELPER_H #include #include "global.h" QT_BEGIN_NAMESPACE class QPlatformOpenGLContext; class QPlatformSurface; class QOpenGLContext; QT_END_NAMESPACE DPP_BEGIN_NAMESPACE class DPlatformOpenGLContextHelper { public: DPlatformOpenGLContextHelper(); bool addOpenGLContext(QOpenGLContext *object, QPlatformOpenGLContext *context); QPlatformOpenGLContext *context() const { return reinterpret_cast(const_cast(this));} void initialize(); void swapBuffers(QPlatformSurface *surface); }; DPP_END_NAMESPACE #endif // DPLATFORMOPENGLCONTEXTHELPER_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformwindowhelper.cpp000066400000000000000000001303661325534707400266070ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dplatformwindowhelper.h" #include "dplatformintegration.h" #include "dframewindow.h" #include "vtablehook.h" #include "dwmsupport.h" #ifdef Q_OS_LINUX #include "qxcbwindow.h" #include #include #include #endif #include #include #include Q_DECLARE_METATYPE(QPainterPath) Q_DECLARE_METATYPE(QMargins) DPP_BEGIN_NAMESPACE #define HOOK_VFPTR(Fun) VtableHook::overrideVfptrFun(window, &QPlatformWindow::Fun, this, &DPlatformWindowHelper::Fun) #define CALL this->window()->QNativeWindow PUBLIC_CLASS(QWindow, DPlatformWindowHelper); PUBLIC_CLASS(QMouseEvent, DPlatformWindowHelper); PUBLIC_CLASS(QDropEvent, DPlatformWindowHelper); PUBLIC_CLASS(QNativeWindow, DPlatformWindowHelper); QHash DPlatformWindowHelper::mapped; DPlatformWindowHelper::DPlatformWindowHelper(QNativeWindow *window) : QObject(window->window()) , m_nativeWindow(window) { mapped[window] = this; m_frameWindow = new DFrameWindow(window->window()); m_frameWindow->setFlags((window->window()->flags() | Qt::FramelessWindowHint | Qt::CustomizeWindowHint | Qt::NoDropShadowWindowHint) & ~Qt::WindowMinMaxButtonsHint); m_frameWindow->create(); m_frameWindow->installEventFilter(this); m_frameWindow->setShadowRadius(getShadowRadius()); m_frameWindow->setShadowColor(m_shadowColor); m_frameWindow->setShadowOffset(m_shadowOffset); m_frameWindow->setBorderWidth(m_borderWidth); m_frameWindow->setBorderColor(getBorderColor()); m_frameWindow->setEnableSystemMove(m_enableSystemMove); m_frameWindow->setEnableSystemResize(m_enableSystemResize); window->setParent(m_frameWindow->handle()); window->window()->installEventFilter(this); window->window()->setScreen(m_frameWindow->screen()); window->window()->setProperty("_d_real_winId", window->winId()); window->window()->setProperty(::frameMargins, QVariant::fromValue(m_frameWindow->contentMarginsHint())); #ifdef Q_OS_LINUX if (windowRedirectContent(window->window())) { xcb_composite_redirect_window(window->xcb_connection(), window->xcb_window(), XCB_COMPOSITE_REDIRECT_MANUAL); damage_id = xcb_generate_id(window->xcb_connection()); xcb_damage_create(window->xcb_connection(), damage_id, window->xcb_window(), XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY); } #endif updateClipPathByWindowRadius(window->window()->size()); updateClipPathFromProperty(); updateFrameMaskFromProperty(); updateWindowRadiusFromProperty(); updateBorderWidthFromProperty(); updateBorderColorFromProperty(); updateShadowRadiusFromProperty(); updateShadowOffsetFromProperty(); updateShadowColorFromProperty(); updateEnableSystemResizeFromProperty(); updateEnableSystemMoveFromProperty(); updateEnableBlurWindowFromProperty(); updateWindowBlurAreasFromProperty(); updateWindowBlurPathsFromProperty(); updateAutoInputMaskByClipPathFromProperty(); HOOK_VFPTR(setGeometry); HOOK_VFPTR(geometry); HOOK_VFPTR(normalGeometry); HOOK_VFPTR(frameMargins); HOOK_VFPTR(setVisible); HOOK_VFPTR(setWindowFlags); HOOK_VFPTR(setWindowState); HOOK_VFPTR(winId); HOOK_VFPTR(setParent); HOOK_VFPTR(setWindowTitle); HOOK_VFPTR(setWindowFilePath); HOOK_VFPTR(setWindowIcon); HOOK_VFPTR(raise); HOOK_VFPTR(lower); // HOOK_VFPTR(isExposed); HOOK_VFPTR(isEmbedded); HOOK_VFPTR(setOpacity); HOOK_VFPTR(propagateSizeHints); HOOK_VFPTR(requestActivateWindow); // HOOK_VFPTR(setKeyboardGrabEnabled); // HOOK_VFPTR(setMouseGrabEnabled); HOOK_VFPTR(setWindowModified); // HOOK_VFPTR(windowEvent); HOOK_VFPTR(startSystemResize); HOOK_VFPTR(setFrameStrutEventsEnabled); HOOK_VFPTR(frameStrutEventsEnabled); HOOK_VFPTR(setAlertState); HOOK_VFPTR(isAlertState); connect(m_frameWindow, &DFrameWindow::contentMarginsHintChanged, this, &DPlatformWindowHelper::onFrameWindowContentMarginsHintChanged); connect(DWMSupport::instance(), &DXcbWMSupport::hasCompositeChanged, this, &DPlatformWindowHelper::onWMHasCompositeChanged); connect(DWMSupport::instance(), &DXcbWMSupport::windowManagerChanged, this, &DPlatformWindowHelper::updateWindowBlurAreasForWM); connect(m_frameWindow, &DFrameWindow::screenChanged, window->window(), &QWindow::setScreen); connect(m_frameWindow, &DFrameWindow::contentOrientationChanged, window->window(), &QWindow::reportContentOrientationChange); static_cast(window)->propagateSizeHints(); } DPlatformWindowHelper::~DPlatformWindowHelper() { mapped.remove(m_nativeWindow); m_frameWindow->deleteLater(); #ifdef Q_OS_LINUX // clear damage xcb_damage_destroy(DPlatformIntegration::xcbConnection()->xcb_connection(), damage_id); #endif } DPlatformWindowHelper *DPlatformWindowHelper::me() const { return DPlatformWindowHelper::mapped.value(window()); } void DPlatformWindowHelper::setGeometry(const QRect &rect) { DPlatformWindowHelper *helper = me(); qreal device_pixel_ratio = helper->m_frameWindow->devicePixelRatio(); // update clip path helper->updateClipPathByWindowRadius(rect.size() / device_pixel_ratio); const QMargins &content_margins = helper->m_frameWindow->contentMarginsHint() * device_pixel_ratio; qt_window_private(helper->m_frameWindow)->positionAutomatic = qt_window_private(helper->m_nativeWindow->window())->positionAutomatic; helper->m_frameWindow->handle()->setGeometry(rect + content_margins); // NOTE(zccrs): 此处必须要更新内容窗口的大小,因为frame窗口大小改变后可能不会触发resize事件调用updateContentWindowGeometry() // 就会导致内容窗口大小不对,此问题可在文件管理器复制文件对话框重现(多试几次) helper->setNativeWindowGeometry(rect, true); helper->m_nativeWindow->QPlatformWindow::setGeometry(rect); } QRect DPlatformWindowHelper::geometry() const { DPlatformWindowHelper *helper = me(); const QRect &geometry = helper->m_frameWindow->handle()->geometry(); if (geometry.topLeft() == QPoint(0, 0) && geometry.size() == QSize(0, 0)) return geometry; QRect rect = geometry - helper->m_frameWindow->contentMarginsHint() * helper->m_frameWindow->devicePixelRatio(); rect.setSize(helper->m_nativeWindow->QNativeWindow::geometry().size()); return rect; } QRect DPlatformWindowHelper::normalGeometry() const { return me()->m_frameWindow->handle()->normalGeometry(); } QMargins DPlatformWindowHelper::frameMargins() const { return me()->m_frameWindow->handle()->frameMargins(); } QWindow *topvelWindow(QWindow *w) { QWindow *tw = w; while (tw->parent()) tw = tw->parent(); DPlatformWindowHelper *helper = DPlatformWindowHelper::mapped.value(tw->handle()); return helper ? helper->m_frameWindow : tw; } void DPlatformWindowHelper::setVisible(bool visible) { DPlatformWindowHelper *helper = me(); if (visible) { QWindow *tp = helper->m_nativeWindow->window()->transientParent(); helper->m_nativeWindow->window()->setTransientParent(helper->m_frameWindow); if (tp) { QWindow *tw = topvelWindow(tp); if (tw != helper->m_frameWindow) helper->m_frameWindow->setTransientParent(tw); } #ifdef Q_OS_LINUX // reupdate _MOTIF_WM_HINTS DQNativeWindow *window = static_cast(helper->m_frameWindow->handle()); Utility::QtMotifWmHints mwmhints = Utility::getMotifWmHints(window->m_window); if (window->window()->modality() != Qt::NonModal) { switch (window->window()->modality()) { case Qt::WindowModal: mwmhints.input_mode = DXcbWMSupport::MWM_INPUT_PRIMARY_APPLICATION_MODAL; break; case Qt::ApplicationModal: default: mwmhints.input_mode = DXcbWMSupport::MWM_INPUT_FULL_APPLICATION_MODAL; break; } mwmhints.flags |= DXcbWMSupport::MWM_HINTS_INPUT_MODE; } else { mwmhints.input_mode = DXcbWMSupport::MWM_INPUT_MODELESS; mwmhints.flags &= ~DXcbWMSupport::MWM_HINTS_INPUT_MODE; } QWindow *content_window = helper->m_nativeWindow->window(); Utility::QtMotifWmHints cw_hints = Utility::getMotifWmHints(helper->m_nativeWindow->QNativeWindow::winId()); bool size_fixed = content_window->minimumSize() == content_window->maximumSize(); if (size_fixed) { // fixed size, remove the resize handle (since mwm/dtwm // isn't smart enough to do it itself) mwmhints.flags |= DXcbWMSupport::MWM_HINTS_FUNCTIONS; if (mwmhints.functions & DXcbWMSupport::MWM_FUNC_ALL) { mwmhints.functions = DXcbWMSupport::MWM_FUNC_MOVE; } else { mwmhints.functions &= ~DXcbWMSupport::MWM_FUNC_RESIZE; } if (mwmhints.decorations & DXcbWMSupport::MWM_DECOR_ALL) { mwmhints.flags |= DXcbWMSupport::MWM_HINTS_DECORATIONS; mwmhints.decorations = (DXcbWMSupport::MWM_DECOR_BORDER | DXcbWMSupport::MWM_DECOR_TITLE | DXcbWMSupport::MWM_DECOR_MENU); } else { mwmhints.decorations &= ~DXcbWMSupport::MWM_DECOR_RESIZEH; } // set content window decoration hints cw_hints.flags |= DXcbWMSupport::MWM_HINTS_DECORATIONS; cw_hints.decorations = DXcbWMSupport::MWM_DECOR_MINIMIZE; } if (content_window->flags() & Qt::WindowMinimizeButtonHint) { mwmhints.functions |= DXcbWMSupport::MWM_FUNC_MINIMIZE; cw_hints.decorations |= DXcbWMSupport::MWM_DECOR_MINIMIZE; } if (content_window->flags() & Qt::WindowMaximizeButtonHint) { mwmhints.functions |= DXcbWMSupport::MWM_FUNC_MAXIMIZE; if (!size_fixed) cw_hints.decorations |= DXcbWMSupport::MWM_DECOR_MAXIMIZE; } if (content_window->flags() & Qt::WindowCloseButtonHint) { mwmhints.functions |= DXcbWMSupport::MWM_FUNC_CLOSE; } if (content_window->flags() & Qt::WindowTitleHint) { cw_hints.decorations |= DXcbWMSupport::MWM_DECOR_TITLE; } if (content_window->flags() & Qt::WindowSystemMenuHint) { cw_hints.decorations |= DXcbWMSupport::MWM_DECOR_MENU; } #endif helper->m_frameWindow->setVisible(visible); helper->updateContentWindowGeometry(); helper->m_nativeWindow->QNativeWindow::setVisible(visible); helper->updateWindowBlurAreasForWM(); // restore if (tp) helper->m_nativeWindow->window()->setTransientParent(tp); #ifdef Q_OS_LINUX // Fix the window can't show minimized if window is fixed size Utility::setMotifWmHints(window->m_window, mwmhints); Utility::setMotifWmHints(helper->m_nativeWindow->QNativeWindow::winId(), cw_hints); #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) // 当Qt版本在5.9及以上时, 如果窗口设置了BypassWindowManagerHint标志, 窗口就无法通过鼠标点击获得焦点 if (helper->m_nativeWindow->window()->flags().testFlag(Qt::BypassWindowManagerHint) && QGuiApplication::modalWindow() == helper->m_nativeWindow->window()) { helper->m_nativeWindow->requestActivateWindow(); } #endif return; } helper->m_frameWindow->setVisible(visible); helper->m_nativeWindow->QNativeWindow::setVisible(visible); helper->updateWindowBlurAreasForWM(); } void DPlatformWindowHelper::setWindowFlags(Qt::WindowFlags flags) { me()->m_frameWindow->setFlags((flags | Qt::FramelessWindowHint | Qt::CustomizeWindowHint | Qt::NoDropShadowWindowHint) & ~Qt::WindowMinMaxButtonsHint); window()->QNativeWindow::setWindowFlags(flags); } #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) void DPlatformWindowHelper::setWindowState(Qt::WindowState state) #else void DPlatformWindowHelper::setWindowState(Qt::WindowStates state) #endif { #ifdef Q_OS_LINUX DQNativeWindow *window = static_cast(me()->m_frameWindow->handle()); if (window->m_windowState == state) return; if (state == Qt::WindowMinimized && (window->m_windowState == Qt::WindowMaximized || window->m_windowState == Qt::WindowFullScreen)) { window->changeNetWmState(true, Utility::internAtom("_NET_WM_STATE_HIDDEN")); Utility::XIconifyWindow(window->connection()->xlib_display(), window->m_window, window->connection()->primaryScreenNumber()); window->connection()->sync(); window->m_windowState = state; } else #endif { #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) me()->m_frameWindow->setWindowState(state); #else me()->m_frameWindow->setWindowStates(state); #endif } } WId DPlatformWindowHelper::winId() const { return me()->m_frameWindow->handle()->winId(); } void DPlatformWindowHelper::setParent(const QPlatformWindow *window) { me()->m_frameWindow->handle()->setParent(window); } void DPlatformWindowHelper::setWindowTitle(const QString &title) { me()->m_frameWindow->handle()->setWindowTitle(title); } void DPlatformWindowHelper::setWindowFilePath(const QString &title) { me()->m_frameWindow->handle()->setWindowFilePath(title); } void DPlatformWindowHelper::setWindowIcon(const QIcon &icon) { me()->m_frameWindow->handle()->setWindowIcon(icon); } void DPlatformWindowHelper::raise() { me()->m_frameWindow->handle()->raise(); } void DPlatformWindowHelper::lower() { me()->m_frameWindow->handle()->lower(); } bool DPlatformWindowHelper::isExposed() const { return me()->m_frameWindow->handle()->isExposed(); } #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) bool DPlatformWindowHelper::isEmbedded() const { return me()->m_frameWindow->handle()->isEmbedded(); } #else bool DPlatformWindowHelper::isEmbedded(const QPlatformWindow *parentWindow) const { return me()->m_frameWindow->handle()->isEmbedded(parentWindow); } #endif void DPlatformWindowHelper::propagateSizeHints() { me()->updateSizeHints(); const QWindow *window = this->window()->window(); if (window->maximumSize() == window->minimumSize()) { Utility::QtMotifWmHints cw_hints = Utility::getMotifWmHints(this->window()->QNativeWindow::winId()); cw_hints.flags |= DXcbWMSupport::MWM_HINTS_DECORATIONS; cw_hints.decorations = DXcbWMSupport::MWM_DECOR_MINIMIZE; if (window->flags() & Qt::WindowTitleHint) { cw_hints.decorations |= DXcbWMSupport::MWM_DECOR_TITLE; } if (window->flags() & Qt::WindowSystemMenuHint) { cw_hints.decorations |= DXcbWMSupport::MWM_DECOR_MENU; } Utility::setMotifWmHints(this->window()->QNativeWindow::winId(), cw_hints); } } void DPlatformWindowHelper::setOpacity(qreal level) { me()->m_frameWindow->setOpacity(level); } void DPlatformWindowHelper::requestActivateWindow() { DPlatformWindowHelper *helper = me(); #ifdef Q_OS_LINUX if (helper->m_frameWindow->handle()->isExposed() && !DXcbWMSupport::instance()->hasComposite() && helper->m_frameWindow->windowState() == Qt::WindowMinimized) { #ifdef Q_XCB_CALL Q_XCB_CALL(xcb_map_window(DPlatformIntegration::xcbConnection()->xcb_connection(), helper->m_frameWindow->winId())); #else xcb_map_window(DPlatformIntegration::xcbConnection()->xcb_connection(), helper->m_frameWindow->winId()); #endif } #endif helper->m_frameWindow->handle()->requestActivateWindow(); } bool DPlatformWindowHelper::setKeyboardGrabEnabled(bool grab) { return me()->m_frameWindow->handle()->setKeyboardGrabEnabled(grab); } bool DPlatformWindowHelper::setMouseGrabEnabled(bool grab) { return me()->m_frameWindow->handle()->setMouseGrabEnabled(grab); } bool DPlatformWindowHelper::setWindowModified(bool modified) { return me()->m_frameWindow->handle()->setWindowModified(modified); } bool DPlatformWindowHelper::startSystemResize(const QPoint &pos, Qt::Corner corner) { return me()->m_frameWindow->handle()->startSystemResize(pos, corner); } void DPlatformWindowHelper::setFrameStrutEventsEnabled(bool enabled) { me()->m_frameWindow->handle()->setFrameStrutEventsEnabled(enabled); } bool DPlatformWindowHelper::frameStrutEventsEnabled() const { return me()->m_frameWindow->handle()->frameStrutEventsEnabled(); } void DPlatformWindowHelper::setAlertState(bool enabled) { me()->m_frameWindow->handle()->setAlertState(enabled); } bool DPlatformWindowHelper::isAlertState() const { return me()->m_frameWindow->handle()->isAlertState(); } bool DPlatformWindowHelper::windowRedirectContent(QWindow *window) { const QVariant &value = window->property(redirectContent); if (value.type() == QVariant::Bool) return value.toBool(); if (qEnvironmentVariableIsSet("DXCB_REDIRECT_CONTENT")) { const QByteArray &value = qgetenv("DXCB_REDIRECT_CONTENT"); if (value == "true") { window->setProperty(redirectContent, true); return true; } else if (value == "false") { return false; } } return window->surfaceType() == QSurface::OpenGLSurface; } bool DPlatformWindowHelper::eventFilter(QObject *watched, QEvent *event) { if (watched == m_frameWindow) { switch ((int)event->type()) { case QEvent::Close: m_nativeWindow->window()->close(); break; case QEvent::KeyPress: case QEvent::KeyRelease: case QEvent::WindowDeactivate: QCoreApplication::sendEvent(m_nativeWindow->window(), event); return true; case QEvent::Move: { QRect geometry = m_frameWindow->handle()->geometry(); if (geometry.topLeft() != QPoint(0, 0) || geometry.size() != QSize(0, 0)) { geometry.translate(-m_frameWindow->contentOffsetHint()); geometry.setSize(m_nativeWindow->QNativeWindow::geometry().size()); } m_nativeWindow->QPlatformWindow::setGeometry(geometry); QWindowSystemInterface::handleGeometryChange(m_nativeWindow->window(), geometry); return true; } case QEvent::FocusIn: QWindowSystemInterface::handleWindowActivated(m_nativeWindow->window(), static_cast(event)->reason()); return true; case QEvent::WindowActivate: QWindowSystemInterface::handleWindowActivated(m_nativeWindow->window(), Qt::OtherFocusReason); return true; case QEvent::Resize: { updateContentWindowGeometry(); break; } case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { DQMouseEvent *e = static_cast(event); const QRectF rectF(m_windowVaildGeometry); const QPointF posF(e->localPos() - m_frameWindow->contentOffsetHint()); // QRectF::contains中判断时加入了右下边界 if (!qFuzzyCompare(posF.x(), rectF.width()) && !qFuzzyCompare(posF.y(), rectF.height()) && rectF.contains(posF)) { m_frameWindow->unsetCursor(); e->l = e->w = m_nativeWindow->window()->mapFromGlobal(e->globalPos()); qApp->sendEvent(m_nativeWindow->window(), e); return true; } break; } case QEvent::WindowStateChange: qt_window_private(m_nativeWindow->window())->windowState = m_frameWindow->windowState(); QCoreApplication::sendEvent(m_nativeWindow->window(), event); updateClipPathByWindowRadius(m_nativeWindow->window()->size()); break; case QEvent::DragEnter: case QEvent::DragMove: case QEvent::DragLeave: case QEvent::Drop: { DQDropEvent *e = static_cast(event); e->p -= m_frameWindow->contentOffsetHint(); QCoreApplication::sendEvent(m_nativeWindow->window(), event); return true; } case QEvent::PlatformSurface: { const QPlatformSurfaceEvent *e = static_cast(event); if (e->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) m_nativeWindow->window()->destroy(); break; } case QEvent::Expose: { // ###(zccrs): 在频繁切换窗口管理器时,可能会出现frame窗口被外部(可能是窗管)调用map // 但是content窗口还是隐藏状态,所以在此做状态检查和同步 if (m_frameWindow->handle()->isExposed() && !m_nativeWindow->isExposed()) { m_nativeWindow->setVisible(true); } } default: break; } } else if (watched == m_nativeWindow->window()) { switch ((int)event->type()) { case QEvent::MouseMove: { if (qApp->mouseButtons() != Qt::LeftButton) break; static QEvent *last_event = NULL; if (last_event == event) { last_event = NULL; return false; } last_event = event; QCoreApplication::sendEvent(watched, event); if (!event->isAccepted()) { DQMouseEvent *e = static_cast(event); e->l = e->w = m_frameWindow->mapFromGlobal(e->globalPos()); QGuiApplicationPrivate::setMouseEventSource(e, Qt::MouseEventSynthesizedByQt); m_frameWindow->mouseMoveEvent(e); return true; } break; } case QEvent::MouseButtonRelease: { if (m_frameWindow->m_isSystemMoveResizeState) { Utility::cancelWindowMoveResize(Utility::getNativeTopLevelWindow(m_frameWindow->winId())); m_frameWindow->m_isSystemMoveResizeState = false; } break; } case QEvent::PlatformSurface: { const QPlatformSurfaceEvent *e = static_cast(event); if (e->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) m_frameWindow->create(); break; } case QEvent::Resize: if (m_isUserSetClipPath) { setWindowVaildGeometry(m_clipPath.boundingRect().toRect() & QRect(QPoint(0, 0), static_cast(event)->size())); } else { updateClipPathByWindowRadius(static_cast(event)->size()); } break; // ###(zccrs): 在9b1a28e6这个提交中因为调用了内部窗口的setVisible,所以需要过滤掉visible为false时产生的不必要的Leave事件 // 这段代码会引起窗口被其它窗口覆盖时的Leave事件丢失 // 因为已经移除了setVisible相关的代码,故先注释掉这部分代码,看是否有不良影响 // case QEvent::Leave: { // QWindow::Visibility visibility = m_nativeWindow->window()->visibility(); // if (visibility == QWindow::Hidden || visibility == QWindow::Minimized || !m_nativeWindow->window()->isActive()) // break; // const QPoint &pos = Utility::translateCoordinates(QPoint(0, 0), m_nativeWindow->winId(), // DPlatformIntegration::instance()->defaultConnection()->rootWindow()); // const QPoint &cursor_pos = qApp->primaryScreen()->handle()->cursor()->pos(); // return m_clipPath.contains(QPointF(cursor_pos - pos) / m_nativeWindow->window()->devicePixelRatio()); // } default: break; } } return false; } void DPlatformWindowHelper::setNativeWindowGeometry(const QRect &rect, bool onlyResize) { qt_window_private(m_nativeWindow->window())->parentWindow = m_frameWindow; qt_window_private(m_nativeWindow->window())->positionAutomatic = onlyResize; m_nativeWindow->QNativeWindow::setGeometry(rect); qt_window_private(m_nativeWindow->window())->parentWindow = 0; qt_window_private(m_nativeWindow->window())->positionAutomatic = false; updateWindowNormalHints(); } void DPlatformWindowHelper::updateClipPathByWindowRadius(const QSize &windowSize) { if (!m_isUserSetClipPath) { setWindowVaildGeometry(QRect(QPoint(0, 0), windowSize)); int window_radius = getWindowRadius(); QPainterPath path; path.addRoundedRect(m_windowVaildGeometry, window_radius, window_radius); setClipPath(path); } } void DPlatformWindowHelper::setClipPath(const QPainterPath &path) { if (m_clipPath == path) return; m_clipPath = path; if (m_isUserSetClipPath) { setWindowVaildGeometry(m_clipPath.boundingRect().toRect() & QRect(QPoint(0, 0), m_nativeWindow->window()->size())); } const QPainterPath &real_path = m_clipPath * m_nativeWindow->window()->devicePixelRatio(); QPainterPathStroker stroker; stroker.setJoinStyle(Qt::MiterJoin); stroker.setWidth(4 * m_nativeWindow->window()->devicePixelRatio()); Utility::setShapePath(m_nativeWindow->QNativeWindow::winId(), stroker.createStroke(real_path).united(real_path), m_frameWindow->m_redirectContent || !m_isUserSetClipPath, m_nativeWindow->window()->flags().testFlag(Qt::WindowTransparentForInput)); updateWindowBlurAreasForWM(); updateContentPathForFrameWindow(); } void DPlatformWindowHelper::setWindowVaildGeometry(const QRect &geometry) { if (geometry == m_windowVaildGeometry) return; m_windowVaildGeometry = geometry; // The native window geometry may not update now, need to waiting for reisze // event is procceed. QTimer::singleShot(1, this, &DPlatformWindowHelper::updateWindowBlurAreasForWM); } bool DPlatformWindowHelper::updateWindowBlurAreasForWM() { // NOTE(zccrs): 当窗口unmap时清理模糊区域的属性,否则可能会导致窗口已经隐藏,但模糊区域没有消失的问题。因为窗口管理器不是绝对根据窗口是否map来绘制 // 模糊背景,当窗口unmap但是窗口的WM State值为Normal时也会绘制模糊背景(这种情况可能出现在连续多次快速切换窗口管理器时) if (!m_nativeWindow->window()->isVisible() || (!m_enableBlurWindow && m_blurAreaList.isEmpty() && m_blurPathList.isEmpty())) { Utility::clearWindowBlur(m_frameWindow->winId()); return true; } qreal device_pixel_ratio = m_nativeWindow->window()->devicePixelRatio(); const QRect &windowValidRect = m_windowVaildGeometry * device_pixel_ratio; if (windowValidRect.isEmpty() || !m_nativeWindow->window()->isVisible()) return false; quint32 top_level_w = Utility::getNativeTopLevelWindow(m_frameWindow->winId()); QPoint offset = m_frameWindow->contentOffsetHint() * device_pixel_ratio; if (top_level_w != m_frameWindow->winId()) { offset += Utility::translateCoordinates(QPoint(0, 0), m_frameWindow->winId(), top_level_w); } QVector newAreas; if (m_enableBlurWindow) { if (m_isUserSetClipPath) { QList list; list << (m_clipPath * device_pixel_ratio).translated(offset); return Utility::blurWindowBackgroundByPaths(top_level_w, list); } Utility::BlurArea area; area.x = windowValidRect.x() + offset.x(); area.y = windowValidRect.y() + offset.y(); area.width = windowValidRect.width(); area.height = windowValidRect.height(); area.xRadius = getWindowRadius() * device_pixel_ratio; area.yRaduis = getWindowRadius() * device_pixel_ratio; newAreas.append(std::move(area)); return Utility::blurWindowBackground(top_level_w, newAreas); } QPainterPath window_vaild_path; window_vaild_path.addRect(QRect(offset, m_nativeWindow->QPlatformWindow::geometry().size())); window_vaild_path &= (m_clipPath * device_pixel_ratio).translated(offset); if (m_blurPathList.isEmpty()) { if (m_blurAreaList.isEmpty()) return true; newAreas.reserve(m_blurAreaList.size()); foreach (Utility::BlurArea area, m_blurAreaList) { area *= device_pixel_ratio; area.x += offset.x(); area.y += offset.y(); QPainterPath path; path.addRoundedRect(area.x, area.y, area.width, area.height, area.xRadius, area.yRaduis); if (!window_vaild_path.contains(path)) { const QPainterPath vaild_blur_path = window_vaild_path & path; const QRectF vaild_blur_rect = vaild_blur_path.boundingRect(); if (path.boundingRect() != vaild_blur_rect) { area.x = vaild_blur_rect.x(); area.y = vaild_blur_rect.y(); area.width = vaild_blur_rect.width(); area.height = vaild_blur_rect.height(); path = QPainterPath(); path.addRoundedRect(vaild_blur_rect.x(), vaild_blur_rect.y(), vaild_blur_rect.width(), vaild_blur_rect.height(), area.xRadius, area.yRaduis); if (vaild_blur_path != path) { break; } } else if (vaild_blur_path != path) { break; } } newAreas.append(std::move(area)); } if (newAreas.size() == m_blurAreaList.size()) return Utility::blurWindowBackground(top_level_w, newAreas); } QList newPathList; newPathList.reserve(m_blurAreaList.size()); foreach (Utility::BlurArea area, m_blurAreaList) { QPainterPath path; area *= device_pixel_ratio; path.addRoundedRect(area.x + offset.x(), area.y + offset.y(), area.width, area.height, area.xRadius, area.yRaduis); path = path.intersected(window_vaild_path); if (!path.isEmpty()) newPathList << path; } if (!m_blurPathList.isEmpty()) { newPathList.reserve(newPathList.size() + m_blurPathList.size()); foreach (const QPainterPath &path, m_blurPathList) { newPathList << (path * device_pixel_ratio).translated(offset).intersected(window_vaild_path); } } if (newPathList.isEmpty()) return true; return Utility::blurWindowBackgroundByPaths(top_level_w, newPathList); } void DPlatformWindowHelper::updateSizeHints() { const QMargins &content_margins = m_frameWindow->contentMarginsHint(); const QSize extra_size(content_margins.left() + content_margins.right(), content_margins.top() + content_margins.bottom()); qt_window_private(m_frameWindow)->minimumSize = m_nativeWindow->window()->minimumSize() + extra_size; qt_window_private(m_frameWindow)->maximumSize = m_nativeWindow->window()->maximumSize() + extra_size; qt_window_private(m_frameWindow)->baseSize = m_nativeWindow->window()->baseSize() + extra_size; qt_window_private(m_frameWindow)->sizeIncrement = m_nativeWindow->window()->sizeIncrement(); m_frameWindow->handle()->propagateSizeHints(); updateWindowNormalHints(); } void DPlatformWindowHelper::updateContentPathForFrameWindow() { if (m_isUserSetClipPath) { m_frameWindow->setContentPath(m_clipPath); } else { m_frameWindow->setContentRoundedRect(m_windowVaildGeometry, getWindowRadius()); } } void DPlatformWindowHelper::updateContentWindowGeometry() { const auto windowRatio = m_nativeWindow->window()->devicePixelRatio(); const auto &contentMargins = m_frameWindow->contentMarginsHint(); const auto &contentPlatformMargins = contentMargins * windowRatio; const QSize &size = m_frameWindow->handle()->geometry().marginsRemoved(contentPlatformMargins).size(); // update the content window gemetry setNativeWindowGeometry(QRect(contentPlatformMargins.left(), contentPlatformMargins.top(), size.width(), size.height())); } #ifdef Q_OS_LINUX void DPlatformWindowHelper::updateWindowNormalHints() { // update WM_NORMAL_HINTS xcb_size_hints_t hints; memset(&hints, 0, sizeof(hints)); xcb_icccm_size_hints_set_resize_inc(&hints, 1, 1); xcb_icccm_set_wm_normal_hints(m_nativeWindow->xcb_connection(), m_nativeWindow->xcb_window(), &hints); QSize size_inc = m_frameWindow->sizeIncrement(); if (size_inc.isEmpty()) size_inc = QSize(1, 1); xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_normal_hints(m_nativeWindow->xcb_connection(), m_frameWindow->winId()); if (xcb_get_property_reply_t *reply = xcb_get_property_reply(m_nativeWindow->xcb_connection(), cookie, 0)) { xcb_icccm_get_wm_size_hints_from_reply(&hints, reply); free(reply); if (hints.width_inc == 1 && hints.height_inc == 1) { return; } } else { return; } xcb_icccm_size_hints_set_resize_inc(&hints, size_inc.width(), size_inc.height()); xcb_icccm_set_wm_normal_hints(m_nativeWindow->xcb_connection(), m_frameWindow->winId(), &hints); } #endif int DPlatformWindowHelper::getWindowRadius() const { if (m_frameWindow->windowState() == Qt::WindowFullScreen || m_frameWindow->windowState() == Qt::WindowMaximized) return 0; return (m_isUserSetWindowRadius || DWMSupport::instance()->hasComposite()) ? m_windowRadius : 0; } int DPlatformWindowHelper::getShadowRadius() const { return DWMSupport::instance()->hasComposite() ? m_shadowRadius : 0; } static QColor colorBlend(const QColor &color1, const QColor &color2) { QColor c2 = color2.toRgb(); if (c2.alpha() >= 255) return c2; QColor c1 = color1.toRgb(); qreal c1_weight = 1 - c2.alphaF(); int r = c1_weight * c1.red() + c2.alphaF() * c2.red(); int g = c1_weight * c1.green() + c2.alphaF() * c2.green(); int b = c1_weight * c1.blue() + c2.alphaF() * c2.blue(); return QColor(r, g, b); } QColor DPlatformWindowHelper::getBorderColor() const { return DWMSupport::instance()->hasComposite() ? m_borderColor : colorBlend(QColor("#e0e0e0"), m_borderColor); } void DPlatformWindowHelper::updateWindowRadiusFromProperty() { const QVariant &v = m_nativeWindow->window()->property(windowRadius); if (!v.isValid()) { m_nativeWindow->window()->setProperty(windowRadius, m_windowRadius); return; } bool ok; int radius = v.toInt(&ok); if (ok && radius != m_windowRadius) { m_windowRadius = radius; m_isUserSetWindowRadius = true; m_isUserSetClipPath = false; updateClipPathByWindowRadius(m_nativeWindow->window()->size()); } } void DPlatformWindowHelper::updateBorderWidthFromProperty() { const QVariant &v = m_nativeWindow->window()->property(borderWidth); if (!v.isValid()) { m_nativeWindow->window()->setProperty(borderWidth, m_borderWidth); return; } bool ok; int width = v.toInt(&ok); if (ok && width != m_borderWidth) { m_borderWidth = width; m_frameWindow->setBorderWidth(width); } } void DPlatformWindowHelper::updateBorderColorFromProperty() { const QVariant &v = m_nativeWindow->window()->property(borderColor); if (!v.isValid()) { m_nativeWindow->window()->setProperty(borderColor, m_borderColor); return; } const QColor &color = qvariant_cast(v); if (color.isValid() && m_borderColor != color) { m_borderColor = color; m_frameWindow->setBorderColor(getBorderColor()); } } void DPlatformWindowHelper::updateShadowRadiusFromProperty() { const QVariant &v = m_nativeWindow->window()->property(shadowRadius); if (!v.isValid()) { m_nativeWindow->window()->setProperty(shadowRadius, m_shadowRadius); return; } bool ok; int radius = qMax(v.toInt(&ok), 0); if (ok && radius != m_shadowRadius) { m_shadowRadius = radius; if (DWMSupport::instance()->hasComposite()) m_frameWindow->setShadowRadius(radius); } } void DPlatformWindowHelper::updateShadowOffsetFromProperty() { const QVariant &v = m_nativeWindow->window()->property(shadowOffset); if (!v.isValid()) { m_nativeWindow->window()->setProperty(shadowOffset, m_shadowOffset); return; } const QPoint &offset = v.toPoint(); if (offset != m_shadowOffset) { m_shadowOffset = offset; m_frameWindow->setShadowOffset(offset); } } void DPlatformWindowHelper::updateShadowColorFromProperty() { const QVariant &v = m_nativeWindow->window()->property(shadowColor); if (!v.isValid()) { m_nativeWindow->window()->setProperty(shadowColor, m_shadowColor); return; } const QColor &color = qvariant_cast(v); if (color.isValid() && m_shadowColor != color) { m_shadowColor = color; m_frameWindow->setShadowColor(color); } } void DPlatformWindowHelper::updateEnableSystemResizeFromProperty() { const QVariant &v = m_nativeWindow->window()->property(enableSystemResize); if (!v.isValid()) { m_nativeWindow->window()->setProperty(enableSystemResize, m_enableSystemResize); return; } if (m_enableSystemResize == v.toBool()) return; m_enableSystemResize = v.toBool(); m_frameWindow->setEnableSystemResize(m_enableSystemResize); } void DPlatformWindowHelper::updateEnableSystemMoveFromProperty() { const QVariant &v = m_nativeWindow->window()->property(enableSystemMove); if (!v.isValid()) { m_nativeWindow->window()->setProperty(enableSystemMove, m_enableSystemMove); return; } m_enableSystemMove = v.toBool(); m_frameWindow->setEnableSystemMove(m_enableSystemMove); } void DPlatformWindowHelper::updateEnableBlurWindowFromProperty() { const QVariant &v = m_nativeWindow->window()->property(enableBlurWindow); if (!v.isValid()) { m_nativeWindow->window()->setProperty(enableBlurWindow, m_enableBlurWindow); return; } if (m_enableBlurWindow != v.toBool()) { m_enableBlurWindow = v.toBool(); if (m_enableBlurWindow) { QObject::connect(DWMSupport::instance(), &DWMSupport::windowManagerChanged, this, &DPlatformWindowHelper::updateWindowBlurAreasForWM); } else { QObject::disconnect(DWMSupport::instance(), &DWMSupport::windowManagerChanged, this, &DPlatformWindowHelper::updateWindowBlurAreasForWM); } updateWindowBlurAreasForWM(); } } void DPlatformWindowHelper::updateWindowBlurAreasFromProperty() { const QVariant &v = m_nativeWindow->window()->property(windowBlurAreas); const QVector &tmpV = qvariant_cast>(v); const QVector &a = *(reinterpret_cast*>(&tmpV)); if (a.isEmpty() && m_blurAreaList.isEmpty()) return; m_blurAreaList = a; updateWindowBlurAreasForWM(); } void DPlatformWindowHelper::updateWindowBlurPathsFromProperty() { const QVariant &v = m_nativeWindow->window()->property(windowBlurPaths); const QList paths = qvariant_cast>(v); if (paths.isEmpty() && m_blurPathList.isEmpty()) return; m_blurPathList = paths; updateWindowBlurAreasForWM(); } void DPlatformWindowHelper::updateAutoInputMaskByClipPathFromProperty() { const QVariant &v = m_nativeWindow->window()->property(autoInputMaskByClipPath); if (!v.isValid()) { m_nativeWindow->window()->setProperty(autoInputMaskByClipPath, m_autoInputMaskByClipPath); return; } if (m_autoInputMaskByClipPath != v.toBool()) { m_autoInputMaskByClipPath = v.toBool(); } m_frameWindow->m_enableAutoInputMaskByContentPath = m_autoInputMaskByClipPath; } void DPlatformWindowHelper::setWindowProperty(QWindow *window, const char *name, const QVariant &value) { const QVariant &old_value = window->property(name); if (old_value == value) return; if (value.typeName() == QByteArray("QPainterPath")) { const QPainterPath &old_path = qvariant_cast(old_value); const QPainterPath &new_path = qvariant_cast(value); if (old_path == new_path) { return; } } window->setProperty(name, value); if (!mapped.value(window->handle())) return; QByteArray name_array(name); if (!name_array.startsWith("_d_")) return; // to upper name_array[3] = name_array.at(3) & ~0x20; const QByteArray slot_name = "update" + name_array.mid(3) + "FromProperty"; if (!QMetaObject::invokeMethod(mapped.value(window->handle()), slot_name.constData(), Qt::DirectConnection)) { qWarning() << "Failed to update property:" << slot_name; } } void DPlatformWindowHelper::onFrameWindowContentMarginsHintChanged(const QMargins &oldMargins) { updateWindowBlurAreasForWM(); updateSizeHints(); const QMargins &contentMargins = m_frameWindow->contentMarginsHint(); m_nativeWindow->window()->setProperty(::frameMargins, QVariant::fromValue(contentMargins)); m_frameWindow->setGeometry(m_frameWindow->geometry() + contentMargins - oldMargins); updateContentWindowGeometry(); } void DPlatformWindowHelper::onWMHasCompositeChanged() { const QSize &window_size = m_nativeWindow->window()->size(); updateClipPathByWindowRadius(window_size); if (!DXcbWMSupport::instance()->hasComposite()) m_frameWindow->disableRepaintShadow(); m_frameWindow->setShadowRadius(getShadowRadius()); m_frameWindow->enableRepaintShadow(); // QPainterPath clip_path = m_clipPath * m_nativeWindow->window()->devicePixelRatio(); // if (DXcbWMSupport::instance()->hasComposite()) { // QPainterPathStroker stroker; // stroker.setJoinStyle(Qt::MiterJoin); // stroker.setWidth(1); // clip_path = stroker.createStroke(clip_path).united(clip_path); // } m_frameWindow->updateMask(); m_frameWindow->setBorderColor(getBorderColor()); if (m_nativeWindow->window()->inherits("QWidgetWindow")) { QEvent event(QEvent::UpdateRequest); qApp->sendEvent(m_nativeWindow->window(), &event); } else { QMetaObject::invokeMethod(m_nativeWindow->window(), "update"); } } void DPlatformWindowHelper::updateClipPathFromProperty() { const QVariant &v = m_nativeWindow->window()->property(clipPath); if (!v.isValid()) { return; } QPainterPath path; path = qvariant_cast(v); if (!m_isUserSetClipPath && path.isEmpty()) return; m_isUserSetClipPath = !path.isEmpty(); if (m_isUserSetClipPath) setClipPath(path); else updateClipPathByWindowRadius(m_nativeWindow->window()->size()); } void DPlatformWindowHelper::updateFrameMaskFromProperty() { const QVariant &v = m_nativeWindow->window()->property(frameMask); if (!v.isValid()) { return; } QRegion region = qvariant_cast(v); m_frameWindow->setMask(region * m_frameWindow->devicePixelRatio()); m_isUserSetFrameMask = !region.isEmpty(); m_frameWindow->m_enableAutoFrameMask = !m_isUserSetFrameMask; } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformwindowhelper.h000066400000000000000000000130711325534707400262450ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DPLATFORMWINDOWHELPER_H #define DPLATFORMWINDOWHELPER_H #include #ifdef Q_OS_LINUX #define private public #include "qxcbwindow.h" #include "qxcbclipboard.h" typedef QXcbWindow QNativeWindow; #undef private #elif defined(Q_OS_WIN) #include "qwindowswindow.h" typedef QWindowsWindow QNativeWindow; #endif #include "global.h" #include "utility.h" DPP_BEGIN_NAMESPACE class DFrameWindow; class DPlatformWindowHelper : public QObject { Q_OBJECT public: explicit DPlatformWindowHelper(QNativeWindow *window); ~DPlatformWindowHelper(); QNativeWindow *window() const { return static_cast(reinterpret_cast(const_cast(this)));} DPlatformWindowHelper *me() const; void setGeometry(const QRect &rect); QRect geometry() const; QRect normalGeometry() const; QMargins frameMargins() const; void setVisible(bool visible); void setWindowFlags(Qt::WindowFlags flags); #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) void setWindowState(Qt::WindowState state); #else void setWindowState(Qt::WindowStates state); #endif WId winId() const; void setParent(const QPlatformWindow *window); void setWindowTitle(const QString &title); void setWindowFilePath(const QString &title); void setWindowIcon(const QIcon &icon); void raise(); void lower(); bool isExposed() const; // bool isActive() const; #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) bool isEmbedded() const; #else bool isEmbedded(const QPlatformWindow *parentWindow = 0) const; #endif void propagateSizeHints(); void setOpacity(qreal level); void requestActivateWindow(); bool setKeyboardGrabEnabled(bool grab); bool setMouseGrabEnabled(bool grab); bool setWindowModified(bool modified); bool startSystemResize(const QPoint &pos, Qt::Corner corner); void setFrameStrutEventsEnabled(bool enabled); bool frameStrutEventsEnabled() const; void setAlertState(bool enabled); bool isAlertState() const; static bool windowRedirectContent(QWindow *window); private: bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE; void setNativeWindowGeometry(const QRect &rect, bool onlyResize = false); void updateClipPathByWindowRadius(const QSize &windowSize); void setClipPath(const QPainterPath &path); void setWindowVaildGeometry(const QRect &geometry); bool updateWindowBlurAreasForWM(); void updateSizeHints(); void updateContentPathForFrameWindow(); void updateContentWindowGeometry(); #ifdef Q_OS_LINUX void updateWindowNormalHints(); #endif int getWindowRadius() const; int getShadowRadius() const; QColor getBorderColor() const; // update properties Q_SLOT void updateClipPathFromProperty(); Q_SLOT void updateFrameMaskFromProperty(); Q_SLOT void updateWindowRadiusFromProperty(); Q_SLOT void updateBorderWidthFromProperty(); Q_SLOT void updateBorderColorFromProperty(); Q_SLOT void updateShadowRadiusFromProperty(); Q_SLOT void updateShadowOffsetFromProperty(); Q_SLOT void updateShadowColorFromProperty(); Q_SLOT void updateEnableSystemResizeFromProperty(); Q_SLOT void updateEnableSystemMoveFromProperty(); Q_SLOT void updateEnableBlurWindowFromProperty(); Q_SLOT void updateWindowBlurAreasFromProperty(); Q_SLOT void updateWindowBlurPathsFromProperty(); Q_SLOT void updateAutoInputMaskByClipPathFromProperty(); static void setWindowProperty(QWindow *window, const char *name, const QVariant &value); void onFrameWindowContentMarginsHintChanged(const QMargins &old_margins); void onWMHasCompositeChanged(); static QHash mapped; QNativeWindow *m_nativeWindow; DFrameWindow *m_frameWindow; QRect m_windowVaildGeometry; // properties bool m_isUserSetClipPath = false; QPainterPath m_clipPath; bool m_isUserSetFrameMask = false; int m_windowRadius = 4; bool m_isUserSetWindowRadius = false; int m_borderWidth = 1; QColor m_borderColor = QColor(0, 0, 0, 255 * 0.15); int m_shadowRadius = 60; QPoint m_shadowOffset = QPoint(0, 16); QColor m_shadowColor = QColor(0, 0, 0, 255 * 0.6); bool m_enableSystemResize = true; bool m_enableSystemMove = true; bool m_enableBlurWindow = false; bool m_autoInputMaskByClipPath = true; bool m_enableShadow = true; QVector m_blurAreaList; QList m_blurPathList; #ifdef Q_OS_LINUX uint32_t damage_id = 0; #endif friend class DPlatformBackingStoreHelper; friend class DPlatformOpenGLContextHelper; friend class DPlatformIntegration; friend class DPlatformNativeInterfaceHook; friend class XcbNativeEventFilter; friend class WindowEventHook; friend QWindow *topvelWindow(QWindow *); }; DPP_END_NAMESPACE #endif // DPLATFORMWINDOWHELPER_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformwindowhook.cpp000066400000000000000000000214041325534707400262600ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dplatformwindowhook.h" #include "vtablehook.h" #include "global.h" #include "utility.h" #include #ifdef Q_OS_LINUX #include "dxcbwmsupport.h" #include #include #endif #define HOOK_VFPTR(Fun) VtableHook::overrideVfptrFun(window, &QPlatformWindow::Fun, this, &DPlatformWindowHook::Fun) #define CALL this->window()->QNativeWindow DPP_BEGIN_NAMESPACE PUBLIC_CLASS(QNativeWindow, DPlatformWindowHook); QHash DPlatformWindowHook::mapped; DPlatformWindowHook::DPlatformWindowHook(QNativeWindow *window) : QObject(window->window()) , nativeWindow(window) { mapped[window] = this; HOOK_VFPTR(setGeometry); HOOK_VFPTR(geometry); HOOK_VFPTR(frameMargins); // HOOK_VFPTR(setParent); // HOOK_VFPTR(setWindowTitle); // HOOK_VFPTR(setWindowIcon); HOOK_VFPTR(mapToGlobal); HOOK_VFPTR(mapFromGlobal); HOOK_VFPTR(setMask); #ifdef Q_OS_LINUX HOOK_VFPTR(setWindowState); HOOK_VFPTR(setVisible); #endif HOOK_VFPTR(propagateSizeHints); HOOK_VFPTR(requestActivateWindow); } DPlatformWindowHook::~DPlatformWindowHook() { mapped.remove(nativeWindow); VtableHook::clearGhostVtable(static_cast(nativeWindow)); } DPlatformWindowHook *DPlatformWindowHook::me() const { return getHookByWindow(window()); } void DPlatformWindowHook::setGeometry(const QRect &rect) { const QMargins &margins = me()->windowMargins; emit me()->windowGeometryAboutChanged(rect); CALL::setGeometry(rect + margins); } QRect DPlatformWindowHook::geometry() const { const QMargins &margins = me()->windowMargins; // qDebug() << __FUNCTION__ << CALL::geometry() << CALL::window()->isVisible(); return CALL::geometry() - margins; } QMargins DPlatformWindowHook::frameMargins() const { return QMargins(); } void DPlatformWindowHook::setParent(const QPlatformWindow *window) { CALL::setParent(window); } void DPlatformWindowHook::setWindowTitle(const QString &title) { return CALL::setWindowTitle(title); } void DPlatformWindowHook::setWindowIcon(const QIcon &icon) { return CALL::setWindowIcon(icon); } QPoint DPlatformWindowHook::mapToGlobal(const QPoint &pos) const { DPlatformWindowHook *me = DPlatformWindowHook::me(); return CALL::mapToGlobal(pos + QPoint(me->windowMargins.left(), me->windowMargins.top())); } QPoint DPlatformWindowHook::mapFromGlobal(const QPoint &pos) const { DPlatformWindowHook *me = DPlatformWindowHook::me(); return CALL::mapFromGlobal(pos - QPoint(me->windowMargins.left(), me->windowMargins.top())); } void DPlatformWindowHook::setMask(const QRegion ®ion) { QRegion tmp_region; const QMargins &margins = me()->windowMargins; QRect window_rect = CALL::geometry() - margins; window_rect.moveTopLeft(QPoint(margins.left(), margins.top())); for (const QRect &rect : region.rects()) { tmp_region += rect.translated(window_rect.topLeft()).intersected(window_rect) + margins; } QPainterPath path; path.addRegion(region); CALL::window()->setProperty(clipPath, QVariant::fromValue(path)); // CALL::setMask(tmp_region); Utility::setShapeRectangles(CALL::winId(), tmp_region); } #ifdef Q_OS_LINUX void DPlatformWindowHook::setWindowState(Qt::WindowState state) { DQNativeWindow *window = static_cast(this->window()); if (window->m_windowState == state) return; if (state == Qt::WindowMinimized && (window->m_windowState == Qt::WindowMaximized || window->m_windowState == Qt::WindowFullScreen)) { window->changeNetWmState(true, Utility::internAtom("_NET_WM_STATE_HIDDEN")); XIconifyWindow(QX11Info::display(), window->m_window, QX11Info::appScreen()); window->connection()->sync(); window->m_windowState = state; } else { CALL::setWindowState(state); } } void DPlatformWindowHook::setVisible(bool visible) { if (!visible) { return CALL::setVisible(visible); } // reupdate _MOTIF_WM_HINTS DQNativeWindow *window = static_cast(this->window()); Utility::QtMotifWmHints mwmhints = Utility::getMotifWmHints(window->m_window); if (window->window()->modality() != Qt::NonModal) { switch (window->window()->modality()) { case Qt::WindowModal: mwmhints.input_mode = DXcbWMSupport::MWM_INPUT_PRIMARY_APPLICATION_MODAL; break; case Qt::ApplicationModal: default: mwmhints.input_mode = DXcbWMSupport::MWM_INPUT_FULL_APPLICATION_MODAL; break; } mwmhints.flags |= DXcbWMSupport::MWM_HINTS_INPUT_MODE; } else { mwmhints.input_mode = DXcbWMSupport::MWM_INPUT_MODELESS; mwmhints.flags &= ~DXcbWMSupport::MWM_HINTS_INPUT_MODE; } if (window->windowMinimumSize() == window->windowMaximumSize()) { // fixed size, remove the resize handle (since mwm/dtwm // isn't smart enough to do it itself) mwmhints.flags |= DXcbWMSupport::MWM_HINTS_FUNCTIONS; mwmhints.functions &= ~DXcbWMSupport::MWM_FUNC_RESIZE; if (mwmhints.decorations == DXcbWMSupport::MWM_DECOR_ALL) { mwmhints.flags |= DXcbWMSupport::MWM_HINTS_DECORATIONS; mwmhints.decorations = (DXcbWMSupport::MWM_DECOR_BORDER | DXcbWMSupport::MWM_DECOR_TITLE | DXcbWMSupport::MWM_DECOR_MENU); } else { mwmhints.decorations &= ~DXcbWMSupport::MWM_DECOR_RESIZEH; } } if (window->window()->flags() & Qt::WindowMinimizeButtonHint) { mwmhints.functions |= DXcbWMSupport::MWM_FUNC_MINIMIZE; } if (window->window()->flags() & Qt::WindowMaximizeButtonHint) { mwmhints.functions |= DXcbWMSupport::MWM_FUNC_MAXIMIZE; } if (window->window()->flags() & Qt::WindowCloseButtonHint) mwmhints.functions |= DXcbWMSupport::MWM_FUNC_CLOSE; CALL::setVisible(visible); // Fix the window can't show minimized if window is fixed size Utility::setMotifWmHints(window->m_window, mwmhints); } void DPlatformWindowHook::requestActivateWindow() { if (!window()->isExposed() && !DXcbWMSupport::instance()->hasComposite() && window()->window()->windowState() == Qt::WindowMinimized) { Q_XCB_CALL(xcb_map_window(window()->xcb_connection(), window()->winId())); } CALL::requestActivateWindow(); } #endif void DPlatformWindowHook::propagateSizeHints() { QWindow *win = window()->window(); QWindowPrivate *winp = qt_window_private(win); win->setProperty(userWindowMinimumSize, winp->minimumSize); win->setProperty(userWindowMaximumSize, winp->maximumSize); const QMargins &windowMargins = me()->windowMargins; const QSize &marginSize = QSize(windowMargins.left() + windowMargins.right(), windowMargins.top() + windowMargins.bottom()); winp->minimumSize += marginSize / win->devicePixelRatio(); winp->maximumSize += marginSize / win->devicePixelRatio(); winp->maximumSize.setWidth(qMin(QWINDOWSIZE_MAX, winp->maximumSize.width())); winp->maximumSize.setHeight(qMin(QWINDOWSIZE_MAX, winp->maximumSize.height())); CALL::propagateSizeHints(); // qDebug() << winp->minimumSize << winp->maximumSize << marginSize; } DPlatformWindowHook *DPlatformWindowHook::getHookByWindow(const QPlatformWindow *window) { return mapped.value(window); } void DPlatformWindowHook::setWindowMargins(const QMargins &margins, bool propagateSizeHints) { windowMargins = margins; if (!propagateSizeHints) { return; } QWindow *win = nativeWindow->window(); QWindowPrivate *winp = qt_window_private(win); const QSize &user_max_size = win->property(userWindowMaximumSize).toSize(); const QSize &user_min_size = win->property(userWindowMinimumSize).toSize(); if (user_max_size.isValid()) { winp->maximumSize = user_max_size; } if (user_min_size.isValid()) { winp->minimumSize = user_min_size; } static_cast(nativeWindow)->propagateSizeHints(); } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dplatformwindowhook.h000066400000000000000000000047151325534707400257330ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TESTWINDOW_H #define TESTWINDOW_H #include #ifdef Q_OS_LINUX #define private public #include "qxcbwindow.h" #include "qxcbclipboard.h" typedef QXcbWindow QNativeWindow; #undef private #elif defined(Q_OS_WIN) #include "qwindowswindow.h" typedef QWindowsWindow QNativeWindow; #endif #include "global.h" DPP_BEGIN_NAMESPACE class DPlatformWindowHook : public QObject { Q_OBJECT public: DPlatformWindowHook(QNativeWindow *window); ~DPlatformWindowHook(); QNativeWindow *window() const { return static_cast(reinterpret_cast(const_cast(this)));} DPlatformWindowHook *me() const; void setGeometry(const QRect &rect); QRect geometry() const; QMargins frameMargins() const; void setParent(const QPlatformWindow *window); void setWindowTitle(const QString &title); void setWindowIcon(const QIcon &icon); QPoint mapToGlobal(const QPoint &pos) const; QPoint mapFromGlobal(const QPoint &pos) const; void setMask(const QRegion ®ion); #ifdef Q_OS_LINUX void setWindowState(Qt::WindowState state); void setVisible(bool visible); void requestActivateWindow(); #endif // bool startSystemResize(const QPoint &pos, Qt::Corner corner); void propagateSizeHints(); static DPlatformWindowHook *getHookByWindow(const QPlatformWindow *window); signals: void windowGeometryAboutChanged(const QRect &rect); private: void setWindowMargins(const QMargins &margins, bool propagateSizeHints = false); QMargins windowMargins; static QHash mapped; QNativeWindow *nativeWindow; friend class DPlatformBackingStore; }; DPP_END_NAMESPACE Q_DECLARE_METATYPE(QPainterPath) #endif // TESTWINDOW_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dpp.json000066400000000000000000000000341325534707400231250ustar00rootroot00000000000000{ "Keys" : [ "dxcb" ] } deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dwmsupport.h000066400000000000000000000016471325534707400240570ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DWMSUPPORT_H #define DWMSUPPORT_H #include #include "global.h" DPP_USE_NAMESPACE #ifdef Q_OS_LINUX #include "dxcbwmsupport.h" typedef DXcbWMSupport DWMSupport; #elif defined(Q_OS_WIN) #endif #endif // DWMSUPPORT_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dxcbwmsupport.cpp000066400000000000000000000277611325534707400251140ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dxcbwmsupport.h" #include "dplatformintegration.h" #include "utility.h" #include "dframewindow.h" #include "qxcbconnection.h" #include "qxcbscreen.h" #include "qxcbwindow.h" DPP_BEGIN_NAMESPACE class _DXcbWMSupport : public DXcbWMSupport {}; Q_GLOBAL_STATIC(_DXcbWMSupport, globalXWMS) DXcbWMSupport::DXcbWMSupport() { updateWMName(false); connect(this, &DXcbWMSupport::windowMotifWMHintsChanged, this, [this] (quint32 winId) { for (const DFrameWindow *frame : DFrameWindow::frameWindowList) { if (frame->m_contentWindow && frame->m_contentWindow->handle() && static_cast(frame->m_contentWindow->handle())->QXcbWindow::winId() == winId) { if (frame->handle()) emit windowMotifWMHintsChanged(frame->handle()->winId()); break; } } }); } void DXcbWMSupport::updateWMName(bool emitSignal) { _net_wm_deepin_blur_region_rounded_atom = Utility::internAtom(QT_STRINGIFY(_NET_WM_DEEPIN_BLUR_REGION_ROUNDED)); _net_wm_deepin_blur_region_mask = Utility::internAtom(QT_STRINGIFY(_NET_WM_DEEPIN_BLUR_REGION_MASK)); _kde_net_wm_blur_rehind_region_atom = Utility::internAtom(QT_STRINGIFY(_KDE_NET_WM_BLUR_BEHIND_REGION)); m_wmName.clear(); xcb_connection_t *xcb_connection = DPlatformIntegration::xcbConnection()->xcb_connection(); xcb_window_t root = DPlatformIntegration::xcbConnection()->primaryScreen()->root(); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection, xcb_get_property_unchecked(xcb_connection, false, root, DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_NET_SUPPORTING_WM_CHECK), XCB_ATOM_WINDOW, 0, 1024), NULL); if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) { xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply)); if (windowManager != XCB_WINDOW_NONE) { xcb_get_property_reply_t *windowManagerReply = xcb_get_property_reply(xcb_connection, xcb_get_property_unchecked(xcb_connection, false, windowManager, DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_NET_WM_NAME), DPlatformIntegration::xcbConnection()->atom(QXcbAtom::UTF8_STRING), 0, 1024), NULL); if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == DPlatformIntegration::xcbConnection()->atom(QXcbAtom::UTF8_STRING)) { m_wmName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply), xcb_get_property_value_length(windowManagerReply)); } free(windowManagerReply); } } free(reply); m_isDeepinWM = (m_wmName == QStringLiteral("Mutter(DeepinGala)")); m_isKwin = !m_isDeepinWM && (m_wmName == QStringLiteral("KWin")); updateNetWMAtoms(); updateRootWindowProperties(); updateHasComposite(); if (emitSignal) emit windowManagerChanged(); } void DXcbWMSupport::updateNetWMAtoms() { net_wm_atoms.clear(); xcb_window_t root = DPlatformIntegration::xcbConnection()->primaryScreen()->root(); int offset = 0; int remaining = 0; xcb_connection_t *xcb_connection = DPlatformIntegration::xcbConnection()->xcb_connection(); do { xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection, false, root, DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_NET_SUPPORTED), XCB_ATOM_ATOM, offset, 1024); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection, cookie, NULL); if (!reply) break; remaining = 0; if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { int len = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t); xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); int s = net_wm_atoms.size(); net_wm_atoms.resize(s + len); memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t)); remaining = reply->bytes_after; offset += len; } free(reply); } while (remaining > 0); updateHasBlurWindow(); } void DXcbWMSupport::updateRootWindowProperties() { root_window_properties.clear(); xcb_window_t root = DPlatformIntegration::xcbConnection()->primaryScreen()->root(); xcb_connection_t *xcb_connection = DPlatformIntegration::xcbConnection()->xcb_connection(); xcb_list_properties_cookie_t cookie = xcb_list_properties(xcb_connection, root); xcb_list_properties_reply_t *reply = xcb_list_properties_reply(xcb_connection, cookie, NULL); if (!reply) return; int len = xcb_list_properties_atoms_length(reply); xcb_atom_t *atoms = (xcb_atom_t *)xcb_list_properties_atoms(reply); root_window_properties.resize(len); memcpy(root_window_properties.data(), atoms, len * sizeof(xcb_atom_t)); free(reply); updateHasBlurWindow(); } void DXcbWMSupport::updateHasBlurWindow() { bool hasBlurWindow((m_isDeepinWM && isSupportedByWM(_net_wm_deepin_blur_region_rounded_atom)) || (m_isKwin && isContainsForRootWindow(_kde_net_wm_blur_rehind_region_atom))); if (m_hasBlurWindow == hasBlurWindow) return; m_hasBlurWindow = hasBlurWindow; emit hasBlurWindowChanged(hasBlurWindow); } void DXcbWMSupport::updateHasComposite() { xcb_connection_t *xcb_connection = DPlatformIntegration::xcbConnection()->xcb_connection(); xcb_get_selection_owner_cookie_t cookit = xcb_get_selection_owner(xcb_connection, DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_NET_WM_CM_S0)); xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply(xcb_connection, cookit, NULL); if (!reply) return; bool hasComposite(reply->owner != XCB_NONE); free(reply); if (m_hasComposite == hasComposite) return; m_hasComposite = hasComposite; emit hasCompositeChanged(hasComposite); } DXcbWMSupport *DXcbWMSupport::instance() { return globalXWMS; } bool DXcbWMSupport::connectWindowManagerChangedSignal(QObject *object, std::function slot) { if (!object) return QObject::connect(globalXWMS, &DXcbWMSupport::windowManagerChanged, slot); return QObject::connect(globalXWMS, &DXcbWMSupport::windowManagerChanged, object, slot); } bool DXcbWMSupport::connectHasBlurWindowChanged(QObject *object, std::function slot) { if (!object) return QObject::connect(globalXWMS, &DXcbWMSupport::hasBlurWindowChanged, slot); return QObject::connect(globalXWMS, &DXcbWMSupport::hasBlurWindowChanged, object, slot); } bool DXcbWMSupport::connectHasCompositeChanged(QObject *object, std::function slot) { if (!object) return QObject::connect(globalXWMS, &DXcbWMSupport::hasCompositeChanged, slot); return QObject::connect(globalXWMS, &DXcbWMSupport::hasCompositeChanged, object, slot); } bool DXcbWMSupport::connectWindowListChanged(QObject *object, std::function slot) { if (!object) return QObject::connect(globalXWMS, &DXcbWMSupport::windowListChanged, slot); return QObject::connect(globalXWMS, &DXcbWMSupport::windowListChanged, object, slot); } bool DXcbWMSupport::connectWindowMotifWMHintsChanged(QObject *object, std::function slot) { if (!object) return QObject::connect(globalXWMS, &DXcbWMSupport::windowMotifWMHintsChanged, slot); return QObject::connect(globalXWMS, &DXcbWMSupport::windowMotifWMHintsChanged, object, slot); } void DXcbWMSupport::setMWMFunctions(quint32 winId, quint32 func) { // FIXME(zccrs): The Openbox window manager does not support the Motif Hints if (instance()->windowManagerName() == "Openbox") return; Utility::QtMotifWmHints hints = Utility::getMotifWmHints(winId); hints.flags |= MWM_HINTS_FUNCTIONS; hints.functions = func; Utility::setMotifWmHints(winId, hints); } quint32 DXcbWMSupport::getMWMFunctions(quint32 winId) { Utility::QtMotifWmHints hints = Utility::getMotifWmHints(winId); if (hints.flags & MWM_HINTS_FUNCTIONS) return hints.functions; return MWM_FUNC_ALL; } quint32 DXcbWMSupport::getRealWinId(quint32 winId) { for (const DFrameWindow *frame : DFrameWindow::frameWindowList) { if (frame->handle() && frame->handle()->winId() == winId && frame->m_contentWindow && frame->m_contentWindow->handle()) { return static_cast(frame->m_contentWindow->handle())->QXcbWindow::winId(); } } return winId; } void DXcbWMSupport::setMWMDecorations(quint32 winId, quint32 decor) { winId = getRealWinId(winId); Utility::QtMotifWmHints hints = Utility::getMotifWmHints(winId); hints.flags |= MWM_HINTS_DECORATIONS; hints.decorations = decor; Utility::setMotifWmHints(winId, hints); } quint32 DXcbWMSupport::getMWMDecorations(quint32 winId) { winId = getRealWinId(winId); Utility::QtMotifWmHints hints = Utility::getMotifWmHints(winId); if (hints.flags & MWM_HINTS_DECORATIONS) return hints.decorations; return MWM_DECOR_ALL; } void DXcbWMSupport::popupSystemWindowMenu(quint32 winId) { Utility::showWindowSystemMenu(winId); } QString DXcbWMSupport::windowManagerName() const { return m_wmName; } QVector DXcbWMSupport::allWindow() const { QVector window_list_stacking; xcb_window_t root = DPlatformIntegration::xcbConnection()->primaryScreen()->root(); int offset = 0; int remaining = 0; xcb_connection_t *xcb_connection = DPlatformIntegration::xcbConnection()->xcb_connection(); do { xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection, false, root, Utility::internAtom("_NET_CLIENT_LIST_STACKING"), XCB_ATOM_WINDOW, offset, 1024); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection, cookie, NULL); if (!reply) break; remaining = 0; if (reply->type == XCB_ATOM_WINDOW && reply->format == 32) { int len = xcb_get_property_value_length(reply)/sizeof(xcb_window_t); xcb_window_t *windows = (xcb_window_t *)xcb_get_property_value(reply); int s = window_list_stacking.size(); window_list_stacking.resize(s + len); memcpy(window_list_stacking.data() + s, windows, len*sizeof(xcb_window_t)); remaining = reply->bytes_after; offset += len; } free(reply); } while (remaining > 0); return window_list_stacking; } bool DXcbWMSupport::isDeepinWM() const { return m_isDeepinWM; } bool DXcbWMSupport::isKwin() const { return m_isKwin; } bool DXcbWMSupport::isSupportedByWM(xcb_atom_t atom) const { return net_wm_atoms.contains(atom); } bool DXcbWMSupport::isContainsForRootWindow(xcb_atom_t atom) const { return root_window_properties.contains(atom); } bool DXcbWMSupport::hasBlurWindow() const { return m_hasBlurWindow; } bool DXcbWMSupport::hasComposite() const { return m_hasComposite; } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/dxcbwmsupport.h000066400000000000000000000077731325534707400245620ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DXCBWMSUPPORT_H #define DXCBWMSUPPORT_H #include "global.h" #include #include #include #include QT_BEGIN_NAMESPACE class QWindow; QT_END_NAMESPACE DPP_BEGIN_NAMESPACE class DXcbWMSupport : public QObject { Q_OBJECT Q_PROPERTY(bool hasBlurWindow READ hasBlurWindow NOTIFY hasBlurWindowChanged) Q_PROPERTY(bool hasComposite READ hasComposite NOTIFY hasCompositeChanged) public: enum { MWM_HINTS_FUNCTIONS = (1L << 0), MWM_FUNC_ALL = (1L << 0), MWM_FUNC_RESIZE = (1L << 1), MWM_FUNC_MOVE = (1L << 2), MWM_FUNC_MINIMIZE = (1L << 3), MWM_FUNC_MAXIMIZE = (1L << 4), MWM_FUNC_CLOSE = (1L << 5), MWM_HINTS_DECORATIONS = (1L << 1), MWM_DECOR_ALL = (1L << 0), MWM_DECOR_BORDER = (1L << 1), MWM_DECOR_RESIZEH = (1L << 2), MWM_DECOR_TITLE = (1L << 3), MWM_DECOR_MENU = (1L << 4), MWM_DECOR_MINIMIZE = (1L << 5), MWM_DECOR_MAXIMIZE = (1L << 6), MWM_HINTS_INPUT_MODE = (1L << 2), MWM_INPUT_MODELESS = 0L, MWM_INPUT_PRIMARY_APPLICATION_MODAL = 1L, MWM_INPUT_FULL_APPLICATION_MODAL = 3L }; static DXcbWMSupport *instance(); static bool connectWindowManagerChangedSignal(QObject *object, std::function slot); static bool connectHasBlurWindowChanged(QObject *object, std::function slot); static bool connectHasCompositeChanged(QObject *object, std::function slot); static bool connectWindowListChanged(QObject *object, std::function slot); static bool connectWindowMotifWMHintsChanged(QObject *object, std::function slot); static void setMWMFunctions(quint32 winId, quint32 func); static quint32 getMWMFunctions(quint32 winId); static void setMWMDecorations(quint32 windId, quint32 decor); static quint32 getMWMDecorations(quint32 winId); static void popupSystemWindowMenu(quint32 winId); bool isDeepinWM() const; bool isKwin() const; bool isSupportedByWM(xcb_atom_t atom) const; bool isContainsForRootWindow(xcb_atom_t atom) const; bool hasBlurWindow() const; bool hasComposite() const; QString windowManagerName() const; QVector allWindow() const; signals: void windowManagerChanged(); void hasBlurWindowChanged(bool hasBlurWindow); void hasCompositeChanged(bool hasComposite); void windowListChanged(); void windowMotifWMHintsChanged(quint32 winId); protected: explicit DXcbWMSupport(); private: void updateWMName(bool emitSignal = true); void updateNetWMAtoms(); void updateRootWindowProperties(); void updateHasBlurWindow(); void updateHasComposite(); static quint32 getRealWinId(quint32 winId); bool m_isDeepinWM = false; bool m_isKwin = false; bool m_hasBlurWindow = false; bool m_hasComposite = false; QString m_wmName; xcb_atom_t _net_wm_deepin_blur_region_rounded_atom = 0; xcb_atom_t _kde_net_wm_blur_rehind_region_atom = 0; xcb_atom_t _net_wm_deepin_blur_region_mask = 0; QVector net_wm_atoms; QVector root_window_properties; friend class XcbNativeEventFilter; friend class Utility; }; DPP_END_NAMESPACE #endif // DXCBWMSUPPORT_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/global.h000066400000000000000000000054351325534707400230720ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GLOBAL_H #define GLOBAL_H #define MOUSE_MARGINS 10 #define DPP_BEGIN_NAMESPACE namespace deepin_platform_plugin { #define DPP_END_NAMESPACE } #define DPP_USE_NAMESPACE using namespace deepin_platform_plugin; #define PUBLIC_CLASS(Class, Target) \ class D##Class : public Class\ {friend class Target;} #define DEFINE_CONST_CHAR(Name) const char Name[] = "_d_" #Name DEFINE_CONST_CHAR(useDxcb); DEFINE_CONST_CHAR(redirectContent); DEFINE_CONST_CHAR(netWmStates); DEFINE_CONST_CHAR(windowRadius); DEFINE_CONST_CHAR(borderWidth); DEFINE_CONST_CHAR(borderColor); DEFINE_CONST_CHAR(shadowRadius); DEFINE_CONST_CHAR(shadowOffset); DEFINE_CONST_CHAR(shadowColor); DEFINE_CONST_CHAR(clipPath); DEFINE_CONST_CHAR(frameMask); DEFINE_CONST_CHAR(frameMargins); DEFINE_CONST_CHAR(translucentBackground); DEFINE_CONST_CHAR(enableSystemResize); DEFINE_CONST_CHAR(enableSystemMove); DEFINE_CONST_CHAR(enableBlurWindow); DEFINE_CONST_CHAR(userWindowMinimumSize); DEFINE_CONST_CHAR(userWindowMaximumSize); DEFINE_CONST_CHAR(windowBlurAreas); DEFINE_CONST_CHAR(windowBlurPaths); DEFINE_CONST_CHAR(autoInputMaskByClipPath); DEFINE_CONST_CHAR(popupSystemWindowMenu); // functions DEFINE_CONST_CHAR(setWmBlurWindowBackgroundArea); DEFINE_CONST_CHAR(setWmBlurWindowBackgroundPathList); DEFINE_CONST_CHAR(setWmBlurWindowBackgroundMaskImage); DEFINE_CONST_CHAR(hasBlurWindow); DEFINE_CONST_CHAR(hasComposite); DEFINE_CONST_CHAR(connectWindowManagerChangedSignal); DEFINE_CONST_CHAR(connectHasBlurWindowChanged); DEFINE_CONST_CHAR(connectHasCompositeChanged); DEFINE_CONST_CHAR(getWindows); DEFINE_CONST_CHAR(getCurrentWorkspaceWindows); DEFINE_CONST_CHAR(connectWindowListChanged); DEFINE_CONST_CHAR(setMWMFunctions); DEFINE_CONST_CHAR(getMWMFunctions); DEFINE_CONST_CHAR(setMWMDecorations); DEFINE_CONST_CHAR(getMWMDecorations); DEFINE_CONST_CHAR(connectWindowMotifWMHintsChanged); DEFINE_CONST_CHAR(setWindowProperty); DEFINE_CONST_CHAR(pluginVersion); DEFINE_CONST_CHAR(disableOverrideCursor); // others DEFINE_CONST_CHAR(WmWindowTypes); DEFINE_CONST_CHAR(WmNetDesktop); DEFINE_CONST_CHAR(WmClass); DEFINE_CONST_CHAR(ProcessId); #endif // GLOBAL_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/linux.pri000066400000000000000000000041431325534707400233270ustar00rootroot00000000000000TARGET = dxcb CONFIG += link_pkgconfig PKGCONFIG += x11-xcb xi xcb-renderutil sm ice xcb-render dbus-1 xcb\ xcb-image xcb-icccm xcb-sync xcb-xfixes xcb-shm xcb-randr\ xcb-shape xcb-keysyms xcb-xkb xcb-composite xkbcommon-x11\ xcb-damage mtdev egl cairo greaterThan(QT_MINOR_VERSION, 5): PKGCONFIG += xcb-xinerama #LIBS += -ldl greaterThan(QT_MINOR_VERSION, 4): LIBS += -lQt5XcbQpa HEADERS += \ $$PWD/windoweventhook.h \ $$PWD/xcbnativeeventfilter.h \ $$PWD/dxcbwmsupport.h SOURCES += \ $$PWD/windoweventhook.cpp \ $$PWD/xcbnativeeventfilter.cpp \ $$PWD/utility_x11.cpp \ $$PWD/dxcbwmsupport.cpp \ $$PWD/dforeignplatformwindow_x11.cpp contains(QT_CONFIG, xcb-xlib)|qtConfig(xcb-xlib) { DEFINES += XCB_USE_XLIB QMAKE_USE += xcb_xlib contains(QT_CONFIG, xinput2)|qtConfig(xinput2) { DEFINES += XCB_USE_XINPUT2 QMAKE_USE += xinput2 !isEmpty(QMAKE_LIBXI_VERSION_MAJOR) { DEFINES += LIBXI_MAJOR=$$QMAKE_LIBXI_VERSION_MAJOR \ LIBXI_MINOR=$$QMAKE_LIBXI_VERSION_MINOR \ LIBXI_PATCH=$$QMAKE_LIBXI_VERSION_PATCH } } } # build with session management support contains(QT_CONFIG, xcb-sm)|qtConfig(xcb-sm) { DEFINES += XCB_USE_SM QMAKE_USE += x11sm } !contains(QT_CONFIG, system-xcb)|qtConfig(system-xcb) { DEFINES += XCB_USE_RENDER QMAKE_USE += xcb } else { LIBS += -lxcb-xinerama ### there is no configure test for this! contains(QT_CONFIG, xkb)|qtConfig(xkb): QMAKE_USE += xcb_xkb # to support custom cursors with depth > 1 contains(QT_CONFIG, xcb-render)|qtConfig(xkb) { DEFINES += XCB_USE_RENDER QMAKE_USE += xcb_render } QMAKE_USE += xcb_syslibs } contains(QT_CONFIG, xcb-qt) { DEFINES += XCB_USE_RENDER } exists($$PWD/libqt5xcbqpa-dev/$$QT_VERSION) { INCLUDEPATH += $$PWD/libqt5xcbqpa-dev/$$QT_VERSION } else:exists($$[QT_INSTALL_HEADERS]/QtXcb/$$[QT_VERSION]) { INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QtXcb/$$[QT_VERSION]/QtXcb/private } else { error(Not support Qt Version: $$QT_VERSION) } deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/main.cpp000066400000000000000000000026751325534707400231140ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "dplatformintegration.h" #include DPP_USE_NAMESPACE QT_BEGIN_NAMESPACE class DPlatformIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "dpp.json") public: QPlatformIntegration *create(const QString&, const QStringList&, int &, char **) Q_DECL_OVERRIDE; }; QPlatformIntegration* DPlatformIntegrationPlugin::create(const QString& system, const QStringList& parameters, int &argc, char **argv) { #ifdef Q_OS_LINUX if (!system.compare(QLatin1String("dxcb"), Qt::CaseInsensitive)) return new DPlatformIntegration(parameters, argc, argv); #endif return 0; } QT_END_NAMESPACE #include "main.moc" deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/qt5platform-plugin.pro000066400000000000000000000053161325534707400257530ustar00rootroot00000000000000#------------------------------------------------- # # Project created by QtCreator 2016-08-10T19:46:44 # #------------------------------------------------- !isEqual(QMAKE_HOST.arch, x86_64):!isEqual(QMAKE_HOST.arch, i386):!isEqual(QMAKE_HOST.arch, i686) { # 在非x86架构的cpu下降低编译器的优化等级 # 编译器优化可能会导致虚函数调用不通过虚表 QMAKE_CXXFLAGS_RELEASE -= $$QMAKE_CFLAGS_OPTIMIZE QMAKE_CXXFLAGS_RELEASE += -O1 } PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = DXcbIntegrationPlugin !equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - DESTDIR = $$_PRO_FILE_PWD_/../bin/plugins/platforms QT += opengl x11extras QT += core-private #xcb_qpa_lib-private greaterThan(QT_MAJOR_VERSION, 4) { QT += widgets widgets-private # Qt >= 5.8 greaterThan(QT_MINOR_VERSION, 7): QT += gui-private else: QT += platformsupport-private # Qt >= 5.10 greaterThan(QT_MINOR_VERSION, 9): QT += edid_support-private } TEMPLATE = lib isEmpty(VERSION) { isEmpty(VERSION): VERSION = $$system(git describe --tags --abbrev=0) isEmpty(VERSION): VERSION = $$DXCB_VERSION isEmpty(VERSION): error(VERSION is empty) VERSION = $$replace(VERSION, [^0-9.],) } DEFINES += DXCB_VERSION=\\\"$$VERSION\\\" linux: include($$PWD/linux.pri) windows: include($$PWD/windows.pri) CONFIG += plugin c++11 SOURCES += \ $$PWD/main.cpp \ $$PWD/dplatformintegration.cpp \ $$PWD/vtablehook.cpp \ $$PWD/dplatformnativeinterfacehook.cpp \ dhighdpi.cpp HEADERS += \ $$PWD/dplatformintegration.h \ $$PWD/vtablehook.h \ $$PWD/utility.h \ $$PWD/global.h \ $$PWD/dplatformnativeinterfacehook.h \ $$PWD/dforeignplatformwindow.h \ $$PWD/dwmsupport.h \ dhighdpi.h DISTFILES += \ $$PWD/dpp.json isEmpty(INSTALL_PATH) { target.path = $$[QT_INSTALL_PLUGINS]/platforms } else { target.path = $$INSTALL_PATH } message($$target.path) INSTALLS += target CONFIG(release, debug|release) { DEFINES += QT_NO_DEBUG_OUTPUT USE_NEW_IMPLEMENTING } else { DEFINES += USE_NEW_IMPLEMENTING } contains(DEFINES, USE_NEW_IMPLEMENTING) { SOURCES += \ $$PWD/dframewindow.cpp \ $$PWD/dplatformwindowhelper.cpp \ $$PWD/dplatformbackingstorehelper.cpp \ $$PWD/dplatformopenglcontexthelper.cpp HEADERS += \ $$PWD/dframewindow.h \ $$PWD/dplatformwindowhelper.h \ $$PWD/dplatformbackingstorehelper.h \ $$PWD/dplatformopenglcontexthelper.h } else { SOURCES += \ $$PWD/dplatformbackingstore.cpp \ $$PWD/dplatformwindowhook.cpp HEADERS += \ $$PWD/dplatformbackingstore.h \ $$PWD/dplatformwindowhook.h } RESOURCES += \ cursors/cursor.qrc deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/utility.h000066400000000000000000000145601325534707400233340ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UTILITY_H #define UTILITY_H #include #include "global.h" QT_BEGIN_NAMESPACE class QXcbWindow; QT_END_NAMESPACE typedef uint32_t xcb_atom_t; DPP_BEGIN_NAMESPACE class Utility { public: enum CornerEdge { TopLeftCorner = 0, TopEdge = 1, TopRightCorner = 2, RightEdge = 3, BottomRightCorner = 4, BottomEdge = 5, BottomLeftCorner = 6, LeftEdge = 7 }; static QImage dropShadow(const QPixmap &px, qreal radius, const QColor &color); static QImage borderImage(const QPixmap &px, const QMargins &borders, const QSize &size, QImage::Format format = QImage::Format_ARGB32_Premultiplied); static QList sudokuByRect(const QRect &rect, QMargins borders); static xcb_atom_t internAtom(const char *name); static void startWindowSystemMove(quint32 WId); static void cancelWindowMoveResize(quint32 WId); static void showWindowSystemMenu(quint32 WId, QPoint globalPos = QPoint()); static void setFrameExtents(WId wid, const QMargins &margins); static void setShapeRectangles(quint32 WId, const QRegion ®ion, bool onlyInput = true, bool transparentInput = false); static void setShapePath(quint32 WId, const QPainterPath &path, bool onlyInput = true, bool transparentInput = false); static void startWindowSystemResize(quint32 WId, CornerEdge cornerEdge, const QPoint &globalPos = QPoint()); static bool setWindowCursor(quint32 WId, CornerEdge ce); static QRegion regionAddMargins(const QRegion ®ion, const QMargins &margins, const QPoint &offset = QPoint(0, 0)); static QByteArray windowProperty(quint32 WId, xcb_atom_t propAtom, xcb_atom_t typeAtom, quint32 len); static void setWindowProperty(quint32 WId, xcb_atom_t propAtom, xcb_atom_t typeAtom, const void *data, quint32 len, uint8_t format = 8); static void clearWindowProperty(quint32 WId, xcb_atom_t propAtom); struct BlurArea { qint32 x; qint32 y; qint32 width; qint32 height; qint32 xRadius; qint32 yRaduis; inline BlurArea operator *(qreal scale) { if (qFuzzyCompare(1.0, scale)) return *this; BlurArea new_area; new_area.x = qRound64(x * scale); new_area.y = qRound64(y * scale); new_area.width = qRound64(width * scale); new_area.height = qRound64(height * scale); new_area.xRadius = qRound64(xRadius * scale); new_area.yRaduis = qRound64(yRaduis * scale); return new_area; } inline BlurArea &operator *=(qreal scale) { return *this = *this * scale; } }; // by Deepin Window Manager static bool hasBlurWindow(); static bool hasComposite(); static bool blurWindowBackground(const quint32 WId, const QVector &areas); static bool blurWindowBackgroundByPaths(const quint32 WId, const QList &paths); static bool blurWindowBackgroundByImage(const quint32 WId, const QRect &blurRect, const QImage &maskImage); static void clearWindowBlur(const quint32 WId); static quint32 getWorkspaceForWindow(quint32 WId); static QVector getWindows(); static QVector getCurrentWorkspaceWindows(); struct QtMotifWmHints { quint32 flags, functions, decorations; qint32 input_mode; quint32 status; }; static QtMotifWmHints getMotifWmHints(quint32 WId); static void setMotifWmHints(quint32 WId, const QtMotifWmHints &hints); static quint32 getNativeTopLevelWindow(quint32 WId); static QPoint translateCoordinates(const QPoint &pos, quint32 src, quint32 dst); static QRect windowGeometry(quint32 WId); #ifdef Q_OS_LINUX static int XIconifyWindow(void *display, quint32 w, int screen_number); #endif private: static void sendMoveResizeMessage(quint32 WId, uint32_t action, QPoint globalPos = QPoint(), Qt::MouseButton qbutton = Qt::LeftButton); static QWindow *getWindowById(quint32 WId); static qreal getWindowDevicePixelRatio(quint32 WId); }; DPP_END_NAMESPACE QT_BEGIN_NAMESPACE DPP_USE_NAMESPACE QDebug operator<<(QDebug deg, const Utility::BlurArea &area); inline QPainterPath operator *(const QPainterPath &path, qreal scale) { if (qFuzzyCompare(1.0, scale)) return path; QPainterPath new_path = path; for (int i = 0; i < path.elementCount(); ++i) { const QPainterPath::Element &e = path.elementAt(i); new_path.setElementPositionAt(i, qRound(e.x * scale), qRound(e.y * scale)); } return new_path; } inline QPainterPath &operator *=(QPainterPath &path, qreal scale) { if (qFuzzyCompare(1.0, scale)) return path; for (int i = 0; i < path.elementCount(); ++i) { const QPainterPath::Element &e = path.elementAt(i); path.setElementPositionAt(i, qRound(e.x * scale), qRound(e.y * scale)); } return path; } inline QRect operator *(const QRect &rect, qreal scale) { if (qFuzzyCompare(1.0, scale)) return rect; return QRect(qRound(rect.left() * scale), qRound(rect.top() * scale), qRound(rect.width() * scale), qRound(rect.height() * scale)); } inline QMargins operator -(const QRect &r1, const QRect &r2) { return QMargins(r2.left() - r1.left(), r2.top() - r1.top(), r1.right() - r2.right(), r1.bottom() - r2.bottom()); } inline QRegion operator *(const QRegion &pointRegion, qreal scale) { if (qFuzzyCompare(1.0, scale)) return pointRegion; QRegion pixelRegon; foreach (const QRect &rect, pointRegion.rects()) { pixelRegon += rect * scale; } return pixelRegon; } QT_END_NAMESPACE #endif // UTILITY_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/utility_x11.cpp000066400000000000000000000620311325534707400243540ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "utility.h" #include "qxcbintegration.h" #include "qxcbconnection.h" #include "qxcbscreen.h" #include "dplatformintegration.h" #include "dxcbwmsupport.h" #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) #include #endif #include #include #include #define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */ #define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */ #define XATOM_MOVE_RESIZE "_NET_WM_MOVERESIZE" #define XDEEPIN_BLUR_REGION "_NET_WM_DEEPIN_BLUR_REGION" #define XDEEPIN_BLUR_REGION_ROUNDED "_NET_WM_DEEPIN_BLUR_REGION_ROUNDED" #define _GTK_SHOW_WINDOW_MENU "_GTK_SHOW_WINDOW_MENU" QT_BEGIN_NAMESPACE //extern Q_WIDGETS_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); extern Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0); QT_END_NAMESPACE DPP_BEGIN_NAMESPACE QImage Utility::dropShadow(const QPixmap &px, qreal radius, const QColor &color) { if (px.isNull()) return QImage(); QImage tmp(px.size() + QSize(radius * 2, radius * 2), QImage::Format_ARGB32_Premultiplied); tmp.fill(0); QPainter tmpPainter(&tmp); tmpPainter.setCompositionMode(QPainter::CompositionMode_Source); tmpPainter.drawPixmap(QPoint(radius, radius), px); tmpPainter.end(); // blur the alpha channel QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied); blurred.fill(0); QPainter blurPainter(&blurred); qt_blurImage(&blurPainter, tmp, radius, false, true); blurPainter.end(); if (color == QColor(Qt::black)) return blurred; tmp = blurred; // blacken the image... tmpPainter.begin(&tmp); tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); tmpPainter.fillRect(tmp.rect(), color); tmpPainter.end(); return tmp; } QList Utility::sudokuByRect(const QRect &rect, QMargins borders) { QList list; // qreal border_width = borders.left() + borders.right(); // if ( border_width > rect.width()) { // borders.setLeft(borders.left() / border_width * rect.width()); // borders.setRight(rect.width() - borders.left()); // } // qreal border_height = borders.top() + borders.bottom(); // if (border_height > rect.height()) { // borders.setTop(borders.top()/ border_height * rect.height()); // borders.setBottom(rect.height() - borders.top()); // } const QRect &contentsRect = rect - borders; list << QRect(0, 0, borders.left(), borders.top()); list << QRect(list.at(0).topRight(), QSize(contentsRect.width(), borders.top())).translated(1, 0); list << QRect(list.at(1).topRight(), QSize(borders.right(), borders.top())).translated(1, 0); list << QRect(list.at(0).bottomLeft(), QSize(borders.left(), contentsRect.height())).translated(0, 1); list << contentsRect; list << QRect(contentsRect.topRight(), QSize(borders.right(), contentsRect.height())).translated(1, 0); list << QRect(list.at(3).bottomLeft(), QSize(borders.left(), borders.bottom())).translated(0, 1); list << QRect(contentsRect.bottomLeft(), QSize(contentsRect.width(), borders.bottom())).translated(0, 1); list << QRect(contentsRect.bottomRight(), QSize(borders.left(), borders.bottom())).translated(1, 1); return list; } QImage Utility::borderImage(const QPixmap &px, const QMargins &borders, const QSize &size, QImage::Format format) { QImage image(size, format); QPainter pa(&image); const QList sudoku_src = sudokuByRect(px.rect(), borders); const QList sudoku_tar = sudokuByRect(QRect(QPoint(0, 0), size), borders); pa.setCompositionMode(QPainter::CompositionMode_Source); for (int i = 0; i < 9; ++i) { pa.drawPixmap(sudoku_tar[i], px, sudoku_src[i]); } pa.end(); return image; } xcb_atom_t Utility::internAtom(const char *name) { if (!name || *name == 0) return XCB_NONE; xcb_intern_atom_cookie_t cookie = xcb_intern_atom(QX11Info::connection(), true, strlen(name), name); xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(QX11Info::connection(), cookie, 0); if (!reply) return XCB_NONE; xcb_atom_t atom = reply->atom; free(reply); return atom; } void Utility::startWindowSystemMove(quint32 WId) { sendMoveResizeMessage(WId, _NET_WM_MOVERESIZE_MOVE); } void Utility::cancelWindowMoveResize(quint32 WId) { sendMoveResizeMessage(WId, _NET_WM_MOVERESIZE_CANCEL); } void Utility::showWindowSystemMenu(quint32 WId, QPoint globalPos) { if (globalPos.isNull()) { globalPos = qApp->primaryScreen()->handle()->cursor()->pos(); } xcb_client_message_event_t xev; xev.response_type = XCB_CLIENT_MESSAGE; xev.type = internAtom(_GTK_SHOW_WINDOW_MENU); xev.window = WId; xev.format = 32; xev.data.data32[1] = globalPos.x(); xev.data.data32[2] = globalPos.y(); xcb_send_event(QX11Info::connection(), false, QX11Info::appRootWindow(QX11Info::appScreen()), XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, (const char *)&xev); xcb_flush(QX11Info::connection()); } void Utility::setFrameExtents(WId wid, const QMargins &margins) { xcb_atom_t frameExtents = internAtom("_GTK_FRAME_EXTENTS"); if (frameExtents == XCB_NONE) { qWarning() << "Failed to create atom with name _GTK_FRAME_EXTENTS"; return; } int32_t datas[4]; datas[0] = int32_t(margins.left()); datas[1] = int32_t(margins.right()); datas[2] = int32_t(margins.top()); datas[3] = int32_t(margins.bottom()); xcb_change_property_checked(QX11Info::connection(), XCB_PROP_MODE_REPLACE, xcb_window_t(wid), frameExtents, XCB_ATOM_CARDINAL, 32, 4, datas); } static QVector qregion2XcbRectangles(const QRegion ®ion) { QVector rectangles; rectangles.reserve(region.rectCount()); for (const QRect &rect : region.rects()) { xcb_rectangle_t r; r.x = rect.x(); r.y = rect.y(); r.width = rect.width(); r.height = rect.height(); rectangles << r; } return rectangles; } static void setShapeRectangles(quint32 WId, const QVector &rectangles, bool onlyInput, bool transparentInput = false) { xcb_shape_mask(QX11Info::connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, WId, 0, 0, XCB_NONE); if (transparentInput) { xcb_shape_rectangles(QX11Info::connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_YX_BANDED, WId, 0, 0, 0, 0); if (onlyInput) return; } else { xcb_shape_mask(QX11Info::connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, WId, 0, 0, XCB_NONE); } if (rectangles.isEmpty()) { return; } xcb_shape_rectangles(QX11Info::connection(), XCB_SHAPE_SO_SET, onlyInput ? XCB_SHAPE_SK_INPUT : XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_YX_BANDED, WId, 0, 0, rectangles.size(), rectangles.constData()); } void Utility::setShapeRectangles(quint32 WId, const QRegion ®ion, bool onlyInput, bool transparentInput) { ::setShapeRectangles(WId, qregion2XcbRectangles(region), onlyInput, transparentInput); } void Utility::setShapePath(quint32 WId, const QPainterPath &path, bool onlyInput, bool transparentInput) { if (path.isEmpty()) { return ::setShapeRectangles(WId, QVector(), onlyInput, transparentInput); } QVector rectangles; foreach(const QPolygonF &polygon, path.toFillPolygons()) { foreach(const QRect &area, QRegion(polygon.toPolygon()).rects()) { xcb_rectangle_t rectangle; rectangle.x = area.x(); rectangle.y = area.y(); rectangle.width = area.width(); rectangle.height = area.height(); rectangles.append(std::move(rectangle)); } } ::setShapeRectangles(WId, rectangles, onlyInput, transparentInput); } void Utility::sendMoveResizeMessage(quint32 WId, uint32_t action, QPoint globalPos, Qt::MouseButton qbutton) { int xbtn = qbutton == Qt::LeftButton ? XCB_BUTTON_INDEX_1 : qbutton == Qt::RightButton ? XCB_BUTTON_INDEX_3 : XCB_BUTTON_INDEX_ANY; if (globalPos.isNull()) { globalPos = qApp->primaryScreen()->handle()->cursor()->pos(); } xcb_client_message_event_t xev; xev.response_type = XCB_CLIENT_MESSAGE; xev.type = internAtom(XATOM_MOVE_RESIZE); xev.window = WId; xev.format = 32; xev.data.data32[0] = globalPos.x(); xev.data.data32[1] = globalPos.y(); xev.data.data32[2] = action; xev.data.data32[3] = xbtn; xev.data.data32[4] = 0; if (action != _NET_WM_MOVERESIZE_CANCEL) xcb_ungrab_pointer(QX11Info::connection(), QX11Info::appTime()); xcb_send_event(QX11Info::connection(), false, QX11Info::appRootWindow(QX11Info::appScreen()), XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, (const char *)&xev); xcb_flush(QX11Info::connection()); } QWindow *Utility::getWindowById(quint32 WId) { for (QWindow *w : qApp->allWindows()) { if (w->handle() && w->handle()->winId() == WId) { return w; } } return Q_NULLPTR; } qreal Utility::getWindowDevicePixelRatio(quint32 WId) { if (const QWindow *w = getWindowById(WId)) return w->devicePixelRatio(); return qApp->devicePixelRatio(); } void Utility::startWindowSystemResize(quint32 WId, CornerEdge cornerEdge, const QPoint &globalPos) { sendMoveResizeMessage(WId, cornerEdge, globalPos); } static xcb_cursor_t CornerEdge2Xcb_cursor_t(Utility::CornerEdge ce) { switch (ce) { case Utility::TopEdge: return XC_top_side; case Utility::TopRightCorner: return XC_top_right_corner; case Utility::RightEdge: return XC_right_side; case Utility::BottomRightCorner: return XC_bottom_right_corner; case Utility::BottomEdge: return XC_bottom_side; case Utility::BottomLeftCorner: return XC_bottom_left_corner; case Utility::LeftEdge: return XC_left_side; case Utility::TopLeftCorner: return XC_top_left_corner; default: return XCB_CURSOR_NONE; } } bool Utility::setWindowCursor(quint32 WId, Utility::CornerEdge ce) { const auto display = QX11Info::display(); Cursor cursor = XCreateFontCursor(display, CornerEdge2Xcb_cursor_t(ce)); if (!cursor) { qWarning() << "[ui]::setWindowCursor() call XCreateFontCursor() failed"; return false; } const int result = XDefineCursor(display, WId, cursor); XFlush(display); return result == Success; } QRegion Utility::regionAddMargins(const QRegion ®ion, const QMargins &margins, const QPoint &offset) { QRegion tmp; for (const QRect &rect : region.rects()) { tmp += rect.translated(offset) + margins; } return tmp; } QByteArray Utility::windowProperty(quint32 WId, xcb_atom_t propAtom, xcb_atom_t typeAtom, quint32 len) { QByteArray data; xcb_connection_t* conn = QX11Info::connection(); xcb_get_property_cookie_t cookie = xcb_get_property(conn, false, WId, propAtom, typeAtom, 0, len); xcb_generic_error_t* err = nullptr; xcb_get_property_reply_t* reply = xcb_get_property_reply(conn, cookie, &err); if (reply != nullptr) { len = xcb_get_property_value_length(reply); const char* buf = static_cast(xcb_get_property_value(reply)); data.append(buf, len); free(reply); } if (err != nullptr) { free(err); } return data; } void Utility::setWindowProperty(quint32 WId, xcb_atom_t propAtom, xcb_atom_t typeAtom, const void *data, quint32 len, uint8_t format) { xcb_connection_t* conn = QX11Info::connection(); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, WId, propAtom, typeAtom, format, len, data); xcb_flush(conn); } void Utility::clearWindowProperty(quint32 WId, xcb_atom_t propAtom) { xcb_delete_property_checked(QX11Info::connection(), WId, propAtom); } bool Utility::hasBlurWindow() { return DXcbWMSupport::instance()->hasBlurWindow(); } bool Utility::hasComposite() { return DXcbWMSupport::instance()->hasComposite(); } bool Utility::blurWindowBackground(const quint32 WId, const QVector &areas) { if (!hasBlurWindow()) return false; if (DXcbWMSupport::instance()->isDeepinWM()) { xcb_atom_t atom = DXcbWMSupport::instance()->_net_wm_deepin_blur_region_rounded_atom; if (atom == XCB_NONE) return false; if (areas.isEmpty()) { QVector areas; areas << BlurArea(); } clearWindowProperty(WId, DXcbWMSupport::instance()->_net_wm_deepin_blur_region_mask); setWindowProperty(WId, atom, XCB_ATOM_CARDINAL, areas.constData(), areas.size() * sizeof(BlurArea) / sizeof(quint32), sizeof(quint32) * 8); } else { xcb_atom_t atom = DXcbWMSupport::instance()->_kde_net_wm_blur_rehind_region_atom; if (atom == XCB_NONE) return false; QVector rects; foreach (const BlurArea &area, areas) { if (area.xRadius <= 0 || area.yRaduis <= 0) { rects << area.x << area.y << area.width << area.height; } else { QPainterPath path; path.addRoundedRect(area.x, area.y, area.width, area.height, area.xRadius, area.yRaduis); foreach(const QPolygonF &polygon, path.toFillPolygons()) { foreach(const QRect &area, QRegion(polygon.toPolygon()).rects()) { rects << area.x() << area.y() << area.width() << area.height(); } } } } clearWindowProperty(WId, DXcbWMSupport::instance()->_net_wm_deepin_blur_region_mask); setWindowProperty(WId, atom, XCB_ATOM_CARDINAL, rects.constData(), rects.size(), sizeof(quint32) * 8); } return true; } bool Utility::blurWindowBackgroundByPaths(const quint32 WId, const QList &paths) { if (DXcbWMSupport::instance()->isDeepinWM()) { QRect boundingRect; for (const QPainterPath &p : paths) { boundingRect |= p.boundingRect().toRect(); } QImage image(boundingRect.size(), QImage::Format_Alpha8); image.fill(Qt::transparent); QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing); painter.translate(-boundingRect.topLeft()); for (const QPainterPath &p : paths) { painter.fillPath(p, Qt::black); } return blurWindowBackgroundByImage(WId, boundingRect, image); } else if (DXcbWMSupport::instance()->isKwin()) { xcb_atom_t atom = DXcbWMSupport::instance()->_kde_net_wm_blur_rehind_region_atom; if (atom == XCB_NONE) return false; QVector rects; foreach (const QPainterPath &path, paths) { foreach(const QPolygonF &polygon, path.toFillPolygons()) { foreach(const QRect &area, QRegion(polygon.toPolygon()).rects()) { rects << area.x() << area.y() << area.width() << area.height(); } } } setWindowProperty(WId, atom, XCB_ATOM_CARDINAL, rects.constData(), rects.size(), sizeof(quint32) * 8); } return true; } bool Utility::blurWindowBackgroundByImage(const quint32 WId, const QRect &blurRect, const QImage &maskImage) { if (!DXcbWMSupport::instance()->isDeepinWM() || maskImage.format() != QImage::Format_Alpha8) return false; QByteArray array; QVector area; area.reserve(5); area << blurRect.x() << blurRect.y() << blurRect.width() << blurRect.height() << maskImage.bytesPerLine(); array.reserve(area.size() * sizeof(qint32) / sizeof(char) * area.size() + maskImage.byteCount()); array.append((const char*)area.constData(), sizeof(qint32) / sizeof(char) * area.size()); array.append((const char*)maskImage.constBits(), maskImage.byteCount()); clearWindowProperty(WId, DXcbWMSupport::instance()->_net_wm_deepin_blur_region_rounded_atom); setWindowProperty(WId, DXcbWMSupport::instance()->_net_wm_deepin_blur_region_mask, DXcbWMSupport::instance()->_net_wm_deepin_blur_region_mask, array.constData(), array.length(), 8); return true; } void Utility::clearWindowBlur(const quint32 WId) { clearWindowProperty(WId, DXcbWMSupport::instance()->_net_wm_deepin_blur_region_rounded_atom); clearWindowProperty(WId, DXcbWMSupport::instance()->_net_wm_deepin_blur_region_mask); clearWindowProperty(WId, DXcbWMSupport::instance()->_kde_net_wm_blur_rehind_region_atom); } quint32 Utility::getWorkspaceForWindow(quint32 WId) { xcb_get_property_cookie_t cookie = xcb_get_property(DPlatformIntegration::xcbConnection()->xcb_connection(), false, WId, Utility::internAtom("_NET_WM_DESKTOP"), XCB_ATOM_CARDINAL, 0, 1); QScopedPointer reply( xcb_get_property_reply(DPlatformIntegration::xcbConnection()->xcb_connection(), cookie, NULL)); if (reply && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 && reply->value_len == 1) { return *(quint32*)xcb_get_property_value(reply.data()); } return 0; } Utility::QtMotifWmHints Utility::getMotifWmHints(quint32 WId) { xcb_connection_t *xcb_connect = DPlatformIntegration::xcbConnection()->xcb_connection(); QtMotifWmHints hints; xcb_get_property_cookie_t get_cookie = xcb_get_property_unchecked(xcb_connect, 0, WId, DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_MOTIF_WM_HINTS), DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_MOTIF_WM_HINTS), 0, 20); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connect, get_cookie, NULL); if (reply && reply->format == 32 && reply->type == DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_MOTIF_WM_HINTS)) { hints = *((QtMotifWmHints *)xcb_get_property_value(reply)); } else { hints.flags = 0L; hints.functions = DXcbWMSupport::MWM_FUNC_ALL; hints.decorations = DXcbWMSupport::MWM_DECOR_ALL; hints.input_mode = 0L; hints.status = 0L; } free(reply); return hints; } void Utility::setMotifWmHints(quint32 WId, const Utility::QtMotifWmHints &hints) { if (hints.flags != 0l) { #ifdef Q_XCB_CALL2 Q_XCB_CALL2(xcb_change_property(DPlatformIntegration::xcbConnection()->xcb_connection(), XCB_PROP_MODE_REPLACE, WId, DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_MOTIF_WM_HINTS), DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_MOTIF_WM_HINTS), 32, 5, &hints), c); #else xcb_change_property(DPlatformIntegration::xcbConnection()->xcb_connection(), XCB_PROP_MODE_REPLACE, WId, DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_MOTIF_WM_HINTS), DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_MOTIF_WM_HINTS), 32, 5, &hints); #endif } else { #ifdef Q_XCB_CALL2 Q_XCB_CALL2(xcb_delete_property(DPlatformIntegration::xcbConnection()->xcb_connection(), WId, DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_MOTIF_WM_HINTS)), DPlatformIntegration::xcbConnection()->xcb_connection()); #else xcb_delete_property(DPlatformIntegration::xcbConnection()->xcb_connection(), WId, DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_MOTIF_WM_HINTS)); #endif } } quint32 Utility::getNativeTopLevelWindow(quint32 WId) { xcb_connection_t *xcb_connection = DPlatformIntegration::xcbConnection()->xcb_connection(); do { xcb_query_tree_cookie_t cookie = xcb_query_tree_unchecked(xcb_connection, WId); xcb_query_tree_reply_t *reply = xcb_query_tree_reply(xcb_connection, cookie, NULL); if (reply) { if (reply->parent == reply->root) break; QtMotifWmHints hints = getMotifWmHints(reply->parent); if (hints.flags == 0) break; hints = getMotifWmHints(WId); if ((hints.decorations & DXcbWMSupport::MWM_DECOR_BORDER) == DXcbWMSupport::MWM_DECOR_BORDER) break; WId = reply->parent; free(reply); } else { break; } } while (true); return WId; } QPoint Utility::translateCoordinates(const QPoint &pos, quint32 src, quint32 dst) { QPoint ret; xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(DPlatformIntegration::xcbConnection()->xcb_connection(), src, dst, pos.x(), pos.y()); xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(DPlatformIntegration::xcbConnection()->xcb_connection(), cookie, NULL); if (reply) { ret.setX(reply->dst_x); ret.setY(reply->dst_y); free(reply); } return ret; } QRect Utility::windowGeometry(quint32 WId) { xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply( DPlatformIntegration::xcbConnection()->xcb_connection(), xcb_get_geometry(DPlatformIntegration::xcbConnection()->xcb_connection(), WId), NULL); QRect rect; if (geom) { // -- // add the border_width for the window managers frame... some window managers // do not use a border_width of zero for their frames, and if we the left and // top strut, we ensure that pos() is absolutely correct. frameGeometry() // will still be incorrect though... perhaps i should have foffset as well, to // indicate the frame offset (equal to the border_width on X). // - Brad // -- copied from qwidget_x11.cpp rect = QRect(geom->x, geom->y, geom->width, geom->height); free(geom); } return rect; } int Utility::XIconifyWindow(void *display, quint32 w, int screen_number) { return ::XIconifyWindow(reinterpret_cast(display), w, screen_number); } QVector Utility::getWindows() { return DXcbWMSupport::instance()->allWindow(); } QVector Utility::getCurrentWorkspaceWindows() { quint32 current_workspace = 0; xcb_get_property_cookie_t cookie = xcb_get_property(DPlatformIntegration::xcbConnection()->xcb_connection(), false, DPlatformIntegration::xcbConnection()->rootWindow(), Utility::internAtom("_NET_CURRENT_DESKTOP"), XCB_ATOM_CARDINAL, 0, 1); QScopedPointer reply( xcb_get_property_reply(DPlatformIntegration::xcbConnection()->xcb_connection(), cookie, NULL)); if (reply && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 && reply->value_len == 1) { current_workspace = *(quint32*)xcb_get_property_value(reply.data()); } QVector windows; foreach (quint32 WId, getWindows()) { if (getWorkspaceForWindow(WId) == current_workspace) { windows << WId; } } return windows; } DPP_END_NAMESPACE QT_BEGIN_NAMESPACE QDebug operator<<(QDebug deg, const Utility::BlurArea &area) { QDebugStateSaver saver(deg); Q_UNUSED(saver) deg.setAutoInsertSpaces(true); deg << "x:" << area.x << "y:" << area.y << "width:" << area.width << "height:" << area.height << "xRadius:" << area.xRadius << "yRadius:" << area.yRaduis; return deg; } QT_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/vtablehook.cpp000066400000000000000000000037521325534707400243230ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "vtablehook.h" DPP_BEGIN_NAMESPACE QHash VtableHook::objToOriginalVfptr; QHash VtableHook::objToGhostVfptr; QMap VtableHook::objDestructFun; bool VtableHook::copyVtable(quintptr **obj) { quintptr *vtable = *obj; while (*vtable > 0) { ++vtable; } int vtable_size = vtable - *obj; if (vtable_size == 0) return false; quintptr *new_vtable = new quintptr[++vtable_size]; memcpy(new_vtable, *obj, (vtable_size) * sizeof(quintptr)); //! save original vfptr objToOriginalVfptr[obj] = *obj; *obj = new_vtable; //! save ghost vfptr objToGhostVfptr[obj] = new_vtable; return true; } bool VtableHook::clearGhostVtable(void *obj) { objToOriginalVfptr.remove((quintptr**)obj); objDestructFun.remove(obj); quintptr *vtable = objToGhostVfptr.take(obj); if (vtable) { delete[] vtable; return true; } return false; } void VtableHook::autoCleanVtable(void *obj) { quintptr fun = objDestructFun.value(obj); if (!fun) return; typedef void(*Destruct)(void*); Destruct destruct = *reinterpret_cast(&fun); // call origin destruct function destruct(obj); // clean clearGhostVtable(obj); } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/vtablehook.h000066400000000000000000000251551325534707400237710ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef VTABLEHOOK_H #define VTABLEHOOK_H #include #include #include #include "global.h" DPP_BEGIN_NAMESPACE static inline quintptr toQuintptr(void *ptr) { return *(quintptr*)ptr; } template struct _TMP { public: template static ReturnType callOriginalFun(const QHash &objToOriginalVfptr, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) { quintptr *vfptr_t2 = objToOriginalVfptr.value((quintptr**)obj, 0); if (!vfptr_t2) return (obj->*fun)(std::forward(args)...); quintptr fun1_offset = toQuintptr(&fun); if (fun1_offset < 0 || fun1_offset > UINT_LEAST16_MAX) return (obj->*fun)(std::forward(args)...); quintptr *vfptr_t1 = *(quintptr**)obj; quintptr old_fun = *(vfptr_t1 + fun1_offset / sizeof(quintptr)); quintptr new_fun = *(vfptr_t2 + fun1_offset / sizeof(quintptr)); // reset to original fun *(vfptr_t1 + fun1_offset / sizeof(quintptr)) = new_fun; // call const ReturnType &return_value = (obj->*fun)(std::forward(args)...); // reset to old_fun *(vfptr_t1 + fun1_offset / sizeof(quintptr)) = old_fun; return return_value; } }; template <> struct _TMP { public: template static void callOriginalFun(const QHash &objToOriginalVfptr, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) { quintptr *vfptr_t2 = objToOriginalVfptr.value((quintptr**)obj, 0); if (!vfptr_t2) return (obj->*fun)(std::forward(args)...); quintptr fun1_offset = toQuintptr(&fun); if (fun1_offset < 0 || fun1_offset > UINT_LEAST16_MAX) return (obj->*fun)(std::forward(args)...); quintptr *vfptr_t1 = *(quintptr**)obj; quintptr old_fun = *(vfptr_t1 + fun1_offset / sizeof(quintptr)); quintptr new_fun = *(vfptr_t2 + fun1_offset / sizeof(quintptr)); // reset to original fun *(vfptr_t1 + fun1_offset / sizeof(quintptr)) = new_fun; // call (obj->*fun)(std::forward(args)...); // reset to old_fun *(vfptr_t1 + fun1_offset / sizeof(quintptr)) = old_fun; } }; class VtableHook { public: //###(zccrs): 由于无法通过代码直接获取析构函数在虚表中的位置 // 暂定QObject类型对象为第5项, 其它为第2项 enum DestructFunIndex { Normal = 1, Qt_Object = 4 }; static constexpr DestructFunIndex getDestructFunIndex(...) { return Normal;} static constexpr DestructFunIndex getDestructFunIndex(const QObject*) { return Qt_Object;} static void autoCleanVtable(void *obj); template static bool ensureVtable(T *obj) { quintptr **_obj = (quintptr**)(obj); if (objToOriginalVfptr.contains(_obj)) { // 不知道什么原因, 此时obj对象的虚表已经被还原 if (objToGhostVfptr.value((void*)obj) != *_obj) { clearGhostVtable((void*)obj); } else { return true; } } if (!copyVtable(_obj)) return false; // 备份对象的析构函数 DestructFunIndex index = getDestructFunIndex(obj); quintptr *new_vtable = *((quintptr**)obj); objDestructFun[(void*)obj] = new_vtable[index]; // 覆盖对象的析构函数, 用于自动清理虚表数据 static bool testResult = false; class TestClass { public: static void testClean(T *that) { Q_UNUSED(that) testResult = true; } }; // 尝试覆盖析构函数并测试 testResult = false; new_vtable[index] = reinterpret_cast(&TestClass::testClean); delete obj; // 析构函数覆盖失败 if (!testResult) { qFatal("Failed do override destruct function"); qDebug() << "object:" << obj; abort(); } // 真正覆盖析构函数 new_vtable[index] = reinterpret_cast(&autoCleanVtable); return true; } template class OverrideDestruct : public T { ~OverrideDestruct() override;}; template struct CheckCompatibleArguments { enum { value = false }; }; template struct CheckCompatibleArguments { enum { value = true }; }; template static bool overrideVfptrFun(const typename QtPrivate::FunctionPointer::Object *t1, Fun1 fun1, const typename QtPrivate::FunctionPointer::Object *t2, Fun2 fun2) { typedef QtPrivate::FunctionPointer FunInfo1; typedef QtPrivate::FunctionPointer FunInfo2; // 检查析构函数是否为虚 class OverrideDestruct : public FunInfo1::Object { ~OverrideDestruct() override;}; //compilation error if the arguments does not match. Q_STATIC_ASSERT_X((CheckCompatibleArguments::value), "Function1 and Function2 arguments are not compatible."); Q_STATIC_ASSERT_X((CheckCompatibleArguments, QtPrivate::List>::value), "Function1 and Function2 return type are not compatible.."); //! ({code}) in the form of a code is to eliminate - Wstrict - aliasing build warnings quintptr fun1_offset = toQuintptr(&fun1); quintptr fun2_offset = toQuintptr(&fun2); if (fun1_offset < 0 || fun1_offset > UINT_LEAST16_MAX) return false; if (!ensureVtable(t1)) { return false; } quintptr *vfptr_t1 = *(quintptr**)t1; quintptr *vfptr_t2 = *(quintptr**)t2; if (fun2_offset > UINT_LEAST16_MAX) *(vfptr_t1 + fun1_offset / sizeof(quintptr)) = fun2_offset; else *(vfptr_t1 + fun1_offset / sizeof(quintptr)) = *(vfptr_t2 + fun2_offset / sizeof(quintptr)); return true; } template struct FunctionPointer { }; template struct FunctionPointer { typedef QtPrivate::List Arguments; }; template struct FunctionPointer { typedef QtPrivate::List Arguments; }; template static bool overrideVfptrFun(const typename QtPrivate::FunctionPointer::Object *t1, Fun1 fun1, Fun2 fun2) { typedef QtPrivate::FunctionPointer FunInfo1; typedef QtPrivate::FunctionPointer FunInfo2; // 检查析构函数是否为虚 class OverrideDestruct : public FunInfo1::Object { ~OverrideDestruct() override;}; Q_STATIC_ASSERT(!FunInfo2::IsPointerToMemberFunction); //compilation error if the arguments does not match. Q_STATIC_ASSERT_X((CheckCompatibleArguments::Arguments, typename FunInfo2::Arguments>::value), "Function1 and Function2 arguments are not compatible."); Q_STATIC_ASSERT_X((CheckCompatibleArguments, QtPrivate::List>::value), "Function1 and Function2 return type are not compatible.."); //! ({code}) in the form of a code is to eliminate - Wstrict - aliasing build warnings quintptr fun1_offset = toQuintptr(&fun1); quintptr fun2_offset = toQuintptr(&fun2); if (fun1_offset < 0 || fun1_offset > UINT_LEAST16_MAX) return false; if (!ensureVtable(t1)) { return false; } quintptr *vfptr_t1 = *(quintptr**)t1; *(vfptr_t1 + fun1_offset / sizeof(quintptr)) = fun2_offset; return true; } template static bool resetVfptrFun(const typename QtPrivate::FunctionPointer::Object *t1, Fun1 fun1) { quintptr *vfptr_t2 = objToOriginalVfptr.value((quintptr**)t1, 0); if (!vfptr_t2) return false; quintptr fun1_offset = toQuintptr(&fun1); if (fun1_offset < 0 || fun1_offset > UINT_LEAST16_MAX) return false; quintptr *vfptr_t1 = *(quintptr**)t1; *(vfptr_t1 + fun1_offset / sizeof(quintptr)) = *(vfptr_t2 + fun1_offset / sizeof(quintptr)); return true; } template static Fun originalFun(const typename QtPrivate::FunctionPointer::Object *obj, Fun fun) { quintptr *vfptr_t2 = objToOriginalVfptr.value((quintptr**)obj, 0); if (!vfptr_t2) return fun; quintptr fun1_offset = *(quintptr *)&fun; if (fun1_offset < 0 || fun1_offset > UINT_LEAST16_MAX) return fun; quintptr *o_fun = vfptr_t2 + fun1_offset / sizeof(quintptr); return *reinterpret_cast(o_fun); } template static typename QtPrivate::FunctionPointer::ReturnType callOriginalFun(typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) { return _TMP::ReturnType>::callOriginalFun(objToOriginalVfptr, obj, fun, std::forward(args)...); } private: static bool copyVtable(quintptr **obj); static bool clearGhostVtable(void *obj); static QHash objToOriginalVfptr; static QHash objToGhostVfptr; static QMap objDestructFun; }; DPP_END_NAMESPACE #endif // VTABLEHOOK_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/windoweventhook.cpp000066400000000000000000000400611325534707400254110ustar00rootroot00000000000000/* * Copyright (C) 2016 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "windoweventhook.h" #include "vtablehook.h" #include "utility.h" #include "dframewindow.h" #include "dplatformwindowhelper.h" #include "dhighdpi.h" #define private public #define protected public #include "qxcbdrag.h" #include "qxcbkeyboard.h" #undef private #undef protected #include #include #include #include #include DPP_BEGIN_NAMESPACE PUBLIC_CLASS(QXcbWindow, WindowEventHook); WindowEventHook::WindowEventHook(QXcbWindow *window, bool redirectContent) { const Qt::WindowType &type = window->window()->type(); if (redirectContent) { VtableHook::overrideVfptrFun(window, &QXcbWindowEventListener::handleConfigureNotifyEvent, this, &WindowEventHook::handleConfigureNotifyEvent); VtableHook::overrideVfptrFun(window, &QXcbWindowEventListener::handleMapNotifyEvent, this, &WindowEventHook::handleMapNotifyEvent); } if (type == Qt::Widget || type == Qt::Window || type == Qt::Dialog) { VtableHook::overrideVfptrFun(window, &QXcbWindowEventListener::handleClientMessageEvent, this, &WindowEventHook::handleClientMessageEvent); VtableHook::overrideVfptrFun(window, &QXcbWindowEventListener::handleFocusInEvent, this, &WindowEventHook::handleFocusInEvent); VtableHook::overrideVfptrFun(window, &QXcbWindowEventListener::handleFocusOutEvent, this, &WindowEventHook::handleFocusOutEvent); #ifdef XCB_USE_XINPUT22 VtableHook::overrideVfptrFun(window, &QXcbWindowEventListener::handleXIEnterLeave, this, &WindowEventHook::handleXIEnterLeave); #endif } if (type == Qt::Window) { VtableHook::overrideVfptrFun(window, &QXcbWindowEventListener::handlePropertyNotifyEvent, this, &WindowEventHook::handlePropertyNotifyEvent); } } //#define DND_DEBUG #ifdef DND_DEBUG #define DEBUG qDebug #else #define DEBUG if(0) qDebug #endif #ifdef DND_DEBUG #define DNDDEBUG qDebug() #else #define DNDDEBUG if(0) qDebug() #endif static inline xcb_window_t xcb_window(QWindow *w) { return static_cast(w->handle())->xcb_window(); } xcb_atom_t toXdndAction(const QXcbDrag *drag, Qt::DropAction a) { switch (a) { case Qt::CopyAction: return drag->atom(QXcbAtom::XdndActionCopy); case Qt::LinkAction: return drag->atom(QXcbAtom::XdndActionLink); case Qt::MoveAction: case Qt::TargetMoveAction: return drag->atom(QXcbAtom::XdndActionMove); case Qt::IgnoreAction: return XCB_NONE; default: return drag->atom(QXcbAtom::XdndActionCopy); } } void WindowEventHook::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event) { QXcbWindow *me = window(); me->QXcbWindow::handleConfigureNotifyEvent(event); if (DPlatformWindowHelper *helper = DPlatformWindowHelper::mapped.value(me)) { helper->m_frameWindow->markXPixmapToDirty(event->width, event->height); } } void WindowEventHook::handleMapNotifyEvent(const xcb_map_notify_event_t *event) { QXcbWindow *me = window(); me->QXcbWindow::handleMapNotifyEvent(event); if (DFrameWindow *frame = qobject_cast(me->window())) { frame->markXPixmapToDirty(); } else if (DPlatformWindowHelper *helper = DPlatformWindowHelper::mapped.value(me)) { helper->m_frameWindow->markXPixmapToDirty(); } } void WindowEventHook::handleClientMessageEvent(const xcb_client_message_event_t *event) { QXcbWindow *me = window(); if (event->format == 32 && event->type == me->atom(QXcbAtom::XdndDrop)) { QXcbDrag *drag = me->connection()->drag(); DEBUG("xdndHandleDrop"); if (!drag->currentWindow) { drag->xdnd_dragsource = 0; return; // sanity } const uint32_t *l = event->data.data32; DEBUG("xdnd drop"); if (l[0] != drag->xdnd_dragsource) { DEBUG("xdnd drop from unexpected source (%x not %x", l[0], drag->xdnd_dragsource); return; } // update the "user time" from the timestamp in the event. if (l[2] != 0) drag->target_time = /*X11->userTime =*/ l[2]; Qt::DropActions supported_drop_actions; QMimeData *dropData = 0; if (drag->currentDrag()) { dropData = drag->currentDrag()->mimeData(); supported_drop_actions = Qt::DropActions(l[4]); } else { #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) dropData = drag->platformDropData(); #else //FIXME(zccrs): must use the drop data object dropData = reinterpret_cast(drag->m_dropData); #endif supported_drop_actions = drag->accepted_drop_action; // Drop coming from another app? Update keyboard modifiers. QGuiApplicationPrivate::modifier_buttons = QGuiApplication::queryKeyboardModifiers(); } if (!dropData) return; // ### // int at = findXdndDropTransactionByTime(target_time); // if (at != -1) // dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data; // if we can't find it, then use the data in the drag manager bool directSaveMode = dropData->hasFormat("XdndDirectSave0"); dropData->setProperty("IsDirectSaveMode", directSaveMode); QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(drag->currentWindow.data(), dropData, drag->currentPosition, supported_drop_actions); drag->setExecutedDropAction(response.acceptedAction()); if (directSaveMode) { const QUrl &url = dropData->property("DirectSaveUrl").toUrl(); if (url.isValid() && drag->xdnd_dragsource) { xcb_atom_t XdndDirectSaveAtom = me->connection()->internAtom("XdndDirectSave0"); xcb_atom_t textAtom = me->connection()->internAtom("text/plain"); QByteArray basename = Utility::windowProperty(drag->xdnd_dragsource, XdndDirectSaveAtom, textAtom, 1024); QByteArray fileUri = url.toString().toLocal8Bit() + "/" + basename; Utility::setWindowProperty(drag->xdnd_dragsource, XdndDirectSaveAtom, textAtom, fileUri.constData(), fileUri.length()); Q_UNUSED(dropData->data("XdndDirectSave0")); } } xcb_client_message_event_t finished; finished.response_type = XCB_CLIENT_MESSAGE; finished.sequence = 0; finished.window = drag->xdnd_dragsource; finished.format = 32; finished.type = drag->atom(QXcbAtom::XdndFinished); finished.data.data32[0] = drag->currentWindow ? xcb_window(drag->currentWindow.data()) : XCB_NONE; finished.data.data32[1] = response.isAccepted(); // flags finished.data.data32[2] = toXdndAction(drag, response.acceptedAction()); #ifdef Q_XCB_CALL Q_XCB_CALL(xcb_send_event(drag->xcb_connection(), false, drag->current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (char *)&finished)); #else xcb_send_event(drag->xcb_connection(), false, drag->current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (char *)&finished); #endif drag->xdnd_dragsource = 0; drag->currentWindow.clear(); drag->waiting_for_status = false; // reset drag->target_time = XCB_CURRENT_TIME; } else { me->QXcbWindow::handleClientMessageEvent(event); } } bool WindowEventHook::relayFocusToModalWindow(QWindow *w, QXcbConnection *connection) { QWindow *modal_window = 0; if (QGuiApplicationPrivate::instance()->isWindowBlocked(w,&modal_window) && modal_window != w) { if (!modal_window->isExposed()) return false; modal_window->requestActivate(); connection->flush(); return true; } return false; } void WindowEventHook::handleFocusInEvent(const xcb_focus_in_event_t *event) { // Ignore focus events that are being sent only because the pointer is over // our window, even if the input focus is in a different window. if (event->detail == XCB_NOTIFY_DETAIL_POINTER) return; QXcbWindow *xcbWindow = window(); QWindow *w = static_cast(QObjectPrivate::get(xcbWindow->window()))->eventReceiver(); if (DFrameWindow *frame = qobject_cast(w)) { if (frame->m_contentWindow) w = frame->m_contentWindow; else return; } if (relayFocusToModalWindow(w, xcbWindow->connection())) return; #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) xcbWindow->connection()->setFocusWindow(w); #else xcbWindow->connection()->setFocusWindow(static_cast(w->handle())); #endif QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason); } enum QX11EmbedMessageType { XEMBED_EMBEDDED_NOTIFY = 0, XEMBED_WINDOW_ACTIVATE = 1, XEMBED_WINDOW_DEACTIVATE = 2, XEMBED_REQUEST_FOCUS = 3, XEMBED_FOCUS_IN = 4, XEMBED_FOCUS_OUT = 5, XEMBED_FOCUS_NEXT = 6, XEMBED_FOCUS_PREV = 7, XEMBED_MODALITY_ON = 10, XEMBED_MODALITY_OFF = 11, XEMBED_REGISTER_ACCELERATOR = 12, XEMBED_UNREGISTER_ACCELERATOR = 13, XEMBED_ACTIVATE_ACCELERATOR = 14 }; static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event) { if (!event) { // FocusIn event is not in the queue, proceed with FocusOut normally. QWindowSystemInterface::handleWindowActivated(0, Qt::ActiveWindowFocusReason); return true; } uint response_type = event->response_type & ~0x80; if (response_type == XCB_FOCUS_IN) { // Ignore focus events that are being sent only because the pointer is over // our window, even if the input focus is in a different window. xcb_focus_in_event_t *e = (xcb_focus_in_event_t *) event; if (e->detail != XCB_NOTIFY_DETAIL_POINTER) return true; } /* We are also interested in XEMBED_FOCUS_IN events */ if (response_type == XCB_CLIENT_MESSAGE) { xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event; if (cme->type == connection->atom(QXcbAtom::_XEMBED) && cme->data.data32[1] == XEMBED_FOCUS_IN) return true; } return false; } void WindowEventHook::handleFocusOutEvent(const xcb_focus_out_event_t *event) { // Ignore focus events if (event->mode == XCB_NOTIFY_MODE_GRAB) { return; } // Ignore focus events that are being sent only because the pointer is over // our window, even if the input focus is in a different window. if (event->detail == XCB_NOTIFY_DETAIL_POINTER) return; QXcbWindow *xcbWindow = window(); QWindow *w = static_cast(QObjectPrivate::get(xcbWindow->window()))->eventReceiver(); if (relayFocusToModalWindow(w, xcbWindow->connection())) return; xcbWindow->connection()->setFocusWindow(0); // Do not set the active window to 0 if there is a FocusIn coming. // There is however no equivalent for XPutBackEvent so register a // callback for QXcbConnection instead. xcbWindow->connection()->addPeekFunc(focusInPeeker); } void WindowEventHook::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) { DQXcbWindow *window = reinterpret_cast(this->window()); QWindow *ww = window->window(); window->QXcbWindow::handlePropertyNotifyEvent(event); if (event->window == window->xcb_window() && event->atom == window->atom(QXcbAtom::_NET_WM_STATE)) { QXcbWindow::NetWmStates states = window->netWmStates(); ww->setProperty(netWmStates, (int)states); if (const DFrameWindow *frame = qobject_cast(ww)) { if (frame->m_contentWindow) frame->m_contentWindow->setProperty(netWmStates, (int)states); } } } #ifdef XCB_USE_XINPUT22 static Qt::KeyboardModifiers translateModifiers(const QXcbKeyboard::_mod_masks &rmod_masks, int s) { Qt::KeyboardModifiers ret = 0; if (s & XCB_MOD_MASK_SHIFT) ret |= Qt::ShiftModifier; if (s & XCB_MOD_MASK_CONTROL) ret |= Qt::ControlModifier; if (s & rmod_masks.alt) ret |= Qt::AltModifier; if (s & rmod_masks.meta) ret |= Qt::MetaModifier; if (s & rmod_masks.altgr) ret |= Qt::GroupSwitchModifier; return ret; } static inline int fixed1616ToInt(FP1616 val) { return int((qreal(val >> 16)) + (val & 0xFFFF) / (qreal)0xFFFF); } void WindowEventHook::handleXIEnterLeave(xcb_ge_event_t *event) { DQXcbWindow *me = reinterpret_cast(window()); xXIEnterEvent *ev = reinterpret_cast(event); // Compare the window with current mouse grabber to prevent deliver events to any other windows. // If leave event occurs and the window is under mouse - allow to deliver the leave event. QXcbWindow *mouseGrabber = me->connection()->mouseGrabber(); if (mouseGrabber && mouseGrabber != me && (ev->evtype != XI_Leave || QGuiApplicationPrivate::currentMouseWindow != me->window())) { return; } if (ev->evtype == XI_Enter) { if (ev->buttons_len > 0) { #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) Qt::MouseButtons buttons = me->connection()->buttons(); #else Qt::MouseButtons buttons = me->connection()->buttonState(); #endif const Qt::KeyboardModifiers modifiers = translateModifiers(me->connection()->keyboard()->rmod_masks, ev->mods.effective_mods); unsigned char *buttonMask = (unsigned char *) &ev[1]; for (int i = 1; i <= 15; ++i) { Qt::MouseButton b = me->connection()->translateMouseButton(i); if (b == Qt::NoButton) continue; bool isSet = XIMaskIsSet(buttonMask, i); #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) me->connection()->setButton(b, isSet); #else me->connection()->setButtonState(b, isSet); #endif const int event_x = fixed1616ToInt(ev->event_x); const int event_y = fixed1616ToInt(ev->event_y); const int root_x = fixed1616ToInt(ev->root_x); const int root_y = fixed1616ToInt(ev->root_y); if (buttons.testFlag(b)) { if (!isSet) { QGuiApplicationPrivate::lastCursorPosition = DHighDpi::fromNativePixels(QPointF(root_x, root_y), me->window()); me->handleButtonReleaseEvent(event_x, event_y, root_x, root_y, 0, modifiers, ev->time); } } else if (isSet) { QGuiApplicationPrivate::lastCursorPosition = DHighDpi::fromNativePixels(QPointF(root_x, root_y), me->window()); me->handleButtonPressEvent(event_x, event_y, root_x, root_y, 0, modifiers, ev->time); } } } } me->QXcbWindow::handleXIEnterLeave(event); } #endif DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/windoweventhook.h000066400000000000000000000032611325534707400250570ustar00rootroot00000000000000/* * Copyright (C) 2016 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef WINDOWEVENTHOOK_H #define WINDOWEVENTHOOK_H #include "qxcbwindow.h" #include "global.h" DPP_BEGIN_NAMESPACE class WindowEventHook { public: WindowEventHook(QXcbWindow *window, bool redirectContent); QXcbWindow *window() const { return static_cast(reinterpret_cast(const_cast(this)));} void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *); void handleMapNotifyEvent(const xcb_map_notify_event_t *); void handleClientMessageEvent(const xcb_client_message_event_t *event); void handleFocusInEvent(const xcb_focus_in_event_t *event); void handleFocusOutEvent(const xcb_focus_out_event_t *event); void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event); #ifdef XCB_USE_XINPUT22 void handleXIEnterLeave(xcb_ge_event_t *event); #endif private: static bool relayFocusToModalWindow(QWindow *w, QXcbConnection *connection); }; DPP_END_NAMESPACE #endif // WINDOWEVENTHOOK_H deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/windows.pri000066400000000000000000000000001325534707400236460ustar00rootroot00000000000000deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/xcbnativeeventfilter.cpp000066400000000000000000000201211325534707400264050ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "xcbnativeeventfilter.h" #include "utility.h" #include "dplatformwindowhelper.h" #include "dframewindow.h" #define private public #include "qxcbconnection.h" #include "qxcbclipboard.h" #undef private #include "dplatformintegration.h" #include "dxcbwmsupport.h" #include #include #include #include #include DPP_BEGIN_NAMESPACE XcbNativeEventFilter::XcbNativeEventFilter(QXcbConnection *connection) : m_connection(connection) { // init damage first event value xcb_prefetch_extension_data(connection->xcb_connection(), &xcb_damage_id); const auto* reply = xcb_get_extension_data(connection->xcb_connection(), &xcb_damage_id); if (reply->present) { m_damageFirstEvent = reply->first_event; xcb_damage_query_version_unchecked(connection->xcb_connection(), XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION); } else { m_damageFirstEvent = 0; } } QClipboard::Mode XcbNativeEventFilter::clipboardModeForAtom(xcb_atom_t a) const { if (a == XCB_ATOM_PRIMARY) return QClipboard::Selection; if (a == m_connection->atom(QXcbAtom::CLIPBOARD)) return QClipboard::Clipboard; // not supported enum value, used to detect errors return QClipboard::FindBuffer; } typedef struct qt_xcb_ge_event_t { uint8_t response_type; uint8_t extension; uint16_t sequence; uint32_t length; uint16_t event_type; } qt_xcb_ge_event_t; static inline bool isXIEvent(xcb_generic_event_t *event, int opCode) { qt_xcb_ge_event_t *e = (qt_xcb_ge_event_t *)event; return e->extension == opCode; } bool XcbNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { Q_UNUSED(eventType) Q_UNUSED(result) xcb_generic_event_t *event = reinterpret_cast(message); uint response_type = event->response_type & ~0x80; if (response_type == m_connection->xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) { xcb_xfixes_selection_notify_event_t *xsn = (xcb_xfixes_selection_notify_event_t *)event; if (xsn->selection == DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_NET_WM_CM_S0)) { DXcbWMSupport::instance()->updateHasComposite(); } QClipboard::Mode mode = clipboardModeForAtom(xsn->selection); if (mode > QClipboard::Selection) return false; // here we care only about the xfixes events that come from non Qt processes if (xsn->owner == XCB_NONE && xsn->subtype == XCB_XFIXES_SELECTION_EVENT_SET_SELECTION_OWNER) { QXcbClipboard *xcbClipboard = m_connection->m_clipboard; xcbClipboard->emitChanged(mode); } } else if (response_type == m_damageFirstEvent + XCB_DAMAGE_NOTIFY) { xcb_damage_notify_event_t *ev = (xcb_damage_notify_event_t*)event; QXcbWindow *window = m_connection->platformWindowFromId(ev->drawable); if (Q_LIKELY(window)) { DPlatformWindowHelper *helper = DPlatformWindowHelper::mapped.value(window); if (Q_LIKELY(helper)) { helper->m_frameWindow->updateFromContents(ev); } } } else { switch (response_type) { case XCB_PROPERTY_NOTIFY: { xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; if (pn->atom == DPlatformIntegration::xcbConnection()->atom(QXcbAtom::_MOTIF_WM_HINTS)) { emit DXcbWMSupport::instance()->windowMotifWMHintsChanged(pn->window); } else { if (pn->window != DPlatformIntegration::instance()->defaultConnection()->rootWindow()) { return false; } if (pn->atom == DPlatformIntegration::instance()->defaultConnection()->atom(QXcbAtom::_NET_SUPPORTED)) { DXcbWMSupport::instance()->updateNetWMAtoms(); } else if (pn->atom == DPlatformIntegration::instance()->defaultConnection()->atom(QXcbAtom::_NET_SUPPORTING_WM_CHECK)) { DXcbWMSupport::instance()->updateWMName(); } else if (pn->atom == DXcbWMSupport::instance()->_kde_net_wm_blur_rehind_region_atom) { DXcbWMSupport::instance()->updateRootWindowProperties(); } else if (pn->atom == Utility::internAtom("_NET_CLIENT_LIST_STACKING")) { emit DXcbWMSupport::instance()->windowListChanged(); } } break; } // 修复Qt程序对触摸板的自然滚动开关后不能实时生效 // 由于在收到xi的DeviceChanged事件后,Qt更新ScrollingDevice时没有更新verticalIncrement字段 // 导致那些使用increment的正负值控制自然滚动开关的设备对Qt程序无法实时生效 // 有些电脑上触摸板没有此问题,是因为他的系统环境中没有安装xserver-xorg-input-synaptics #ifdef XCB_USE_XINPUT21 case XCB_GE_GENERIC: { QXcbConnection *xcb_connect = DPlatformIntegration::xcbConnection(); if (xcb_connect->m_xi2Enabled && isXIEvent(event, xcb_connect->m_xiOpCode)) { xXIGenericDeviceEvent *xiEvent = reinterpret_cast(event); if (xiEvent->evtype != XI_DeviceChanged) { return false; } xXIDeviceChangedEvent *xiDCEvent = reinterpret_cast(xiEvent); QHash::iterator device = xcb_connect->m_scrollingDevices.find(xiDCEvent->sourceid); int nrDevices = 0; XIDeviceInfo* xiDeviceInfo = XIQueryDevice(static_cast(xcb_connect->xlib_display()), xiDCEvent->sourceid, &nrDevices); if (nrDevices <= 0) { return false; } for (int c = 0; c < xiDeviceInfo->num_classes; ++c) { if (xiDeviceInfo->classes[c]->type == XIScrollClass) { XIScrollClassInfo *sci = reinterpret_cast(xiDeviceInfo->classes[c]); if (sci->scroll_type == XIScrollTypeVertical) { device->legacyOrientations = device->orientations; device->orientations |= Qt::Vertical; device->verticalIndex = sci->number; device->verticalIncrement = std::signbit(sci->increment) ? -std::abs(device->verticalIncrement) : std::abs(device->verticalIncrement); } else if (sci->scroll_type == XIScrollTypeHorizontal) { device->legacyOrientations = device->orientations; device->orientations |= Qt::Horizontal; device->horizontalIndex = sci->number; device->horizontalIncrement = std::signbit(sci->increment) ? -std::abs(device->horizontalIncrement) : std::abs(device->horizontalIncrement); } } } XIFreeDeviceInfo(xiDeviceInfo); } break; } #endif default: break; } } return false; } DPP_END_NAMESPACE deepin-qt5dxcb-plugin-1.1.8.4+ds/platformplugin/xcbnativeeventfilter.h000066400000000000000000000025341325534707400260620ustar00rootroot00000000000000/* * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XCBNATIVEEVENTFILTER_H #define XCBNATIVEEVENTFILTER_H #include "global.h" #include #include #include QT_BEGIN_NAMESPACE class QXcbConnection; QT_END_NAMESPACE DPP_BEGIN_NAMESPACE class XcbNativeEventFilter : public QAbstractNativeEventFilter { public: XcbNativeEventFilter(QXcbConnection *connection); QClipboard::Mode clipboardModeForAtom(xcb_atom_t a) const; bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE; private: QXcbConnection *m_connection; uint8_t m_damageFirstEvent; }; DPP_END_NAMESPACE #endif // XCBNATIVEEVENTFILTER_H deepin-qt5dxcb-plugin-1.1.8.4+ds/qt5dxcb-plugin.pro000066400000000000000000000001121325534707400217710ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS += \ platformplugin/qt5platform-plugin.pro