├── .eslintrc.yml
├── .github
└── images
│ └── thumbnail-dash2dock-lite.png
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── animator.js
├── extension.js
├── lint
├── eslintrc-gjs.yml
└── eslintrc-shell.yml
├── metadata.json
├── package.json
├── stylesheet.css
├── stylesheet.tests.css
└── utils.js
/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | extends:
2 | - ./lint/eslintrc-gjs.yml
3 | - ./lint/eslintrc-shell.yml
4 |
--------------------------------------------------------------------------------
/.github/images/thumbnail-dash2dock-lite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icedman/dash-animator/44498435a0059082685a6808b57102c3b4065dc0/.github/images/thumbnail-dash2dock-lite.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 | *.log
4 | *.zip
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | all: build install lint
2 |
3 | .PHONY: build install
4 |
5 | build:
6 | echo "glib-compile-schemas --strict --targetdir=schemas/ schemas"
7 |
8 | install:
9 | mkdir -p ~/.local/share/gnome-shell/extensions/dash-animator@icedman.github.com/
10 | cp -R ./* ~/.local/share/gnome-shell/extensions/dash-animator@icedman.github.com/
11 |
12 | publish:
13 | rm -rf build
14 | mkdir build
15 | cp LICENSE ./build
16 | cp *.js ./build
17 | cp metadata.json ./build
18 | cp stylesheet.css ./build
19 | cp README.md ./build
20 | echo "cp -R schemas ./build"
21 | rm -rf ./*.zip
22 | cd build ; \
23 | zip -qr ../dash-animator@icedman.github.com.zip .
24 |
25 | lint:
26 | eslint ./
27 |
28 | pretty:
29 | prettier --single-quote --write "**/*.js"
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IMPORTANT!
2 |
3 | Development of this extension will be limited to bugs and essential/minimal features. Please use Dash2Dock Lite for Animated and Effects-ful Dock.
4 |
5 | *Update*
6 |
7 | I'll myfocus effort instead on three other extensions (Search Light, Dash2Dock Lite, Anino Dock).
8 |
9 | [search light](https://github.com/icedman/search-light)
10 |
11 | [dash2dock lite](https://github.com/icedman/dash2dock-lite)
12 |
13 | [anino dock](https://github.com/icedman/anino-dock)
14 |
15 | Anino Dock will be released soon on EGO. It is based on Dash2Dock Lite (release #20);
16 | Dash2Dock Lite will be made "lightweight" again. The aim would to make it Anino Dock Lite;
17 |
18 | # Dash Animator for Ubuntu
19 |
20 | This is a Gnome Shell extension that animates the Ubuntu Dock, or more precisely, the Dash-to-Dock extension.
21 |
22 | This works with other distribution using Dash-to-Dock extensions.
23 |
24 |
25 | Check out also Dash2Dock lite which is a total replacement of Dash-to-Dock. It is also animated:
26 | https://github.com/icedman/dash2dock-lite
27 |
--------------------------------------------------------------------------------
/animator.js:
--------------------------------------------------------------------------------
1 | const Main = imports.ui.main;
2 | const Dash = imports.ui.dash.Dash;
3 | const Layout = imports.ui.layout;
4 | const Shell = imports.gi.Shell;
5 | const Meta = imports.gi.Meta;
6 | const St = imports.gi.St;
7 | const GLib = imports.gi.GLib;
8 | const Point = imports.gi.Graphene.Point;
9 |
10 | const ExtensionUtils = imports.misc.extensionUtils;
11 | const Me = ExtensionUtils.getCurrentExtension();
12 |
13 | const setTimeout = Me.imports.utils.setTimeout;
14 | const setInterval = Me.imports.utils.setInterval;
15 | const clearInterval = Me.imports.utils.clearInterval;
16 | const clearTimeout = Me.imports.utils.clearTimeout;
17 |
18 | const ANIM_INTERVAL = 15;
19 | const ANIM_INTERVAL_PAD = 15;
20 | const ANIM_POS_COEF = 2;
21 | const ANIM_PULL_COEF = 1.8;
22 | const ANIM_SCALE_COEF = 2.5;
23 | const ANIM_ON_LEAVE_COEF = 1.4;
24 | const ANIM_ICON_RAISE = 0.25;
25 | const ANIM_ICON_SCALE = 1.8;
26 | const ANIM_ICON_SCALE_REDUCE = 0.5;
27 | const ANIM_ICON_HIT_AREA = 1.25;
28 | const ANIM_ICON_QUALITY = 2.0;
29 | const ANIM_REENABLE_DELAY = 750;
30 | const ANIM_DEBOUNCE_END_DELAY = 1000;
31 | const ANIM_PREVIEW_DURATION = 1500;
32 |
33 | const DOT_CANVAS_SIZE = 96;
34 |
35 | var Animator = class {
36 | constructor() {
37 | this._enabled = false;
38 | this.animationInterval = ANIM_INTERVAL;
39 | }
40 |
41 | enable() {
42 | if (this._enabled) return;
43 | this._iconsContainer = new St.Widget({ name: 'iconsContainer' });
44 | Main.uiGroup.add_child(this._iconsContainer);
45 | this._dotsContainer = new St.Widget({ name: 'dotsContainer' });
46 | Main.uiGroup.add_child(this._dotsContainer);
47 | // log('enable animator');
48 | this._enabled = true;
49 | this._dragging = false;
50 | this._oneShotId = null;
51 | this._relayout = 8;
52 |
53 | this.show_dots = true;
54 | }
55 |
56 | disable() {
57 | if (!this._enabled) return;
58 | this._enabled = false;
59 | this._endAnimation();
60 |
61 | if (this._oneShotId) {
62 | clearInterval(this._oneShotId);
63 | this._oneShotId = null;
64 | }
65 |
66 | if (this._iconsContainer) {
67 | Main.uiGroup.remove_child(this._iconsContainer);
68 | delete this._iconsContainer;
69 | this._iconsContainer = null;
70 | Main.uiGroup.remove_child(this._dotsContainer);
71 | delete this._dotsContainer;
72 | this._dotsContainer = null;
73 | }
74 |
75 | this._dots = [];
76 |
77 | if (this.dashContainer) {
78 | this._restoreIcons();
79 | }
80 |
81 | // log('disable animator');
82 | }
83 |
84 | preview() {
85 | this._preview = ANIM_PREVIEW_DURATION;
86 | }
87 |
88 | _precreate_dots(count) {
89 | if (!this._dots) {
90 | this._dots = [];
91 | }
92 | if (this.show_dots && this.extension.xDot) {
93 | for (let i = 0; i < count - this._dots.length; i++) {
94 | let dot = new this.extension.xDot(DOT_CANVAS_SIZE);
95 | this._dots.push(dot);
96 | this._dotsContainer.add_child(dot);
97 | dot.set_position(0, 0);
98 | }
99 | }
100 | this._dots.forEach((d) => {
101 | d.visible = false;
102 | });
103 | }
104 |
105 | _animate() {
106 | if (!this._iconsContainer || !this.dashContainer) return;
107 | this.dash = this.dashContainer.dash;
108 |
109 | if (this._relayout > 0 && this.extension && this._updateLayout) {
110 | this.extension._updateLayout();
111 | this._relayout--;
112 | }
113 |
114 | this._iconsContainer.width = 1;
115 | this._iconsContainer.height = 1;
116 | this._dotsContainer.width = 1;
117 | this._dotsContainer.height = 1;
118 |
119 | let magnification =
120 | (this.extension.animation_magnify * 0.9 || 0) - ANIM_ICON_SCALE_REDUCE;
121 | let spread = 1 - (this.extension.animation_spread * 1 || 0);
122 |
123 | let existingIcons = this._iconsContainer.get_children();
124 | if (this._iconsCount != existingIcons.length) {
125 | this._relayout = 8;
126 | this._iconsCount = existingIcons.length;
127 | }
128 |
129 | let validPosition = true;
130 | let dock_position = 'bottom';
131 | let ix = 0;
132 | let iy = 1;
133 |
134 | let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
135 |
136 | let pivot = new Point();
137 | pivot.x = 0.5;
138 | pivot.y = 1.0;
139 |
140 | let iconSize = this.dash.iconSize * this.extension.scale;
141 |
142 | switch (this.dashContainer._position) {
143 | case 0:
144 | dock_position = 'top';
145 | ix = 0;
146 | iy = -1.0;
147 | pivot.x = 0.0;
148 | pivot.y = 0.0;
149 | break;
150 | case 1:
151 | dock_position = 'right';
152 | ix = 1;
153 | iy = 0;
154 | pivot.x = 1.0;
155 | pivot.y = 0.5;
156 | break;
157 | case 2:
158 | dock_position = 'bottom';
159 | break;
160 | case 3:
161 | dock_position = 'left';
162 | ix = 1;
163 | iy = 0;
164 | pivot.x = 0.0;
165 | pivot.y = 0.5;
166 | break;
167 | default:
168 | // center
169 | break;
170 | }
171 |
172 | pivot.x *= scaleFactor;
173 | pivot.y *= scaleFactor;
174 |
175 | let visible_dots = 0;
176 |
177 | let icons = this._findIcons();
178 | icons.forEach((c) => {
179 | let bin = c._bin;
180 | if (!bin) return;
181 |
182 | if (c._appwell && c._appwell.app.get_n_windows() > 0) {
183 | visible_dots++;
184 | }
185 |
186 | for (let i = 0; i < existingIcons.length; i++) {
187 | if (existingIcons[i]._bin == bin) {
188 | return;
189 | }
190 | }
191 |
192 | let icon = c._icon;
193 |
194 | let uiIcon = new St.Widget({
195 | name: 'icon',
196 | width: iconSize,
197 | height: iconSize,
198 | });
199 |
200 | uiIcon.pivot_point = pivot;
201 | uiIcon._bin = bin;
202 | uiIcon._appwell = c._appwell;
203 | uiIcon._label = c._label;
204 |
205 | this._iconsContainer.add_child(uiIcon);
206 |
207 | // spy dragging events
208 | let draggable = c._draggable;
209 | if (draggable && !draggable._dragBeginId) {
210 | draggable._dragBeginId = draggable.connect('drag-begin', () => {
211 | this._dragging = true;
212 | this.disable();
213 | });
214 | draggable._dragEndId = draggable.connect('drag-end', () => {
215 | this._dragging = false;
216 | this._oneShotId = setTimeout(
217 | this.enable.bind(this),
218 | ANIM_REENABLE_DELAY
219 | );
220 | });
221 | }
222 | });
223 |
224 | this._precreate_dots(visible_dots);
225 |
226 | let pointer = global.get_pointer();
227 |
228 | let nearestIdx = -1;
229 | let nearestIcon = null;
230 | let nearestDistance = -1;
231 |
232 | let animateIcons = this._iconsContainer.get_children();
233 | animateIcons.forEach((c) => {
234 | if (this.extension.services) {
235 | this.extension.services.updateIcon(c.first_child);
236 | }
237 |
238 | let orphan = true;
239 | for (let i = 0; i < icons.length; i++) {
240 | if (icons[i]._bin == c._bin) {
241 | orphan = false;
242 | break;
243 | }
244 | }
245 |
246 | if (orphan) {
247 | this._iconsContainer.remove_child(c);
248 | return;
249 | }
250 | });
251 |
252 | animateIcons = this._iconsContainer.get_children();
253 |
254 | // sort
255 | let cornerPos = this._get_position(this.dashContainer);
256 | animateIcons.sort((a, b) => {
257 | let dstA = this._get_distance(cornerPos, this._get_position(a._bin));
258 | let dstB = this._get_distance(cornerPos, this._get_position(b._bin));
259 | return dstA > dstB ? 1 : -1;
260 | });
261 |
262 | let idx = 0;
263 | animateIcons.forEach((icon) => {
264 | let bin = icon._bin;
265 | let pos = this._get_position(bin);
266 |
267 | bin.first_child.opacity = 0;
268 | // bin.set_size(iconSize, iconSize);
269 | icon.set_size(iconSize, iconSize);
270 |
271 | if (!icon.first_child && bin.first_child) {
272 | let img = new St.Icon({
273 | name: 'icon',
274 | icon_name: bin.first_child.icon_name
275 | ? bin.first_child.icon_name
276 | : null,
277 | gicon: bin.first_child.gicon ? bin.first_child.gicon : null,
278 | });
279 | img._source = bin;
280 | img.set_icon_size(iconSize * ANIM_ICON_QUALITY);
281 | img.set_scale(1 / ANIM_ICON_QUALITY, 1 / ANIM_ICON_QUALITY);
282 | icon.add_child(img);
283 |
284 | let btn = new St.Button({
285 | width: iconSize,
286 | height: iconSize / 2,
287 | });
288 | icon.add_child(btn);
289 | btn.connect('clicked', (arg) => {
290 | if (icon._appwell) {
291 | icon._appwell.emit('clicked', arg);
292 | }
293 | });
294 | icon._btn = btn;
295 | }
296 |
297 | if (
298 | this.extension.autohider &&
299 | this.extension.autohider._enabled &&
300 | !this.extension.autohider._shown
301 | ) {
302 | icon._btn.hide();
303 | } else {
304 | icon._btn.show();
305 | }
306 |
307 | // get nearest
308 | let bposcenter = [...pos];
309 | bposcenter[0] += (iconSize * scaleFactor) / 2;
310 | bposcenter[1] += (iconSize * scaleFactor) / 2;
311 | let dst = this._get_distance(pointer, bposcenter);
312 |
313 | if (
314 | (nearestDistance == -1 || nearestDistance > dst) &&
315 | dst < iconSize * ANIM_ICON_HIT_AREA * scaleFactor
316 | ) {
317 | nearestDistance = dst;
318 | nearestIcon = icon;
319 | nearestIdx = idx;
320 | icon._distance = dst;
321 | icon._dx = bposcenter[0] - pointer[0];
322 | icon._dy = bposcenter[1] - pointer[1];
323 | }
324 |
325 | icon._target = pos;
326 | icon._targetScale = 1;
327 |
328 | if (pos[1] < this.extension.sh / 2) {
329 | validPosition = false;
330 | }
331 |
332 | idx++;
333 | });
334 |
335 | if (this._preview && this._preview > 0) {
336 | nearestIdx = Math.floor(animateIcons.length / 2);
337 | nearestIcon = animateIcons[nearestIdx];
338 | nearestDistance = 0;
339 | this._preview -= this.animationInterval;
340 | } else {
341 | this._preview = null;
342 | }
343 |
344 | //
345 | if (!this.extension.peek_hidden_icons) {
346 | if (
347 | this.extension.autohider &&
348 | this.extension.autohider._enabled &&
349 | !this.extension.autohider._shown
350 | ) {
351 | nearestIcon = null;
352 | }
353 | }
354 |
355 | // set animation behavior here
356 | if (nearestIcon && nearestDistance < iconSize * 2) {
357 | let raise = ANIM_ICON_RAISE;
358 | raise -=
359 | ANIM_ICON_RAISE * (1.0 - (this.extension.animation_rise || 0)) - 0.1;
360 | nearestIcon._target[iy] -= iconSize * raise * scaleFactor;
361 | nearestIcon._targetScale = ANIM_ICON_SCALE + magnification;
362 |
363 | let offset = nearestIcon._dx / 4;
364 | let offsetY = (offset < 0 ? -offset : offset) / 2;
365 | nearestIcon._target[ix] += offset;
366 | nearestIcon._target[iy] += offsetY;
367 |
368 | let prevLeft = nearestIcon;
369 | let prevRight = nearestIcon;
370 | let sz = nearestIcon._targetScale;
371 | let pull_coef = ANIM_PULL_COEF;
372 |
373 | for (let i = 1; i < 80; i++) {
374 | sz *= 0.8 - 0.2 * spread;
375 |
376 | let left = null;
377 | let right = null;
378 | if (nearestIdx - i >= 0) {
379 | left = animateIcons[nearestIdx - i];
380 | left._target[ix] =
381 | (left._target[ix] + prevLeft._target[ix] * pull_coef) /
382 | (pull_coef + 1);
383 | left._target[ix] -= iconSize * (sz + 0.2) * scaleFactor;
384 | if (sz > 1) {
385 | left._targetScale = sz;
386 | }
387 | prevLeft = left;
388 | }
389 | if (nearestIdx + i < animateIcons.length) {
390 | right = animateIcons[nearestIdx + i];
391 | right._target[ix] =
392 | (right._target[ix] + prevRight._target[ix] * pull_coef) /
393 | (pull_coef + 1);
394 | right._target[ix] += iconSize * (sz + 0.2) * scaleFactor;
395 | if (sz > 1) {
396 | right._targetScale = sz;
397 | }
398 | prevRight = right;
399 | }
400 |
401 | if (!left && !right) break;
402 |
403 | pull_coef *= 0.9;
404 | }
405 | }
406 |
407 | let didAnimate = false;
408 |
409 | let dotIndex = 0;
410 |
411 | // animate to target scale and position
412 | // todo .. make this velocity based
413 | animateIcons.forEach((icon) => {
414 | let pos = icon._target;
415 | let scale = icon._targetScale;
416 | let fromScale = icon.get_scale()[0];
417 |
418 | // could happen at login
419 | icon.visible = !isNaN(pos[0]);
420 | if (!icon.visible) return;
421 |
422 | icon.set_scale(1, 1);
423 | let from = this._get_position(icon);
424 | let dst = this._get_distance(from, icon._target);
425 |
426 | let _scale_coef = ANIM_SCALE_COEF;
427 | let _pos_coef = ANIM_POS_COEF;
428 | if (!nearestIcon) {
429 | _scale_coef *= ANIM_ON_LEAVE_COEF;
430 | _pos_coef *= ANIM_ON_LEAVE_COEF;
431 | }
432 |
433 | scale = (fromScale * _scale_coef + scale) / (_scale_coef + 1);
434 |
435 | if (dst > iconSize * 0.01 && dst < iconSize * 3) {
436 | pos[0] = (from[0] * _pos_coef + pos[0]) / (_pos_coef + 1);
437 | pos[1] = (from[1] * _pos_coef + pos[1]) / (_pos_coef + 1);
438 | didAnimate = true;
439 | }
440 |
441 | if (!isNaN(scale)) {
442 | icon.set_scale(scale, scale);
443 | }
444 |
445 | if (!isNaN(pos[0]) && !isNaN(pos[1])) {
446 | // why does NaN happen?
447 | icon.set_position(pos[0], pos[1]);
448 |
449 | // todo find appsButton._label
450 | if (icon._label) {
451 | // icon._label.y = pos[1] - iconSize * scale * 0.95 * scaleFactor;
452 |
453 | switch (dock_position) {
454 | case 'left':
455 | icon._label.x = pos[0] + iconSize * scale * 1.1 * scaleFactor;
456 | break;
457 | case 'right':
458 | icon._label.x = pos[0] - iconSize * scale * 1.1 * scaleFactor;
459 | icon._label.x -= icon._label.width / 1.8;
460 | break;
461 | case 'bottom':
462 | icon._label.y = pos[1] - iconSize * scale * 0.9 * scaleFactor;
463 | break;
464 | case 'top':
465 | icon._label.y = pos[1] + iconSize * scale * 0.9 * scaleFactor;
466 | break;
467 | }
468 | }
469 |
470 | // update the dot
471 | if (
472 | this.show_dots &&
473 | icon._appwell &&
474 | icon._appwell.app.get_n_windows() > 0
475 | ) {
476 | let dot = this._dots[dotIndex++];
477 | if (dot) {
478 | dot.visible = true;
479 | dot.set_position(pos[0], pos[1] + 8 * scaleFactor);
480 | dot.set_scale(
481 | iconSize / DOT_CANVAS_SIZE,
482 | iconSize / DOT_CANVAS_SIZE
483 | );
484 | dot.set_state({
485 | count: icon._appwell.app.get_n_windows(),
486 | color: this.extension.running_indicator_color || 'white',
487 | style: this.extension.running_indicator_style,
488 | });
489 | }
490 | }
491 | }
492 | });
493 |
494 | // todo... remove?
495 | if (validPosition && !this._isInFullscreen()) {
496 | this._iconsContainer.show();
497 | this._dotsContainer.show();
498 | }
499 |
500 | if (didAnimate) {
501 | this._debounceEndAnimation();
502 | }
503 | }
504 |
505 | _findIcons() {
506 | return this.extension._findIcons();
507 | }
508 |
509 | _get_x(obj) {
510 | if (obj == null) return 0;
511 | return obj.get_transformed_position()[0];
512 | }
513 |
514 | _get_y(obj) {
515 | if (obj == null) return 0;
516 | return obj.get_transformed_position()[1];
517 | }
518 |
519 | _get_position(obj) {
520 | return [this._get_x(obj), this._get_y(obj)];
521 | }
522 |
523 | _get_distance_sqr(pos1, pos2) {
524 | let a = pos1[0] - pos2[0];
525 | let b = pos1[1] - pos2[1];
526 | return a * a + b * b;
527 | }
528 |
529 | _get_distance(pos1, pos2) {
530 | return Math.sqrt(this._get_distance_sqr(pos1, pos2));
531 | }
532 |
533 | _beginAnimation() {
534 | if (this._timeoutId) {
535 | clearInterval(this._timeoutId);
536 | this._timeoutId = null;
537 | }
538 | if (this._intervalId == null) {
539 | if (this.dashContainer && this.extension) {
540 | this.animationInterval =
541 | ANIM_INTERVAL +
542 | (this.extension.animation_fps || 0) * ANIM_INTERVAL_PAD;
543 | }
544 |
545 | this._intervalId = setInterval(
546 | this._animate.bind(this),
547 | this.animationInterval
548 | );
549 | }
550 |
551 | if (this.dash && this.extension && this.extension.debug_visual) {
552 | this.dash.first_child.add_style_class_name('hi');
553 | }
554 | }
555 |
556 | _endAnimation() {
557 | if (this._intervalId) {
558 | clearInterval(this._intervalId);
559 | this._intervalId = null;
560 | }
561 | if (this._timeoutId) {
562 | clearInterval(this._timeoutId);
563 | }
564 | this._timeoutId = null;
565 | if (this.dash) {
566 | this.dash.first_child.remove_style_class_name('hi');
567 | }
568 | this._relayout = 0;
569 | }
570 |
571 | _debounceEndAnimation() {
572 | if (this._timeoutId) {
573 | clearInterval(this._timeoutId);
574 | }
575 | this._timeoutId = setTimeout(
576 | this._endAnimation.bind(this),
577 | ANIM_DEBOUNCE_END_DELAY + this.animationInterval
578 | );
579 | }
580 |
581 | _onMotionEvent() {
582 | this._onEnterEvent();
583 | }
584 |
585 | _onEnterEvent() {
586 | this._inDash = true;
587 | this._startAnimation();
588 | }
589 |
590 | _onLeaveEvent() {
591 | this._inDash = false;
592 | this._debounceEndAnimation();
593 | }
594 |
595 | _onFocusWindow() {
596 | this._endAnimation();
597 | this._startAnimation();
598 | this._relayout = 8;
599 | }
600 |
601 | _onFullScreen() {
602 | if (!this._iconsContainer) return;
603 | if (!this._isInFullscreen()) {
604 | this._iconsContainer.show();
605 | this._dotsContainer.show();
606 | } else {
607 | this._iconsContainer.hide();
608 | this._dotsContainer.hide();
609 | }
610 | }
611 |
612 | _isInFullscreen() {
613 | let monitor = this.dashContainer.monitor || this.dashContainer._monitor;
614 | return monitor.inFullscreen;
615 | }
616 |
617 | _startAnimation() {
618 | this._beginAnimation();
619 | this._debounceEndAnimation();
620 | }
621 |
622 | _restoreIcons() {
623 | let icons = this._findIcons();
624 | icons.forEach((c) => {
625 | let bin = c._bin;
626 | c._icon.opacity = 255;
627 | // c._icon.get_parent().remove_child(c._icon);
628 | // c._bin.add_child(c._icon);
629 | });
630 | }
631 | };
632 |
--------------------------------------------------------------------------------
/extension.js:
--------------------------------------------------------------------------------
1 | /* extension.js
2 | *
3 | * This program is free software: you can redistribute it and/or modify
4 | * it under the terms of the GNU General Public License as published by
5 | * the Free Software Foundation, either version 2 of the License, or
6 | * (at your option) any later version.
7 | *
8 | * This program is distributed in the hope that it will be useful,
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | * GNU General Public License for more details.
12 | *
13 | * You should have received a copy of the GNU General Public License
14 | * along with this program. If not, see .
15 | *
16 | * SPDX-License-Identifier: GPL-2.0-or-later
17 | */
18 |
19 | /* exported init */
20 |
21 | const Main = imports.ui.main;
22 | const Dash = imports.ui.dash.Dash;
23 | const Layout = imports.ui.layout;
24 | const Shell = imports.gi.Shell;
25 | const Meta = imports.gi.Meta;
26 | const St = imports.gi.St;
27 | const GLib = imports.gi.GLib;
28 | const Point = imports.gi.Graphene.Point;
29 |
30 | const ExtensionUtils = imports.misc.extensionUtils;
31 | const Me = ExtensionUtils.getCurrentExtension();
32 |
33 | const Animator = Me.imports.animator.Animator;
34 |
35 | const setTimeout = Me.imports.utils.setTimeout;
36 | const setInterval = Me.imports.utils.setInterval;
37 | const clearInterval = Me.imports.utils.clearInterval;
38 | const clearTimeout = Me.imports.utils.clearTimeout;
39 |
40 | class Extension {
41 | constructor() {}
42 |
43 | enable() {
44 | this.animator = new Animator();
45 | this.animator.extension = this;
46 |
47 | this.services = {
48 | updateIcon: (icon) => {
49 | if (icon && icon.icon_name && icon.icon_name.startsWith('user-trash')) {
50 | if (
51 | icon._source &&
52 | icon._source.first_child &&
53 | icon.icon_name != icon._source.first_child.icon_name
54 | ) {
55 | icon.icon_name = icon._source.first_child.icon_name;
56 | }
57 | }
58 | },
59 | };
60 |
61 | // animator setting
62 | this.animation_fps = 0;
63 | this.animation_magnify = 0.5;
64 | this.animation_spread = 0.6;
65 | this.animation_rise = 0.2;
66 |
67 | this.enabled = true;
68 | this._dragging = false;
69 | this._oneShotId = null;
70 |
71 | this._layoutManagerEvents = [];
72 | if (!this._findDashContainer()) {
73 | this._layoutManagerEvents.push(
74 | Main.layoutManager.connect('startup-complete', () => {
75 | log('startup-complete');
76 | this._findDashContainer();
77 | })
78 | );
79 | }
80 |
81 | this._displayEvents = [];
82 | this._displayEvents.push(
83 | global.display.connect(
84 | 'notify::focus-window',
85 | this._onFocusWindow.bind(this)
86 | )
87 | );
88 | this._displayEvents.push(
89 | global.display.connect(
90 | 'in-fullscreen-changed',
91 | this._onFullScreen.bind(this)
92 | )
93 | );
94 |
95 | this.animator.enable();
96 | }
97 |
98 | disable() {
99 | this.enabled = false;
100 | this.animator.disable();
101 |
102 | if (this._findDashIntervalId) {
103 | clearInterval(this._findDashIntervalId);
104 | this._findDashIntervalId = null;
105 | }
106 |
107 | if (this._intervals) {
108 | this._intervals.forEach((id) => {
109 | clearInterval(id);
110 | });
111 | this._intervals = [];
112 | }
113 | if (this._oneShotId) {
114 | clearInterval(this._oneShotId);
115 | this._oneShotId = null;
116 | }
117 |
118 | if (this.dashContainer) {
119 | // unhook
120 | this.dashContainer._animateIn = this.dashContainer.__animateIn;
121 | this.dashContainer._animateOut = this.dashContainer.__animateOut;
122 | this.dashContainer.set_reactive(false);
123 | this.dashContainer.set_track_hover(false);
124 | this.dashContainerEvents.forEach((id) => {
125 | if (this.dashContainer) {
126 | // needed?
127 | this.dashContainer.disconnect(id);
128 | }
129 | });
130 | this.dashContainerEvents = [];
131 | this.dashContainer = null;
132 | }
133 |
134 | if (this._iconsContainer) {
135 | Main.uiGroup.remove_child(this._iconsContainer);
136 | delete this._iconsContainer;
137 | this._iconsContainer = null;
138 | }
139 |
140 | if (this.dash) {
141 | this.dashEvents.forEach((id) => {
142 | if (this.dash) {
143 | this.dash.disconnect(id);
144 | }
145 | });
146 | this.dashEvents = [];
147 | this.dash = null;
148 | }
149 |
150 | if (this._layoutManagerEvents) {
151 | this._layoutManagerEvents.forEach((id) => {
152 | Main.layoutManager.disconnect(id);
153 | });
154 | }
155 | this._layoutManagerEvents = [];
156 |
157 | // log('disable animator');
158 |
159 | this.animator = null;
160 | }
161 |
162 | _findDashContainer() {
163 | log('searching for dash container');
164 |
165 | if (this.dashContainer) {
166 | return false;
167 | }
168 |
169 | this.dashContainer = Main.uiGroup.find_child_by_name('dashtodockContainer');
170 | if (!this.dashContainer) {
171 | return false;
172 | }
173 |
174 | if (this._findDashIntervalId) {
175 | clearInterval(this._findDashIntervalId);
176 | this._findDashIntervalId = null;
177 | }
178 |
179 | this.scale = 1;
180 | this.dashContainer.delegate = this;
181 | this.animator.dashContainer = this.dashContainer;
182 |
183 | log('dashtodockContainer found!');
184 |
185 | this.dash = this.dashContainer.find_child_by_name('dash');
186 | this.dashEvents = [];
187 | this.dashEvents.push(
188 | this.dash.connect('icon-size-changed', this._startAnimation.bind(this))
189 | );
190 |
191 | this.dashContainer.set_reactive(true);
192 | this.dashContainer.set_track_hover(true);
193 |
194 | this.dashContainerEvents = [];
195 | this.dashContainerEvents.push(
196 | this.dashContainer.connect('motion-event', this._onMotionEvent.bind(this))
197 | );
198 | this.dashContainerEvents.push(
199 | this.dashContainer.connect('enter-event', this._onEnterEvent.bind(this))
200 | );
201 | this.dashContainerEvents.push(
202 | this.dashContainer.connect('leave-event', this._onLeaveEvent.bind(this))
203 | );
204 | this.dashContainerEvents.push(
205 | this.dashContainer.connect('destroy', () => {
206 | this.animator.disable();
207 | this.animator.enable();
208 | this.dashContainer = null;
209 | this._findDashIntervalId = setInterval(
210 | this._findDashContainer.bind(this),
211 | 500
212 | );
213 | })
214 | );
215 |
216 | // hooks
217 | this.dashContainer.__animateIn = this.dashContainer._animateIn;
218 | this.dashContainer.__animateOut = this.dashContainer._animateOut;
219 |
220 | this.dashContainer._animateIn = (time, delay) => {
221 | this._startAnimation();
222 | this.dashContainer.__animateIn(time, delay);
223 | };
224 | this.dashContainer._animateOut = (time, delay) => {
225 | this._startAnimation();
226 | this.dashContainer.__animateOut(time, delay);
227 | };
228 |
229 | this.animator._animate();
230 | return true;
231 | }
232 |
233 | _findIcons() {
234 | if (!this.dash || !this.dashContainer) return [];
235 |
236 | // hook on showApps
237 | if (this.dash.showAppsButton && !this.dash.showAppsButton._checkEventId) {
238 | this.dash.showAppsButton._checkEventId = this.dash.showAppsButton.connect(
239 | 'notify::checked',
240 | () => {
241 | if (!Main.overview.visible) {
242 | Main.uiGroup
243 | .find_child_by_name('overview')
244 | ._controls._toggleAppsPage();
245 | }
246 | }
247 | );
248 | }
249 |
250 | let icons = this.dash._box.get_children().filter((actor) => {
251 | if (actor.child && actor.child._delegate && actor.child._delegate.icon) {
252 | return true;
253 | }
254 | return false;
255 | });
256 |
257 | icons.forEach((c) => {
258 | let label = c.label;
259 | let appwell = c.first_child;
260 | let draggable = appwell._draggable;
261 | let widget = appwell.first_child;
262 | let icongrid = widget.first_child;
263 | let boxlayout = icongrid.first_child;
264 | let bin = boxlayout.first_child;
265 | if (!bin) return; // ??
266 | let icon = bin.first_child;
267 |
268 | c._bin = bin;
269 | c._label = label;
270 | c._draggable = draggable;
271 | c._appwell = appwell;
272 | if (icon) {
273 | c._icon = icon;
274 | }
275 | });
276 |
277 | try {
278 | // this.dash._showAppsIcon;
279 | let apps = Main.overview.dash.last_child.last_child;
280 | if (apps) {
281 | let widget = apps.child;
282 | // account for JustPerfection & dash-to-dock hiding the app button
283 | if (widget && widget.width > 0 && widget.get_parent().visible) {
284 | let icongrid = widget.first_child;
285 | let boxlayout = icongrid.first_child;
286 | let bin = boxlayout.first_child;
287 | let icon = bin.first_child;
288 | let c = {};
289 | c.child = widget;
290 | c._bin = bin;
291 | c._icon = icon;
292 | c._label = widget._delegate.label;
293 | icons.push(c);
294 | }
295 | }
296 | } catch (err) {
297 | // could happen if ShowApps is hidden
298 | }
299 |
300 | this.dashContainer._icons = icons;
301 | return icons;
302 | }
303 |
304 | _beginAnimation() {
305 | if (this.animator)
306 | this.animator._beginAnimation();
307 | }
308 |
309 | _endAnimation() {
310 | if (this.animator)
311 | this.animator._endAnimation();
312 | }
313 |
314 | _debounceEndAnimation() {
315 | if (this.animator)
316 | this.animator._debounceEndAnimation();
317 | }
318 |
319 | _onMotionEvent() {
320 | if (this.animator)
321 | this.animator._onMotionEvent();
322 | }
323 |
324 | _onEnterEvent() {
325 | if (this.animator)
326 | this.animator._onEnterEvent();
327 | }
328 |
329 | _onLeaveEvent() {
330 | if (this.animator)
331 | this.animator._onLeaveEvent();
332 | }
333 |
334 | _onFocusWindow() {
335 | if (this.animator)
336 | this.animator._onFocusWindow();
337 | }
338 |
339 | _onFullScreen() {
340 | if (this.animator)
341 | this.animator._onFullScreen();
342 | }
343 |
344 | _startAnimation() {
345 | if (this.animator)
346 | this.animator._startAnimation();
347 | }
348 | }
349 |
350 | function init() {
351 | return new Extension();
352 | }
353 |
--------------------------------------------------------------------------------
/lint/eslintrc-gjs.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
3 | env:
4 | es6: true
5 | extends: 'eslint:recommended'
6 | rules:
7 | array-bracket-newline:
8 | - error
9 | - consistent
10 | array-bracket-spacing:
11 | - error
12 | - never
13 | array-callback-return: error
14 | arrow-parens:
15 | - error
16 | - as-needed
17 | arrow-spacing: error
18 | block-scoped-var: error
19 | block-spacing: error
20 | brace-style: error
21 | # Waiting for this to have matured a bit in eslint
22 | # camelcase:
23 | # - error
24 | # - properties: never
25 | # allow: [^vfunc_, ^on_, _instance_init]
26 | comma-dangle:
27 | - error
28 | - arrays: always-multiline
29 | objects: always-multiline
30 | functions: never
31 | comma-spacing:
32 | - error
33 | - before: false
34 | after: true
35 | comma-style:
36 | - error
37 | - last
38 | computed-property-spacing: error
39 | curly:
40 | - error
41 | - multi-or-nest
42 | - consistent
43 | dot-location:
44 | - error
45 | - property
46 | eol-last: error
47 | eqeqeq: error
48 | func-call-spacing: error
49 | func-name-matching: error
50 | func-style:
51 | - error
52 | - declaration
53 | - allowArrowFunctions: true
54 | indent:
55 | - error
56 | - 4
57 | - ignoredNodes:
58 | # Allow not indenting the body of GObject.registerClass, since in the
59 | # future it's intended to be a decorator
60 | - 'CallExpression[callee.object.name=GObject][callee.property.name=registerClass] > ClassExpression:first-child'
61 | # Allow dedenting chained member expressions
62 | MemberExpression: 'off'
63 | key-spacing:
64 | - error
65 | - beforeColon: false
66 | afterColon: true
67 | keyword-spacing:
68 | - error
69 | - before: true
70 | after: true
71 | linebreak-style:
72 | - error
73 | - unix
74 | lines-between-class-members: error
75 | max-nested-callbacks: error
76 | max-statements-per-line: error
77 | new-parens: error
78 | no-array-constructor: error
79 | no-await-in-loop: error
80 | no-caller: error
81 | no-constant-condition:
82 | - error
83 | - checkLoops: false
84 | no-div-regex: error
85 | no-empty:
86 | - error
87 | - allowEmptyCatch: true
88 | no-extra-bind: error
89 | no-extra-parens:
90 | - error
91 | - all
92 | - conditionalAssign: false
93 | nestedBinaryExpressions: false
94 | returnAssign: false
95 | no-implicit-coercion:
96 | - error
97 | - allow:
98 | - '!!'
99 | no-invalid-this: error
100 | no-iterator: error
101 | no-label-var: error
102 | no-lonely-if: error
103 | no-loop-func: error
104 | no-nested-ternary: error
105 | no-new-object: error
106 | no-new-wrappers: error
107 | no-octal-escape: error
108 | no-proto: error
109 | no-prototype-builtins: 'off'
110 | no-restricted-properties:
111 | - error
112 | - object: Lang
113 | property: copyProperties
114 | message: Use Object.assign()
115 | - object: Lang
116 | property: bind
117 | message: Use arrow notation or Function.prototype.bind()
118 | - object: Lang
119 | property: Class
120 | message: Use ES6 classes
121 | no-restricted-syntax:
122 | - error
123 | - selector: >-
124 | MethodDefinition[key.name="_init"] >
125 | FunctionExpression[params.length=1] >
126 | BlockStatement[body.length=1]
127 | CallExpression[arguments.length=1][callee.object.type="Super"][callee.property.name="_init"] >
128 | Identifier:first-child
129 | message: _init() that only calls super._init() is unnecessary
130 | - selector: >-
131 | MethodDefinition[key.name="_init"] >
132 | FunctionExpression[params.length=0] >
133 | BlockStatement[body.length=1]
134 | CallExpression[arguments.length=0][callee.object.type="Super"][callee.property.name="_init"]
135 | message: _init() that only calls super._init() is unnecessary
136 | - selector: BinaryExpression[operator="instanceof"][right.name="Array"]
137 | message: Use Array.isArray()
138 | no-return-assign: error
139 | no-return-await: error
140 | no-self-compare: error
141 | no-shadow: error
142 | no-shadow-restricted-names: error
143 | no-spaced-func: error
144 | no-tabs: error
145 | no-template-curly-in-string: error
146 | no-throw-literal: error
147 | no-trailing-spaces: error
148 | no-undef-init: error
149 | no-unneeded-ternary: error
150 | no-unused-expressions: error
151 | no-unused-vars:
152 | - error
153 | # Vars use a suffix _ instead of a prefix because of file-scope private vars
154 | - varsIgnorePattern: (^unused|_$)
155 | argsIgnorePattern: ^(unused|_)
156 | no-useless-call: error
157 | no-useless-computed-key: error
158 | no-useless-concat: error
159 | no-useless-constructor: error
160 | no-useless-rename: error
161 | no-useless-return: error
162 | no-whitespace-before-property: error
163 | no-with: error
164 | nonblock-statement-body-position:
165 | - error
166 | - below
167 | object-curly-newline:
168 | - error
169 | - consistent: true
170 | object-curly-spacing: error
171 | object-shorthand: error
172 | operator-assignment: error
173 | operator-linebreak: error
174 | padded-blocks:
175 | - error
176 | - never
177 | # These may be a bit controversial, we can try them out and enable them later
178 | # prefer-const: error
179 | # prefer-destructuring: error
180 | prefer-numeric-literals: error
181 | prefer-promise-reject-errors: error
182 | prefer-rest-params: error
183 | prefer-spread: error
184 | prefer-template: error
185 | quotes:
186 | - error
187 | - single
188 | - avoidEscape: true
189 | require-await: error
190 | rest-spread-spacing: error
191 | semi:
192 | - error
193 | - always
194 | semi-spacing:
195 | - error
196 | - before: false
197 | after: true
198 | semi-style: error
199 | space-before-blocks: error
200 | space-before-function-paren:
201 | - error
202 | - named: never
203 | # for `function ()` and `async () =>`, preserve space around keywords
204 | anonymous: always
205 | asyncArrow: always
206 | space-in-parens: error
207 | space-infix-ops:
208 | - error
209 | - int32Hint: false
210 | space-unary-ops: error
211 | spaced-comment: error
212 | switch-colon-spacing: error
213 | symbol-description: error
214 | template-curly-spacing: error
215 | template-tag-spacing: error
216 | unicode-bom: error
217 | valid-jsdoc:
218 | - error
219 | - requireReturn: false
220 | wrap-iife:
221 | - error
222 | - inside
223 | yield-star-spacing: error
224 | yoda: error
225 | globals:
226 | ARGV: readonly
227 | Debugger: readonly
228 | GIRepositoryGType: readonly
229 | globalThis: readonly
230 | imports: readonly
231 | Intl: readonly
232 | log: readonly
233 | logError: readonly
234 | print: readonly
235 | printerr: readonly
236 | parserOptions:
237 | ecmaVersion: 2020
238 |
--------------------------------------------------------------------------------
/lint/eslintrc-shell.yml:
--------------------------------------------------------------------------------
1 | rules:
2 | camelcase:
3 | - error
4 | - properties: never
5 | allow: [^vfunc_, ^on_]
6 | object-curly-spacing:
7 | - error
8 | - always
9 | prefer-arrow-callback: error
10 | globals:
11 | global: readonly
12 |
--------------------------------------------------------------------------------
/metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Animate the icons of dash to dock",
3 | "name": "Dash to Dock Animator",
4 | "original-authors": [
5 | "icedman"
6 | ],
7 | "shell-version": [
8 | "40", "41", "42", "43"
9 | ],
10 | "url": "https://github.com/icedman/dash-animator",
11 | "uuid": "dash-animator@icedman.github.com",
12 | "schema-id": "org.gnome.shell.extensions.dash-animator",
13 | "gettext-domain": "dash-animator",
14 | "version": 5
15 | }
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dash-animator",
3 | "version": "1.0.1",
4 | "main": "index.js",
5 | "repository": "git@github.com:icedman/dash-animator",
6 | "author": "icedman ",
7 | "license": "MIT",
8 | "scripts": {
9 | "pretty": "prettier --single-quote --write \"**/*.js\""
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/stylesheet.css:
--------------------------------------------------------------------------------
1 | /* Add your custom extension styling here */
2 |
3 | .invisible {
4 | /*border: 1px solid magenta;*/
5 | color: rgba(255,0,255,0);
6 | }
7 |
8 | .hi {
9 | border: 1px solid magenta;
10 | }
11 |
12 | #dashtodockContainer.bottom #dash .dash-item-container .app-well-app.focused .overview-icon {
13 | background-color: rgba(238, 238, 236, 0.08) !important; }
--------------------------------------------------------------------------------
/stylesheet.tests.css:
--------------------------------------------------------------------------------
1 |
2 | #MyDash {
3 | padding-left: 0px !important;
4 | padding-right: 0px !important;
5 | margin-top: 0px !important;
6 | margin-bottom: 0px !important;
7 | }
8 |
9 | #MyDash .dash-item-container {
10 | padding-left: 0px !important;
11 | padding-right: 0px !important;
12 | padding-top: 0px !important;
13 | padding-bottom: 0px !important;
14 | margin-top: 0px !important;
15 | margin-bottom: 0px !important;
16 | margin-left: 0px !important;
17 | margin-right: 0px !important;
18 |
19 | width: 60px !important;
20 | /*height: 54px !important;*/
21 | /*border:2px solid red;*/
22 | }
23 |
24 | #MyDash > StBoxLayout {
25 | /*height: 20px !important;*/
26 | /*border:2px solid red;*/
27 | /*padding-left: 0px !important;*/
28 | /*padding-right: 0px !important;*/
29 | /*padding-top: 0px !important;*/
30 | /*padding-bottom: 0px !important;*/
31 |
32 | }
33 |
34 | #MyDash .dash-item-container > StWidget,
35 | #MyDash .dash-item-container > StDrawingArea,
36 | #MyDash .dash-item-container > StButton {
37 | /*width: 48px !important;*/
38 | /*height: 48px !important;*/
39 |
40 | padding-left: 0px !important;
41 | padding-right: 0px !important;
42 | padding-top: 0px !important;
43 | padding-bottom: 0px !important;
44 | /*margin-top: 0px !important;*/
45 | /*margin-bottom: 0px !important;*/
46 | margin-left: 0px !important;
47 | margin-right: 0px !important;
48 | }
49 |
50 |
51 | #MyDash .dash-item-container > StButton.show-apps > .overview-icon {
52 | background-color: rgba(0,0,0,0.2) !important;
53 | }
54 |
55 | #MyDash .dash-item-container > StWidget .overview-icon {
56 | border:2px solid magenta;
57 | }
58 |
59 | #MyDash .dash-item-container > StWidget:hover .overview-icon {
60 | /*border:2px solid magenta;*/
61 | /*height: 48px !important;*/
62 | background-color: rgba(0,0,0,0.4) !important;
63 | }
64 |
65 | #MyDash .dash-item-container > .overview-icon,
66 | #MyDash .dash-item-container > .show-apps,
67 | #MyDash .dash-item-container > .app-well-app {
68 | /*border:2px solid magenta;*/
69 | /*width: 48px !important;*/
70 | /*height: 48px !important;*/
71 | /*padding-top: 0px !important;*/
72 | /*padding-bottom: 0px !important;*/
73 | /*margin-top: 0px !important;*/
74 | /*margin-bottom: 0px !important;*/
75 | }
76 |
77 | #MyDash > StWidget.dash-background {
78 | padding-left: 2px !important;
79 | padding-right: 2px !important;
80 | padding-top: 2px !important;
81 | padding-bottom: 2px !important;
82 | margin-left: 2px !important;
83 | margin-right: 2px !important;
84 | margin-top: 2px !important;
85 | margin-bottom: 2px !important;
86 | background-color: rgba(0,0,0,0.6) !important;
87 | opacity: 0.6 !important;
88 | border-radius: 12px !important;
89 | border: 0px !important;
90 | /*border: 2px solid magenta !important;*/
91 | }
92 |
93 | .hi {
94 | border: 2px solid magenta !important;
95 | /*background: magenta;*/
96 | }
--------------------------------------------------------------------------------
/utils.js:
--------------------------------------------------------------------------------
1 | const GLib = imports.gi.GLib;
2 |
3 | var setTimeout = (func, delay, ...args) => {
4 | const wrappedFunc = () => {
5 | func.apply(this, args);
6 | };
7 | return GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, wrappedFunc);
8 | };
9 |
10 | var setInterval = (func, delay, ...args) => {
11 | const wrappedFunc = () => {
12 | return func.apply(this, args) || true;
13 | };
14 | return GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, wrappedFunc);
15 | };
16 |
17 | var clearTimeout = (id) => {
18 | GLib.source_remove(id);
19 | };
20 |
21 | var clearInterval = (id) => {
22 | GLib.source_remove(id);
23 | };
24 |
--------------------------------------------------------------------------------