├── .vscode └── settings.json ├── COPYING ├── README.md ├── com.ml4w.settings.json ├── com.ml4w.settings.pkginst ├── data ├── com.ml4w.settings.desktop.in ├── com.ml4w.settings.gschema.xml ├── com.ml4w.settings.metainfo.xml.in ├── com.ml4w.settings.service.in ├── com.ml4w.settings.svg ├── icons │ ├── hicolor │ │ ├── scalable │ │ │ ├── actions │ │ │ │ └── settings-symbolic.svg │ │ │ └── apps │ │ │ │ └── com.ml4w.settings.svg │ │ └── symbolic │ │ │ └── apps │ │ │ └── com.ml4w.settings-symbolic.svg │ └── meson.build └── meson.build ├── meson.build ├── po ├── LINGUAS ├── POTFILES.in └── meson.build ├── setup.sh └── src ├── __init__.py ├── dotfiles-settings.gresource.xml ├── dotfiles-settings.in ├── gtk └── help-overlay.ui ├── main.py ├── meson.build ├── window.py └── window.ui /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.watcherExclude": { 3 | "**/.git/objects/**": true, 4 | "**/.git/subtree-cache/**": true, 5 | "**/.hg/store/**": true, 6 | ".flatpak/**": true, 7 | "_build/**": true 8 | } 9 | } -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | 676 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ML4W Dotfiles Settings App 2 | 3 | Users of the ML4W Dotfiles for Hyprland can use the ML4W Settings App to configure settings of the configuration. 4 | 5 | ![image](https://github.com/user-attachments/assets/fb222c31-17a0-40e7-97ca-75017db85b0a) 6 | 7 | You can configure the behaviour and modules of the status bar Waybar, appearance options for the application launcher Rofi and many aspects of your Hyprland configuration with configuration variations. 8 | 9 | https://github.com/mylinuxforwork/dotfiles/wiki/Configuration-Variations 10 | 11 | The ML4W Settings App will be installed with the Dotfiles as Flatpak. 12 | 13 | ## Installation 14 | 15 | Copy the following command into your terminal. 16 | 17 | ``` 18 | bash -c "$(curl -s https://raw.githubusercontent.com/mylinuxforwork/dotfiles-settings/master/setup.sh)" 19 | ``` 20 | > The installation is build with ML4W Packages Installer. https://github.com/mylinuxforwork/packages-installer 21 | 22 | ## Uninstall 23 | 24 | ``` 25 | flatpak uninstall com.ml4w.settings 26 | ``` -------------------------------------------------------------------------------- /com.ml4w.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "id" : "com.ml4w.settings", 3 | "runtime" : "org.gnome.Platform", 4 | "runtime-version" : "47", 5 | "sdk" : "org.gnome.Sdk", 6 | "command" : "dotfiles-settings", 7 | "finish-args" : [ 8 | "--share=network", 9 | "--share=ipc", 10 | "--socket=fallback-x11", 11 | "--device=dri", 12 | "--socket=wayland", 13 | "--talk-name=org.freedesktop.Flatpak", 14 | "--filesystem=home" 15 | ], 16 | "cleanup" : [ 17 | "/include", 18 | "/lib/pkgconfig", 19 | "/man", 20 | "/share/doc", 21 | "/share/gtk-doc", 22 | "/share/man", 23 | "/share/pkgconfig", 24 | "*.la", 25 | "*.a" 26 | ], 27 | "modules" : [ 28 | { 29 | "name" : "dotfiles-settings", 30 | "builddir" : true, 31 | "buildsystem" : "meson", 32 | "sources" : [ 33 | { 34 | "type" : "git", 35 | "url" : "file:///home/raabe/Projects" 36 | } 37 | ] 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /com.ml4w.settings.pkginst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mylinuxforwork/dotfiles-settings/e22677fa20e649f1de08af6295782937d1f04249/com.ml4w.settings.pkginst -------------------------------------------------------------------------------- /data/com.ml4w.settings.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=ML4W Setting App 3 | Exec=dotfiles-settings 4 | Icon=com.ml4w.settings 5 | Terminal=false 6 | Type=Application 7 | Categories=Utility; 8 | Keywords=GTK; 9 | StartupNotify=true 10 | DBusActivatable=true 11 | -------------------------------------------------------------------------------- /data/com.ml4w.settings.gschema.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /data/com.ml4w.settings.metainfo.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.ml4w.settings 4 | CC0-1.0 5 | GPL-3.0-or-later 6 | 7 | Dotfiles-settings 8 | Keep the summary shorter, between 10 and 35 characters 9 | 10 |

No description

11 |
12 | 13 | 14 | Developer name 15 | 16 | 17 | 18 | https://example.org/ 19 | 20 | https://example.org/repository 21 | 22 | https://example.org/issues 23 | 24 | 25 | https://example.org/translate 26 | https://example.org/faq 27 | 28 | https://example.org/help 29 | 30 | https://example.org/donate 31 | 32 | https://example.org/contact 33 | 34 | https://example.org/contribute 35 | 36 | dotfiles-settings 37 | 39 | com.ml4w.settings.desktop 40 | 41 | 42 | 43 | 44 | 45 | #ff00ff 46 | #993d3d 47 | 48 | 49 | 50 | 51 | https://example.org/example1.png 52 | A caption 53 | 54 | 55 | https://example.org/example2.png 56 | A caption 57 | 58 | 59 | 60 | 61 | 62 | https://example.org/changelog.html#version_1.0.1 63 | 64 |

Release description

65 |
    66 |
  • List of changes
  • 67 |
  • List of changes
  • 68 |
69 |
70 |
71 |
72 | 73 |
74 | -------------------------------------------------------------------------------- /data/com.ml4w.settings.service.in: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=com.ml4w.settings 3 | Exec=@bindir@/dotfiles-settings --gapplication-service 4 | -------------------------------------------------------------------------------- /data/icons/hicolor/scalable/actions/settings-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/hicolor/scalable/apps/com.ml4w.settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /data/icons/hicolor/symbolic/apps/com.ml4w.settings-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /data/icons/meson.build: -------------------------------------------------------------------------------- 1 | application_id = 'com.ml4w.settings' 2 | 3 | scalable_dir = 'hicolor' / 'scalable' / 'apps' 4 | install_data( 5 | scalable_dir / ('@0@.svg').format(application_id), 6 | install_dir: get_option('datadir') / 'icons' / scalable_dir 7 | ) 8 | 9 | symbolic_dir = 'hicolor' / 'symbolic' / 'apps' 10 | install_data( 11 | symbolic_dir / ('@0@-symbolic.svg').format(application_id), 12 | install_dir: get_option('datadir') / 'icons' / symbolic_dir 13 | ) 14 | 15 | action_dir = join_paths('hicolor', 'scalable', 'actions') 16 | action_icons = [ 17 | # each icon must be registered here 18 | join_paths(action_dir, 'settings-symbolic.svg'), 19 | ] 20 | 21 | install_data( 22 | action_icons, 23 | install_dir: join_paths(get_option('datadir'), 'icons', action_dir) 24 | ) -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | desktop_file = i18n.merge_file( 2 | input: 'com.ml4w.settings.desktop.in', 3 | output: 'com.ml4w.settings.desktop', 4 | type: 'desktop', 5 | po_dir: '../po', 6 | install: true, 7 | install_dir: get_option('datadir') / 'applications' 8 | ) 9 | 10 | desktop_utils = find_program('desktop-file-validate', required: false) 11 | if desktop_utils.found() 12 | test('Validate desktop file', desktop_utils, args: [desktop_file]) 13 | endif 14 | 15 | appstream_file = i18n.merge_file( 16 | input: 'com.ml4w.settings.metainfo.xml.in', 17 | output: 'com.ml4w.settings.metainfo.xml', 18 | po_dir: '../po', 19 | install: true, 20 | install_dir: get_option('datadir') / 'metainfo' 21 | ) 22 | 23 | appstreamcli = find_program('appstreamcli', required: false, disabler: true) 24 | test('Validate appstream file', appstreamcli, 25 | args: ['validate', '--no-net', '--explain', appstream_file]) 26 | 27 | install_data('com.ml4w.settings.gschema.xml', 28 | install_dir: get_option('datadir') / 'glib-2.0' / 'schemas' 29 | ) 30 | 31 | compile_schemas = find_program('glib-compile-schemas', required: false, disabler: true) 32 | test('Validate schema file', 33 | compile_schemas, 34 | args: ['--strict', '--dry-run', meson.current_source_dir()]) 35 | 36 | 37 | service_conf = configuration_data() 38 | service_conf.set('bindir', get_option('prefix') / get_option('bindir')) 39 | configure_file( 40 | input: 'com.ml4w.settings.service.in', 41 | output: 'com.ml4w.settings.service', 42 | configuration: service_conf, 43 | install_dir: get_option('datadir') / 'dbus-1' / 'services' 44 | ) 45 | 46 | subdir('icons') 47 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('dotfiles-settings', 2 | version: '0.1.0', 3 | meson_version: '>= 1.0.0', 4 | default_options: [ 'warning_level=2', 'werror=false', ], 5 | ) 6 | 7 | i18n = import('i18n') 8 | gnome = import('gnome') 9 | 10 | 11 | 12 | 13 | subdir('data') 14 | subdir('src') 15 | subdir('po') 16 | 17 | gnome.post_install( 18 | glib_compile_schemas: true, 19 | gtk_update_icon_cache: true, 20 | update_desktop_database: true, 21 | ) 22 | -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | # Please keep this file sorted alphabetically. 2 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | # List of source files containing translatable strings. 2 | # Please keep this file sorted alphabetically. 3 | data/com.ml4w.settings.desktop.in 4 | data/com.ml4w.settings.metainfo.xml.in 5 | data/com.ml4w.settings.gschema.xml 6 | src/main.py 7 | src/window.py 8 | src/window.ui 9 | -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext('dotfiles-settings', preset: 'glib') 2 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ---------------------------------------------------------- 4 | # Flatpak Information 5 | # ---------------------------------------------------------- 6 | 7 | runtime="org.gnome.Platform/x86_64/47" 8 | app="com.ml4w.settings" 9 | download="https://github.com/mylinuxforwork/dotfiles-settings/releases/latest/download/$app.flatpak" 10 | 11 | # ---------------------------------------------------------- 12 | # Check if command exists 13 | # ---------------------------------------------------------- 14 | 15 | _commandExists() { 16 | package="$1" 17 | if ! type $package >/dev/null 2>&1; then 18 | echo 1 19 | else 20 | echo 0 21 | fi 22 | } 23 | 24 | # ---------------------------------------------------------- 25 | # Check if app is already installed 26 | # ---------------------------------------------------------- 27 | 28 | _checkFlatpakAppExists() { 29 | app="$1" 30 | flatpak_output=$(flatpak info $runtime) 31 | if [[ $flatpak_output == *"ID:"* ]]; then 32 | echo 0 33 | else 34 | echo 1 35 | fi 36 | } 37 | 38 | # ---------------------------------------------------------- 39 | # Check if flatpak is already installed 40 | # ---------------------------------------------------------- 41 | 42 | if [ "$(_commandExists "flatpak")" == "1" ]; then 43 | echo "ERROR: Please install flatpak first." 44 | exit 45 | fi 46 | 47 | # ---------------------------------------------------------- 48 | # Adding flathub remote 49 | # ---------------------------------------------------------- 50 | 51 | flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo 52 | 53 | # ---------------------------------------------------------- 54 | # Check for runtime 55 | # ---------------------------------------------------------- 56 | 57 | if [ "$(_checkFlatpakAppExists "$runtime")" == "1" ]; then 58 | echo 59 | echo ":: Installing runtime $runtime" 60 | sudo flatpak -y install $runtime 61 | fi 62 | 63 | # ---------------------------------------------------------- 64 | # Download app 65 | # ---------------------------------------------------------- 66 | 67 | echo 68 | echo ":: Downloading $app" 69 | if [ ! -d "$HOME/.cache" ]; then 70 | mkdir -p "$HOME/.cache" 71 | fi 72 | if [ -f "$HOME/.cache/$app.flatpak" ]; then 73 | rm "$HOME/.cache/$app.flatpak" 74 | fi 75 | wget -P "$HOME/.cache" "$download" 76 | if [ ! -f "$HOME/.cache/$app.flatpak" ]; then 77 | echo "ERROR: Download of $app.flatpak failed." 78 | exit 79 | fi 80 | # ---------------------------------------------------------- 81 | # Install app 82 | # ---------------------------------------------------------- 83 | 84 | cd "$HOME/.cache" 85 | flatpak --user -y --reinstall install $app.flatpak 86 | 87 | # ---------------------------------------------------------- 88 | # Cleanup 89 | # ---------------------------------------------------------- 90 | 91 | if [ -f "$HOME/.cache/$app.flatpak" ]; then 92 | rm "$HOME/.cache/$app.flatpak" 93 | fi 94 | 95 | # ---------------------------------------------------------- 96 | # Finishing up 97 | # ---------------------------------------------------------- 98 | 99 | echo 100 | echo ":: Setup complete. Run the app with flatpak run $app" 101 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mylinuxforwork/dotfiles-settings/e22677fa20e649f1de08af6295782937d1f04249/src/__init__.py -------------------------------------------------------------------------------- /src/dotfiles-settings.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | window.ui 5 | gtk/help-overlay.ui 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/dotfiles-settings.in: -------------------------------------------------------------------------------- 1 | #!@PYTHON@ 2 | 3 | # dotfiles-settings.in 4 | # 5 | # Copyright 2025 Unknown 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | # 20 | # SPDX-License-Identifier: GPL-3.0-or-later 21 | 22 | import os 23 | import sys 24 | import signal 25 | import locale 26 | import gettext 27 | 28 | VERSION = '@VERSION@' 29 | pkgdatadir = '@pkgdatadir@' 30 | localedir = '@localedir@' 31 | 32 | sys.path.insert(1, pkgdatadir) 33 | signal.signal(signal.SIGINT, signal.SIG_DFL) 34 | locale.bindtextdomain('dotfiles-settings', localedir) 35 | locale.textdomain('dotfiles-settings') 36 | gettext.install('dotfiles-settings', localedir) 37 | 38 | if __name__ == '__main__': 39 | import gi 40 | 41 | from gi.repository import Gio 42 | resource = Gio.Resource.load(os.path.join(pkgdatadir, 'dotfiles-settings.gresource')) 43 | resource._register() 44 | 45 | from dotfiles_settings import main 46 | sys.exit(main.main(VERSION)) 47 | -------------------------------------------------------------------------------- /src/gtk/help-overlay.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | True 5 | 6 | 7 | shortcuts 8 | 10 9 | 10 | 11 | General 12 | 13 | 14 | Show Shortcuts 15 | win.show-help-overlay 16 | 17 | 18 | 19 | 20 | Quit 21 | app.quit 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | # main.py 2 | # 3 | # Copyright 2025 Stephan Raabe 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | # SPDX-License-Identifier: GPL-3.0-or-later 19 | 20 | import sys 21 | import gi 22 | import subprocess 23 | import os 24 | import threading 25 | import json 26 | import pathlib 27 | import shutil 28 | import shlex 29 | import time 30 | 31 | gi.require_version('Gtk', '4.0') 32 | gi.require_version('Adw', '1') 33 | 34 | from gi.repository import Gtk, Gio, Adw 35 | from .window import DotfilesSettingsWindow 36 | 37 | # Get script path 38 | pathname = os.path.dirname(sys.argv[0]) 39 | 40 | #The main application singleton class. 41 | class DotfilesSettingsApplication(Adw.Application): 42 | 43 | path_name = pathname # Path of Application 44 | homeFolder = os.path.expanduser('~') # Path to home folder 45 | dotfiles = homeFolder + "/.config/" 46 | terminal = "alacritty" 47 | 48 | waybar_themes = [ 49 | "ml4w-minimal", 50 | "ml4w", 51 | "ml4w-blur", 52 | "ml4w-blur-bottom", 53 | "ml4w-bottom", 54 | "ml4w-modern" 55 | ] 56 | 57 | def __init__(self): 58 | super().__init__(application_id='com.ml4w.settings', 59 | flags=Gio.ApplicationFlags.DEFAULT_FLAGS) 60 | self.create_action('quit', lambda *_: self.quit(), ['q']) 61 | self.create_action('about', self.on_about_action) 62 | self.create_action('rofi_bordersize', self.on_rofi_bordersize) 63 | self.create_action('waybar_workspaces', self.on_waybar_workspaces) 64 | self.create_action('blur_radius', self.on_blur_radius) 65 | self.create_action('blur_sigma', self.on_blur_sigma) 66 | self.create_action('open_about_variations', self.on_open_about_variations) 67 | self.create_action('on_edit_wallpaper_effects', self.on_edit_animations) 68 | self.create_action('on_clearcache_wallpaper', self.on_clearcache_wallpaper) 69 | self.create_action('on_open_animations_folder', self.on_open_animations) 70 | self.create_action('on_edit_animations', self.on_edit_animations) 71 | self.create_action('on_reload_animations', self.on_reload_animations) 72 | self.create_action('on_open_decorations_folder', self.on_open_decorations) 73 | self.create_action('on_edit_decorations', self.on_edit_decorations) 74 | self.create_action('on_reload_decorations', self.on_reload_decorations) 75 | self.create_action('on_open_windows_folder', self.on_open_windows) 76 | self.create_action('on_edit_windows', self.on_edit_windows) 77 | self.create_action('on_reload_windows', self.on_reload_windows) 78 | self.create_action('on_open_workspaces_folder', self.on_open_workspaces) 79 | self.create_action('on_edit_workspaces', self.on_edit_workspaces) 80 | self.create_action('on_reload_workspaces', self.on_reload_workspaces) 81 | self.create_action('on_open_monitors_folder', self.on_open_monitors) 82 | self.create_action('on_edit_monitors', self.on_edit_monitors) 83 | self.create_action('on_reload_monitors', self.on_reload_monitors) 84 | self.create_action('on_open_keybindings_folder', self.on_open_keybindings) 85 | self.create_action('on_edit_keybindings', self.on_edit_keybindings) 86 | self.create_action('on_reload_keybindings', self.on_reload_keybindings) 87 | self.create_action('on_open_environments_folder', self.on_open_environments) 88 | self.create_action('on_edit_environments', self.on_edit_environments) 89 | self.create_action('on_reload_environments', self.on_reload_environments) 90 | self.create_action('on_open_layouts_folder', self.on_open_layouts) 91 | self.create_action('on_edit_layouts', self.on_edit_layouts) 92 | self.create_action('on_reload_layouts', self.on_reload_layouts) 93 | self.create_action('on_open_windowrules_folder', self.on_open_windowrules) 94 | self.create_action('on_edit_windowrules', self.on_edit_windowrules) 95 | self.create_action('on_reload_windowrules', self.on_reload_windowrules) 96 | 97 | # Called when the application is activated. 98 | def do_activate(self): 99 | self.win = self.props.active_window 100 | if not self.win: 101 | self.win = DotfilesSettingsWindow(application=self) 102 | 103 | self.waybar_toggle = self.win.waybar_toggle 104 | self.wallpaper_cache_toggle = self.win.wallpaper_cache_toggle 105 | self.waybar_workspaces = self.win.waybar_workspaces 106 | self.rofi_bordersize = self.win.rofi_bordersize 107 | self.waybar_toggle = self.win.waybar_toggle 108 | self.rofi_font = self.win.rofi_font 109 | self.dock_toggle = self.win.dock_toggle 110 | self.gamemode_toggle = self.win.gamemode_toggle 111 | self.default_browser = self.win.default_browser 112 | self.default_email = self.win.default_email 113 | self.default_filemanager = self.win.default_filemanager 114 | self.default_editor = self.win.default_editor 115 | self.default_networkmanager = self.win.default_networkmanager 116 | self.default_softwaremanager = self.win.default_softwaremanager 117 | self.default_terminal = self.win.default_terminal 118 | self.default_screenshoteditor = self.win.default_screenshoteditor 119 | self.default_calculator = self.win.default_calculator 120 | self.default_systemmonitor = self.win.default_systemmonitor 121 | self.default_emojipicker = self.win.default_emojipicker 122 | self.default_aurhelper = self.win.default_aurhelper 123 | self.default_installupdates = self.win.default_installupdates 124 | self.dd_wallpaper_effects = self.win.dd_wallpaper_effects 125 | self.dd_animations = self.win.dd_animations 126 | self.dd_environments = self.win.dd_environments 127 | self.dd_layouts = self.win.dd_layouts 128 | self.dd_monitors = self.win.dd_monitors 129 | self.dd_decorations = self.win.dd_decorations 130 | self.dd_windows = self.win.dd_windows 131 | self.dd_workspaces = self.win.dd_workspaces 132 | self.dd_windowrules = self.win.dd_windowrules 133 | self.dd_keybindings = self.win.dd_keybindings 134 | self.dd_timeformats = self.win.dd_timeformats 135 | self.dd_dateformats = self.win.dd_dateformats 136 | self.custom_datetime = self.win.custom_datetime 137 | self.custom_timezone = self.win.custom_timezone 138 | self.blur_radius = self.win.blur_radius 139 | self.blur_sigma = self.win.blur_sigma 140 | 141 | self.win.waybar_toggle.connect("notify::active",self.on_waybar_toggle) 142 | self.win.waybar_show_appmenu.connect("notify::active",self.on_waybar_show_appmenu) 143 | self.win.waybar_show_taskbar.connect("notify::active",self.on_waybar_show_taskbar) 144 | self.win.waybar_show_quicklinks.connect("notify::active",self.on_waybar_show_quicklinks) 145 | self.win.waybar_show_network.connect("notify::active",self.on_waybar_show_network) 146 | self.win.waybar_show_screenlock.connect("notify::active",self.on_waybar_show_screenlock) 147 | self.win.waybar_show_chatgpt.connect("notify::active",self.on_waybar_show_chatgpt) 148 | self.win.waybar_show_systray.connect("notify::active",self.on_waybar_show_systray) 149 | self.win.waybar_show_window.connect("notify::active",self.on_waybar_show_window) 150 | self.win.dock_toggle.connect("notify::active",self.on_dock_toggle) 151 | self.win.gamemode_toggle.connect("notify::active",self.on_gamemode_toggle) 152 | self.win.wallpaper_cache_toggle.connect("notify::active",self.on_wallpaper_cache_toggle) 153 | 154 | self.win.open_customconf.connect("clicked", self.on_open_customconf) 155 | self.win.open_quicklinks.connect("clicked", self.on_open_quicklinks) 156 | self.win.open_wallpaper_effects.connect("clicked", self.on_open_wallpaper_effects_folder) 157 | self.win.open_waybar_folder.connect("clicked", self.on_open_waybar_folder) 158 | self.win.open_timeformatspecifications.connect("clicked", self.on_open_timeformatspecifications) 159 | 160 | self.win.default_browser.connect("apply", self.on_default_browser) 161 | self.win.default_email.connect("apply", self.on_default_email) 162 | self.win.default_filemanager.connect("apply", self.on_default_filemanager) 163 | self.win.default_editor.connect("apply", self.on_default_editor) 164 | self.win.default_networkmanager.connect("apply", self.on_default_networkmanager) 165 | self.win.default_softwaremanager.connect("apply", self.on_default_softwaremanager) 166 | self.win.default_terminal.connect("apply", self.on_default_terminal) 167 | self.win.default_screenshoteditor.connect("apply", self.on_default_screenshoteditor) 168 | self.win.default_calculator.connect("apply", self.on_default_calculator) 169 | self.win.default_systemmonitor.connect("apply", self.on_default_systemmonitor) 170 | self.win.default_emojipicker.connect("apply", self.on_default_emojipicker) 171 | self.win.default_aurhelper.connect("apply", self.on_default_aurhelper) 172 | self.win.default_installupdates.connect("apply", self.on_default_installupdates) 173 | 174 | self.dd_wallpaper_effects.connect("notify::selected-item", self.on_wallpaper_effects_changed) 175 | self.dd_animations.connect("notify::selected-item", self.on_variation_changed,"animation") 176 | self.dd_monitors.connect("notify::selected-item", self.on_variation_changed,"monitor") 177 | self.dd_environments.connect("notify::selected-item", self.on_variation_changed,"environment") 178 | self.dd_layouts.connect("notify::selected-item", self.on_variation_changed,"layout") 179 | self.dd_decorations.connect("notify::selected-item", self.on_variation_changed,"decoration") 180 | self.dd_windows.connect("notify::selected-item", self.on_variation_changed,"window") 181 | self.dd_workspaces.connect("notify::selected-item", self.on_variation_changed,"workspace") 182 | self.dd_windowrules.connect("notify::selected-item", self.on_variation_changed,"windowrule") 183 | self.dd_keybindings.connect("notify::selected-item", self.on_variation_changed,"keybinding") 184 | self.dd_timeformats.connect("notify::selected-item", self.on_timeformats_changed) 185 | self.dd_dateformats.connect("notify::selected-item", self.on_dateformats_changed) 186 | self.custom_datetime.connect("apply", self.on_custom_datetime) 187 | self.custom_timezone.connect("apply", self.on_custom_timezone) 188 | 189 | self.waybar_workspaces.get_adjustment().connect("value-changed", self.on_waybar_workspaces) 190 | self.rofi_bordersize.get_adjustment().connect("value-changed", self.on_rofi_bordersize) 191 | self.blur_radius.get_adjustment().connect("value-changed", self.on_blur_radius) 192 | self.blur_sigma.get_adjustment().connect("value-changed", self.on_blur_sigma) 193 | self.rofi_font.connect("apply", self.on_rofi_font) 194 | 195 | self.win.present() 196 | 197 | # Open editor with custom.conf 198 | def on_open_customconf(self, widget): 199 | subprocess.Popen(["flatpak-spawn", "--host", self.default_editor.get_text(), self.dotfiles + "hypr/conf/custom.conf"]) 200 | 201 | # Open editor with quicklinks.conf 202 | def on_open_quicklinks(self, widget): 203 | subprocess.Popen(["flatpak-spawn", "--host", self.default_editor.get_text(), self.dotfiles + "ml4w/settings/waybar-quicklinks.json"]) 204 | 205 | def on_open_timeformatspecifications(self, widget): 206 | subprocess.Popen(["flatpak-spawn", "--host", self.default_browser.get_text(), "https://fmt.dev/latest/syntax/#chrono-format-specifications"]) 207 | 208 | def on_open_about_variations(self, widget, _): 209 | subprocess.Popen(["flatpak-spawn", "--host", self.default_browser.get_text(), "-new-window", "https://github.com/mylinuxforwork/dotfiles/wiki/Configuration-Variations"]) 210 | 211 | # Load default app 212 | def loadDefaultApp(self,f,d): 213 | with open(self.dotfiles + f, 'r') as file: 214 | value = file.read() 215 | d.set_text(value.strip()) 216 | d.set_show_apply_button(True) 217 | 218 | def on_variation_changed(self,widget,*data): 219 | value = widget.get_selected_item().get_string() 220 | self.overwriteFile("hypr/conf/" + data[1] + ".conf", "source = ~/.config/hypr/conf/" + data[1] + "s/" + value) 221 | 222 | def on_clearcache_wallpaper(self, widget, _): 223 | subprocess.Popen(["bash", self.dotfiles + "hypr/scripts/wallpaper-cache.sh"]) 224 | 225 | def on_timeformats_changed(self,widget,_): 226 | value = widget.get_selected_item().get_string() 227 | dateformat = self.dd_dateformats.get_selected_item().get_string() 228 | timedate = ' "format": "{:' + value + ' - ' + dateformat + '}",' 229 | self.updateSettingsBash("waybar_timeformat", value) 230 | self.replaceInFileCheckpoint("waybar/modules.json", '"clock"', '"format"', timedate) 231 | self.replaceInFileCheckpoint("hypr/hyprlock.conf", 'clock', 'cmd[update:1000]', ' text = cmd[update:1000] echo "$(date +"' + value + '")"') 232 | self.reloadWaybar() 233 | 234 | def on_dateformats_changed(self,widget,_): 235 | value = widget.get_selected_item().get_string() 236 | timeformat = self.dd_timeformats.get_selected_item().get_string() 237 | timedate = ' "format": "{:' + timeformat + ' - ' + value + '}",' 238 | self.updateSettingsBash("waybar_dateformat", value) 239 | self.replaceInFileCheckpoint("waybar/modules.json", '"clock"', '"format"', timedate) 240 | self.reloadWaybar() 241 | 242 | def on_custom_timezone(self, widget): 243 | value = widget.get_text() 244 | timezone = ' "timezone": "' + value + '",' 245 | print(timezone) 246 | self.replaceInFileCheckpoint("waybar/modules.json", '"clock"', '"timezone"', timezone) 247 | self.updateSettingsBash("waybar_timezone", value) 248 | self.reloadWaybar() 249 | 250 | def on_custom_datetime(self, widget): 251 | value = widget.get_text() 252 | if value != "": 253 | timedate = ' "format": "{:' + value + '}",' 254 | print(timedate) 255 | self.replaceInFileCheckpoint("waybar/modules.json", '"clock"', '"format"', timedate) 256 | self.updateSettingsBash("waybar_custom_timedateformat", value) 257 | else: 258 | dateformat = self.dd_dateformats.get_selected_item().get_string() 259 | timeformat = self.dd_timeformats.get_selected_item().get_string() 260 | timedate = ' "format": "{:' + timeformat + ' - ' + dateformat + '}",' 261 | print(timedate) 262 | self.replaceInFileCheckpoint("waybar/modules.json", '"clock"', '"format"', timedate) 263 | self.updateSettingsBash("waybar_custom_timedateformat", "") 264 | self.reloadWaybar() 265 | 266 | def on_wallpaper_effects_changed(self, widget, _): 267 | value = widget.get_selected_item().get_string() 268 | self.overwriteFile("ml4w/settings/wallpaper-effect.sh", value) 269 | subprocess.Popen(["flatpak-spawn", "--host", "bash", self.dotfiles + "hypr/scripts/wallpaper-effects.sh", "reload"]) 270 | 271 | def on_open_wallpaper_effects_folder(self, widget): 272 | self.on_open(widget, self.default_filemanager.get_text(), "hypr/effects/wallpaper") 273 | 274 | def on_open_waybar_folder(self, widget): 275 | self.on_open(widget, self.default_filemanager.get_text(), "waybar") 276 | 277 | # -------------------------------------------------------------- 278 | # VARIATIONS 279 | # -------------------------------------------------------------- 280 | 281 | # Animation 282 | def on_open_animations(self, widget, _): 283 | self.on_open(widget, self.default_filemanager.get_text(), "hypr/conf/animations") 284 | 285 | def on_reload_animations(self, widget, _): 286 | self.win.loadVariations(self.dd_animations,"animation") 287 | 288 | def on_edit_animations(self, widget, _): 289 | i = self.dd_animations.get_selected() 290 | f = self.dd_animations.get_model()[i].get_string() 291 | self.on_open(widget, self.default_editor.get_text(), "hypr/conf/animations/" + f) 292 | 293 | # Environment 294 | def on_open_environments(self, widget, _): 295 | self.on_open(widget, self.default_filemanager.get_text(), "hypr/conf/environments") 296 | 297 | def on_reload_environments(self, widget, _): 298 | self.win.loadVariations(self.dd_environments,"environment") 299 | 300 | def on_edit_environments(self, widget, _): 301 | i = self.dd_environments.get_selected() 302 | f = self.dd_environments.get_model()[i].get_string() 303 | self.on_open(widget, self.default_editor.get_text(), "hypr/conf/environments/" + f) 304 | 305 | # Layouts 306 | def on_open_layouts(self, widget, _): 307 | self.on_open(widget, self.default_filemanager.get_text(), "hypr/conf/layouts") 308 | 309 | def on_reload_layouts(self, widget, _): 310 | self.win.loadVariations(self.dd_layouts,"layout") 311 | 312 | def on_edit_layouts(self, widget, _): 313 | i = self.dd_layouts.get_selected() 314 | f = self.dd_layouts.get_model()[i].get_string() 315 | self.on_open(widget, self.default_editor.get_text(), "hypr/conf/layouts/" + f) 316 | 317 | # Monitors 318 | def on_open_monitors(self, widget, _): 319 | self.on_open(widget, self.default_filemanager.get_text(), "hypr/conf/monitors") 320 | 321 | def on_reload_monitors(self, widget, _): 322 | self.win.loadVariations(self.dd_monitors,"monitor") 323 | 324 | def on_edit_monitors(self, widget, _): 325 | i = self.dd_monitors.get_selected() 326 | f = self.dd_monitors.get_model()[i].get_string() 327 | self.on_open(widget, self.default_editor.get_text(), "hypr/conf/monitors/" + f) 328 | 329 | # Decorations 330 | def on_open_decorations(self, widget, _): 331 | self.on_open(widget, self.default_filemanager.get_text(), "hypr/conf/decorations") 332 | 333 | def on_reload_decorations(self, widget, _): 334 | self.win.loadVariations(self.dd_decorations,"decoration") 335 | 336 | def on_edit_decorations(self, widget, _): 337 | i = self.dd_decorations.get_selected() 338 | f = self.dd_decorations.get_model()[i].get_string() 339 | self.on_open(widget, self.default_editor.get_text(), "hypr/conf/decorations/" + f) 340 | 341 | # Workspaces 342 | def on_open_workspaces(self, widget, _): 343 | self.on_open(widget, self.default_filemanager.get_text(), "hypr/conf/workspaces") 344 | 345 | def on_reload_workspaces(self, widget, _): 346 | self.win.loadVariations(self.dd_windows,"workspace") 347 | 348 | def on_edit_workspaces(self, widget, _): 349 | i = self.dd_workspaces.get_selected() 350 | f = self.dd_workspaces.get_model()[i].get_string() 351 | print(f) 352 | self.on_open(widget, self.default_editor.get_text(), "hypr/conf/workspaces/" + f) 353 | 354 | # Monitors 355 | def on_open_windows(self, widget, _): 356 | self.on_open(widget, self.default_filemanager.get_text(), "hypr/conf/windows") 357 | 358 | def on_reload_windows(self, widget, _): 359 | self.win.loadVariations(self.dd_windows,"window") 360 | 361 | def on_edit_windows(self, widget, _): 362 | i = self.dd_windows.get_selected() 363 | f = self.dd_windows.get_model()[i].get_string() 364 | self.on_open(widget, self.default_editor.get_text(), "hypr/conf/windows/" + f) 365 | 366 | # Window Rules 367 | def on_open_windowrules(self, widget, _): 368 | self.on_open(widget, self.default_filemanager.get_text(), "hypr/conf/windowrules") 369 | 370 | def on_reload_windowrules(self, widget, _): 371 | self.win.loadVariations(self.dd_windowrules,"windowrule") 372 | 373 | def on_edit_windowrules(self, widget, _): 374 | i = self.dd_windowrules.get_selected() 375 | f = self.dd_windowrules.get_model()[i].get_string() 376 | self.on_open(widget, self.default_editor.get_text(), "hypr/conf/windowrules/" + f) 377 | 378 | # Key Bindings 379 | def on_open_keybindings(self, widget, _): 380 | self.on_open(widget, self.default_filemanager.get_text(), "hypr/conf/keybindings") 381 | 382 | def on_reload_keybindings(self, widget, _): 383 | self.win.loadVariations(self.dd_keybindings,"keybinding") 384 | 385 | def on_edit_keybindings(self, widget, _): 386 | i = self.dd_keybindings.get_selected() 387 | f = self.dd_keybindings.get_model()[i].get_string() 388 | self.on_open(widget, self.default_editor.get_text(), "hypr/conf/keybindings/" + f) 389 | 390 | def on_open(self, widget, a, u): 391 | a = shlex.split(a, posix=False) 392 | subprocess.Popen(["flatpak-spawn", "--host", *a, self.dotfiles + u]) 393 | 394 | # -------------------------------------------------------------- 395 | # Default Apps 396 | # -------------------------------------------------------------- 397 | 398 | def on_default_browser(self, widget): 399 | self.overwriteFile("ml4w/settings/browser.sh",widget.get_text()) 400 | 401 | def on_default_email(self, widget): 402 | self.overwriteFile("ml4w/settings/email.sh",widget.get_text()) 403 | 404 | def on_default_installupdates(self, widget): 405 | self.overwriteFile("ml4w/settings/installupdates.sh",widget.get_text()) 406 | 407 | def on_default_filemanager(self, widget): 408 | self.overwriteFile("ml4w/settings/filemanager.sh",widget.get_text()) 409 | 410 | def on_default_editor(self, widget): 411 | self.overwriteFile("ml4w/settings/editor.sh",widget.get_text()) 412 | 413 | def on_default_networkmanager(self, widget): 414 | self.overwriteFile("ml4w/settings/networkmanager.sh",widget.get_text()) 415 | 416 | def on_default_softwaremanager(self, widget): 417 | self.overwriteFile("ml4w/settings/software.sh",widget.get_text()) 418 | 419 | def on_default_terminal(self, widget): 420 | self.overwriteFile("ml4w/settings/terminal.sh",widget.get_text()) 421 | 422 | def on_default_screenshoteditor(self, widget): 423 | self.overwriteFile("ml4w/settings/screenshot-editor.sh",widget.get_text()) 424 | 425 | def on_default_calculator(self, widget): 426 | self.overwriteFile("ml4w/settings/calculator.sh",widget.get_text()) 427 | 428 | def on_default_systemmonitor(self, widget): 429 | self.overwriteFile("ml4w/settings/system-monitor.sh",widget.get_text()) 430 | 431 | def on_default_emojipicker(self, widget): 432 | self.overwriteFile("ml4w/settings/emojipicker.sh",widget.get_text()) 433 | 434 | def on_default_aurhelper(self, widget): 435 | self.overwriteFile("ml4w/settings/aur.sh",widget.get_text()) 436 | 437 | def on_rofi_font(self, widget): 438 | value = 'configuration { font: "' + widget.get_text() + '"; }' 439 | self.overwriteFile("ml4w/settings/rofi-font.rasi",value) 440 | 441 | def on_waybar_workspaces(self, widget): 442 | value = int(widget.get_value()) 443 | text = ' "*": ' + str(value) 444 | self.replaceInFileCheckpoint("waybar/modules.json", "persistent-workspaces",'"*"', text) 445 | self.reloadWaybar() 446 | print(value) 447 | self.updateSettingsBash("waybar_workspaces", value) 448 | 449 | def on_gamemode_toggle(self, widget, _): 450 | subprocess.Popen(["flatpak-spawn", "--host", "bash", self.dotfiles + "hypr/scripts/gamemode.sh"]) 451 | 452 | def on_dock_toggle(self, widget, _): 453 | if (os.path.exists(self.homeFolder + "/.config/ml4w/settings/dock-disabled")): 454 | os.remove(self.homeFolder + "/.config/ml4w/settings/dock-disabled") 455 | subprocess.Popen(["flatpak-spawn", "--host", "bash", self.dotfiles + "nwg-dock-hyprland/launch.sh"]) 456 | else: 457 | file = open(self.homeFolder + "/.config/ml4w/settings/dock-disabled", "w+") 458 | subprocess.Popen(["flatpak-spawn", "--host", "killall", "nwg-dock-hyprland"]) 459 | 460 | def on_wallpaper_cache_toggle(self, widget, _): 461 | if (os.path.exists(self.dotfiles + "ml4w/settings/wallpaper_cache")): 462 | os.remove(self.dotfiles + "ml4w/settings/wallpaper_cache") 463 | else: 464 | file = open(self.dotfiles + "ml4w/settings/wallpaper_cache", "w+") 465 | 466 | def on_waybar_toggle(self, widget, _): 467 | if (os.path.exists(self.homeFolder + "/.config/ml4w/settings/waybar-disabled")): 468 | os.remove(self.homeFolder + "/.config/ml4w/settings/waybar-disabled") 469 | else: 470 | file = open(self.homeFolder + "/.config/ml4w/settings/waybar-disabled", "w+") 471 | self.reloadWaybar() 472 | 473 | def on_rofi_bordersize(self, widget): 474 | value = int(widget.get_value()) 475 | text = "* { border-width: " + str(value) + "px; }" 476 | self.overwriteFile("ml4w/settings/rofi-border.rasi",text) 477 | self.updateSettingsBash("rofi_bordersize", value) 478 | 479 | def on_blur_radius(self, widget): 480 | radius = str(int(widget.get_value())) 481 | sigma = str(int(self.blur_sigma.get_adjustment().get_value())) 482 | text = radius + "x" + sigma 483 | self.overwriteFile("ml4w/settings/blur.sh",text) 484 | 485 | def on_blur_sigma(self, widget): 486 | sigma = str(int(widget.get_value())) 487 | radius = str(int(self.blur_radius.get_adjustment().get_value())) 488 | text = radius + "x" + sigma 489 | self.overwriteFile("ml4w/settings/blur.sh",text) 490 | 491 | def on_waybar_show_appmenu(self, widget, _): 492 | if widget.get_active(): 493 | for t in self.waybar_themes: 494 | self.replaceInFile("waybar/themes/" + t + "/config",'"custom/appmenu"',' "custom/appmenu",') 495 | for t in self.waybar_themes: 496 | self.replaceInFile("waybar/themes/" + t + "/config",'"custom/appmenuicon"',' "custom/appmenuicon",') 497 | self.updateSettingsBash("waybar_appmenu", True) 498 | else: 499 | for t in self.waybar_themes: 500 | self.replaceInFile("waybar/themes/" + t + "/config",'"custom/appmenu"',' //"custom/appmenu",') 501 | for t in self.waybar_themes: 502 | self.replaceInFile("waybar/themes/" + t + "/config",'"custom/appmenuicon"',' //"custom/appmenuicon",') 503 | self.updateSettingsBash("waybar_appmenu", False) 504 | self.reloadWaybar() 505 | 506 | def on_waybar_show_taskbar(self, widget, _): 507 | if widget.get_active(): 508 | for t in self.waybar_themes: 509 | self.replaceInFile("waybar/themes/" + t + "/config",'"wlr/taskbar"',' "wlr/taskbar",') 510 | self.updateSettingsBash("waybar_taskbar", True) 511 | else: 512 | for t in self.waybar_themes: 513 | self.replaceInFile("waybar/themes/" + t + "/config",'"wlr/taskbar"',' //"wlr/taskbar",') 514 | self.updateSettingsBash("waybar_taskbar", False) 515 | self.reloadWaybar() 516 | 517 | def on_waybar_show_quicklinks(self, widget, _): 518 | if widget.get_active(): 519 | for t in self.waybar_themes: 520 | self.replaceInFile("waybar/themes/" + t + "/config",'"group/quicklinks"',' "group/quicklinks",') 521 | self.updateSettingsBash("waybar_quicklinks", True) 522 | else: 523 | for t in self.waybar_themes: 524 | self.replaceInFile("waybar/themes/" + t + "/config",'"group/quicklinks"',' //"group/quicklinks",') 525 | self.updateSettingsBash("waybar_quicklinks", False) 526 | self.reloadWaybar() 527 | 528 | def on_waybar_show_network(self, widget, _): 529 | if widget.get_active(): 530 | for t in self.waybar_themes: 531 | self.replaceInFile("waybar/themes/" + t + "/config",'"network"',' "network",') 532 | self.updateSettingsBash("waybar_network", True) 533 | else: 534 | for t in self.waybar_themes: 535 | self.replaceInFile("waybar/themes/" + t + "/config",'"network"',' //"network",') 536 | self.updateSettingsBash("waybar_network", False) 537 | self.reloadWaybar() 538 | 539 | def on_waybar_show_window(self, widget, _): 540 | if widget.get_active(): 541 | for t in self.waybar_themes: 542 | self.replaceInFile("waybar/themes/" + t + "/config",'"hyprland/window"',' "hyprland/window",') 543 | self.updateSettingsBash("waybar_window", True) 544 | else: 545 | for t in self.waybar_themes: 546 | self.replaceInFile("waybar/themes/" + t + "/config",'"hyprland/window"',' //"hyprland/window",') 547 | self.updateSettingsBash("waybar_window", False) 548 | self.reloadWaybar() 549 | 550 | def on_waybar_show_systray(self, widget, _): 551 | if widget.get_active(): 552 | for t in self.waybar_themes: 553 | self.replaceInFile("waybar/themes/" + t + "/config",'"tray"',' "tray",') 554 | self.updateSettingsBash("waybar_systray", True) 555 | else: 556 | for t in self.waybar_themes: 557 | self.replaceInFile("waybar/themes/" + t + "/config",'"tray"',' //"tray",') 558 | self.updateSettingsBash("waybar_systray", False) 559 | self.reloadWaybar() 560 | 561 | def on_waybar_show_screenlock(self, widget, _): 562 | if widget.get_active(): 563 | self.replaceInFileCheckpoint("waybar/modules.json", 'group/tools', '"custom/hypridle"', ' "custom/hypridle",') 564 | self.updateSettingsBash("waybar_screenlock", True) 565 | else: 566 | self.replaceInFileCheckpoint("waybar/modules.json", 'group/tools', '"custom/hypridle"', '// "custom/hypridle",') 567 | self.updateSettingsBash("waybar_screenlock", False) 568 | self.reloadWaybar() 569 | 570 | def on_waybar_show_chatgpt(self, widget, _): 571 | if widget.get_active(): 572 | self.replaceInFileCheckpoint("waybar/modules.json", 'group/links', '"custom/chatgpt"', ' "custom/chatgpt",') 573 | self.updateSettingsBash("waybar_chatgpt", True) 574 | else: 575 | self.replaceInFileCheckpoint("waybar/modules.json", 'group/links', '"custom/chatgpt"', '// "custom/chatgpt",') 576 | self.updateSettingsBash("waybar_chatgpt", False) 577 | self.reloadWaybar() 578 | 579 | def updateSettingsBash(self,keyword,value): 580 | self.overwriteFile("ml4w/settings/" + keyword + ".sh",value) 581 | 582 | def searchInFile(self, f, search): 583 | with open(self.dotfiles + f, 'r') as file: 584 | content = file.read() 585 | if search in content: 586 | return True 587 | else: 588 | return False 589 | 590 | def overwriteFile(self, f, text): 591 | file=open(self.dotfiles + f,"w+") 592 | file.write(str(text)) 593 | file.close() 594 | 595 | def replaceInFile(self, f, search, replace): 596 | file = open(self.dotfiles + f, 'r') 597 | lines = file.readlines() 598 | count = 0 599 | found = 0 600 | for l in lines: 601 | count += 1 602 | if search in l: 603 | found = count 604 | break 605 | if found > 0: 606 | lines[found - 1] = replace + "\n" 607 | with open(self.dotfiles + f, 'w') as file: 608 | file.writelines(lines) 609 | 610 | def replaceInFileNext(self, f, search, replace): 611 | file = open(self.dotfiles + f, 'r') 612 | lines = file.readlines() 613 | count = 0 614 | found = 0 615 | for l in lines: 616 | count += 1 617 | if search in l: 618 | found = count 619 | break 620 | if found > 0: 621 | lines[found] = replace + "\n" 622 | with open(self.dotfiles + f, 'w') as file: 623 | file.writelines(lines) 624 | 625 | def replaceInFileCheckpoint(self, f, checkpoint, search, replace): 626 | file = open(self.dotfiles + f, 'r') 627 | lines = file.readlines() 628 | count = 0 629 | checkpoint_found = 0 630 | found = 0 631 | for l in lines: 632 | count += 1 633 | if checkpoint in l: 634 | checkpoint_found = count 635 | break 636 | print("Checkpoint: " + str(checkpoint_found)) 637 | 638 | count = 0 639 | if checkpoint_found > 0: 640 | for l in lines: 641 | count += 1 642 | if count > checkpoint_found: 643 | if search in l: 644 | found = count 645 | break 646 | print("Found: " + str(found)) 647 | 648 | if found > 0: 649 | lines[found-1] = replace + "\n" 650 | with open(self.dotfiles + f, 'w') as file: 651 | file.writelines(lines) 652 | 653 | def reloadWaybar(self): 654 | launch_script = self.dotfiles + "waybar/launch.sh" 655 | subprocess.Popen(["flatpak-spawn", "--host", "setsid", launch_script, "1>/dev/null" ,"2>&1" "&"]) 656 | 657 | # Callback for the app.about action. 658 | def on_about_action(self, *args): 659 | about = Adw.AboutDialog( 660 | application_name="ML4W Settings App", 661 | developer_name="Stephan Raabe", 662 | version="2.9.8.4", 663 | website="https://github.com/mylinuxforwork/dotfiles-settings", 664 | issue_url="https://github.com/mylinuxforwork/dotfiles-settings/issues", 665 | support_url="https://github.com/mylinuxforwork/dotfiles-settings/issues", 666 | copyright="© 2025 Stephan Raabe", 667 | license_type=Gtk.License.GPL_3_0_ONLY 668 | ) 669 | about.present(self.props.active_window) 670 | 671 | # Add an application action. 672 | def create_action(self, name, callback, shortcuts=None): 673 | action = Gio.SimpleAction.new(name, None) 674 | action.connect("activate", callback) 675 | self.add_action(action) 676 | if shortcuts: 677 | self.set_accels_for_action(f"app.{name}", shortcuts) 678 | 679 | # The application's entry point. 680 | def main(version): 681 | app = DotfilesSettingsApplication() 682 | return app.run(sys.argv) 683 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | pkgdatadir = get_option('prefix') / get_option('datadir') / meson.project_name() 2 | moduledir = pkgdatadir / 'dotfiles_settings' 3 | gnome = import('gnome') 4 | 5 | gnome.compile_resources('dotfiles-settings', 6 | 'dotfiles-settings.gresource.xml', 7 | gresource_bundle: true, 8 | install: true, 9 | install_dir: pkgdatadir, 10 | ) 11 | 12 | python = import('python') 13 | 14 | conf = configuration_data() 15 | conf.set('PYTHON', python.find_installation('python3').full_path()) 16 | conf.set('VERSION', meson.project_version()) 17 | conf.set('localedir', get_option('prefix') / get_option('localedir')) 18 | conf.set('pkgdatadir', pkgdatadir) 19 | 20 | configure_file( 21 | input: 'dotfiles-settings.in', 22 | output: 'dotfiles-settings', 23 | configuration: conf, 24 | install: true, 25 | install_dir: get_option('bindir'), 26 | install_mode: 'r-xr-xr-x' 27 | ) 28 | 29 | dotfiles_settings_sources = [ 30 | '__init__.py', 31 | 'main.py', 32 | 'window.py', 33 | ] 34 | 35 | install_data(dotfiles_settings_sources, install_dir: moduledir) 36 | -------------------------------------------------------------------------------- /src/window.py: -------------------------------------------------------------------------------- 1 | # window.py 2 | # 3 | # Copyright 2025 Unknown 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | # SPDX-License-Identifier: GPL-3.0-or-later 19 | 20 | from gi.repository import Adw 21 | from gi.repository import Gtk 22 | import sys 23 | import gi 24 | import subprocess 25 | import os 26 | import threading 27 | import json 28 | import pathlib 29 | import shutil 30 | import shlex 31 | import time 32 | 33 | @Gtk.Template(resource_path='/com/ml4w/settings/window.ui') 34 | class DotfilesSettingsWindow(Adw.PreferencesWindow): 35 | __gtype_name__ = 'Ml4wSettingsWindow' 36 | 37 | # Get script path 38 | pathname = os.path.dirname(sys.argv[0]) 39 | 40 | path_name = pathname # Path of Application 41 | homeFolder = os.path.expanduser('~') # Path to home folder 42 | dotfiles = homeFolder + "/.config/" 43 | 44 | settings = { 45 | "waybar_timeformat": "%H:%M", 46 | "waybar_dateformat": "%a", 47 | "waybar_custom_timedateformat": "", 48 | "waybar_timezone": "", 49 | "waybar_workspaces": 5, 50 | "rofi_bordersize": 3, 51 | "waybar_appmenu": True, 52 | "waybar_taskbar": False, 53 | "waybar_quicklinks": True, 54 | "waybar_network": True, 55 | "waybar_chatgpt": True, 56 | "waybar_systray": True, 57 | "waybar_screenlock": True, 58 | "waybar_window": True, 59 | "waybar_settings": True 60 | } 61 | 62 | # {: time date} 63 | timeformats = [ 64 | "%H:%M", 65 | "%I:%M", 66 | "%I:%M %p" 67 | ] 68 | 69 | dateformats = [ 70 | "%a", 71 | "%A", 72 | "%a %Od", 73 | "%Od.%Om.%y", 74 | "%Od.%Om.%Y", 75 | "%a %Od.%Om.%y", 76 | "%a %Od.%Om.%Y", 77 | "%Om/%Od/%y", 78 | "%Om/%Od/%Y" 79 | ] 80 | 81 | timeformat = "" 82 | dateformat = "" 83 | 84 | waybar_show_appmenu = Gtk.Template.Child() 85 | waybar_show_taskbar = Gtk.Template.Child() 86 | waybar_show_quicklinks = Gtk.Template.Child() 87 | waybar_show_network = Gtk.Template.Child() 88 | waybar_show_chatgpt = Gtk.Template.Child() 89 | waybar_show_systray = Gtk.Template.Child() 90 | waybar_show_screenlock = Gtk.Template.Child() 91 | waybar_show_window = Gtk.Template.Child() 92 | waybar_toggle = Gtk.Template.Child() 93 | wallpaper_cache_toggle = Gtk.Template.Child() 94 | gamemode_toggle = Gtk.Template.Child() 95 | dock_toggle = Gtk.Template.Child() 96 | rofi_font = Gtk.Template.Child() 97 | rofi_bordersize = Gtk.Template.Child() 98 | waybar_workspaces = Gtk.Template.Child() 99 | default_browser = Gtk.Template.Child() 100 | default_email = Gtk.Template.Child() 101 | default_filemanager = Gtk.Template.Child() 102 | default_editor = Gtk.Template.Child() 103 | default_networkmanager = Gtk.Template.Child() 104 | default_softwaremanager = Gtk.Template.Child() 105 | default_terminal = Gtk.Template.Child() 106 | default_screenshoteditor = Gtk.Template.Child() 107 | default_calculator = Gtk.Template.Child() 108 | default_systemmonitor = Gtk.Template.Child() 109 | default_emojipicker = Gtk.Template.Child() 110 | default_aurhelper = Gtk.Template.Child() 111 | default_installupdates = Gtk.Template.Child() 112 | open_customconf = Gtk.Template.Child() 113 | open_quicklinks = Gtk.Template.Child() 114 | open_wallpaper_effects = Gtk.Template.Child() 115 | open_waybar_folder = Gtk.Template.Child() 116 | open_timeformatspecifications = Gtk.Template.Child() 117 | dd_wallpaper_effects = Gtk.Template.Child() 118 | dd_animations = Gtk.Template.Child() 119 | dd_environments = Gtk.Template.Child() 120 | dd_layouts = Gtk.Template.Child() 121 | dd_monitors = Gtk.Template.Child() 122 | dd_decorations = Gtk.Template.Child() 123 | dd_windows = Gtk.Template.Child() 124 | dd_workspaces = Gtk.Template.Child() 125 | dd_windowrules = Gtk.Template.Child() 126 | dd_keybindings = Gtk.Template.Child() 127 | dd_timeformats = Gtk.Template.Child() 128 | dd_dateformats = Gtk.Template.Child() 129 | custom_datetime = Gtk.Template.Child() 130 | custom_timezone = Gtk.Template.Child() 131 | blur_radius = Gtk.Template.Child() 132 | blur_sigma = Gtk.Template.Child() 133 | 134 | def __init__(self, **kwargs): 135 | super().__init__(**kwargs) 136 | 137 | # Load Settings 138 | result = [] 139 | for k, v in self.settings.items(): 140 | v = self.loadSettingBash(k + ".sh") 141 | result.append({'key': k, 'value': v}) 142 | 143 | for row in result: 144 | self.settings[row["key"]] = row["value"] 145 | 146 | self.loadDefaultApp("ml4w/settings/browser.sh",self.default_browser) 147 | self.loadDefaultApp("ml4w/settings/email.sh",self.default_email) 148 | self.loadDefaultApp("ml4w/settings/filemanager.sh",self.default_filemanager) 149 | self.loadDefaultApp("ml4w/settings/editor.sh",self.default_editor) 150 | self.loadDefaultApp("ml4w/settings/networkmanager.sh",self.default_networkmanager) 151 | self.loadDefaultApp("ml4w/settings/software.sh",self.default_softwaremanager) 152 | self.loadDefaultApp("ml4w/settings/terminal.sh",self.default_terminal) 153 | self.loadDefaultApp("ml4w/settings/screenshot-editor.sh",self.default_screenshoteditor) 154 | self.loadDefaultApp("ml4w/settings/calculator.sh",self.default_calculator) 155 | self.loadDefaultApp("ml4w/settings/system-monitor.sh",self.default_systemmonitor) 156 | self.loadDefaultApp("ml4w/settings/emojipicker.sh",self.default_emojipicker) 157 | self.loadDefaultApp("ml4w/settings/aur.sh",self.default_aurhelper) 158 | self.loadDefaultApp("ml4w/settings/installupdates.sh",self.default_installupdates) 159 | 160 | self.loadWallpaperEffects(self.dd_wallpaper_effects) 161 | self.loadVariations(self.dd_animations,"animation") 162 | self.loadVariations(self.dd_environments,"environment") 163 | self.loadVariations(self.dd_layouts,"layout") 164 | self.loadVariations(self.dd_monitors,"monitor") 165 | self.loadVariations(self.dd_decorations,"decoration") 166 | self.loadVariations(self.dd_windows,"window") 167 | self.loadVariations(self.dd_workspaces,"workspace") 168 | self.loadVariations(self.dd_windowrules,"windowrule") 169 | self.loadVariations(self.dd_keybindings,"keybinding") 170 | self.loadDropDown(self.dd_timeformats,self.timeformats,"waybar_timeformat") 171 | self.loadDropDown(self.dd_dateformats,self.dateformats,"waybar_dateformat") 172 | 173 | self.loadShowModule("waybar_taskbar",self.waybar_show_taskbar) 174 | self.loadShowModule("waybar_appmenu",self.waybar_show_appmenu) 175 | self.loadShowModule("waybar_quicklinks",self.waybar_show_quicklinks) 176 | self.loadShowModule("waybar_window",self.waybar_show_window) 177 | self.loadShowModule("waybar_network",self.waybar_show_network) 178 | self.loadShowModule("waybar_chatgpt",self.waybar_show_chatgpt) 179 | self.loadShowModule("waybar_systray",self.waybar_show_systray) 180 | self.loadShowModule("waybar_screenlock",self.waybar_show_screenlock) 181 | 182 | self.loadGamemode() 183 | self.loadDock() 184 | self.loadWaybar() 185 | self.loadWallpaperCache() 186 | self.loadRofiFont() 187 | self.loadBlurValues() 188 | 189 | self.getTerminal() 190 | 191 | self.custom_datetime.set_show_apply_button(True) 192 | self.custom_datetime.set_text(self.settings["waybar_custom_timedateformat"]) 193 | 194 | self.custom_timezone.set_show_apply_button(True) 195 | self.custom_timezone.set_text(self.settings["waybar_timezone"]) 196 | 197 | # Settings 198 | self.waybar_workspaces.get_adjustment().set_value(int(self.settings["waybar_workspaces"])) 199 | self.rofi_bordersize.get_adjustment().set_value(int(self.settings["rofi_bordersize"])) 200 | 201 | # Load default app 202 | def loadDefaultApp(self,f,d): 203 | with open(self.dotfiles + f, 'r') as file: 204 | value = file.read() 205 | d.set_text(value.strip()) 206 | d.set_show_apply_button(True) 207 | 208 | # Load setting from bash file 209 | def loadSettingBash(self,f): 210 | with open(self.dotfiles + "ml4w/settings/" + f, 'r') as file: 211 | value = file.read() 212 | return value.strip() 213 | 214 | # Load Wallpaper Effects from folder 215 | def loadWallpaperEffects(self,dd): 216 | files_arr = os.listdir(self.dotfiles + "hypr/effects/wallpaper/") 217 | store = Gtk.StringList() 218 | with open(self.dotfiles + "ml4w/settings/wallpaper-effect.sh", 'r') as file: 219 | value = file.read() 220 | selected = 0 221 | counter = 1 222 | store.append("off") 223 | for f in files_arr: 224 | store.append(f) 225 | if f in value: 226 | selected = counter 227 | counter+=1 228 | dd.set_model(store) 229 | dd.set_selected(selected) 230 | 231 | # Load variations 232 | def loadVariations(self,dd,v): 233 | files_arr = os.listdir(self.dotfiles + "hypr/conf/" + v + "s") 234 | store = Gtk.StringList() 235 | with open(self.dotfiles + "hypr/conf/" + v + ".conf", 'r') as file: 236 | value = file.read() 237 | selected = 0 238 | counter = 0 239 | for f in files_arr: 240 | store.append(f) 241 | if f in value: 242 | selected = counter 243 | counter+=1 244 | dd.set_model(store) 245 | dd.set_selected(selected) 246 | 247 | # Load dropdown 248 | def loadDropDown(self,dd,d,v): 249 | store = Gtk.StringList() 250 | selected = 0 251 | counter = 0 252 | value = self.settings[v] 253 | for f in d: 254 | store.append(f) 255 | if f == value: 256 | selected = counter 257 | counter+=1 258 | dd.set_model(store) 259 | dd.set_selected(selected) 260 | 261 | # Load Show Module 262 | def loadShowModule(self,f,d): 263 | if f in self.settings: 264 | if self.settings[f] == "True": 265 | d.set_active(True) 266 | else: 267 | d.set_active(False) 268 | 269 | # Load Gamemode 270 | def loadGamemode(self): 271 | if os.path.isfile(self.homeFolder + "/.config/ml4w/settings/gamemode-enabled"): 272 | self.gamemode_toggle.set_active(True) 273 | else: 274 | self.gamemode_toggle.set_active(False) 275 | 276 | def loadDock(self): 277 | if os.path.isfile(self.homeFolder + "/.config/ml4w/settings/dock-disabled"): 278 | self.dock_toggle.set_active(False) 279 | else: 280 | self.dock_toggle.set_active(True) 281 | 282 | def loadWaybar(self): 283 | if os.path.isfile(self.homeFolder + "/.config/ml4w/settings/waybar-disabled"): 284 | self.waybar_toggle.set_active(False) 285 | else: 286 | self.waybar_toggle.set_active(True) 287 | 288 | def loadWallpaperCache(self): 289 | if os.path.isfile(self.dotfiles + "ml4w/settings/wallpaper_cache"): 290 | self.wallpaper_cache_toggle.set_active(True) 291 | else: 292 | self.wallpaper_cache_toggle.set_active(False) 293 | 294 | # Load Blur Values 295 | def loadBlurValues(self): 296 | with open(self.dotfiles + "ml4w/settings/blur.sh", 'r') as file: 297 | value = file.read().strip() 298 | value = value.split("x") 299 | self.blur_radius.get_adjustment().set_value(int(value[0])) 300 | self.blur_sigma.get_adjustment().set_value(int(value[1])) 301 | 302 | # Load Rofi Font 303 | def loadRofiFont(self): 304 | with open(self.dotfiles + "ml4w/settings/rofi-font.rasi", 'r') as file: 305 | value = file.read().strip() 306 | value = value.split('"') 307 | self.rofi_font.set_text(value[1]) 308 | self.rofi_font.set_show_apply_button(True) 309 | 310 | def getTerminal(self): 311 | try: 312 | result = subprocess.run(["cat", self.homeFolder + "/.config/ml4w/settings/terminal.sh"], capture_output=True, text=True) 313 | self.terminal = result.stdout.strip() 314 | # print (":: Using Terminal " + self.terminal) 315 | except: 316 | print("ERROR: Could not read the file ~/.config/ml4w/settings/terminal.sh") 317 | -------------------------------------------------------------------------------- /src/window.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 757 | 758 | 759 |
760 | 761 | Open Variation Folder 762 | app.on_open_animations_folder 763 | 764 | 765 | Edit Current Variation 766 | app.on_edit_animations 767 | 768 | 769 | Reload Variations 770 | app.on_reload_animations 771 | 772 |
773 |
774 | 775 | About Variations 776 | app.open_about_variations 777 | 778 |
779 |
780 | 781 | 782 |
783 | 784 | Open Variation Folder 785 | app.on_open_hypridle_folder 786 | 787 | 788 | Edit Current Variation 789 | app.on_edit_hypridle 790 | 791 | 792 | Reload Variations 793 | app.on_reload_hypridle 794 | 795 |
796 |
797 | 798 | Restart Hypridle 799 | app.on_restart_hypridle 800 | 801 |
802 |
803 | 804 | About Variations 805 | app.open_about_variations 806 | 807 |
808 |
809 | 810 | 811 |
812 | 813 | Open Variation Folder 814 | app.on_open_decorations_folder 815 | 816 | 817 | Edit Current Variation 818 | app.on_edit_decorations 819 | 820 | 821 | Reload Variations 822 | app.on_reload_decorations 823 | 824 |
825 |
826 | 827 | About Variations 828 | app.open_about_variations 829 | 830 |
831 |
832 | 833 | 834 |
835 | 836 | Open Variation Folder 837 | app.on_open_windows_folder 838 | 839 | 840 | Edit Current Variation 841 | app.on_edit_windows 842 | 843 | 844 | Reload Variations 845 | app.on_reload_windows 846 | 847 |
848 |
849 | 850 | About Variations 851 | app.open_about_variations 852 | 853 |
854 |
855 | 856 | 857 |
858 | 859 | Open Variation Folder 860 | app.on_open_workspaces_folder 861 | 862 | 863 | Edit Current Variation 864 | app.on_edit_workspaces 865 | 866 | 867 | Reload Variations 868 | app.on_reload_workspaces 869 | 870 |
871 |
872 | 873 | About Variations 874 | app.open_about_variations 875 | 876 |
877 |
878 | 879 | 880 |
881 | 882 | Open Variation Folder 883 | app.on_open_monitors_folder 884 | 885 | 886 | Edit Current Variation 887 | app.on_edit_monitors 888 | 889 | 890 | Reload Variations 891 | app.on_reload_monitors 892 | 893 |
894 |
895 | 896 | About Variations 897 | app.open_about_variations 898 | 899 |
900 |
901 | 902 | 903 |
904 | 905 | Open Variation Folder 906 | app.on_open_keybindings_folder 907 | 908 | 909 | Edit Current Variation 910 | app.on_edit_keybindings 911 | 912 | 913 | Reload Variations 914 | app.on_reload_keybindings 915 | 916 |
917 |
918 | 919 | About Variations 920 | app.open_about_variations 921 | 922 |
923 |
924 | 925 | 926 |
927 | 928 | Open Variation Folder 929 | app.on_open_layouts_folder 930 | 931 | 932 | Edit Current Variation 933 | app.on_edit_layouts 934 | 935 | 936 | Reload Variations 937 | app.on_reload_layouts 938 | 939 |
940 |
941 | 942 | About Variations 943 | app.open_about_variations 944 | 945 |
946 |
947 | 948 | 949 |
950 | 951 | Open Variation Folder 952 | app.on_open_environments_folder 953 | 954 | 955 | Edit Current Variation 956 | app.on_edit_environments 957 | 958 | 959 | Reload Variations 960 | app.on_reload_environments 961 | 962 |
963 |
964 | 965 | About Variations 966 | app.open_about_variations 967 | 968 |
969 |
970 | 971 | 972 |
973 | 974 | Open Variation Folder 975 | app.on_open_windowrules_folder 976 | 977 | 978 | Edit Current Variation 979 | app.on_edit_windowrules 980 | 981 | 982 | Reload Variations 983 | app.on_reload_windowrules 984 | 985 |
986 |
987 | 988 | About Variations 989 | app.open_about_variations 990 | 991 |
992 |
993 | 994 | 995 |
996 | 997 | Clear Cache Folder 998 | app.on_clearcache_wallpaper 999 | 1000 |
1001 |
1002 | 1003 |
1004 | 1005 | 1006 | --------------------------------------------------------------------------------