├── .travis.yml
├── COPYING
├── README.md
├── meson.build
├── po
├── LINGUAS
└── meson.build
├── snap-store.key.enc
├── snap
└── snapcraft.yaml
└── src
├── adjectives.txt
├── main.c
├── meson.build
├── mp-application.c
├── mp-application.h
├── mp-client.c
├── mp-client.h
├── mp-configured-instance-row.c
├── mp-configured-instance-row.h
├── mp-configured-instance-row.ui
├── mp-details-dialog.c
├── mp-details-dialog.h
├── mp-details-dialog.ui
├── mp-instance.c
├── mp-instance.h
├── mp-launch-dialog.c
├── mp-launch-dialog.h
├── mp-launch-dialog.ui
├── mp-resources.gresource.xml
├── mp-running-instance-row.c
├── mp-running-instance-row.h
├── mp-running-instance-row.ui
├── mp-window.c
├── mp-window.h
├── mp-window.ui
├── multipass-gui.desktop.in
└── names.txt
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 |
3 | services:
4 | - docker
5 |
6 | language: c
7 |
8 | script:
9 | - docker pull ubuntudesktop/gnome-3-28-1804
10 | - cid=`docker run --tty --detach --volume $TRAVIS_BUILD_DIR:/multipass-gui --workdir /multipass-gui ubuntudesktop/gnome-3-28-1804 bash`
11 | - docker exec $cid apt update
12 | - docker exec $cid snapcraft
13 | - if [ -n "$encrypted_4266e9dfa90e_key" -a "$TRAVIS_PULL_REQUEST" = false -a "$TRAVIS_BRANCH" = "master" ]; then docker exec $cid bash -c "openssl aes-256-cbc -K $encrypted_4266e9dfa90e_key -iv $encrypted_4266e9dfa90e_iv -in snap-store.key.enc -out snap-store.key -d"; fi
14 | - if [ -n "$encrypted_4266e9dfa90e_key" -a "$TRAVIS_PULL_REQUEST" = false -a "$TRAVIS_BRANCH" = "master" ]; then docker exec $cid bash -c "snapcraft login --with snap-store.key"; fi
15 | - if [ -n "$encrypted_4266e9dfa90e_key" -a "$TRAVIS_PULL_REQUEST" = false -a "$TRAVIS_BRANCH" = "master" ]; then docker exec $cid snapcraft push multipass-gui*.snap --release edge; fi
16 | - if [ -n "$encrypted_4266e9dfa90e_key" -a "$TRAVIS_PULL_REQUEST" = false -a "$TRAVIS_BRANCH" = "master" ]; then docker exec $cid snapcraft logout; fi
17 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/robert-ancell/multipass-gui)
2 | [](https://gitlab.gnome.org/robert-ancell/multipass-gui/blob/master/COPYING)
3 |
4 | A graphical interface to [Multipass](https://github.com/CanonicalLtd/multipass).
5 |
6 | Install with:
7 | ```
8 | $ snap install multipass-gui --classic
9 | ```
10 |
11 | Build with:
12 | ```
13 | $ snap install snapcraft --edge --classic
14 | $ snap install multipass --edge --classic
15 | $ export SNAPCRAFT_BUILD_ENVIRONMENT=multipass
16 | $ git clone git@github.com:robert-ancell/multipass-gui
17 | $ cd multipass-gui
18 | $ snapcraft
19 | ```
20 |
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project ('multipass-gui', 'c',
2 | meson_version: '>= 0.37.1')
3 |
4 | gnome = import ('gnome')
5 | i18n = import ('i18n')
6 |
7 | gtk_dep = dependency ('gtk+-3.0', version: '>= 3.10')
8 | vte_dep = dependency ('vte-2.91', version: '>= 0.48')
9 |
10 | subdir ('po')
11 | subdir ('src')
12 |
--------------------------------------------------------------------------------
/po/LINGUAS:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robert-ancell/multipass-gui/cff182d4e4ba5571b1d9c92fc9258048750c1394/po/LINGUAS
--------------------------------------------------------------------------------
/po/meson.build:
--------------------------------------------------------------------------------
1 | i18n.gettext ('multipass-gui', preset: 'glib')
2 |
--------------------------------------------------------------------------------
/snap-store.key.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robert-ancell/multipass-gui/cff182d4e4ba5571b1d9c92fc9258048750c1394/snap-store.key.enc
--------------------------------------------------------------------------------
/snap/snapcraft.yaml:
--------------------------------------------------------------------------------
1 | name: multipass-gui
2 | adopt-info: multipass-gui
3 | summary: Multipass
4 | description: |
5 | Multipass allows you to to quickly launch Ubuntu virtual machines.
6 |
7 | base: core18
8 | grade: stable
9 | confinement: classic
10 |
11 | apps:
12 | multipass-gui:
13 | command: usr/bin/multipass-gui
14 | desktop: usr/share/applications/multipass-gui.desktop
15 |
16 | parts:
17 | desktop-gtk3:
18 | source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
19 | source-subdir: gtk
20 | plugin: make
21 | make-parameters: ["FLAVOR=gtk3"]
22 | build-packages:
23 | - build-essential
24 | - libgtk-3-dev
25 | override-build: |
26 | snapcraftctl build
27 | mkdir -pv $SNAPCRAFT_PART_INSTALL/gnome-platform
28 |
29 | multipass-gui:
30 | after: [desktop-gtk3]
31 | plugin: meson
32 | meson-parameters: [--prefix=/usr]
33 | source: .
34 | override-pull: |
35 | snapcraftctl pull
36 | version=$(date --utc +%Y%m%d).$(git rev-parse HEAD | cut -c -7)
37 | snapcraftctl set-version $version
38 | build-packages:
39 | - libgtk-3-dev
40 | - libvte-2.91-dev
41 | - libxml2-utils
42 | stage-packages:
43 | - libvte-2.91-0
44 |
--------------------------------------------------------------------------------
/src/adjectives.txt:
--------------------------------------------------------------------------------
1 | abiding
2 | able
3 | abounding
4 | above
5 | aboveboard
6 | absolute
7 | absolved
8 | abundant
9 | acceptable
10 | accepted
11 | accepting
12 | accessible
13 | accredited
14 | accurate
15 | accustomed
16 | ace
17 | achieving
18 | acquainted
19 | active
20 | actual
21 | adaptable
22 | adapted
23 | adapting
24 | adaptive
25 | adept
26 | adequate
27 | adjusted
28 | admirable
29 | admired
30 | admissible
31 | adorable
32 | adored
33 | adoring
34 | adroit
35 | advanced
36 | advantaged
37 | advisable
38 | aesthetic
39 | affable
40 | affecting
41 | affirming
42 | affluent
43 | affordable
44 | agile
45 | agreeable
46 | airy
47 | alert
48 | alive
49 | allied
50 | allowed
51 | allowing
52 | alluring
53 | altruistic
54 | amazed
55 | amazing
56 | ambitious
57 | amenable
58 | amiable
59 | amicable
60 | ample
61 | amused
62 | amusing
63 | angelic
64 | animated
65 | animating
66 | anointed
67 | apparent
68 | appealing
69 | appeasing
70 | applauded
71 | apposite
72 | approving
73 | apt
74 | ardent
75 | aroused
76 | arresting
77 | arriving
78 | artful
79 | articulate
80 | artistic
81 | ascending
82 | aspirant
83 | aspiring
84 | assertive
85 | assisting
86 | assured
87 | assuring
88 | astounding
89 | astute
90 | athletic
91 | attentive
92 | attractive
93 | august
94 | auspicious
95 | authentic
96 | autonomous
97 | available
98 | avid
99 | awaited
100 | awake
101 | aware
102 | awed
103 | awesome
104 | balanced
105 | balmy
106 | beaming
107 | beautified
108 | beautiful
109 | becoming
110 | beefy
111 | befriended
112 | believable
113 | beloved
114 | beneficial
115 | benevolent
116 | benign
117 | better
118 | bewitching
119 | big
120 | blameless
121 | blazing
122 | blessed
123 | blissful
124 | blithe
125 | blooming
126 | blossoming
127 | boisterous
128 | bold
129 | boss
130 | bounding
131 | bountiful
132 | brainy
133 | brave
134 | brawny
135 | breezy
136 | brief
137 | bright
138 | brilliant
139 | brimming
140 | brisk
141 | brotherly
142 | bubbly
143 | budding
144 | buff
145 | buoyant
146 | bursting
147 | bustling
148 | busy
149 | calm
150 | calming
151 | canny
152 | capable
153 | capital
154 | carefree
155 | careful
156 | caring
157 | casual
158 | causal
159 | celebrated
160 | celestial
161 | central
162 | cerebral
163 | certain
164 | champion
165 | changeable
166 | charitable
167 | charmed
168 | charming
169 | cheerful
170 | cherished
171 | cherry
172 | chic
173 | chief
174 | childlike
175 | chipper
176 | chivalrous
177 | choice
178 | chummy
179 | civic
180 | civil
181 | classic
182 | classical
183 | classy
184 | clean
185 | cleansing
186 | clear
187 | clever
188 | climactic
189 | climbing
190 | close
191 | closing
192 | cogent
193 | coherent
194 | collected
195 | colossal
196 | comforting
197 | comic
198 | comical
199 | commanding
200 | commending
201 | committed
202 | communal
203 | compatible
204 | compelling
205 | competent
206 | complete
207 | completed
208 | composed
209 | concise
210 | conclusive
211 | concrete
212 | conducive
213 | confident
214 | confirmed
215 | congenial
216 | congruent
217 | connected
218 | conquering
219 | conscious
220 | consistent
221 | consonant
222 | content
223 | contiguous
224 | continuous
225 | convenient
226 | conversant
227 | convincing
228 | cool
229 | copious
230 | cordial
231 | corking
232 | correct
233 | cosmic
234 | courageous
235 | courteous
236 | crack
237 | cranked
238 | creamy
239 | creative
240 | credible
241 | creditable
242 | credited
243 | crisp
244 | crucial
245 | cuddly
246 | cultivated
247 | cultured
248 | cunning
249 | curious
250 | current
251 | cute
252 | dainty
253 | dandy
254 | dapper
255 | daring
256 | darling
257 | dashing
258 | dauntless
259 | dazzled
260 | dazzling
261 | dear
262 | debonair
263 | decent
264 | deciding
265 | decisive
266 | decorous
267 | dedicated
268 | deductive
269 | deep
270 | defiant
271 | definite
272 | definitive
273 | deft
274 | delectable
275 | deliberate
276 | delicate
277 | delicious
278 | delighted
279 | delightful
280 | deluxe
281 | democratic
282 | dependable
283 | deserving
284 | desirable
285 | desired
286 | desirous
287 | destined
288 | determined
289 | developed
290 | developing
291 | devoted
292 | devout
293 | dexterous
294 | different
295 | dignified
296 | diligent
297 | diplomatic
298 | direct
299 | disarming
300 | discerning
301 | discreet
302 | discrete
303 | distinct
304 | diverse
305 | diverting
306 | divine
307 | dominant
308 | doting
309 | dreamy
310 | driven
311 | driving
312 | droll
313 | durable
314 | dutiful
315 | dynamic
316 | eager
317 | earnest
318 | earthy
319 | easy
320 | easygoing
321 | eclectic
322 | economic
323 | ecstatic
324 | educated
325 | effective
326 | effectual
327 | efficient
328 | effortless
329 | electric
330 | elegant
331 | elemental
332 | elevated
333 | elevating
334 | eligible
335 | eloquent
336 | emerging
337 | eminent
338 | empowered
339 | empowering
340 | emulated
341 | enabled
342 | enabling
343 | enchanted
344 | enchanting
345 | encouraged
346 | endeared
347 | endearing
348 | endless
349 | endorsed
350 | endorsing
351 | endowed
352 | enduring
353 | energetic
354 | engaged
355 | engaging
356 | engrossed
357 | engrossing
358 | enhanced
359 | enjoyable
360 | enjoyed
361 | enlivened
362 | enlivening
363 | enormous
364 | enough
365 | enriched
366 | enriching
367 | enthralled
368 | enticed
369 | enticing
370 | entranced
371 | entrancing
372 | epic
373 | equal
374 | equipped
375 | equitable
376 | erudite
377 | especial
378 | essential
379 | esteemed
380 | eternal
381 | ethereal
382 | ethical
383 | eventful
384 | evident
385 | evocative
386 | evolved
387 | evolving
388 | exact
389 | exalted
390 | exalting
391 | exceeding
392 | excellent
393 | excelling
394 | excited
395 | exciting
396 | exclusive
397 | executive
398 | exemplary
399 | exhaustive
400 | exotic
401 | expansive
402 | expectant
403 | expedient
404 | expensive
405 | expert
406 | expressive
407 | exquisite
408 | exuberant
409 | exultant
410 | exulting
411 | fabulous
412 | factual
413 | fair
414 | faithful
415 | famed
416 | familiar
417 | famous
418 | fancy
419 | fantastic
420 | fascinated
421 | fast
422 | fatherly
423 | faultless
424 | fearless
425 | feasible
426 | feminine
427 | fertile
428 | fervent
429 | festive
430 | fetching
431 | fiery
432 | fine
433 | finer
434 | firm
435 | first
436 | fit
437 | fitting
438 | flamboyant
439 | flashy
440 | flawless
441 | fleet
442 | flexible
443 | flowing
444 | fluent
445 | fluttering
446 | flying
447 | fond
448 | foolproof
449 | forbearing
450 | forceful
451 | foremost
452 | forgiving
453 | formidable
454 | forthright
455 | fortified
456 | fortifying
457 | fortuitous
458 | fortunate
459 | foxy
460 | fragrant
461 | frank
462 | fraternal
463 | free
464 | fresh
465 | frisky
466 | fruitful
467 | fulfilled
468 | fulfilling
469 | full
470 | fun
471 | funny
472 | gainful
473 | gallant
474 | galore
475 | game
476 | generous
477 | genial
478 | gentle
479 | genuine
480 | gifted
481 | giving
482 | glad
483 | glamorous
484 | gleaming
485 | glistening
486 | glorious
487 | glowing
488 | godlike
489 | golden
490 | good
491 | gorgeous
492 | graced
493 | graceful
494 | gracious
495 | grand
496 | grateful
497 | gratified
498 | gratifying
499 | great
500 | gregarious
501 | groovy
502 | grounded
503 | growing
504 | grown
505 | guaranteed
506 | guided
507 | guiding
508 | guiltless
509 | hale
510 | haloed
511 | handsome
512 | handy
513 | happening
514 | happy
515 | hardy
516 | harmless
517 | harmonic
518 | harmonious
519 | haunting
520 | healing
521 | healthful
522 | healthy
523 | heartfelt
524 | hearty
525 | helped
526 | helpful
527 | helping
528 | heralded
529 | heroic
530 | heuristic
531 | hilarious
532 | hip
533 | holy
534 | honest
535 | honeyed
536 | honorary
537 | hopeful
538 | hospitable
539 | hot
540 | huge
541 | humane
542 | humble
543 | humorous
544 | hygienic
545 | ideal
546 | idealistic
547 | immaculate
548 | immediate
549 | immense
550 | immortal
551 | immune
552 | impartial
553 | impeccable
554 | impish
555 | important
556 | impressive
557 | improved
558 | improving
559 | in
560 | incisive
561 | included
562 | inclusive
563 | incredible
564 | infallible
565 | infinite
566 | informed
567 | ingenious
568 | initiative
569 | innate
570 | innocent
571 | innocuous
572 | innovative
573 | inspired
574 | inspiring
575 | integral
576 | integrated
577 | intense
578 | intent
579 | interested
580 | internal
581 | intimate
582 | intrepid
583 | intrigued
584 | intriguing
585 | intrinsic
586 | inventive
587 | invincible
588 | inviting
589 | iridescent
590 | jaunty
591 | jesting
592 | jocular
593 | joint
594 | jointed
595 | jovial
596 | joyful
597 | joyous
598 | jubilant
599 | judicious
600 | juicy
601 | just
602 | justified
603 | keen
604 | key
605 | kind
606 | kindred
607 | knowing
608 | known
609 | ladylike
610 | large
611 | lasting
612 | laudable
613 | laureate
614 | lavish
615 | lawful
616 | leading
617 | learning
618 | legal
619 | legendary
620 | legible
621 | legitimate
622 | leisurely
623 | lenient
624 | lettered
625 | liberal
626 | liberated
627 | liberating
628 | light
629 | lightened
630 | liked
631 | limber
632 | literary
633 | literate
634 | lithe
635 | live
636 | living
637 | logical
638 | lovable
639 | loved
640 | loving
641 | loyal
642 | lucid
643 | lucky
644 | lucrative
645 | luminous
646 | luscious
647 | lush
648 | lustrous
649 | lusty
650 | luxuriant
651 | magical
652 | magnetic
653 | maiden
654 | main
655 | majestic
656 | major
657 | malleable
658 | manageable
659 | manifest
660 | many
661 | marketable
662 | masculine
663 | massive
664 | master
665 | masterful
666 | matchless
667 | maternal
668 | mature
669 | maturing
670 | maximal
671 | maximum
672 | meaningful
673 | measured
674 | meek
675 | meet
676 | mellow
677 | melodious
678 | memorable
679 | merciful
680 | merry
681 | meteoric
682 | methodical
683 | meticulous
684 | mighty
685 | mindful
686 | mint
687 | miraculous
688 | model
689 | modern
690 | modest
691 | momentous
692 | monumental
693 | moral
694 | more
695 | motivated
696 | motivating
697 | moved
698 | moving
699 | muscular
700 | musical
701 | mutual
702 | national
703 | nationwide
704 | native
705 | natty
706 | natural
707 | nearby
708 | neat
709 | necessary
710 | needed
711 | neutral
712 | new
713 | newborn
714 | next
715 | nice
716 | nifty
717 | nimble
718 | noble
719 | nonchalant
720 | normal
721 | notable
722 | noted
723 | noteworthy
724 | nourished
725 | nourishing
726 | novel
727 | nurtured
728 | nurturing
729 | objective
730 | obliging
731 | observant
732 | obtainable
733 | omnipotent
734 | on
735 | one
736 | open
737 | opportune
738 | optimal
739 | optimistic
740 | optimum
741 | opulent
742 | organic
743 | oriented
744 | original
745 | ornamental
746 | outgoing
747 | outspoken
748 | overriding
749 | overruling
750 | pacific
751 | palatable
752 | paramount
753 | pardonable
754 | parental
755 | particular
756 | passionate
757 | paternal
758 | patient
759 | peaceable
760 | peaceful
761 | peerless
762 | perceptive
763 | perennial
764 | perfect
765 | perky
766 | permanent
767 | permissive
768 | perpetual
769 | persistent
770 | personable
771 | persuasive
772 | pert
773 | pertinent
774 | pet
775 | petite
776 | phenomenal
777 | phlegmatic
778 | picked
779 | pioneering
780 | pious
781 | pithy
782 | pivotal
783 | placid
784 | planetary
785 | plausible
786 | playful
787 | pleasant
788 | pleased
789 | pleasing
790 | plentiful
791 | pliable
792 | plucky
793 | poetic
794 | poignant
795 | poised
796 | polished
797 | polite
798 | popular
799 | positive
800 | possible
801 | potent
802 | potential
803 | powerful
804 | practical
805 | pragmatic
806 | praised
807 | precious
808 | precise
809 | precocious
810 | preeminent
811 | preferable
812 | preferred
813 | premier
814 | premium
815 | prepared
816 | present
817 | pretty
818 | prevailing
819 | prevalent
820 | priceless
821 | primal
822 | primary
823 | prime
824 | primed
825 | principal
826 | privileged
827 | pro
828 | probable
829 | prodigious
830 | productive
831 | proficient
832 | profitable
833 | profound
834 | profuse
835 | prolific
836 | prominent
837 | promising
838 | promoted
839 | promoting
840 | prompt
841 | proper
842 | prophetic
843 | prospering
844 | prosperous
845 | protected
846 | protective
847 | proud
848 | proven
849 | prudent
850 | psychic
851 | pumped
852 | punctual
853 | pure
854 | purified
855 | purifying
856 | purposeful
857 | quaint
858 | qualified
859 | quality
860 | queenly
861 | quick
862 | quickened
863 | quiet
864 | racy
865 | radiant
866 | rapid
867 | rapt
868 | rapturous
869 | rare
870 | rational
871 | ravishing
872 | ready
873 | real
874 | realistic
875 | reasonable
876 | reassuring
877 | receiving
878 | receptive
879 | reciprocal
880 | refined
881 | refreshed
882 | refreshing
883 | regal
884 | regular
885 | rejoicing
886 | related
887 | relative
888 | relaxed
889 | relaxing
890 | relevant
891 | reliable
892 | relieved
893 | relieving
894 | relished
895 | relishing
896 | remarkable
897 | renewed
898 | renewing
899 | renowned
900 | replete
901 | reputable
902 | resilient
903 | resolute
904 | resolved
905 | resounding
906 | respected
907 | respectful
908 | responsive
909 | rested
910 | restful
911 | revealing
912 | revered
913 | reverent
914 | revived
915 | rewarded
916 | rewarding
917 | rich
918 | right
919 | righteous
920 | rightful
921 | robust
922 | romantic
923 | rosy
924 | roused
925 | rousing
926 | ruling
927 | sacred
928 | safe
929 | sage
930 | saintly
931 | sanctified
932 | sanctioned
933 | sassy
934 | satisfied
935 | satisfying
936 | saucy
937 | saved
938 | saving
939 | savvy
940 | scented
941 | scholarly
942 | scientific
943 | scrupulous
944 | seasoned
945 | secure
946 | secured
947 | select
948 | selected
949 | sensible
950 | sensitive
951 | sensual
952 | sensuous
953 | serene
954 | set
955 | settled
956 | settling
957 | shapely
958 | sharing
959 | sharp
960 | sheltering
961 | shining
962 | shipshape
963 | showy
964 | shrewd
965 | simple
966 | sincere
967 | sinewy
968 | singular
969 | sisterly
970 | skilled
971 | sleek
972 | slick
973 | smart
974 | smashing
975 | smiling
976 | smitten
977 | smooth
978 | snappy
979 | snug
980 | soaring
981 | sociable
982 | social
983 | solid
984 | soothed
985 | soothing
986 | sought
987 | sound
988 | sovereign
989 | spacious
990 | spanking
991 | sparkling
992 | special
993 | speedy
994 | spicy
995 | spirited
996 | spiritual
997 | splendid
998 | sporting
999 | spotless
1000 | spruce
1001 | spry
1002 | square
1003 | stable
1004 | staid
1005 | stalwart
1006 | star
1007 | staunch
1008 | steadfast
1009 | steady
1010 | stellar
1011 | sterling
1012 | still
1013 | stimulated
1014 | stirred
1015 | stirring
1016 | strapping
1017 | strategic
1018 | striking
1019 | striving
1020 | strong
1021 | studious
1022 | stunning
1023 | stupendous
1024 | sturdy
1025 | stylish
1026 | suave
1027 | sublime
1028 | subtle
1029 | successful
1030 | succinct
1031 | succulent
1032 | sufficient
1033 | suitable
1034 | suited
1035 | summary
1036 | sumptuous
1037 | sunny
1038 | super
1039 | superb
1040 | superior
1041 | supersonic
1042 | supple
1043 | supported
1044 | supporting
1045 | supportive
1046 | supreme
1047 | sure
1048 | surpassing
1049 | surprised
1050 | surprising
1051 | sustained
1052 | sustaining
1053 | swaying
1054 | sweeping
1055 | sweet
1056 | swell
1057 | systematic
1058 | tactful
1059 | talented
1060 | tangible
1061 | tasteful
1062 | tasty
1063 | teaching
1064 | teeming
1065 | temperate
1066 | tenable
1067 | tenacious
1068 | tender
1069 | terrific
1070 | thankful
1071 | thorough
1072 | thoughtful
1073 | thrilled
1074 | thrilling
1075 | thriving
1076 | tickled
1077 | tidy
1078 | tight
1079 | timeless
1080 | tireless
1081 | titillated
1082 | together
1083 | tolerant
1084 | tonic
1085 | top
1086 | topical
1087 | tops
1088 | touched
1089 | touching
1090 | tough
1091 | touted
1092 | tranquil
1093 | treasured
1094 | tremendous
1095 | trim
1096 | triumphant
1097 | true
1098 | trusted
1099 | trustful
1100 | trusting
1101 | trusty
1102 | truthful
1103 | tuneful
1104 | ubiquitous
1105 | ultimate
1106 | unaffected
1107 | unanimous
1108 | unassuming
1109 | unattached
1110 | unbeatable
1111 | unbiased
1112 | unbroken
1113 | uncommon
1114 | undamaged
1115 | undaunted
1116 | understood
1117 | undoubted
1118 | unerring
1119 | unfailing
1120 | unified
1121 | unique
1122 | united
1123 | universal
1124 | unlimited
1125 | unruffled
1126 | untiring
1127 | untouched
1128 | unusual
1129 | up
1130 | upbeat
1131 | uplifted
1132 | uplifting
1133 | uppermost
1134 | upright
1135 | upstanding
1136 | uptown
1137 | upward
1138 | urbane
1139 | usable
1140 | useful
1141 | utmost
1142 | valiant
1143 | valid
1144 | validating
1145 | valuable
1146 | valued
1147 | vast
1148 | vaulting
1149 | vehement
1150 | venerable
1151 | venerated
1152 | verified
1153 | veritable
1154 | versatile
1155 | versed
1156 | veteran
1157 | viable
1158 | vibrant
1159 | victorious
1160 | vigilant
1161 | vigorous
1162 | virile
1163 | virtuous
1164 | visionary
1165 | vital
1166 | vivacious
1167 | vivid
1168 | vocal
1169 | volcanic
1170 | voluptuous
1171 | wanted
1172 | warm
1173 | warranted
1174 | wealthy
1175 | weighty
1176 | welcome
1177 | welcomed
1178 | welcoming
1179 | well
1180 | whimsical
1181 | whole
1182 | wholesome
1183 | willing
1184 | winged
1185 | winning
1186 | winsome
1187 | wired
1188 | wise
1189 | witty
1190 | wonderful
1191 | wondrous
1192 | workable
1193 | working
1194 | worthwhile
1195 | worthy
1196 | youthful
1197 | zany
1198 | zealous
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #include "mp-application.h"
12 |
13 | int
14 | main (int argc, char **argv)
15 | {
16 | g_autoptr(MpApplication) app = mp_application_new ();
17 | return g_application_run (G_APPLICATION (app), argc, argv);
18 | }
19 |
--------------------------------------------------------------------------------
/src/meson.build:
--------------------------------------------------------------------------------
1 | resources = gnome.compile_resources('mp-resources',
2 | 'mp-resources.gresource.xml')
3 | executable ('multipass-gui',
4 | [ 'main.c',
5 | 'mp-application.c',
6 | 'mp-client.c',
7 | 'mp-configured-instance-row.c',
8 | 'mp-details-dialog.c',
9 | 'mp-instance.c',
10 | 'mp-launch-dialog.c',
11 | 'mp-running-instance-row.c',
12 | 'mp-window.c' ] + resources,
13 | dependencies: [ gtk_dep, vte_dep ],
14 | install: true)
15 |
16 | i18n.merge_file ('desktop-file',
17 | input: 'multipass-gui.desktop.in',
18 | output: 'multipass-gui.desktop',
19 | install: true,
20 | install_dir: join_paths (get_option ('prefix'), get_option ('datadir'), 'applications'),
21 | po_dir: '../po',
22 | type: 'desktop')
23 |
--------------------------------------------------------------------------------
/src/mp-application.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #include "mp-application.h"
12 | #include "mp-window.h"
13 |
14 | struct _MpApplication
15 | {
16 | GtkApplication parent_instance;
17 | };
18 |
19 | G_DEFINE_TYPE (MpApplication, mp_application, GTK_TYPE_APPLICATION)
20 |
21 | static void
22 | mp_application_startup (GApplication *application)
23 | {
24 | G_APPLICATION_CLASS (mp_application_parent_class)->startup (application);
25 | }
26 |
27 | static void
28 | mp_application_activate (GApplication *application)
29 | {
30 | MpWindow *window = mp_window_new ();
31 | gtk_application_add_window (GTK_APPLICATION (application), GTK_WINDOW (window));
32 | gtk_window_present (GTK_WINDOW (window));
33 | }
34 |
35 | void
36 | mp_application_class_init (MpApplicationClass *klass)
37 | {
38 | GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
39 |
40 | application_class->startup = mp_application_startup;
41 | application_class->activate = mp_application_activate;
42 | }
43 |
44 | void
45 | mp_application_init (MpApplication *application)
46 | {
47 | }
48 |
49 | MpApplication *
50 | mp_application_new (void)
51 | {
52 | return g_object_new (MP_TYPE_APPLICATION,
53 | "application-id", "com.ubuntu.multipass-gui",
54 | NULL);
55 | }
56 |
--------------------------------------------------------------------------------
/src/mp-application.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #pragma once
12 |
13 | #include
14 |
15 | G_BEGIN_DECLS
16 |
17 | #define MP_TYPE_APPLICATION (mp_application_get_type ())
18 | G_DECLARE_FINAL_TYPE (MpApplication, mp_application, MP, APPLICATION, GtkApplication)
19 |
20 | MpApplication *mp_application_new (void);
21 |
22 | G_END_DECLS
23 |
--------------------------------------------------------------------------------
/src/mp-client.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #include
12 |
13 | #include "mp-client.h"
14 | #include "mp-instance.h"
15 |
16 | struct _MpClient
17 | {
18 | GObject parent_instance;
19 | };
20 |
21 | G_DEFINE_TYPE (MpClient, mp_client, G_TYPE_OBJECT)
22 |
23 | void
24 | mp_client_class_init (MpClientClass *klass)
25 | {
26 | }
27 |
28 | void
29 | mp_client_init (MpClient *client)
30 | {
31 | }
32 |
33 | MpClient *
34 | mp_client_new (void)
35 | {
36 | return g_object_new (MP_TYPE_CLIENT, NULL);
37 | }
38 |
39 | gchar **
40 | split_line (const gchar *line, int max_split)
41 | {
42 | const gchar *c = line;
43 |
44 | g_autoptr(GPtrArray) tokens = g_ptr_array_new ();
45 | while (*c != '\0') {
46 | const gchar *start = c;
47 | while (*c != '\0' && !isspace (*c))
48 | c++;
49 |
50 | if (max_split > 0 && tokens->len >= max_split - 1)
51 | while (*c != '\0')
52 | c++;
53 |
54 | if (c != start)
55 | g_ptr_array_add (tokens, g_strndup (start, c - start));
56 |
57 | while (isspace (*c))
58 | c++;
59 | }
60 | g_ptr_array_add (tokens, NULL);
61 |
62 | return (gchar **) g_steal_pointer (&tokens->pdata);
63 | }
64 |
65 | static gchar *
66 | get_random_word (const gchar *resource)
67 | {
68 | g_autofree gchar *uri = g_strdup_printf ("resource:%s", resource);
69 | g_autoptr(GFile) file = g_file_new_for_uri (uri);
70 | g_autofree gchar *contents = NULL;
71 | g_autoptr(GError) error = NULL;
72 | if (!g_file_load_contents (file, NULL, &contents, NULL, NULL, &error)) {
73 | g_warning ("Failed to read word list %s: %s\n", resource, error->message);
74 | return NULL;
75 | }
76 |
77 | g_auto(GStrv) words = g_strsplit (contents, "\n", -1);
78 | int i = g_random_int_range (0, g_strv_length (words));
79 |
80 | return g_strdup (words[i]);
81 | }
82 |
83 | gchar *
84 | mp_client_generate_name (MpClient *client)
85 | {
86 | g_autofree gchar *adjective = get_random_word ("/com/ubuntu/multipass/adjectives.txt");
87 | g_autofree gchar *name = get_random_word ("/com/ubuntu/multipass/names.txt");
88 | return g_strdup_printf ("%s-%s", adjective, name);
89 | }
90 |
91 | gchar *
92 | mp_client_get_version_sync (MpClient *client, GCancellable *cancellable, GError **error)
93 | {
94 | g_autoptr(GSubprocess) subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, error, "multipass", "version", NULL);
95 | if (subprocess == NULL)
96 | return NULL;
97 | g_autofree gchar *output = NULL;
98 | if (!g_subprocess_communicate_utf8 (subprocess, NULL, cancellable, &output, NULL, error))
99 | return NULL;
100 |
101 | g_auto(GStrv) lines = g_strsplit (output, "\n", -1);
102 | for (int i = 0; lines[i] != NULL; i++) {
103 | g_auto(GStrv) tokens = split_line (lines[i], -1);
104 | if (g_strv_length (tokens) < 2)
105 | continue;
106 |
107 | if (g_strcmp0 (tokens[0], "multipassd") == 0)
108 | return g_strdup (tokens[1]);
109 | }
110 |
111 | // FIXME: Generate an error
112 | return NULL;
113 | }
114 |
115 | static void
116 | list_cb (GObject *object, GAsyncResult *result, gpointer user_data)
117 | {
118 | GSubprocess *subprocess = G_SUBPROCESS (object);
119 | g_autoptr(GTask) task = user_data;
120 |
121 | g_autofree gchar *output = NULL;
122 | g_autoptr(GError) error = NULL;
123 | if (!g_subprocess_communicate_utf8_finish (subprocess, result, &output, NULL, &error)) {
124 | g_task_return_error (task, g_steal_pointer (&error));
125 | return;
126 | }
127 |
128 | gint exit_status = g_subprocess_get_exit_status (subprocess);
129 | if (exit_status != 0) {
130 | g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "multipass returned exit status %d", exit_status);
131 | return;
132 | }
133 |
134 | g_auto(GStrv) lines = g_strsplit (output, "\n", -1);
135 | g_autoptr(GPtrArray) instances = g_ptr_array_new_with_free_func (g_object_unref);
136 | for (int i = 0; lines[i] != NULL; i++) {
137 | /* Skip header line */
138 | if (i == 0)
139 | continue;
140 |
141 | g_auto(GStrv) tokens = split_line (lines[i], 4);
142 | if (tokens[0] == NULL)
143 | continue;
144 |
145 | g_autoptr(MpInstance) instance = g_object_new (MP_TYPE_INSTANCE,
146 | "name", tokens[0],
147 | "state", tokens[1],
148 | "ipv4", tokens[2],
149 | "release", tokens[3],
150 | NULL);
151 |
152 | g_ptr_array_add (instances, g_object_ref (instance));
153 | }
154 |
155 | g_task_return_pointer (task, g_steal_pointer (&instances), (GDestroyNotify) g_ptr_array_unref);
156 | }
157 |
158 | void
159 | mp_client_list_async (MpClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer callback_data)
160 | {
161 | g_autoptr(GTask) task = g_task_new (client, cancellable, callback, callback_data);
162 |
163 | g_autoptr(GError) error = NULL;
164 | g_autoptr(GSubprocess) subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "multipass", "list", NULL);
165 | if (subprocess == NULL) {
166 | g_warning ("Failed to make subprocess: %s\n", error->message);
167 | return;
168 | }
169 | g_subprocess_communicate_utf8_async (subprocess, NULL, cancellable, list_cb, g_steal_pointer (&task));
170 | }
171 |
172 | GPtrArray *
173 | mp_client_list_finish (MpClient *client, GAsyncResult *result, GError **error)
174 | {
175 | g_return_val_if_fail (g_task_is_valid (G_TASK (result), client), NULL);
176 | return g_task_propagate_pointer (G_TASK (result), error);
177 | }
178 |
179 | static void
180 | find_cb (GObject *object, GAsyncResult *result, gpointer user_data)
181 | {
182 | GSubprocess *subprocess = G_SUBPROCESS (object);
183 | g_autoptr(GTask) task = user_data;
184 |
185 | g_autofree gchar *output = NULL;
186 | g_autoptr(GError) error = NULL;
187 | if (!g_subprocess_communicate_utf8_finish (subprocess, result, &output, NULL, &error)) {
188 | g_task_return_error (task, g_steal_pointer (&error));
189 | return;
190 | }
191 |
192 | gint exit_status = g_subprocess_get_exit_status (subprocess);
193 | if (exit_status != 0) {
194 | g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "multipass returned exit status %d", exit_status);
195 | return;
196 | }
197 |
198 | g_auto(GStrv) lines = g_strsplit (output, "\n", -1);
199 | g_autoptr(GPtrArray) instance_names = g_ptr_array_new ();
200 | for (int i = 0; lines[i] != NULL; i++) {
201 | /* First two lines are header */
202 | if (i < 2)
203 | continue;
204 |
205 | /* Skip alias information */
206 | if (lines[i][0] == ' ')
207 | continue;
208 |
209 | g_auto(GStrv) tokens = split_line (lines[i], -1);
210 | if (tokens[0] == NULL)
211 | continue;
212 |
213 | g_ptr_array_add (instance_names, g_strdup (tokens[0]));
214 | }
215 | g_ptr_array_add (instance_names, NULL);
216 |
217 | g_task_return_pointer (task, g_steal_pointer (&instance_names->pdata), (GDestroyNotify) g_strfreev);
218 | }
219 |
220 | void
221 | mp_client_find_async (MpClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer callback_data)
222 | {
223 | g_autoptr(GTask) task = g_task_new (client, cancellable, callback, callback_data);
224 |
225 | g_autoptr(GError) error = NULL;
226 | g_autoptr(GSubprocess) subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "multipass", "find", NULL);
227 | if (subprocess == NULL) {
228 | g_warning ("Failed to make subprocess: %s\n", error->message);
229 | return;
230 | }
231 | g_subprocess_communicate_utf8_async (subprocess, NULL, cancellable, find_cb, g_steal_pointer (&task));
232 | }
233 |
234 | gchar **
235 | mp_client_find_finish (MpClient *client, GAsyncResult *result, GError **error)
236 | {
237 | g_return_val_if_fail (g_task_is_valid (G_TASK (result), client), NULL);
238 | return g_task_propagate_pointer (G_TASK (result), error);
239 | }
240 |
241 | static void
242 | launch_cb (GObject *object, GAsyncResult *result, gpointer user_data)
243 | {
244 | GSubprocess *subprocess = G_SUBPROCESS (object);
245 | g_autoptr(GTask) task = user_data;
246 |
247 | g_autofree gchar *output = NULL;
248 | g_autoptr(GError) error = NULL;
249 | if (!g_subprocess_communicate_utf8_finish (subprocess, result, &output, NULL, &error)) {
250 | g_task_return_error (task, g_steal_pointer (&error));
251 | return;
252 | }
253 |
254 | gint exit_status = g_subprocess_get_exit_status (subprocess);
255 | if (exit_status != 0) {
256 | g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "multipass returned exit status %d", exit_status);
257 | return;
258 | }
259 |
260 | g_task_return_boolean (task, TRUE);
261 | }
262 |
263 | void
264 | mp_client_launch_async (MpClient *client, const gchar *name, const gchar *image, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer callback_data)
265 | {
266 | g_autoptr(GTask) task = g_task_new (client, cancellable, callback, callback_data);
267 |
268 | g_autoptr(GError) error = NULL;
269 | g_autoptr(GSubprocess) subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "multipass", "launch", "--name", name, image, NULL);
270 | if (subprocess == NULL) {
271 | g_warning ("Failed to make subprocess: %s\n", error->message);
272 | return;
273 | }
274 | g_subprocess_communicate_utf8_async (subprocess, NULL, cancellable, launch_cb, g_steal_pointer (&task));
275 | }
276 |
277 | gboolean
278 | mp_client_launch_finish (MpClient *client, GAsyncResult *result, GError **error)
279 | {
280 | g_return_val_if_fail (g_task_is_valid (G_TASK (result), client), FALSE);
281 | return g_task_propagate_boolean (G_TASK (result), error);
282 | }
283 |
284 | static void
285 | start_cb (GObject *object, GAsyncResult *result, gpointer user_data)
286 | {
287 | GSubprocess *subprocess = G_SUBPROCESS (object);
288 | g_autoptr(GTask) task = user_data;
289 |
290 | g_autofree gchar *output = NULL;
291 | g_autoptr(GError) error = NULL;
292 | if (!g_subprocess_communicate_utf8_finish (subprocess, result, &output, NULL, &error)) {
293 | g_task_return_error (task, g_steal_pointer (&error));
294 | return;
295 | }
296 |
297 | gint exit_status = g_subprocess_get_exit_status (subprocess);
298 | if (exit_status != 0) {
299 | g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "multipass returned exit status %d", exit_status);
300 | return;
301 | }
302 |
303 | g_task_return_boolean (task, TRUE);
304 | }
305 |
306 | void
307 | mp_client_start_async (MpClient *client, const gchar *name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer callback_data)
308 | {
309 | g_autoptr(GTask) task = g_task_new (client, cancellable, callback, callback_data);
310 |
311 | g_autoptr(GError) error = NULL;
312 | g_autoptr(GSubprocess) subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "multipass", "start", name, NULL);
313 | if (subprocess == NULL) {
314 | g_warning ("Failed to make subprocess: %s\n", error->message);
315 | return;
316 | }
317 | g_subprocess_communicate_utf8_async (subprocess, NULL, cancellable, start_cb, g_steal_pointer (&task));
318 | }
319 |
320 | gboolean
321 | mp_client_start_finish (MpClient *client, GAsyncResult *result, GError **error)
322 | {
323 | g_return_val_if_fail (g_task_is_valid (G_TASK (result), client), FALSE);
324 | return g_task_propagate_boolean (G_TASK (result), error);
325 | }
326 |
327 | static void
328 | stop_cb (GObject *object, GAsyncResult *result, gpointer user_data)
329 | {
330 | GSubprocess *subprocess = G_SUBPROCESS (object);
331 | g_autoptr(GTask) task = user_data;
332 |
333 | g_autofree gchar *output = NULL;
334 | g_autoptr(GError) error = NULL;
335 | if (!g_subprocess_communicate_utf8_finish (subprocess, result, &output, NULL, &error)) {
336 | g_task_return_error (task, g_steal_pointer (&error));
337 | return;
338 | }
339 |
340 | gint exit_status = g_subprocess_get_exit_status (subprocess);
341 | if (exit_status != 0) {
342 | g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "multipass returned exit status %d", exit_status);
343 | return;
344 | }
345 |
346 | g_task_return_boolean (task, TRUE);
347 | }
348 |
349 | void
350 | mp_client_stop_async (MpClient *client, const gchar *name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer callback_data)
351 | {
352 | g_autoptr(GTask) task = g_task_new (client, cancellable, callback, callback_data);
353 |
354 | g_autoptr(GError) error = NULL;
355 | g_autoptr(GSubprocess) subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "multipass", "stop", name, NULL);
356 | if (subprocess == NULL) {
357 | g_warning ("Failed to make subprocess: %s\n", error->message);
358 | return;
359 | }
360 | g_subprocess_communicate_utf8_async (subprocess, NULL, cancellable, stop_cb, g_steal_pointer (&task));
361 | }
362 |
363 | gboolean
364 | mp_client_stop_finish (MpClient *client, GAsyncResult *result, GError **error)
365 | {
366 | g_return_val_if_fail (g_task_is_valid (G_TASK (result), client), FALSE);
367 | return g_task_propagate_boolean (G_TASK (result), error);
368 | }
369 |
370 | static void
371 | delete_cb (GObject *object, GAsyncResult *result, gpointer user_data)
372 | {
373 | GSubprocess *subprocess = G_SUBPROCESS (object);
374 | g_autoptr(GTask) task = user_data;
375 |
376 | g_autofree gchar *output = NULL;
377 | g_autoptr(GError) error = NULL;
378 | if (!g_subprocess_communicate_utf8_finish (subprocess, result, &output, NULL, &error)) {
379 | g_task_return_error (task, g_steal_pointer (&error));
380 | return;
381 | }
382 |
383 | gint exit_status = g_subprocess_get_exit_status (subprocess);
384 | if (exit_status != 0) {
385 | g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "multipass returned exit status %d", exit_status);
386 | return;
387 | }
388 |
389 | g_task_return_boolean (task, TRUE);
390 | }
391 |
392 | void
393 | mp_client_delete_async (MpClient *client, const gchar *name, gboolean purge, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer callback_data)
394 | {
395 | g_autoptr(GTask) task = g_task_new (client, cancellable, callback, callback_data);
396 |
397 | g_autoptr(GError) error = NULL;
398 | g_autoptr(GSubprocess) subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "multipass", "delete", name, purge ? "--purge" : NULL, NULL);
399 | if (subprocess == NULL) {
400 | g_warning ("Failed to make subprocess: %s\n", error->message);
401 | return;
402 | }
403 | g_subprocess_communicate_utf8_async (subprocess, NULL, cancellable, delete_cb, g_steal_pointer (&task));
404 | }
405 |
406 | gboolean
407 | mp_client_delete_finish (MpClient *client, GAsyncResult *result, GError **error)
408 | {
409 | g_return_val_if_fail (g_task_is_valid (G_TASK (result), client), FALSE);
410 | return g_task_propagate_boolean (G_TASK (result), error);
411 | }
412 |
413 | static void
414 | recover_cb (GObject *object, GAsyncResult *result, gpointer user_data)
415 | {
416 | GSubprocess *subprocess = G_SUBPROCESS (object);
417 | g_autoptr(GTask) task = user_data;
418 |
419 | g_autofree gchar *output = NULL;
420 | g_autoptr(GError) error = NULL;
421 | if (!g_subprocess_communicate_utf8_finish (subprocess, result, &output, NULL, &error)) {
422 | g_task_return_error (task, g_steal_pointer (&error));
423 | return;
424 | }
425 |
426 | gint exit_status = g_subprocess_get_exit_status (subprocess);
427 | if (exit_status != 0) {
428 | g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "multipass returned exit status %d", exit_status);
429 | return;
430 | }
431 |
432 | g_task_return_boolean (task, TRUE);
433 | }
434 |
435 | void
436 | mp_client_recover_async (MpClient *client, const gchar *name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer callback_data)
437 | {
438 | g_autoptr(GTask) task = g_task_new (client, cancellable, callback, callback_data);
439 |
440 | g_autoptr(GError) error = NULL;
441 | g_autoptr(GSubprocess) subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "multipass", "recover", name, NULL);
442 | if (subprocess == NULL) {
443 | g_warning ("Failed to make subprocess: %s\n", error->message);
444 | return;
445 | }
446 | g_subprocess_communicate_utf8_async (subprocess, NULL, cancellable, recover_cb, g_steal_pointer (&task));
447 | }
448 |
449 | gboolean
450 | mp_client_recover_finish (MpClient *client, GAsyncResult *result, GError **error)
451 | {
452 | g_return_val_if_fail (g_task_is_valid (G_TASK (result), client), FALSE);
453 | return g_task_propagate_boolean (G_TASK (result), error);
454 | }
455 |
--------------------------------------------------------------------------------
/src/mp-client.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #pragma once
12 |
13 | #include
14 |
15 | G_BEGIN_DECLS
16 |
17 | #define MP_TYPE_CLIENT (mp_client_get_type ())
18 | G_DECLARE_FINAL_TYPE (MpClient, mp_client, MP, CLIENT, GObject)
19 |
20 | MpClient *mp_client_new (void);
21 |
22 | gchar *mp_client_generate_name (MpClient *client);
23 |
24 | gchar *mp_client_get_version_sync (MpClient *client,
25 | GCancellable *cancellable,
26 | GError **error);
27 |
28 | void mp_client_list_async (MpClient *client,
29 | GCancellable *cancellable,
30 | GAsyncReadyCallback callback,
31 | gpointer callback_data);
32 |
33 | GPtrArray *mp_client_list_finish (MpClient *client,
34 | GAsyncResult *result,
35 | GError **error);
36 |
37 | void mp_client_find_async (MpClient *client,
38 | GCancellable *cancellable,
39 | GAsyncReadyCallback callback,
40 | gpointer callback_data);
41 |
42 | gchar **mp_client_find_finish (MpClient *client,
43 | GAsyncResult *result,
44 | GError **error);
45 |
46 | void mp_client_launch_async (MpClient *client,
47 | const gchar *name,
48 | const gchar *image,
49 | GCancellable *cancellable,
50 | GAsyncReadyCallback callback,
51 | gpointer callback_data);
52 |
53 | gboolean mp_client_launch_finish (MpClient *client,
54 | GAsyncResult *result,
55 | GError **error);
56 |
57 | void mp_client_start_async (MpClient *client,
58 | const gchar *name,
59 | GCancellable *cancellable,
60 | GAsyncReadyCallback callback,
61 | gpointer callback_data);
62 |
63 | gboolean mp_client_start_finish (MpClient *client,
64 | GAsyncResult *result,
65 | GError **error);
66 |
67 | void mp_client_stop_async (MpClient *client,
68 | const gchar *name,
69 | GCancellable *cancellable,
70 | GAsyncReadyCallback callback,
71 | gpointer callback_data);
72 |
73 | gboolean mp_client_stop_finish (MpClient *client,
74 | GAsyncResult *result,
75 | GError **error);
76 |
77 | void mp_client_delete_async (MpClient *client,
78 | const gchar *name,
79 | gboolean purge,
80 | GCancellable *cancellable,
81 | GAsyncReadyCallback callback,
82 | gpointer callback_data);
83 |
84 | gboolean mp_client_delete_finish (MpClient *client,
85 | GAsyncResult *result,
86 | GError **error);
87 |
88 | void mp_client_recover_async (MpClient *client,
89 | const gchar *name,
90 | GCancellable *cancellable,
91 | GAsyncReadyCallback callback,
92 | gpointer callback_data);
93 |
94 | gboolean mp_client_recover_finish (MpClient *client,
95 | GAsyncResult *result,
96 | GError **error);
97 |
98 | G_END_DECLS
99 |
--------------------------------------------------------------------------------
/src/mp-configured-instance-row.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #include "mp-configured-instance-row.h"
12 |
13 | struct _MpConfiguredInstanceRow
14 | {
15 | GtkListBoxRow parent_instance;
16 |
17 | GtkLabel *label;
18 | GtkImage *image;
19 |
20 | MpInstance *instance;
21 | };
22 |
23 | G_DEFINE_TYPE (MpConfiguredInstanceRow, mp_configured_instance_row, GTK_TYPE_LIST_BOX_ROW)
24 |
25 | static void
26 | mp_configured_instance_row_dispose (GObject *object)
27 | {
28 | MpConfiguredInstanceRow *row = MP_CONFIGURED_INSTANCE_ROW (object);
29 |
30 | g_clear_object (&row->instance);
31 |
32 | G_OBJECT_CLASS (mp_configured_instance_row_parent_class)->dispose (object);
33 | }
34 |
35 | void
36 | mp_configured_instance_row_class_init (MpConfiguredInstanceRowClass *klass)
37 | {
38 | GObjectClass *object_class = G_OBJECT_CLASS (klass);
39 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
40 |
41 | object_class->dispose = mp_configured_instance_row_dispose;
42 |
43 | gtk_widget_class_set_template_from_resource (widget_class, "/com/ubuntu/multipass/mp-configured-instance-row.ui");
44 |
45 | gtk_widget_class_bind_template_child (widget_class, MpConfiguredInstanceRow, image);
46 | gtk_widget_class_bind_template_child (widget_class, MpConfiguredInstanceRow, label);
47 | }
48 |
49 | void
50 | mp_configured_instance_row_init (MpConfiguredInstanceRow *row)
51 | {
52 | gtk_widget_init_template (GTK_WIDGET (row));
53 | }
54 |
55 | MpConfiguredInstanceRow *
56 | mp_configured_instance_row_new (void)
57 | {
58 | return g_object_new (MP_TYPE_CONFIGURED_INSTANCE_ROW, NULL);
59 | }
60 |
61 | void
62 | mp_configured_instance_row_set_instance (MpConfiguredInstanceRow *row, MpInstance *instance)
63 | {
64 | g_return_if_fail (MP_IS_CONFIGURED_INSTANCE_ROW (row));
65 |
66 | g_clear_object (&row->instance);
67 | row->instance = g_object_ref (instance);
68 | gtk_label_set_label (row->label, mp_instance_get_name (instance));
69 |
70 | const gchar *state = mp_instance_get_state (instance);
71 | if (g_strcmp0 (state, "Deleted") == 0)
72 | gtk_image_set_from_icon_name (row->image, "action-unavailable-symbolic", GTK_ICON_SIZE_BUTTON);
73 | else
74 | gtk_image_set_from_icon_name (row->image, "computer-symbolic", GTK_ICON_SIZE_BUTTON);
75 | }
76 |
77 | MpInstance *
78 | mp_configured_instance_row_get_instance (MpConfiguredInstanceRow *row)
79 | {
80 | g_return_val_if_fail (MP_IS_CONFIGURED_INSTANCE_ROW (row), NULL);
81 | return row->instance;
82 | }
83 |
--------------------------------------------------------------------------------
/src/mp-configured-instance-row.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #pragma once
12 |
13 | #include
14 |
15 | #include "mp-instance.h"
16 |
17 | G_BEGIN_DECLS
18 |
19 | #define MP_TYPE_CONFIGURED_INSTANCE_ROW (mp_configured_instance_row_get_type ())
20 | G_DECLARE_FINAL_TYPE (MpConfiguredInstanceRow, mp_configured_instance_row, MP, CONFIGURED_INSTANCE_ROW, GtkListBoxRow)
21 |
22 | MpConfiguredInstanceRow *mp_configured_instance_row_new (void);
23 |
24 | void mp_configured_instance_row_set_instance (MpConfiguredInstanceRow *row,
25 | MpInstance *instance);
26 |
27 | MpInstance *mp_configured_instance_row_get_instance (MpConfiguredInstanceRow *row);
28 |
29 | G_END_DECLS
30 |
--------------------------------------------------------------------------------
/src/mp-configured-instance-row.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/mp-details-dialog.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #include
12 |
13 | #include "mp-details-dialog.h"
14 |
15 | struct _MpDetailsDialog
16 | {
17 | GtkDialog parent_instance;
18 |
19 | GtkLabel *ipv4_label;
20 | GtkLabel *version_label;
21 |
22 | GCancellable *cancellable;
23 | MpClient *client;
24 | };
25 |
26 | G_DEFINE_TYPE (MpDetailsDialog, mp_details_dialog, GTK_TYPE_DIALOG)
27 |
28 | static void
29 | mp_details_dialog_dispose (GObject *object)
30 | {
31 | MpDetailsDialog *dialog = MP_DETAILS_DIALOG (object);
32 |
33 | g_cancellable_cancel (dialog->cancellable);
34 | g_clear_object (&dialog->cancellable);
35 | g_clear_object (&dialog->client);
36 |
37 | G_OBJECT_CLASS (mp_details_dialog_parent_class)->dispose (object);
38 | }
39 |
40 | void
41 | mp_details_dialog_class_init (MpDetailsDialogClass *klass)
42 | {
43 | GObjectClass *object_class = G_OBJECT_CLASS (klass);
44 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
45 |
46 | object_class->dispose = mp_details_dialog_dispose;
47 |
48 | gtk_widget_class_set_template_from_resource (widget_class, "/com/ubuntu/multipass/mp-details-dialog.ui");
49 |
50 | gtk_widget_class_bind_template_child (widget_class, MpDetailsDialog, ipv4_label);
51 | gtk_widget_class_bind_template_child (widget_class, MpDetailsDialog, version_label);
52 | }
53 |
54 | void
55 | mp_details_dialog_init (MpDetailsDialog *dialog)
56 | {
57 | gtk_widget_init_template (GTK_WIDGET (dialog));
58 | }
59 |
60 | MpDetailsDialog *
61 | mp_details_dialog_new (MpClient *client, MpInstance *instance)
62 | {
63 | MpDetailsDialog *dialog = g_object_new (MP_TYPE_DETAILS_DIALOG,
64 | "use-header-bar", 1,
65 | NULL);
66 |
67 | dialog->cancellable = g_cancellable_new ();
68 | dialog->client = g_object_ref (client);
69 |
70 | g_autofree gchar *title = g_strdup_printf (_("“%s” Details"), mp_instance_get_name (instance));
71 | gtk_window_set_title (GTK_WINDOW (dialog), title);
72 |
73 | gtk_label_set_label (dialog->version_label, mp_instance_get_release (instance));
74 | gtk_label_set_label (dialog->ipv4_label, mp_instance_get_ipv4 (instance));
75 |
76 | return dialog;
77 | }
78 |
--------------------------------------------------------------------------------
/src/mp-details-dialog.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #pragma once
12 |
13 | #include
14 |
15 | #include "mp-client.h"
16 | #include "mp-instance.h"
17 |
18 | G_BEGIN_DECLS
19 |
20 | #define MP_TYPE_DETAILS_DIALOG (mp_details_dialog_get_type ())
21 | G_DECLARE_FINAL_TYPE (MpDetailsDialog, mp_details_dialog, MP, DETAILS_DIALOG, GtkDialog)
22 |
23 | MpDetailsDialog *mp_details_dialog_new (MpClient *client,
24 | MpInstance *instance);
25 |
26 | G_END_DECLS
27 |
--------------------------------------------------------------------------------
/src/mp-details-dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | False
5 |
6 |
7 |
8 |
9 | True
10 | 18
11 | 12
12 | 12
13 |
14 |
15 | True
16 | Ubuntu version:
17 | 1
18 |
19 |
20 | 0
21 | 0
22 |
23 |
24 |
25 |
26 | True
27 | 0
28 |
29 |
30 | 1
31 | 0
32 |
33 |
34 |
35 |
36 | True
37 | IPv4 address:
38 | 1
39 |
40 |
41 | 0
42 | 1
43 |
44 |
45 |
46 |
47 | True
48 | 0
49 |
50 |
51 | 1
52 | 1
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/mp-instance.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #include "mp-instance.h"
12 |
13 | enum {
14 | PROP_NAME = 1,
15 | PROP_STATE,
16 | PROP_IPV4,
17 | PROP_RELEASE
18 | };
19 |
20 | struct _MpInstance
21 | {
22 | GObject parent_instance;
23 |
24 | gchar *ipv4;
25 | gchar *name;
26 | gchar *release;
27 | gchar *state;
28 | };
29 |
30 | G_DEFINE_TYPE (MpInstance, mp_instance, G_TYPE_OBJECT)
31 |
32 | static void
33 | mp_instance_set_property (GObject *object,
34 | guint prop_id,
35 | const GValue *value,
36 | GParamSpec *pspec)
37 | {
38 | MpInstance *instance = MP_INSTANCE (object);
39 |
40 | switch (prop_id) {
41 | case PROP_NAME:
42 | g_clear_pointer (&instance->name, g_free);
43 | instance->name = g_value_dup_string (value);
44 | break;
45 | case PROP_STATE:
46 | g_clear_pointer (&instance->state, g_free);
47 | instance->state = g_value_dup_string (value);
48 | break;
49 | case PROP_IPV4:
50 | g_clear_pointer (&instance->ipv4, g_free);
51 | instance->ipv4 = g_value_dup_string (value);
52 | break;
53 | case PROP_RELEASE:
54 | g_clear_pointer (&instance->release, g_free);
55 | instance->release = g_value_dup_string (value);
56 | break;
57 | default:
58 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
59 | break;
60 | }
61 | }
62 |
63 | static void
64 | mp_instance_get_property (GObject *object,
65 | guint prop_id,
66 | GValue *value,
67 | GParamSpec *pspec)
68 | {
69 | MpInstance *instance = MP_INSTANCE (object);
70 |
71 | switch (prop_id) {
72 | case PROP_NAME:
73 | g_value_set_string (value, instance->name);
74 | break;
75 | case PROP_STATE:
76 | g_value_set_string (value, instance->state);
77 | break;
78 | case PROP_IPV4:
79 | g_value_set_string (value, instance->ipv4);
80 | break;
81 | case PROP_RELEASE:
82 | g_value_set_string (value, instance->release);
83 | break;
84 | default:
85 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
86 | break;
87 | }
88 | }
89 |
90 | static void
91 | mp_instance_dispose (GObject *object)
92 | {
93 | MpInstance *instance = MP_INSTANCE (object);
94 |
95 | g_clear_pointer (&instance->ipv4, g_free);
96 | g_clear_pointer (&instance->name, g_free);
97 | g_clear_pointer (&instance->release, g_free);
98 | g_clear_pointer (&instance->state, g_free);
99 |
100 | G_OBJECT_CLASS (mp_instance_parent_class)->dispose (object);
101 | }
102 |
103 | void
104 | mp_instance_class_init (MpInstanceClass *klass)
105 | {
106 | GObjectClass *object_class = G_OBJECT_CLASS (klass);
107 |
108 | object_class->get_property = mp_instance_get_property;
109 | object_class->set_property = mp_instance_set_property;
110 | object_class->dispose = mp_instance_dispose;
111 |
112 | g_object_class_install_property (object_class,
113 | PROP_NAME,
114 | g_param_spec_string ("name",
115 | "name",
116 | "Name",
117 | NULL,
118 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
119 | g_object_class_install_property (object_class,
120 | PROP_STATE,
121 | g_param_spec_string ("state",
122 | "state",
123 | "State",
124 | NULL,
125 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
126 | g_object_class_install_property (object_class,
127 | PROP_IPV4,
128 | g_param_spec_string ("ipv4",
129 | "ipv4",
130 | "IPv4 address",
131 | NULL,
132 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
133 | g_object_class_install_property (object_class,
134 | PROP_RELEASE,
135 | g_param_spec_string ("release",
136 | "release",
137 | "Release",
138 | NULL,
139 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
140 | }
141 |
142 | void
143 | mp_instance_init (MpInstance *instance)
144 | {
145 | }
146 |
147 | const gchar *
148 | mp_instance_get_name (MpInstance *instance)
149 | {
150 | g_return_val_if_fail (MP_IS_INSTANCE (instance), NULL);
151 | return instance->name;
152 | }
153 |
154 | const gchar *
155 | mp_instance_get_state (MpInstance *instance)
156 | {
157 | g_return_val_if_fail (MP_IS_INSTANCE (instance), NULL);
158 | return instance->state;
159 | }
160 |
161 | const gchar *
162 | mp_instance_get_ipv4 (MpInstance *instance)
163 | {
164 | g_return_val_if_fail (MP_IS_INSTANCE (instance), NULL);
165 | return instance->ipv4;
166 | }
167 |
168 | const gchar *
169 | mp_instance_get_release (MpInstance *instance)
170 | {
171 | g_return_val_if_fail (MP_IS_INSTANCE (instance), NULL);
172 | return instance->release;
173 | }
174 |
--------------------------------------------------------------------------------
/src/mp-instance.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #pragma once
12 |
13 | #include
14 |
15 | G_BEGIN_DECLS
16 |
17 | #define MP_TYPE_INSTANCE (mp_instance_get_type ())
18 | G_DECLARE_FINAL_TYPE (MpInstance, mp_instance, MP, INSTANCE, GObject)
19 |
20 | const gchar *mp_instance_get_name (MpInstance *instance);
21 |
22 | const gchar *mp_instance_get_state (MpInstance *instance);
23 |
24 | const gchar *mp_instance_get_ipv4 (MpInstance *instance);
25 |
26 | const gchar *mp_instance_get_release (MpInstance *instance);
27 |
28 | G_END_DECLS
29 |
--------------------------------------------------------------------------------
/src/mp-launch-dialog.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #include "mp-launch-dialog.h"
12 |
13 | struct _MpLaunchDialog
14 | {
15 | GtkDialog parent_instance;
16 |
17 | GtkComboBox *image_combo;
18 | GtkListStore *image_model;
19 | GtkEntry *name_entry;
20 |
21 | GCancellable *cancellable;
22 | MpClient *client;
23 | };
24 |
25 | G_DEFINE_TYPE (MpLaunchDialog, mp_launch_dialog, GTK_TYPE_DIALOG)
26 |
27 | static void
28 | mp_launch_dialog_dispose (GObject *object)
29 | {
30 | MpLaunchDialog *dialog = MP_LAUNCH_DIALOG (object);
31 |
32 | g_cancellable_cancel (dialog->cancellable);
33 | g_clear_object (&dialog->cancellable);
34 | g_clear_object (&dialog->client);
35 |
36 | G_OBJECT_CLASS (mp_launch_dialog_parent_class)->dispose (object);
37 | }
38 |
39 | void
40 | mp_launch_dialog_class_init (MpLaunchDialogClass *klass)
41 | {
42 | GObjectClass *object_class = G_OBJECT_CLASS (klass);
43 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
44 |
45 | object_class->dispose = mp_launch_dialog_dispose;
46 |
47 | gtk_widget_class_set_template_from_resource (widget_class, "/com/ubuntu/multipass/mp-launch-dialog.ui");
48 |
49 | gtk_widget_class_bind_template_child (widget_class, MpLaunchDialog, image_combo);
50 | gtk_widget_class_bind_template_child (widget_class, MpLaunchDialog, image_model);
51 | gtk_widget_class_bind_template_child (widget_class, MpLaunchDialog, name_entry);
52 | }
53 |
54 | void
55 | mp_launch_dialog_init (MpLaunchDialog *dialog)
56 | {
57 | gtk_widget_init_template (GTK_WIDGET (dialog));
58 |
59 | GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
60 | gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->image_combo), renderer, TRUE);
61 | gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (dialog->image_combo), renderer, "text", 0);
62 | }
63 |
64 | static void
65 | find_cb (GObject *client, GAsyncResult *result, gpointer user_data)
66 | {
67 | MpLaunchDialog *dialog = user_data;
68 |
69 | g_autoptr(GError) error = NULL;
70 | g_auto(GStrv) image_names = mp_client_find_finish (MP_CLIENT (client), result, &error);
71 | if (image_names == NULL) {
72 | if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
73 | g_printerr ("Failed to get images: %s\n", error->message);
74 | return;
75 | }
76 |
77 | for (int i = 0; image_names[i] != NULL; i++) {
78 | GtkTreeIter iter;
79 | gtk_list_store_append (dialog->image_model, &iter);
80 | gtk_list_store_set (dialog->image_model, &iter, 0, image_names[i], -1);
81 |
82 | if (gtk_combo_box_get_active (dialog->image_combo) < 0)
83 | gtk_combo_box_set_active_iter (dialog->image_combo, &iter);
84 | }
85 | }
86 |
87 | MpLaunchDialog *
88 | mp_launch_dialog_new (MpClient *client)
89 | {
90 | MpLaunchDialog *dialog = g_object_new (MP_TYPE_LAUNCH_DIALOG,
91 | "use-header-bar", 1,
92 | NULL);
93 |
94 | dialog->cancellable = g_cancellable_new ();
95 | dialog->client = g_object_ref (client);
96 | mp_client_find_async (dialog->client, dialog->cancellable, find_cb, dialog);
97 |
98 | g_autofree gchar *name = mp_client_generate_name (client);
99 | gtk_entry_set_text (dialog->name_entry, name);
100 |
101 | return dialog;
102 | }
103 |
104 | const gchar *
105 | mp_launch_dialog_get_name (MpLaunchDialog *dialog)
106 | {
107 | g_return_val_if_fail (MP_IS_LAUNCH_DIALOG (dialog), NULL);
108 | return gtk_entry_get_text (dialog->name_entry);
109 | }
110 |
111 | gchar *
112 | mp_launch_dialog_get_image_name (MpLaunchDialog *dialog)
113 | {
114 | g_return_val_if_fail (MP_IS_LAUNCH_DIALOG (dialog), NULL);
115 |
116 | GtkTreeIter iter;
117 | if (!gtk_combo_box_get_active_iter (dialog->image_combo, &iter))
118 | return NULL;
119 |
120 | gchar *name;
121 | gtk_tree_model_get (GTK_TREE_MODEL (dialog->image_model), &iter, 0, &name, -1);
122 | return name;
123 | }
124 |
--------------------------------------------------------------------------------
/src/mp-launch-dialog.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #pragma once
12 |
13 | #include
14 |
15 | #include "mp-client.h"
16 |
17 | G_BEGIN_DECLS
18 |
19 | #define MP_TYPE_LAUNCH_DIALOG (mp_launch_dialog_get_type ())
20 | G_DECLARE_FINAL_TYPE (MpLaunchDialog, mp_launch_dialog, MP, LAUNCH_DIALOG, GtkDialog)
21 |
22 | MpLaunchDialog *mp_launch_dialog_new (MpClient *client);
23 |
24 | const gchar *mp_launch_dialog_get_name (MpLaunchDialog *dialog);
25 |
26 | gchar *mp_launch_dialog_get_image_name (MpLaunchDialog *dialog);
27 |
28 | G_END_DECLS
29 |
--------------------------------------------------------------------------------
/src/mp-launch-dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Launch Ubuntu Instance
5 | False
6 |
7 |
8 | True
9 | _Launch
10 | True
11 | True
12 |
13 |
14 |
15 |
16 | True
17 | _Cancel
18 | True
19 |
20 |
21 |
22 |
23 |
24 |
25 | True
26 | 18
27 | 12
28 | 12
29 |
30 |
31 | True
32 | Ubuntu version:
33 |
34 |
35 | 0
36 | 0
37 |
38 |
39 |
40 |
41 | True
42 | image_model
43 | True
44 |
45 |
46 | 1
47 | 0
48 |
49 |
50 |
51 |
52 | True
53 | Name this instance:
54 |
55 |
56 | 0
57 | 1
58 |
59 |
60 |
61 |
62 | True
63 | True
64 |
65 |
66 | 1
67 | 1
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | launch_button
76 | cancel_button
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/mp-resources.gresource.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | mp-configured-instance-row.ui
5 | mp-details-dialog.ui
6 | mp-launch-dialog.ui
7 | mp-running-instance-row.ui
8 | mp-window.ui
9 | adjectives.txt
10 | names.txt
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/mp-running-instance-row.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #include
12 |
13 | #include "mp-running-instance-row.h"
14 |
15 | struct _MpRunningInstanceRow
16 | {
17 | GtkListBoxRow parent_instance;
18 |
19 | GtkLabel *address_label;
20 | GtkLabel *label;
21 | GtkSpinner *spinner;
22 |
23 | MpInstance *instance;
24 | };
25 |
26 | G_DEFINE_TYPE (MpRunningInstanceRow, mp_running_instance_row, GTK_TYPE_LIST_BOX_ROW)
27 |
28 | static void
29 | mp_running_instance_row_dispose (GObject *object)
30 | {
31 | MpRunningInstanceRow *row = MP_RUNNING_INSTANCE_ROW (object);
32 |
33 | g_clear_object (&row->instance);
34 |
35 | G_OBJECT_CLASS (mp_running_instance_row_parent_class)->dispose (object);
36 | }
37 |
38 | void
39 | mp_running_instance_row_class_init (MpRunningInstanceRowClass *klass)
40 | {
41 | GObjectClass *object_class = G_OBJECT_CLASS (klass);
42 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
43 |
44 | object_class->dispose = mp_running_instance_row_dispose;
45 |
46 | gtk_widget_class_set_template_from_resource (widget_class, "/com/ubuntu/multipass/mp-running-instance-row.ui");
47 |
48 | gtk_widget_class_bind_template_child (widget_class, MpRunningInstanceRow, address_label);
49 | gtk_widget_class_bind_template_child (widget_class, MpRunningInstanceRow, label);
50 | gtk_widget_class_bind_template_child (widget_class, MpRunningInstanceRow, spinner);
51 | }
52 |
53 | void
54 | mp_running_instance_row_init (MpRunningInstanceRow *row)
55 | {
56 | gtk_widget_init_template (GTK_WIDGET (row));
57 | }
58 |
59 | MpRunningInstanceRow *
60 | mp_running_instance_row_new (void)
61 | {
62 | return g_object_new (MP_TYPE_RUNNING_INSTANCE_ROW, NULL);
63 | }
64 |
65 | void
66 | mp_running_instance_row_set_instance (MpRunningInstanceRow *row, MpInstance *instance)
67 | {
68 | g_return_if_fail (MP_IS_RUNNING_INSTANCE_ROW (row));
69 |
70 | g_clear_object (&row->instance);
71 | row->instance = g_object_ref (instance);
72 | gtk_label_set_label (row->label, mp_instance_get_name (instance));
73 |
74 | const gchar *state = mp_instance_get_state (instance);
75 | if (g_strcmp0 (state, "STARTING") == 0) {
76 | gtk_label_set_label (row->address_label, _("Starting…"));
77 | gtk_spinner_start (row->spinner);
78 | }
79 | else if (g_strcmp0 (state, "RESTARTING") == 0) {
80 | gtk_label_set_label (row->address_label, _("Restarting…"));
81 | gtk_spinner_start (row->spinner);
82 | }
83 | else {
84 | gtk_label_set_label (row->address_label, mp_instance_get_ipv4 (instance));
85 | gtk_spinner_stop (row->spinner);
86 | }
87 | }
88 |
89 | MpInstance *
90 | mp_running_instance_row_get_instance (MpRunningInstanceRow *row)
91 | {
92 | g_return_val_if_fail (MP_IS_RUNNING_INSTANCE_ROW (row), NULL);
93 | return row->instance;
94 | }
95 |
--------------------------------------------------------------------------------
/src/mp-running-instance-row.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #pragma once
12 |
13 | #include
14 |
15 | #include "mp-instance.h"
16 |
17 | G_BEGIN_DECLS
18 |
19 | #define MP_TYPE_RUNNING_INSTANCE_ROW (mp_running_instance_row_get_type ())
20 | G_DECLARE_FINAL_TYPE (MpRunningInstanceRow, mp_running_instance_row, MP, RUNNING_INSTANCE_ROW, GtkListBoxRow)
21 |
22 | MpRunningInstanceRow *mp_running_instance_row_new (void);
23 |
24 | void mp_running_instance_row_set_instance (MpRunningInstanceRow *row,
25 | MpInstance *instance);
26 |
27 | MpInstance *mp_running_instance_row_get_instance (MpRunningInstanceRow *row);
28 |
29 | G_END_DECLS
30 |
--------------------------------------------------------------------------------
/src/mp-running-instance-row.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | True
7 | 6
8 | 6
9 | 12
10 |
11 |
12 | True
13 |
14 |
15 | 0
16 | 1
17 |
18 |
19 |
20 |
21 | True
22 | computer-symbolic
23 |
24 |
25 | 0
26 | 0
27 |
28 |
29 |
30 |
31 | True
32 | 0
33 |
34 |
35 | 1
36 | 0
37 |
38 |
39 |
40 |
41 | True
42 | 0
43 |
46 |
47 |
48 | 1
49 | 1
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/src/mp-window.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #include
12 | #include
13 |
14 | #include "mp-client.h"
15 | #include "mp-configured-instance-row.h"
16 | #include "mp-details-dialog.h"
17 | #include "mp-instance.h"
18 | #include "mp-launch-dialog.h"
19 | #include "mp-running-instance-row.h"
20 | #include "mp-window.h"
21 |
22 | struct _MpWindow
23 | {
24 | GtkWindow parent_instance;
25 |
26 | GtkLabel *configured_instances_label;
27 | GtkListBox *configured_instances_listbox;
28 | GtkStack *configured_instances_stack;
29 | GtkButton *shell_button;
30 | GtkButton *create_button;
31 | GtkButton *details_button;
32 | GtkBox *instances_box;
33 | GtkStack *main_stack;
34 | GtkLabel *running_instances_label;
35 | GtkListBox *running_instances_listbox;
36 | GtkStack *running_instances_stack;
37 | GtkButton *start_button;
38 | GtkButton *stop_button;
39 | GtkButton *trash_button;
40 |
41 | GCancellable *cancellable;
42 | MpClient *client;
43 | GSource *list_timeout_source;
44 | };
45 |
46 | G_DEFINE_TYPE (MpWindow, mp_window, GTK_TYPE_WINDOW)
47 |
48 | static MpConfiguredInstanceRow *
49 | find_configured_row (MpWindow *window, const gchar *name)
50 | {
51 | g_autoptr(GList) children = gtk_container_get_children (GTK_CONTAINER (window->configured_instances_listbox));
52 | for (GList *link = children; link; link = link->next) {
53 | if (!MP_IS_CONFIGURED_INSTANCE_ROW (link->data))
54 | continue;
55 |
56 | MpConfiguredInstanceRow *row = link->data;
57 | if (g_strcmp0 (mp_instance_get_name (mp_configured_instance_row_get_instance (row)), name) == 0)
58 | return row;
59 | }
60 |
61 | return NULL;
62 | }
63 |
64 | static MpRunningInstanceRow *
65 | find_running_row (MpWindow *window, const gchar *name)
66 | {
67 | g_autoptr(GList) children = gtk_container_get_children (GTK_CONTAINER (window->running_instances_listbox));
68 | for (GList *link = children; link; link = link->next) {
69 | if (!MP_IS_RUNNING_INSTANCE_ROW (link->data))
70 | continue;
71 |
72 | MpRunningInstanceRow *row = link->data;
73 | if (g_strcmp0 (mp_instance_get_name (mp_running_instance_row_get_instance (row)), name) == 0)
74 | return row;
75 | }
76 |
77 | return NULL;
78 | }
79 |
80 | static void
81 | configured_selection_changed_cb (MpWindow *window)
82 | {
83 | g_autoptr(GList) selected_rows = gtk_list_box_get_selected_rows (window->configured_instances_listbox);
84 |
85 | gtk_widget_set_sensitive (GTK_WIDGET (window->start_button), selected_rows != NULL);
86 | gtk_widget_set_sensitive (GTK_WIDGET (window->trash_button), selected_rows != NULL);
87 |
88 | gtk_button_set_label (window->trash_button, _("Trash"));
89 | if (selected_rows != NULL) {
90 | MpConfiguredInstanceRow *row = MP_CONFIGURED_INSTANCE_ROW (gtk_list_box_get_selected_row (window->configured_instances_listbox));
91 | MpInstance *instance = mp_configured_instance_row_get_instance (row);
92 | if (g_strcmp0 (mp_instance_get_state (instance), "Deleted") == 0)
93 | gtk_button_set_label (window->trash_button, _("Recover"));
94 | }
95 | }
96 |
97 | static void
98 | running_selection_changed_cb (MpWindow *window)
99 | {
100 | g_autoptr(GList) selected_rows = gtk_list_box_get_selected_rows (window->running_instances_listbox);
101 |
102 | gtk_widget_set_sensitive (GTK_WIDGET (window->stop_button), selected_rows != NULL);
103 | gtk_widget_set_sensitive (GTK_WIDGET (window->details_button), selected_rows != NULL);
104 | gtk_widget_set_sensitive (GTK_WIDGET (window->shell_button), selected_rows != NULL);
105 | }
106 |
107 | static void
108 | create_button_clicked_cb (MpWindow *window)
109 | {
110 | MpLaunchDialog *dialog = mp_launch_dialog_new (window->client);
111 | gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
112 |
113 | if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
114 | const gchar *name = mp_launch_dialog_get_name (dialog);
115 | g_autofree gchar *image_name = mp_launch_dialog_get_image_name (dialog);
116 |
117 | mp_client_launch_async (window->client, name, image_name, window->cancellable, NULL, window);
118 | }
119 |
120 | gtk_widget_destroy (GTK_WIDGET (dialog));
121 | }
122 |
123 | static void
124 | trash_button_clicked_cb (MpWindow *window)
125 | {
126 | MpConfiguredInstanceRow *row = MP_CONFIGURED_INSTANCE_ROW (gtk_list_box_get_selected_row (window->configured_instances_listbox));
127 | MpInstance *instance = mp_configured_instance_row_get_instance (row);
128 |
129 | if (g_strcmp0 (mp_instance_get_state (instance), "Deleted") == 0)
130 | mp_client_recover_async (window->client,
131 | mp_instance_get_name (instance),
132 | window->cancellable,
133 | NULL, NULL);
134 | else
135 | mp_client_delete_async (window->client,
136 | mp_instance_get_name (instance),
137 | FALSE,
138 | window->cancellable,
139 | NULL, NULL);
140 | }
141 |
142 | static void
143 | start_button_clicked_cb (MpWindow *window)
144 | {
145 | MpConfiguredInstanceRow *row = MP_CONFIGURED_INSTANCE_ROW (gtk_list_box_get_selected_row (window->configured_instances_listbox));
146 |
147 | mp_client_start_async (window->client,
148 | mp_instance_get_name (mp_configured_instance_row_get_instance (row)),
149 | window->cancellable,
150 | NULL, NULL);
151 | }
152 |
153 | static void
154 | stop_button_clicked_cb (MpWindow *window)
155 | {
156 | MpRunningInstanceRow *row = MP_RUNNING_INSTANCE_ROW (gtk_list_box_get_selected_row (window->running_instances_listbox));
157 |
158 | mp_client_stop_async (window->client,
159 | mp_instance_get_name (mp_running_instance_row_get_instance (row)),
160 | window->cancellable,
161 | NULL, NULL);
162 | }
163 |
164 | static void
165 | details_button_clicked_cb (MpWindow *window)
166 | {
167 | MpRunningInstanceRow *row = MP_RUNNING_INSTANCE_ROW (gtk_list_box_get_selected_row (window->running_instances_listbox));
168 | MpInstance *instance = mp_running_instance_row_get_instance (row);
169 |
170 | MpDetailsDialog *dialog = mp_details_dialog_new (window->client, instance);
171 | gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
172 |
173 | gtk_dialog_run (GTK_DIALOG (dialog));
174 | gtk_widget_destroy (GTK_WIDGET (dialog));
175 | }
176 |
177 | static void
178 | spawn_cb (VteTerminal *terminal, GPid pid, GError *error, gpointer user_data)
179 | {
180 | if (error)
181 | g_warning ("Failed to spawn shell: %s\n", error->message);
182 | }
183 |
184 | static void
185 | shell_button_clicked_cb (MpWindow *window)
186 | {
187 | MpRunningInstanceRow *row = MP_RUNNING_INSTANCE_ROW (gtk_list_box_get_selected_row (window->running_instances_listbox));
188 | MpInstance *instance = mp_running_instance_row_get_instance (row);
189 |
190 | GtkWindow *terminal_window = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
191 | GtkHeaderBar *header_bar = GTK_HEADER_BAR (gtk_header_bar_new ());
192 | gtk_header_bar_set_show_close_button (header_bar, TRUE);
193 | gtk_header_bar_set_title (header_bar, mp_instance_get_name (instance));
194 | gtk_widget_show (GTK_WIDGET (header_bar));
195 | gtk_window_set_titlebar (terminal_window, GTK_WIDGET (header_bar));
196 |
197 | VteTerminal *terminal = VTE_TERMINAL (vte_terminal_new ());
198 | gtk_widget_show (GTK_WIDGET (terminal));
199 | gtk_container_add (GTK_CONTAINER (terminal_window), GTK_WIDGET (terminal));
200 |
201 | g_autoptr(GPtrArray) args = g_ptr_array_new ();
202 | g_ptr_array_add (args, "multipass");
203 | g_ptr_array_add (args, "shell");
204 | g_ptr_array_add (args, (gpointer) mp_instance_get_name (instance));
205 | g_ptr_array_add (args, NULL);
206 | vte_terminal_spawn_async (terminal,
207 | VTE_PTY_DEFAULT,
208 | NULL, /* working directory */
209 | (gchar **) args->pdata,
210 | NULL, /* environment */
211 | G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
212 | NULL, NULL, NULL, /* child setup */
213 | -1, /* timeout */
214 | NULL, /* cancellable */
215 | spawn_cb, window);
216 |
217 | gtk_window_present (terminal_window);
218 | }
219 |
220 | static void
221 | mp_window_dispose (GObject *object)
222 | {
223 | MpWindow *window = MP_WINDOW (object);
224 |
225 | g_cancellable_cancel (window->cancellable);
226 | g_clear_object (&window->cancellable);
227 | g_clear_object (&window->client);
228 |
229 | G_OBJECT_CLASS (mp_window_parent_class)->dispose (object);
230 | }
231 |
232 | void
233 | mp_window_class_init (MpWindowClass *klass)
234 | {
235 | GObjectClass *object_class = G_OBJECT_CLASS (klass);
236 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
237 |
238 | object_class->dispose = mp_window_dispose;
239 |
240 | gtk_widget_class_set_template_from_resource (widget_class, "/com/ubuntu/multipass/mp-window.ui");
241 |
242 | gtk_widget_class_bind_template_child (widget_class, MpWindow, configured_instances_label);
243 | gtk_widget_class_bind_template_child (widget_class, MpWindow, configured_instances_listbox);
244 | gtk_widget_class_bind_template_child (widget_class, MpWindow, configured_instances_stack);
245 | gtk_widget_class_bind_template_child (widget_class, MpWindow, shell_button);
246 | gtk_widget_class_bind_template_child (widget_class, MpWindow, create_button);
247 | gtk_widget_class_bind_template_child (widget_class, MpWindow, details_button);
248 | gtk_widget_class_bind_template_child (widget_class, MpWindow, instances_box);
249 | gtk_widget_class_bind_template_child (widget_class, MpWindow, main_stack);
250 | gtk_widget_class_bind_template_child (widget_class, MpWindow, running_instances_label);
251 | gtk_widget_class_bind_template_child (widget_class, MpWindow, running_instances_listbox);
252 | gtk_widget_class_bind_template_child (widget_class, MpWindow, running_instances_stack);
253 | gtk_widget_class_bind_template_child (widget_class, MpWindow, start_button);
254 | gtk_widget_class_bind_template_child (widget_class, MpWindow, stop_button);
255 | gtk_widget_class_bind_template_child (widget_class, MpWindow, trash_button);
256 |
257 | gtk_widget_class_bind_template_callback (widget_class, configured_selection_changed_cb);
258 | gtk_widget_class_bind_template_callback (widget_class, shell_button_clicked_cb);
259 | gtk_widget_class_bind_template_callback (widget_class, create_button_clicked_cb);
260 | gtk_widget_class_bind_template_callback (widget_class, details_button_clicked_cb);
261 | gtk_widget_class_bind_template_callback (widget_class, running_selection_changed_cb);
262 | gtk_widget_class_bind_template_callback (widget_class, start_button_clicked_cb);
263 | gtk_widget_class_bind_template_callback (widget_class, stop_button_clicked_cb);
264 | gtk_widget_class_bind_template_callback (widget_class, trash_button_clicked_cb);
265 | }
266 |
267 | static void update_list (MpWindow *window);
268 |
269 | static gboolean
270 | list_timeout_cb (gpointer user_data)
271 | {
272 | MpWindow *window = user_data;
273 | g_clear_pointer (&window->list_timeout_source, g_source_unref);
274 | update_list (window);
275 | return G_SOURCE_REMOVE;
276 | }
277 |
278 | static void
279 | list_cb (GObject *client, GAsyncResult *result, gpointer user_data)
280 | {
281 | MpWindow *window = user_data;
282 |
283 | g_autoptr(GError) error = NULL;
284 | g_autoptr(GPtrArray) instances = mp_client_list_finish (MP_CLIENT (client), result, &error);
285 |
286 | if (instances == NULL && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
287 | return;
288 |
289 | if (instances != NULL) {
290 | GHashTable *configured_rows = g_hash_table_new (g_str_hash, g_str_equal);
291 | GHashTable *running_rows = g_hash_table_new (g_str_hash, g_str_equal);
292 | for (int i = 0; i < instances->len; i++) {
293 | MpInstance *instance = g_ptr_array_index (instances, i);
294 | const gchar *name = mp_instance_get_name (instance);
295 | const gchar *state = mp_instance_get_state (instance);
296 |
297 | MpConfiguredInstanceRow *configured_row = find_configured_row (window, name);
298 | if (configured_row == NULL) {
299 | configured_row = mp_configured_instance_row_new ();
300 | gtk_widget_show (GTK_WIDGET (configured_row));
301 | gtk_container_add (GTK_CONTAINER (window->configured_instances_listbox), GTK_WIDGET (configured_row));
302 | }
303 | mp_configured_instance_row_set_instance (configured_row, instance);
304 | g_hash_table_add (configured_rows, (gpointer) name);
305 |
306 | if (g_strcmp0 (state, "Starting") == 0 || g_strcmp0 (state, "Running") == 0 || g_strcmp0 (state, "Restarting") == 0) {
307 | MpRunningInstanceRow *running_row = find_running_row (window, name);
308 | if (running_row == NULL) {
309 | running_row = mp_running_instance_row_new ();
310 | gtk_widget_show (GTK_WIDGET (running_row));
311 | gtk_container_add (GTK_CONTAINER (window->running_instances_listbox), GTK_WIDGET (running_row));
312 | }
313 | mp_running_instance_row_set_instance (running_row, instance);
314 | g_hash_table_add (running_rows, (gpointer) name);
315 | }
316 | }
317 |
318 | /* Remove any unused rows */
319 | g_autoptr(GList) children = gtk_container_get_children (GTK_CONTAINER (window->configured_instances_listbox));
320 | for (GList *link = children; link; link = link->next) {
321 | if (!MP_IS_CONFIGURED_INSTANCE_ROW (link->data))
322 | continue;
323 |
324 | MpConfiguredInstanceRow *row = link->data;
325 | if (g_hash_table_lookup (configured_rows, mp_instance_get_name (mp_configured_instance_row_get_instance (row))) == NULL)
326 | gtk_container_remove (GTK_CONTAINER (window->configured_instances_listbox), GTK_WIDGET (row));
327 | }
328 | g_autoptr(GList) running_children = gtk_container_get_children (GTK_CONTAINER (window->running_instances_listbox));
329 | for (GList *link = running_children; link; link = link->next) {
330 | if (!MP_IS_RUNNING_INSTANCE_ROW (link->data))
331 | continue;
332 |
333 | MpRunningInstanceRow *row = link->data;
334 | if (g_hash_table_lookup (running_rows, mp_instance_get_name (mp_running_instance_row_get_instance (row))) == NULL)
335 | gtk_container_remove (GTK_CONTAINER (window->running_instances_listbox), GTK_WIDGET (row));
336 | }
337 |
338 | /* Show placeholders when empty rows */
339 | if (g_hash_table_size (configured_rows) > 0)
340 | gtk_stack_set_visible_child (window->configured_instances_stack, GTK_WIDGET (window->configured_instances_listbox));
341 | else
342 | gtk_stack_set_visible_child (window->configured_instances_stack, GTK_WIDGET (window->configured_instances_label));
343 | if (g_hash_table_size (running_rows) > 0)
344 | gtk_stack_set_visible_child (window->running_instances_stack, GTK_WIDGET (window->running_instances_listbox));
345 | else
346 | gtk_stack_set_visible_child (window->running_instances_stack, GTK_WIDGET (window->running_instances_label));
347 |
348 | configured_selection_changed_cb (window);
349 | running_selection_changed_cb (window);
350 | } else {
351 | g_printerr ("Failed to get instances: %s\n", error->message);
352 | }
353 |
354 | window->list_timeout_source = g_timeout_source_new_seconds (1);
355 | g_source_set_callback (window->list_timeout_source, list_timeout_cb, window, NULL);
356 | g_source_attach (window->list_timeout_source, g_main_context_default ());
357 | }
358 |
359 | static void
360 | update_list (MpWindow *window)
361 | {
362 | mp_client_list_async (window->client, window->cancellable, list_cb, window);
363 | }
364 |
365 | void
366 | mp_window_init (MpWindow *window)
367 | {
368 | gtk_widget_init_template (GTK_WIDGET (window));
369 |
370 | window->cancellable = g_cancellable_new ();
371 | window->client = mp_client_new ();
372 |
373 | g_autoptr(GError) error = NULL;
374 | g_autofree gchar *version = mp_client_get_version_sync (window->client, window->cancellable, &error);
375 |
376 | if (version != NULL)
377 | gtk_stack_set_visible_child (window->main_stack, GTK_WIDGET (window->instances_box));
378 |
379 | update_list (window);
380 | }
381 |
382 | MpWindow *
383 | mp_window_new (void)
384 | {
385 | return g_object_new (MP_TYPE_WINDOW, NULL);
386 | }
387 |
--------------------------------------------------------------------------------
/src/mp-window.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2018 Canonical Ltd.
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU General Public License as published by the Free Software
6 | * Foundation, either version 3 of the License, or (at your option) any later
7 | * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 | * license.
9 | */
10 |
11 | #pragma once
12 |
13 | #include
14 |
15 | G_BEGIN_DECLS
16 |
17 | #define MP_TYPE_WINDOW (mp_window_get_type ())
18 | G_DECLARE_FINAL_TYPE (MpWindow, mp_window, MP, WINDOW, GtkWindow)
19 |
20 | MpWindow *mp_window_new (void);
21 |
22 | G_END_DECLS
23 |
--------------------------------------------------------------------------------
/src/mp-window.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 350
5 |
6 |
11 |
12 |
13 |
14 | True
15 |
16 |
17 | True
18 | vertical
19 | center
20 | 6
21 |
22 |
23 | True
24 | Multipass is not installed
25 |
26 |
27 |
28 |
29 | True
30 | $ snap install multipass
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | True
41 | 18
42 | 18
43 | 18
44 |
45 |
46 | True
47 | 0
48 | Configured:
49 |
50 |
51 | 0
52 | 0
53 |
54 |
55 |
56 |
57 | True
58 | True
59 | True
60 |
61 |
62 | True
63 | No instances configured
64 |
65 |
66 |
67 |
68 | True
69 |
70 |
71 |
72 |
73 |
74 | 0
75 | 1
76 |
77 |
78 |
79 |
80 | True
81 | 6
82 |
83 |
84 | True
85 | Launch…
86 |
87 |
88 |
89 |
90 |
91 | True
92 | False
93 | Trash
94 |
95 |
96 |
97 |
98 |
99 | True
100 | False
101 | Start
102 |
103 |
104 |
105 | end
106 |
107 |
108 |
109 |
110 | 0
111 | 2
112 |
113 |
114 |
115 |
116 | True
117 | 0
118 | Running:
119 |
120 |
121 | 1
122 | 0
123 |
124 |
125 |
126 |
127 | True
128 | True
129 | True
130 |
131 |
132 | True
133 | No instances running
134 |
135 |
136 |
137 |
138 | True
139 |
140 |
141 |
142 |
143 |
144 | 1
145 | 1
146 |
147 |
148 |
149 |
150 | True
151 | 6
152 |
153 |
154 | True
155 | False
156 | Stop
157 |
158 |
159 |
160 |
161 |
162 | True
163 | False
164 | Shell
165 |
166 |
167 |
168 | end
169 |
170 |
171 |
172 |
173 | True
174 | False
175 | Details
176 |
177 |
178 |
179 | end
180 |
181 |
182 |
183 |
184 | 1
185 | 2
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 | horizontal
196 |
197 |
198 |
199 |
200 |
201 |
202 | horizontal
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
--------------------------------------------------------------------------------
/src/multipass-gui.desktop.in:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Multipass
3 | Comment=Easily launch Ubuntu virtual machines
4 | Keywords=multipass;vm;virtual;machine;ubuntu
5 | Exec=multipass-gui
6 | #Icon=scanner
7 | Terminal=false
8 | Type=Application
9 | StartupNotify=true
10 | Categories=GNOME;GTK;
11 |
--------------------------------------------------------------------------------
/src/names.txt:
--------------------------------------------------------------------------------
1 | aardvark
2 | aardwolf
3 | accentor
4 | adder
5 | adjutant
6 | admiral
7 | agama
8 | agouti
9 | airedale
10 | akita
11 | albacore
12 | albatross
13 | alewife
14 | alien
15 | alligator
16 | alpaca
17 | amberjack
18 | amoeba
19 | amphibian
20 | anaconda
21 | anchovy
22 | anemone
23 | angelfish
24 | angler
25 | anglerfish
26 | angora
27 | anhinga
28 | anoa
29 | ant
30 | anteater
31 | antelope
32 | antlion
33 | ape
34 | aphid
35 | arachnid
36 | arapaima
37 | archerfish
38 | armadillo
39 | asp
40 | auk
41 | avocet
42 | axolotl
43 | baboon
44 | badger
45 | bandicoot
46 | barbel
47 | barbet
48 | barnacle
49 | barracuda
50 | basilisk
51 | bass
52 | basset
53 | bat
54 | batfish
55 | beagle
56 | bear
57 | bedbug
58 | bee
59 | beetle
60 | bellbird
61 | bengal
62 | beta
63 | bettong
64 | bigeye
65 | billfish
66 | binturong
67 | bird
68 | bison
69 | bitterling
70 | bittern
71 | blackbird
72 | blackbuck
73 | blackcap
74 | blackfish
75 | blenny
76 | blesbok
77 | bloodhound
78 | blowfish
79 | bluebill
80 | bluebird
81 | bluefish
82 | bluegill
83 | bluejay
84 | boa
85 | boar
86 | boarfish
87 | boatbill
88 | bobcat
89 | bobolink
90 | bobwhite
91 | bonefish
92 | bongo
93 | bonito
94 | bonobo
95 | bontebok
96 | booklouse
97 | borer
98 | bowerbird
99 | bowfin
100 | boxer
101 | boxfish
102 | brambling
103 | bream
104 | brill
105 | broadbill
106 | brocket
107 | buck
108 | budgerigar
109 | buffalo
110 | bufflehead
111 | bug
112 | bulbul
113 | bull
114 | bulldog
115 | bullfinch
116 | bullfrog
117 | bullhead
118 | bullsnake
119 | bumblebee
120 | bunny
121 | bunting
122 | burbot
123 | burro
124 | bushbuck
125 | bustard
126 | butcherbird
127 | butterfish
128 | butterfly
129 | buzzard
130 | caiman
131 | calf
132 | camel
133 | candlefish
134 | cankerworm
135 | canvasback
136 | capelin
137 | capuchin
138 | capybara
139 | caracal
140 | caracara
141 | cardinal
142 | caribou
143 | carp
144 | cassowary
145 | cat
146 | catbird
147 | caterpillar
148 | catfish
149 | cattle
150 | centipede
151 | cephalopod
152 | chaffinch
153 | chameleon
154 | chamois
155 | char
156 | cheetah
157 | chickadee
158 | chicken
159 | chiffchaff
160 | chigger
161 | chihuahua
162 | chimaera
163 | chimp
164 | chimpanzee
165 | chinchilla
166 | chinook
167 | chipmunk
168 | chow
169 | chub
170 | chuckwalla
171 | cicada
172 | cichlid
173 | cisco
174 | civet
175 | clam
176 | clingfish
177 | coati
178 | coatimundi
179 | cobia
180 | cobra
181 | cockatoo
182 | cockroach
183 | cod
184 | codling
185 | coelacanth
186 | collie
187 | colobus
188 | colt
189 | condor
190 | conger
191 | constrictor
192 | cony
193 | coonhound
194 | copperhead
195 | coral
196 | corgi
197 | cormorant
198 | cotinga
199 | cottonmouth
200 | cougar
201 | courser
202 | cow
203 | cowbird
204 | cowfish
205 | coyote
206 | crab
207 | crake
208 | crane
209 | crappie
210 | crawdad
211 | crawfish
212 | crayfish
213 | creeper
214 | cricket
215 | croaker
216 | crocodile
217 | crossbill
218 | crow
219 | cub
220 | cuckoo
221 | curassow
222 | curlew
223 | cusk
224 | cuttlefish
225 | dabchick
226 | dace
227 | dachshund
228 | dalmatian
229 | damselfish
230 | damselfly
231 | dane
232 | darter
233 | dassie
234 | dealfish
235 | deer
236 | deerhound
237 | dhole
238 | diamondback
239 | dingo
240 | dinosaur
241 | diplodocus
242 | dipper
243 | diver
244 | doberman
245 | dobsonfly
246 | dodo
247 | doe
248 | dog
249 | dogfish
250 | dolphin
251 | donkey
252 | dormouse
253 | dory
254 | dotterel
255 | dove
256 | dowitcher
257 | dragon
258 | dragonet
259 | dragonfly
260 | drake
261 | drongo
262 | drum
263 | duck
264 | duckbill
265 | duckling
266 | dugong
267 | dunlin
268 | dunnock
269 | eagle
270 | earthworm
271 | earwig
272 | echidna
273 | eel
274 | eelpout
275 | eft
276 | egret
277 | eland
278 | elasmobranch
279 | elephant
280 | elf
281 | elk
282 | elver
283 | emperor
284 | emu
285 | ermine
286 | escargot
287 | escolar
288 | euglena
289 | eulachon
290 | ewe
291 | falcon
292 | falconet
293 | fantail
294 | fawn
295 | feline
296 | fennec
297 | ferret
298 | fieldfare
299 | fieldmouse
300 | filefish
301 | filly
302 | finch
303 | finfoot
304 | fireback
305 | firebrat
306 | firefly
307 | fish
308 | fisher
309 | flamingo
310 | flatfish
311 | flathead
312 | flea
313 | flounder
314 | fly
315 | flycatcher
316 | foal
317 | fossa
318 | fowl
319 | fox
320 | foxhound
321 | frog
322 | frogfish
323 | frogmouth
324 | fulmar
325 | gadwall
326 | gallinule
327 | gannet
328 | gar
329 | garfish
330 | garganey
331 | garpike
332 | gator
333 | gaur
334 | gazelle
335 | gecko
336 | gelding
337 | gemsbok
338 | genet
339 | gerbil
340 | gerenuk
341 | ghost
342 | ghoul
343 | gibbon
344 | giraffe
345 | glassfish
346 | glider
347 | glowworm
348 | gnat
349 | gnatcatcher
350 | gnu
351 | goat
352 | goatfish
353 | gobbler
354 | goblin
355 | goby
356 | godwit
357 | goldcrest
358 | goldeneye
359 | goldfinch
360 | goldfish
361 | goose
362 | goosefish
363 | gopher
364 | gorilla
365 | goshawk
366 | gourami
367 | grackle
368 | grasshopper
369 | grayling
370 | grebe
371 | greenfinch
372 | greenling
373 | greenshank
374 | grenadier
375 | greyhound
376 | griffon
377 | grison
378 | grizzly
379 | grosbeak
380 | groundhog
381 | grouper
382 | grouse
383 | grub
384 | grubworm
385 | grunt
386 | grunter
387 | gryphon
388 | guan
389 | guanaco
390 | gudgeon
391 | guillemot
392 | guinea
393 | guineapig
394 | guitarfish
395 | gull
396 | gunnel
397 | guppy
398 | gurnard
399 | gyrfalcon
400 | haddock
401 | hagfish
402 | hairtail
403 | hake
404 | halfbeak
405 | halibut
406 | hammerhead
407 | hamster
408 | hare
409 | harrier
410 | hartebeest
411 | hawfinch
412 | hawk
413 | hedgehog
414 | hen
415 | hermit
416 | heron
417 | herring
418 | hippo
419 | hoatzin
420 | hog
421 | honeybee
422 | hookworm
423 | hoopoe
424 | hornbill
425 | hornet
426 | horntail
427 | horse
428 | hound
429 | houndshark
430 | human
431 | hummingbird
432 | humpback
433 | husky
434 | hyena
435 | hyrax
436 | ibex
437 | ibis
438 | ichthyosaur
439 | iguana
440 | iguanodon
441 | imp
442 | impala
443 | insect
444 | jabiru
445 | jacamar
446 | jackal
447 | jackass
448 | jackdaw
449 | jackrabbit
450 | jaeger
451 | jaguar
452 | jaguarundi
453 | javelin
454 | javelina
455 | jawfish
456 | jay
457 | jaybird
458 | jellyfish
459 | jennet
460 | jerboa
461 | jewfish
462 | joey
463 | junco
464 | kagu
465 | kakapo
466 | kalong
467 | kangaroo
468 | katydid
469 | kea
470 | kelpie
471 | kestrel
472 | kid
473 | killdeer
474 | killifish
475 | kingbird
476 | kingfish
477 | kingfisher
478 | kinglet
479 | kingsnake
480 | kinkajou
481 | kit
482 | kite
483 | kitten
484 | kittiwake
485 | kiwi
486 | klipspringer
487 | koala
488 | kodiak
489 | koel
490 | koi
491 | kookaburra
492 | krait
493 | krill
494 | kudu
495 | lab
496 | labrador
497 | lacewing
498 | ladybeetle
499 | ladybird
500 | ladybug
501 | lagomorph
502 | lamb
503 | lamprey
504 | langur
505 | lanternfish
506 | lapwing
507 | lark
508 | leafcutter
509 | leafhopper
510 | leafroller
511 | leech
512 | lemming
513 | lemur
514 | leopard
515 | leopardess
516 | liger
517 | limpet
518 | limpkin
519 | ling
520 | linnet
521 | lion
522 | lioness
523 | lionfish
524 | livebearer
525 | lizard
526 | lizardfish
527 | llama
528 | loach
529 | lobster
530 | locust
531 | longhorn
532 | longspur
533 | loon
534 | lorikeet
535 | loris
536 | louse
537 | louvar
538 | lumpsucker
539 | lungfish
540 | lynx
541 | lyrebird
542 | macaque
543 | macaw
544 | mackerel
545 | maggot
546 | magpie
547 | mako
548 | malamute
549 | mallard
550 | mamba
551 | mammal
552 | mammoth
553 | manakin
554 | manatee
555 | mandrill
556 | manta
557 | mantis
558 | mara
559 | mare
560 | margay
561 | markhor
562 | marlin
563 | marmoset
564 | marmot
565 | marsupial
566 | marten
567 | martin
568 | mastiff
569 | mastodon
570 | mayfly
571 | meadowlark
572 | mealworm
573 | meerkat
574 | menhaden
575 | merganser
576 | merlin
577 | midge
578 | millipede
579 | minivet
580 | mink
581 | minnow
582 | mite
583 | moccasin
584 | mockingbird
585 | mola
586 | mole
587 | mollusk
588 | molly
589 | monarch
590 | mongoose
591 | mongrel
592 | monitor
593 | monkey
594 | monkfish
595 | monster
596 | mooneye
597 | moonfish
598 | moorhen
599 | moose
600 | moray
601 | mosquito
602 | moth
603 | motmot
604 | mouflon
605 | mouse
606 | mudfish
607 | mudskipper
608 | mudsucker
609 | mule
610 | mullet
611 | murre
612 | murrelet
613 | muskellunge
614 | muskox
615 | muskrat
616 | mustang
617 | mutt
618 | mynah
619 | naiad
620 | narwhal
621 | neanderthal
622 | needlefish
623 | newfoundland
624 | newt
625 | nightcrawler
626 | nighthawk
627 | nightingale
628 | nightjar
629 | nilgai
630 | nit
631 | numbat
632 | nutcracker
633 | nuthatch
634 | nutria
635 | nyala
636 | oarfish
637 | ocelot
638 | octopus
639 | oilbird
640 | okapi
641 | oldwife
642 | onager
643 | opah
644 | opossum
645 | orangutan
646 | orca
647 | oriole
648 | oryx
649 | osprey
650 | ostrich
651 | otter
652 | ouzel
653 | ovenbird
654 | owl
655 | owlet
656 | ox
657 | oxpecker
658 | oyster
659 | paddlefish
660 | pademelon
661 | panda
662 | pangolin
663 | panther
664 | papillon
665 | parakeet
666 | parrot
667 | parrotfish
668 | partridge
669 | passerine
670 | peacock
671 | peafowl
672 | peccary
673 | pegasus
674 | pekingese
675 | pelican
676 | penguin
677 | perch
678 | petrel
679 | pewee
680 | phalarope
681 | pheasant
682 | phoebe
683 | phoenix
684 | pickerel
685 | pig
686 | pigeon
687 | pigfish
688 | piglet
689 | pika
690 | pike
691 | pilchard
692 | pinniped
693 | pinscher
694 | pintail
695 | pipefish
696 | pipit
697 | piranha
698 | pitta
699 | plaice
700 | planarian
701 | planthopper
702 | platy
703 | platypus
704 | plover
705 | poacher
706 | pochard
707 | pointer
708 | polecat
709 | polliwog
710 | pollock
711 | pomfret
712 | pompano
713 | pony
714 | poodle
715 | porcupine
716 | porgy
717 | porpoise
718 | possum
719 | potoroo
720 | pratincole
721 | prawn
722 | primate
723 | pronghorn
724 | protozoa
725 | ptarmigan
726 | puffer
727 | pufferfish
728 | puffin
729 | pug
730 | puma
731 | pumpkinseed
732 | pup
733 | python
734 | quagga
735 | quahog
736 | quail
737 | quetzal
738 | rabbit
739 | rabbitfish
740 | raccoon
741 | racer
742 | ram
743 | raptor
744 | rat
745 | ratel
746 | rattail
747 | rattler
748 | rattlesnake
749 | raven
750 | ray
751 | razorbill
752 | razorfish
753 | redbird
754 | redfish
755 | redhead
756 | redpoll
757 | redshank
758 | redstart
759 | reedbuck
760 | reindeer
761 | remora
762 | reptile
763 | retriever
764 | rhea
765 | rhino
766 | rhinoceros
767 | ribbonfish
768 | ridgeback
769 | ringtail
770 | roach
771 | roadrunner
772 | robin
773 | rockfish
774 | rockhopper
775 | rockling
776 | rodent
777 | roller
778 | rook
779 | rooster
780 | rottweiler
781 | roughy
782 | roundworm
783 | rudd
784 | rudderfish
785 | ruff
786 | sabertooth
787 | sablefish
788 | sailfish
789 | salamander
790 | salmon
791 | sambar
792 | sanderling
793 | sandfish
794 | sandgrouse
795 | sandpiper
796 | sapsucker
797 | sardine
798 | sasquatch
799 | satyr
800 | sauger
801 | saury
802 | sawfish
803 | sawfly
804 | scad
805 | scallop
806 | schnauzer
807 | scorpion
808 | scorpionfish
809 | scoter
810 | screamer
811 | sculpin
812 | scup
813 | seagull
814 | seahorse
815 | seal
816 | seasnail
817 | seriema
818 | serval
819 | setter
820 | shad
821 | shark
822 | sharksucker
823 | shearwater
824 | sheatfish
825 | sheathbill
826 | sheep
827 | sheepdog
828 | sheepshead
829 | shelduck
830 | shepherd
831 | shiner
832 | shoebill
833 | shoveler
834 | shrew
835 | shrike
836 | shrimp
837 | sicklebill
838 | sidewinder
839 | silkworm
840 | silverfish
841 | silverside
842 | siskin
843 | skate
844 | skater
845 | skimmer
846 | skink
847 | skua
848 | skunk
849 | skylark
850 | sleeper
851 | sloth
852 | slug
853 | smelt
854 | smew
855 | snail
856 | snailfish
857 | snake
858 | snapper
859 | snipe
860 | snipefish
861 | snook
862 | soldierfish
863 | sole
864 | sora
865 | sow
866 | spadefish
867 | spaniel
868 | sparrow
869 | sparrowhawk
870 | spearfish
871 | spider
872 | spidermonkey
873 | spittlebug
874 | spitz
875 | sponge
876 | spoonbill
877 | sprat
878 | springbok
879 | springbuck
880 | springer
881 | springtail
882 | squeaker
883 | squid
884 | squirrel
885 | squirrelfish
886 | stag
887 | staghound
888 | stallion
889 | starfish
890 | stargazer
891 | starling
892 | steelhead
893 | steenbok
894 | stickleback
895 | stilt
896 | stingray
897 | stinkbug
898 | stint
899 | stoat
900 | stonechat
901 | stonefish
902 | stork
903 | stud
904 | sturgeon
905 | sunbeam
906 | sunbird
907 | sunfish
908 | surfbird
909 | surfperch
910 | surgeonfish
911 | suricate
912 | swan
913 | sweeper
914 | swift
915 | swiftlet
916 | swine
917 | swordfish
918 | swordtail
919 | sylph
920 | tadpole
921 | tahr
922 | tailorbird
923 | taipan
924 | takin
925 | tamandua
926 | tamarin
927 | tanager
928 | tapir
929 | tarantula
930 | tardigrade
931 | tarpon
932 | tarsier
933 | tattler
934 | tayra
935 | teal
936 | tench
937 | tenpounder
938 | tenrec
939 | termite
940 | tern
941 | terrapin
942 | terrier
943 | tetra
944 | thornbill
945 | thorntail
946 | thrasher
947 | threadfin
948 | thrush
949 | tick
950 | tiger
951 | tigerfish
952 | tilapia
953 | tilefish
954 | tinamou
955 | titmouse
956 | toad
957 | toadfish
958 | tody
959 | tomcat
960 | topi
961 | topminnow
962 | tortoise
963 | toucan
964 | towhee
965 | tragopan
966 | treefrog
967 | trembler
968 | triggerfish
969 | tripletail
970 | trogon
971 | troll
972 | trout
973 | trumpeter
974 | trumpetfish
975 | trunkfish
976 | tuatara
977 | tuna
978 | tunny
979 | turaco
980 | turbot
981 | turkey
982 | turnstone
983 | turtle
984 | unicorn
985 | urchin
986 | urial
987 | veery
988 | velvetbreast
989 | vendace
990 | verdin
991 | vervet
992 | vicuna
993 | violetear
994 | viper
995 | vireo
996 | vizcacha
997 | vole
998 | vulture
999 | wagtail
1000 | wahoo
1001 | wallaby
1002 | wallaroo
1003 | walleye
1004 | walrus
1005 | wapiti
1006 | warbler
1007 | warmouth
1008 | warthog
1009 | wasp
1010 | waterbear
1011 | waterbuck
1012 | waterfowl
1013 | wattlebird
1014 | waxbill
1015 | waxwing
1016 | weasel
1017 | weevil
1018 | weimaraner
1019 | weka
1020 | werewolf
1021 | whale
1022 | wheatear
1023 | whimbrel
1024 | whippet
1025 | whippoorwill
1026 | whipsnake
1027 | whistler
1028 | whitebait
1029 | whitefish
1030 | whitefly
1031 | whitethroat
1032 | whiting
1033 | whydah
1034 | wigeon
1035 | wildcat
1036 | wildebeest
1037 | wildfowl
1038 | willet
1039 | wolf
1040 | wolffish
1041 | wolfhound
1042 | wolverine
1043 | wombat
1044 | woodchuck
1045 | woodcock
1046 | woodcreeper
1047 | woodlouse
1048 | woodpecker
1049 | worm
1050 | wrasse
1051 | wren
1052 | wryneck
1053 | yak
1054 | yellowhammer
1055 | yellowtail
1056 | yellowthroat
1057 | yeti
1058 | zander
1059 | zebra
1060 | zebu
1061 | zingel
1062 | zorilla
--------------------------------------------------------------------------------