├── .gitignore ├── AUTHORS ├── LICENSE ├── LICENSE.GPL ├── Makefile.am ├── NEWS ├── README.md ├── TODO ├── autogen.sh ├── configure.ac ├── data ├── Makefile.am └── org.raspberrypi.maynard.gschema.xml.in.in ├── maynard.in ├── po ├── Makefile.in.in └── POTFILES.in ├── protocol ├── Makefile.am ├── README.txt ├── desktop-shell.xml ├── shell-helper.xml └── weston-desktop-shell.xml └── shell ├── Makefile.am ├── app-icon.c ├── app-icon.h ├── clock.c ├── clock.h ├── favorites.c ├── favorites.h ├── launcher.c ├── launcher.h ├── maynard.c ├── maynard.gresource.xml ├── panel.c ├── panel.h ├── shell-app-system.c ├── shell-app-system.h ├── shell-helper.c ├── style.css ├── vertical-clock.c └── vertical-clock.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.[ao] 2 | *.gcda 3 | *.gcno 4 | *.gcov 5 | *.l[ao] 6 | *.loT 7 | *.orig 8 | *.pc 9 | *.py[co] 10 | *.rej 11 | *.sw[op] 12 | *~ 13 | *# 14 | .#* 15 | .deps 16 | .libs 17 | Makefile 18 | Makefile.in 19 | _gen 20 | /aclocal.m4 21 | /autom4te.cache 22 | /compile 23 | /config.cache 24 | /config.guess 25 | /config.h 26 | /config.h.in 27 | /config.log 28 | /config.status 29 | /config.sub 30 | /configure 31 | /depcomp 32 | /install-sh 33 | /libtool 34 | /ltmain.sh 35 | /m4 36 | /missing 37 | /stamp-h1 38 | /maynard-*.tar.xz 39 | /maynard 40 | shell/desktop-shell-client-protocol.h 41 | shell/desktop-shell-protocol.c 42 | shell/shell-helper-client-protocol.h 43 | shell/shell-helper-protocol.c 44 | shell/shell-helper-server-protocol.h 45 | shell/mod-shell-helper-protocol.c 46 | shell/maynard-resources.c 47 | shell/maynard-resources.h 48 | shell/maynard 49 | data/gschemas.compiled 50 | data/org.raspberrypi.maynard.gschema.valid 51 | data/org.raspberrypi.maynard.gschema.xml 52 | po/POTFILES 53 | po/stamp-it 54 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Emilio Pozuelo Monfort 2 | Jonny Lamb 3 | Marco Barisione 4 | 5 | Tiago Vignatti is the author of 6 | weston-gtk-shell, the original base for maynard, but did not take 7 | part in maynard's development. Please don't bother him about maynard 8 | specific queries! 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | shell/maynard.c is licensed under the MIT License: 2 | 3 | Copyright (c) 2013 Tiago Vignatti 4 | Copyright (c) 2013-2014 Collabora Ltd. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | 24 | All other files are licensed under the GPL 2+ license: 25 | 26 | Copyright (c) 2013-2014 Collabora Ltd. 27 | 28 | This program is free software; you can redistribute it and/or 29 | modify it under the terms of the GNU General Public License as 30 | published by the Free Software Foundation; either version 2 of the 31 | License, or (at your option) any later version. 32 | 33 | This program is distributed in the hope that it will be useful, 34 | but WITHOUT ANY WARRANTY; without even the implied warranty of 35 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 36 | General Public License for more details. 37 | 38 | You should have received a copy of the GNU General Public 39 | License along with this program; if not, write to the 40 | Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 41 | Boston, MA 02110-1301 USA 42 | 43 | Full text of the GPL 2+ license can be found in the LICENSE.GPL file. -------------------------------------------------------------------------------- /LICENSE.GPL: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = data protocol shell po 2 | 3 | bin_SCRIPTS = maynard 4 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Use 'git log' to list the changes to this repository. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # maynard 2 | 3 | This is a desktop shell client for Weston based on GTK. It was based 4 | on weston-gtk-shell, a project by Tiago Vignatti. 5 | 6 | License information can be found in the LICENSE file in the same 7 | directory as this README. 8 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | clock: remove GtkRevealers and replace with a GtkStack 2 | launcher-grid: use GtkFlowGrid 3 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | test -n "$srcdir" || srcdir=`dirname "$0"` 4 | test -n "$srcdir" || srcdir=. 5 | ( 6 | cd "$srcdir" && 7 | autoreconf --force -v --install 8 | ) || exit 9 | test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" 10 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.64]) 2 | AC_INIT([maynard], 3 | [0.2.0+git]) 4 | 5 | AC_CONFIG_HEADERS([config.h]) 6 | 7 | AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) 8 | 9 | AM_SILENT_RULES([yes]) 10 | 11 | # Check for programs 12 | AC_PROG_CC 13 | 14 | IT_PROG_INTLTOOL([0.40]) 15 | 16 | GETTEXT_PACKAGE=maynard 17 | AC_SUBST(GETTEXT_PACKAGE) 18 | AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", 19 | [The prefix for our gettext translation domains.]) 20 | 21 | # Initialize libtool 22 | LT_PREREQ([2.2]) 23 | LT_INIT([disable-static]) 24 | 25 | PKG_PROG_PKG_CONFIG() 26 | 27 | PKG_CHECK_MODULES([GTK], [ 28 | wayland-client >= 1.0.2 29 | weston >= 1.5.91 30 | gtk+-3.0 >= 3.10 31 | gtk+-wayland-3.0 32 | libgnome-menu-3.0 33 | gnome-desktop-3.0 34 | alsa 35 | ]) 36 | 37 | PKG_CHECK_MODULES([NEW_WESTON], [ 38 | weston >= 1.12 39 | libweston-1 40 | ], 41 | [AC_DEFINE([HAVE_NEW_WESTON], 42 | [1], 43 | [Using weston 1.12 or newer])], 44 | [AC_MSG_WARN([Not using weston 1.12 or newer])] 45 | ) 46 | 47 | GLIB_GSETTINGS 48 | 49 | WAYLAND_SCANNER_RULES(['$(top_srcdir)/protocol']) 50 | 51 | AC_CONFIG_FILES([maynard], [chmod +x maynard]) 52 | AC_CONFIG_FILES([Makefile 53 | data/Makefile 54 | shell/Makefile 55 | po/Makefile.in 56 | protocol/Makefile 57 | ]) 58 | AC_OUTPUT 59 | -------------------------------------------------------------------------------- /data/Makefile.am: -------------------------------------------------------------------------------- 1 | gsettings_SCHEMAS = org.raspberrypi.maynard.gschema.xml 2 | 3 | @INTLTOOL_XML_NOMERGE_RULE@ 4 | 5 | %.gschema.xml.in: %.gschema.xml.in.in Makefile 6 | $(AM_V_GEN) sed -e 's|@GETTEXT_PACKAGE[@]|$(GETTEXT_PACKAGE)|g' \ 7 | $< > $@ || rm $@ 8 | 9 | @GSETTINGS_RULES@ 10 | 11 | # We need to compile schemas at make time 12 | # to run from source tree 13 | gschemas.compiled: $(gsettings_SCHEMAS:.xml=.valid) 14 | $(AM_V_GEN) $(GLIB_COMPILE_SCHEMAS) --targetdir=. . 15 | 16 | all-local: gschemas.compiled 17 | 18 | EXTRA_DIST = \ 19 | org.raspberrypi.maynard.gschema.xml.in.in 20 | 21 | CLEANFILES = \ 22 | gschemas.compiled \ 23 | org.raspberrypi.maynard.gschema.valid \ 24 | $(gsettings_SCHEMAS) \ 25 | $(gsettings_SCHEMAS).in 26 | -------------------------------------------------------------------------------- /data/org.raspberrypi.maynard.gschema.xml.in.in: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | [ 'gcalctool.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'weston-terminal.desktop', 'epiphany.desktop' ] 7 | <_summary>List of desktop file IDs for favorite applications 8 | <_description> 9 | The applications corresponding to these identifiers 10 | will be displayed in the panel. 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /maynard.in: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | PREFIX=@prefix@ 4 | LIBEXECDIR=$PREFIX/libexec 5 | ABS_BUILDDIR=@abs_builddir@ 6 | DEFAULT_BACKGROUND=/usr/share/wallpapers/Hanami/contents/images/3872x2592.jpg 7 | 8 | md5() { 9 | cat "$1" 2> /dev/null | md5sum 10 | } 11 | 12 | check_install() { 13 | local_maynard="$ABS_BUILDDIR/shell/maynard" 14 | installed_maynard="$LIBEXECDIR/maynard" 15 | if [ ! -e "$local_maynard" -o \ 16 | ! -e "$installed_maynard" -o \ 17 | "`md5 \"$local_maynard\"`" != "`md5 \"$installed_maynard\"`" ]; then 18 | echo "It looks like you forgot to run 'make install'." >&2 19 | exit 1 20 | fi 21 | } 22 | 23 | mkdir ~/.config > /dev/null 2>&1 24 | 25 | if [ -z "${MAYNARD_BACKGROUND+_}" -a \ 26 | -e "$DEFAULT_BACKGROUND" ]; then 27 | export MAYNARD_BACKGROUND="$DEFAULT_BACKGROUND" 28 | fi 29 | 30 | xdpyinfo > /dev/null 2>&1 31 | if [ "$?" = "0" ]; then 32 | # We are running under X, so let's assume this is a development 33 | # installation. 34 | if ! cat /etc/os-release 2> /dev/null | grep 'ID=raspbian' > /dev/null; then 35 | # Non-Raspbian, we can launch weston under X. 36 | check_install 37 | XDG_DATA_DIRS=$XDG_DATA_DIRS:$PREFIX/share/ $PREFIX/bin/weston 38 | else 39 | echo "You cannot run Maynard under X." >&2 40 | exit 1 41 | fi 42 | else 43 | weston-launch 44 | fi 45 | -------------------------------------------------------------------------------- /po/Makefile.in.in: -------------------------------------------------------------------------------- 1 | # Makefile for program source directory in GNU NLS utilities package. 2 | # Copyright (C) 1995, 1996, 1997 by Ulrich Drepper 3 | # Copyright (C) 2004-2008 Rodney Dawes 4 | # 5 | # This file may be copied and used freely without restrictions. It may 6 | # be used in projects which are not available under a GNU Public License, 7 | # but which still want to provide support for the GNU gettext functionality. 8 | # 9 | # - Modified by Owen Taylor to use GETTEXT_PACKAGE 10 | # instead of PACKAGE and to look for po2tbl in ./ not in intl/ 11 | # 12 | # - Modified by jacob berkman to install 13 | # Makefile.in.in and po2tbl.sed.in for use with glib-gettextize 14 | # 15 | # - Modified by Rodney Dawes for use with intltool 16 | # 17 | # We have the following line for use by intltoolize: 18 | # INTLTOOL_MAKEFILE 19 | 20 | GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ 21 | PACKAGE = @PACKAGE@ 22 | VERSION = @VERSION@ 23 | 24 | SHELL = @SHELL@ 25 | 26 | srcdir = @srcdir@ 27 | top_srcdir = @top_srcdir@ 28 | top_builddir = @top_builddir@ 29 | VPATH = @srcdir@ 30 | 31 | prefix = @prefix@ 32 | exec_prefix = @exec_prefix@ 33 | datadir = @datadir@ 34 | datarootdir = @datarootdir@ 35 | libdir = @libdir@ 36 | DATADIRNAME = @DATADIRNAME@ 37 | itlocaledir = $(prefix)/$(DATADIRNAME)/locale 38 | subdir = po 39 | install_sh = @install_sh@ 40 | # Automake >= 1.8 provides @mkdir_p@. 41 | # Until it can be supposed, use the safe fallback: 42 | mkdir_p = $(install_sh) -d 43 | 44 | INSTALL = @INSTALL@ 45 | INSTALL_DATA = @INSTALL_DATA@ 46 | 47 | GMSGFMT = @GMSGFMT@ 48 | MSGFMT = @MSGFMT@ 49 | XGETTEXT = @XGETTEXT@ 50 | INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ 51 | INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ 52 | MSGMERGE = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist 53 | GENPOT = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot 54 | 55 | ALL_LINGUAS = @ALL_LINGUAS@ 56 | 57 | PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi) 58 | 59 | USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi) 60 | 61 | USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done) 62 | 63 | POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done) 64 | 65 | DISTFILES = Makefile.in.in POTFILES.in $(POFILES) 66 | EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS 67 | 68 | POTFILES = \ 69 | # This comment gets stripped out 70 | 71 | CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) 72 | 73 | .SUFFIXES: 74 | .SUFFIXES: .po .pox .gmo .mo .msg .cat 75 | 76 | AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ 77 | INTLTOOL_V_MSGFMT = $(INTLTOOL__v_MSGFMT_$(V)) 78 | INTLTOOL__v_MSGFMT_= $(INTLTOOL__v_MSGFMT_$(AM_DEFAULT_VERBOSITY)) 79 | INTLTOOL__v_MSGFMT_0 = @echo " MSGFMT" $@; 80 | 81 | .po.pox: 82 | $(MAKE) $(GETTEXT_PACKAGE).pot 83 | $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox 84 | 85 | .po.mo: 86 | $(INTLTOOL_V_MSGFMT)$(MSGFMT) -o $@ $< 87 | 88 | .po.gmo: 89 | $(INTLTOOL_V_MSGFMT)file=`echo $* | sed 's,.*/,,'`.gmo \ 90 | && rm -f $$file && $(GMSGFMT) -o $$file $< 91 | 92 | .po.cat: 93 | sed -f ../intl/po2msg.sed < $< > $*.msg \ 94 | && rm -f $@ && gencat $@ $*.msg 95 | 96 | 97 | all: all-@USE_NLS@ 98 | 99 | all-yes: $(CATALOGS) 100 | all-no: 101 | 102 | $(GETTEXT_PACKAGE).pot: $(POTFILES) 103 | $(GENPOT) 104 | 105 | install: install-data 106 | install-data: install-data-@USE_NLS@ 107 | install-data-no: all 108 | install-data-yes: all 109 | linguas="$(USE_LINGUAS)"; \ 110 | for lang in $$linguas; do \ 111 | dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ 112 | $(mkdir_p) $$dir; \ 113 | if test -r $$lang.gmo; then \ 114 | $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ 115 | echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ 116 | else \ 117 | $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ 118 | echo "installing $(srcdir)/$$lang.gmo as" \ 119 | "$$dir/$(GETTEXT_PACKAGE).mo"; \ 120 | fi; \ 121 | if test -r $$lang.gmo.m; then \ 122 | $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ 123 | echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ 124 | else \ 125 | if test -r $(srcdir)/$$lang.gmo.m ; then \ 126 | $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ 127 | $$dir/$(GETTEXT_PACKAGE).mo.m; \ 128 | echo "installing $(srcdir)/$$lang.gmo.m as" \ 129 | "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ 130 | else \ 131 | true; \ 132 | fi; \ 133 | fi; \ 134 | done 135 | 136 | # Empty stubs to satisfy archaic automake needs 137 | dvi info ctags tags CTAGS TAGS ID: 138 | 139 | # Define this as empty until I found a useful application. 140 | install-exec installcheck: 141 | 142 | uninstall: 143 | linguas="$(USE_LINGUAS)"; \ 144 | for lang in $$linguas; do \ 145 | rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ 146 | rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ 147 | done 148 | 149 | check: all $(GETTEXT_PACKAGE).pot 150 | rm -f missing notexist 151 | srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m 152 | if [ -r missing -o -r notexist ]; then \ 153 | exit 1; \ 154 | fi 155 | 156 | mostlyclean: 157 | rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp 158 | rm -f .intltool-merge-cache 159 | 160 | clean: mostlyclean 161 | 162 | distclean: clean 163 | rm -f Makefile Makefile.in POTFILES stamp-it 164 | rm -f *.mo *.msg *.cat *.cat.m *.gmo 165 | 166 | maintainer-clean: distclean 167 | @echo "This command is intended for maintainers to use;" 168 | @echo "it deletes files that may require special tools to rebuild." 169 | rm -f Makefile.in.in 170 | 171 | distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) 172 | dist distdir: $(DISTFILES) 173 | dists="$(DISTFILES)"; \ 174 | extra_dists="$(EXTRA_DISTFILES)"; \ 175 | for file in $$extra_dists; do \ 176 | test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ 177 | done; \ 178 | for file in $$dists; do \ 179 | test -f $$file || file="$(srcdir)/$$file"; \ 180 | ln $$file $(distdir) 2> /dev/null \ 181 | || cp -p $$file $(distdir); \ 182 | done 183 | 184 | update-po: Makefile 185 | $(MAKE) $(GETTEXT_PACKAGE).pot 186 | tmpdir=`pwd`; \ 187 | linguas="$(USE_LINGUAS)"; \ 188 | for lang in $$linguas; do \ 189 | echo "$$lang:"; \ 190 | result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ 191 | if $$result; then \ 192 | if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ 193 | rm -f $$tmpdir/$$lang.new.po; \ 194 | else \ 195 | if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ 196 | :; \ 197 | else \ 198 | echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ 199 | rm -f $$tmpdir/$$lang.new.po; \ 200 | exit 1; \ 201 | fi; \ 202 | fi; \ 203 | else \ 204 | echo "msgmerge for $$lang.gmo failed!"; \ 205 | rm -f $$tmpdir/$$lang.new.po; \ 206 | fi; \ 207 | done 208 | 209 | Makefile POTFILES: stamp-it 210 | @if test ! -f $@; then \ 211 | rm -f stamp-it; \ 212 | $(MAKE) stamp-it; \ 213 | fi 214 | 215 | stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in 216 | cd $(top_builddir) \ 217 | && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ 218 | $(SHELL) ./config.status 219 | 220 | # Tell versions [3.59,3.63) of GNU make not to export all variables. 221 | # Otherwise a system limit (for SysV at least) may be exceeded. 222 | .NOEXPORT: 223 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | # List of source files containing translatable strings. 2 | # Please keep this file sorted alphabetically. 3 | [encoding: UTF-8] 4 | data/org.raspberrypi.maynard.gschema.xml.in.in 5 | -------------------------------------------------------------------------------- /protocol/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = weston-desktop-shell.xml desktop-shell.xml shell-helper.xml 2 | -------------------------------------------------------------------------------- /protocol/README.txt: -------------------------------------------------------------------------------- 1 | desktop.shell.xml is a straight copy of the one in freedesktop's weston and we 2 | want to use the same version containing there: 3 | 4 | "protocol: XML files need to be installed and discoverable" 5 | https://bugs.freedesktop.org/show_bug.cgi?id=55183 6 | -------------------------------------------------------------------------------- /protocol/desktop-shell.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Traditional user interfaces can rely on this interface to define the 6 | foundations of typical desktops. Currently it's possible to set up 7 | background, panels and locking surfaces. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | The surface set by this request will receive a fake 29 | pointer.enter event during grabs at position 0, 0 and is 30 | expected to set an appropriate cursor image as described by 31 | the grab_cursor event sent just before the enter event. 32 | 33 | 34 | 35 | 36 | 37 | 38 | Tell the server, that enough desktop elements have been drawn 39 | to make the desktop look ready for use. During start-up, the 40 | server can wait for this request with a black screen before 41 | starting to fade in the desktop, for instance. If the client 42 | parts of a desktop take a long time to initialize, we avoid 43 | showing temporary garbage. 44 | 45 | 46 | 47 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Tell the shell we want it to create and set the lock surface, which is 59 | a GUI asking the user to unlock the screen. The lock surface is 60 | announced with 'set_lock_surface'. Whether or not the shell actually 61 | implements locking, it MUST send 'unlock' request to let the normal 62 | desktop resume. 63 | 64 | 65 | 66 | 67 | 68 | This event will be sent immediately before a fake enter event on the 69 | grab surface. 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | Tell the shell which side of the screen the panel is 108 | located. This is so that new windows do not overlap the panel 109 | and maximized windows maximize properly. 110 | 111 | 112 | 113 | 114 | 115 | 116 | Only one client can bind this interface at a time. 117 | 118 | 119 | 120 | 121 | A screensaver surface is normally hidden, and only visible after an 122 | idle timeout. 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /protocol/shell-helper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /protocol/weston-desktop-shell.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Traditional user interfaces can rely on this interface to define the 6 | foundations of typical desktops. Currently it's possible to set up 7 | background, panels and locking surfaces. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | The surface set by this request will receive a fake 29 | pointer.enter event during grabs at position 0, 0 and is 30 | expected to set an appropriate cursor image as described by 31 | the grab_cursor event sent just before the enter event. 32 | 33 | 34 | 35 | 36 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Tell the client we want it to create and set the lock surface, which is 48 | a GUI asking the user to unlock the screen. The lock surface is 49 | announced with 'set_lock_surface'. Whether or not the client actually 50 | implements locking, it MUST send 'unlock' request to let the normal 51 | desktop resume. 52 | 53 | 54 | 55 | 56 | 57 | This event will be sent immediately before a fake enter event on the 58 | grab surface. 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | Tell the server, that enough desktop elements have been drawn 87 | to make the desktop look ready for use. During start-up, the 88 | server can wait for this request with a black screen before 89 | starting to fade in the desktop, for instance. If the client 90 | parts of a desktop take a long time to initialize, we avoid 91 | showing temporary garbage. 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 105 | 106 | 107 | 108 | 109 | Tell the shell which side of the screen the panel is 110 | located. This is so that new windows do not overlap the panel 111 | and maximized windows maximize properly. 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | Only one client can bind this interface at a time. 122 | 123 | 124 | 125 | 126 | A screensaver surface is normally hidden, and only visible after an 127 | idle timeout. 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /shell/Makefile.am: -------------------------------------------------------------------------------- 1 | libexec_PROGRAMS = maynard 2 | 3 | AM_CFLAGS = $(GCC_CFLAGS) 4 | AM_CPPFLAGS = $(CLIENT_CFLAGS) $(GTK_CFLAGS) 5 | 6 | maynard_SOURCES = \ 7 | maynard.c \ 8 | app-icon.c \ 9 | app-icon.h \ 10 | clock.c \ 11 | clock.h \ 12 | favorites.c \ 13 | favorites.h \ 14 | shell-app-system.c \ 15 | shell-app-system.h \ 16 | panel.c \ 17 | panel.h \ 18 | vertical-clock.c \ 19 | vertical-clock.h \ 20 | launcher.c \ 21 | launcher.h \ 22 | maynard-resources.c \ 23 | maynard-resources.h \ 24 | weston-desktop-shell-client-protocol.h \ 25 | weston-desktop-shell-protocol.c \ 26 | desktop-shell-client-protocol.h \ 27 | desktop-shell-protocol.c \ 28 | shell-helper-client-protocol.h \ 29 | shell-helper-protocol.c 30 | maynard_LDADD = $(GTK_LIBS) -lm 31 | 32 | BUILT_SOURCES = \ 33 | weston-desktop-shell-client-protocol.h \ 34 | weston-desktop-shell-protocol.c \ 35 | desktop-shell-client-protocol.h \ 36 | desktop-shell-protocol.c \ 37 | shell-helper-client-protocol.h \ 38 | shell-helper-protocol.c \ 39 | maynard-resources.c \ 40 | maynard-resources.h 41 | 42 | # gresource for css 43 | resource_files = $(shell glib-compile-resources --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/maynard.gresource.xml) 44 | maynard-resources.c: maynard.gresource.xml $(resource_files) 45 | $(AM_V_GEN) glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name maynard $< 46 | maynard-resources.h: maynard.gresource.xml $(resource_files) 47 | $(AM_V_GEN) glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name maynard $< 48 | 49 | EXTRA_DIST = \ 50 | style.css \ 51 | maynard.gresource.xml 52 | 53 | # shell-helper weston module 54 | moduledir = $(libdir)/weston 55 | module_LTLIBRARIES = shell-helper.la 56 | 57 | # otherwise shell-helper-protocol.c is generated twice- once with 58 | # libtool and once without 59 | mod-%-protocol.c : $(wayland_protocoldir)/%.xml 60 | $(AM_V_GEN)$(wayland_scanner) code < $< > $@ 61 | 62 | shell_helper_la_LDFLAGS = -module -avoid-version 63 | shell_helper_la_LIBADD = $(GTK_LIBS) 64 | shell_helper_la_SOURCES = \ 65 | shell-helper.c 66 | nodist_shell_helper_la_SOURCES = \ 67 | mod-shell-helper-protocol.c \ 68 | shell-helper-server-protocol.h 69 | 70 | BUILT_SOURCES += $(nodist_shell_helper_la_SOURCES) 71 | CLEANFILES = $(BUILT_SOURCES) 72 | 73 | @wayland_scanner_rules@ 74 | -------------------------------------------------------------------------------- /shell/app-icon.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Jonny Lamb 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "app-icon.h" 25 | 26 | G_DEFINE_TYPE(MaynardAppIcon, maynard_app_icon, GTK_TYPE_BUTTON) 27 | 28 | static void 29 | maynard_app_icon_init (MaynardAppIcon *self) 30 | { 31 | gtk_style_context_add_class ( 32 | gtk_widget_get_style_context (GTK_WIDGET (self)), 33 | "maynard-apps"); 34 | 35 | gtk_style_context_remove_class ( 36 | gtk_widget_get_style_context (GTK_WIDGET (self)), 37 | "button"); 38 | gtk_style_context_remove_class ( 39 | gtk_widget_get_style_context (GTK_WIDGET (self)), 40 | "image-button"); 41 | 42 | gtk_button_set_relief (GTK_BUTTON (self), GTK_RELIEF_NONE); 43 | } 44 | 45 | static void 46 | maynard_app_icon_class_init (MaynardAppIconClass *klass) 47 | { 48 | } 49 | 50 | GtkWidget * 51 | maynard_app_icon_new (const gchar *icon_name) 52 | { 53 | GtkWidget *widget; 54 | GtkWidget *image; 55 | 56 | image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DIALOG); 57 | widget = g_object_new (MAYNARD_APP_ICON_TYPE, 58 | "image", image, 59 | NULL); 60 | 61 | return widget; 62 | } 63 | 64 | GtkWidget * 65 | maynard_app_icon_new_from_gicon (GIcon *icon) 66 | { 67 | GtkWidget *widget, *image; 68 | 69 | image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG); 70 | 71 | widget = g_object_new (MAYNARD_APP_ICON_TYPE, 72 | "image", image, 73 | NULL); 74 | 75 | return widget; 76 | } 77 | -------------------------------------------------------------------------------- /shell/app-icon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Jonny Lamb 20 | */ 21 | 22 | #ifndef __MAYNARD_APP_ICON_H__ 23 | #define __MAYNARD_APP_ICON_H__ 24 | 25 | #include 26 | 27 | #define MAYNARD_APP_ICON_TYPE (maynard_app_icon_get_type ()) 28 | #define MAYNARD_APP_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAYNARD_APP_ICON_TYPE, MaynardAppIcon)) 29 | #define MAYNARD_APP_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAYNARD_APP_ICON_TYPE, MaynardAppIconClass)) 30 | #define MAYNARD_IS_APP_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAYNARD_APP_ICON_TYPE)) 31 | #define MAYNARD_IS_APP_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAYNARD_APP_ICON_TYPE)) 32 | #define MAYNARD_APP_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAYNARD_APP_ICON_TYPE, MaynardAppIconClass)) 33 | 34 | typedef struct MaynardAppIcon MaynardAppIcon; 35 | typedef struct MaynardAppIconClass MaynardAppIconClass; 36 | typedef struct MaynardAppIconPrivate MaynardAppIconPrivate; 37 | 38 | struct MaynardAppIcon 39 | { 40 | GtkButton parent; 41 | 42 | MaynardAppIconPrivate *priv; 43 | }; 44 | 45 | struct MaynardAppIconClass 46 | { 47 | GtkButtonClass parent_class; 48 | }; 49 | 50 | GType maynard_app_icon_get_type (void) G_GNUC_CONST; 51 | GtkWidget *maynard_app_icon_new (const gchar *icon_name); 52 | GtkWidget *maynard_app_icon_new_from_gicon (GIcon *icon); 53 | 54 | #endif /* __MAYNARD_APP_ICON_H__ */ 55 | -------------------------------------------------------------------------------- /shell/clock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Jonny Lamb 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include 25 | #define GNOME_DESKTOP_USE_UNSTABLE_API 26 | #include 27 | 28 | #include "clock.h" 29 | 30 | enum { 31 | VOLUME_CHANGED, 32 | N_SIGNALS 33 | }; 34 | static guint signals[N_SIGNALS] = { 0 }; 35 | 36 | struct MaynardClockPrivate { 37 | GtkWidget *revealer_clock; 38 | GtkWidget *revealer_system; 39 | GtkWidget *revealer_volume; 40 | 41 | GtkWidget *label; 42 | 43 | GtkWidget *volume_scale; 44 | GtkWidget *volume_image; 45 | 46 | GnomeWallClock *wall_clock; 47 | 48 | snd_mixer_t *mixer_handle; 49 | snd_mixer_elem_t *mixer; 50 | glong min_volume, max_volume; 51 | }; 52 | 53 | G_DEFINE_TYPE(MaynardClock, maynard_clock, GTK_TYPE_WINDOW) 54 | 55 | static void 56 | maynard_clock_init (MaynardClock *self) 57 | { 58 | self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, 59 | MAYNARD_CLOCK_TYPE, 60 | MaynardClockPrivate); 61 | } 62 | 63 | static gdouble 64 | alsa_volume_to_percentage (MaynardClock *self, 65 | glong value) 66 | { 67 | glong range; 68 | 69 | /* min volume isn't always zero unfortunately */ 70 | range = self->priv->max_volume - self->priv->min_volume; 71 | 72 | value -= self->priv->min_volume; 73 | 74 | return (value / (gdouble) range) * 100; 75 | } 76 | 77 | static glong 78 | percentage_to_alsa_volume (MaynardClock *self, 79 | gdouble value) 80 | { 81 | glong range; 82 | 83 | /* min volume isn't always zero unfortunately */ 84 | range = self->priv->max_volume - self->priv->min_volume; 85 | 86 | return (range * value / 100) + self->priv->min_volume; 87 | } 88 | 89 | static void 90 | volume_changed_cb (GtkRange *range, 91 | MaynardClock *self) 92 | { 93 | gdouble value; 94 | const gchar *icon_name; 95 | GtkWidget *box; 96 | 97 | value = gtk_range_get_value (range); 98 | 99 | if (self->priv->mixer != NULL) 100 | { 101 | snd_mixer_selem_set_playback_volume_all (self->priv->mixer, 102 | percentage_to_alsa_volume (self, value)); 103 | } 104 | 105 | /* update the icon */ 106 | if (value > 75) 107 | icon_name = "audio-volume-high-symbolic"; 108 | else if (value > 30) 109 | icon_name = "audio-volume-medium-symbolic"; 110 | else if (value > 0) 111 | icon_name = "audio-volume-low-symbolic"; 112 | else 113 | icon_name = "audio-volume-muted-symbolic"; 114 | 115 | box = gtk_widget_get_parent (self->priv->volume_image); 116 | gtk_widget_destroy (self->priv->volume_image); 117 | self->priv->volume_image = gtk_image_new_from_icon_name ( 118 | icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); 119 | gtk_box_pack_start (GTK_BOX (box), self->priv->volume_image, 120 | FALSE, FALSE, 0); 121 | gtk_widget_show (self->priv->volume_image); 122 | 123 | g_signal_emit (self, signals[VOLUME_CHANGED], 0, value, icon_name); 124 | } 125 | 126 | static gboolean 127 | volume_idle_cb (gpointer data) 128 | { 129 | MaynardClock *self = MAYNARD_CLOCK (data); 130 | glong volume; 131 | 132 | if (self->priv->mixer != NULL) 133 | { 134 | snd_mixer_selem_get_playback_volume (self->priv->mixer, 135 | SND_MIXER_SCHN_MONO, &volume); 136 | 137 | gtk_range_set_value (GTK_RANGE (self->priv->volume_scale), 138 | alsa_volume_to_percentage (self, volume)); 139 | } 140 | 141 | return G_SOURCE_REMOVE; 142 | } 143 | 144 | static GtkWidget * 145 | create_system_box (MaynardClock *self) 146 | { 147 | return gtk_label_new ("Not implemented"); 148 | } 149 | 150 | static GtkWidget * 151 | create_volume_box (MaynardClock *self) 152 | { 153 | GtkWidget *box; 154 | 155 | box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); 156 | 157 | self->priv->volume_image = gtk_image_new_from_icon_name ( 158 | "audio-volume-muted-symbolic", 159 | GTK_ICON_SIZE_LARGE_TOOLBAR); 160 | gtk_box_pack_start (GTK_BOX (box), self->priv->volume_image, 161 | FALSE, FALSE, 0); 162 | 163 | self->priv->volume_scale = gtk_scale_new_with_range ( 164 | GTK_ORIENTATION_HORIZONTAL, 0, 100, 1); 165 | gtk_scale_set_draw_value (GTK_SCALE (self->priv->volume_scale), FALSE); 166 | gtk_widget_set_size_request (self->priv->volume_scale, 100, -1); 167 | gtk_box_pack_end (GTK_BOX (box), self->priv->volume_scale, TRUE, TRUE, 0); 168 | 169 | g_signal_connect (self->priv->volume_scale, "value-changed", 170 | G_CALLBACK (volume_changed_cb), self); 171 | 172 | /* set the initial value in an idle so ::volume-changed is emitted 173 | * when other widgets are connected to the signal and can react 174 | * accordingly. */ 175 | g_idle_add (volume_idle_cb, self); 176 | 177 | return box; 178 | } 179 | 180 | static void 181 | wall_clock_notify_cb (GnomeWallClock *wall_clock, 182 | GParamSpec *pspec, 183 | MaynardClock *self) 184 | { 185 | GDateTime *datetime; 186 | gchar *str; 187 | 188 | datetime = g_date_time_new_now_local (); 189 | 190 | str = g_date_time_format (datetime, 191 | "%H:%M\n" 192 | "%d/%m/%Y"); 193 | gtk_label_set_markup (GTK_LABEL (self->priv->label), str); 194 | 195 | g_free (str); 196 | g_date_time_unref (datetime); 197 | } 198 | 199 | static void 200 | setup_mixer (MaynardClock *self) 201 | { 202 | snd_mixer_selem_id_t *sid; 203 | gint ret; 204 | 205 | /* this is all pretty specific to the rpi */ 206 | 207 | if ((ret = snd_mixer_open (&self->priv->mixer_handle, 0)) < 0) 208 | goto error; 209 | 210 | if ((ret = snd_mixer_attach (self->priv->mixer_handle, "default")) < 0) 211 | goto error; 212 | 213 | if ((ret = snd_mixer_selem_register (self->priv->mixer_handle, NULL, NULL)) < 0) 214 | goto error; 215 | 216 | if ((ret = snd_mixer_load (self->priv->mixer_handle)) < 0) 217 | goto error; 218 | 219 | snd_mixer_selem_id_alloca (&sid); 220 | snd_mixer_selem_id_set_index (sid, 0); 221 | snd_mixer_selem_id_set_name (sid, "PCM"); 222 | self->priv->mixer = snd_mixer_find_selem (self->priv->mixer_handle, sid); 223 | 224 | /* fallback to mixer "Master" */ 225 | if (self->priv->mixer == NULL) 226 | { 227 | snd_mixer_selem_id_set_name (sid, "Master"); 228 | self->priv->mixer = snd_mixer_find_selem (self->priv->mixer_handle, sid); 229 | if (self->priv->mixer == NULL) 230 | goto error; 231 | } 232 | 233 | if ((ret = snd_mixer_selem_get_playback_volume_range (self->priv->mixer, 234 | &self->priv->min_volume, &self->priv->max_volume)) < 0) 235 | goto error; 236 | 237 | return; 238 | 239 | error: 240 | g_debug ("failed to setup mixer: %s", snd_strerror (ret)); 241 | 242 | if (self->priv->mixer_handle != NULL) 243 | snd_mixer_close (self->priv->mixer_handle); 244 | self->priv->mixer_handle = NULL; 245 | self->priv->mixer = NULL; 246 | } 247 | 248 | static void 249 | maynard_clock_constructed (GObject *object) 250 | { 251 | MaynardClock *self = MAYNARD_CLOCK (object); 252 | GtkWidget *box, *system_box, *volume_box; 253 | 254 | G_OBJECT_CLASS (maynard_clock_parent_class)->constructed (object); 255 | 256 | self->priv->wall_clock = g_object_new (GNOME_TYPE_WALL_CLOCK, NULL); 257 | g_signal_connect (self->priv->wall_clock, "notify::clock", 258 | G_CALLBACK (wall_clock_notify_cb), self); 259 | 260 | gtk_window_set_title (GTK_WINDOW (self), "maynard"); 261 | gtk_window_set_decorated (GTK_WINDOW (self), FALSE); 262 | gtk_widget_realize (GTK_WIDGET (self)); 263 | 264 | gtk_style_context_add_class ( 265 | gtk_widget_get_style_context (GTK_WIDGET (self)), 266 | "maynard-clock"); 267 | 268 | /* the box for the revealers */ 269 | box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); 270 | gtk_container_add (GTK_CONTAINER (self), box); 271 | 272 | /* volume */ 273 | self->priv->revealer_volume = gtk_revealer_new (); 274 | gtk_revealer_set_transition_type ( 275 | GTK_REVEALER (self->priv->revealer_volume), 276 | GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT); 277 | gtk_revealer_set_reveal_child ( 278 | GTK_REVEALER (self->priv->revealer_volume), FALSE); 279 | gtk_box_pack_start (GTK_BOX (box), self->priv->revealer_volume, 280 | TRUE, TRUE, 0); 281 | 282 | volume_box = create_volume_box (self); 283 | gtk_container_add (GTK_CONTAINER (self->priv->revealer_volume), 284 | volume_box); 285 | 286 | /* system */ 287 | self->priv->revealer_system = gtk_revealer_new (); 288 | gtk_revealer_set_transition_type ( 289 | GTK_REVEALER (self->priv->revealer_system), 290 | GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT); 291 | gtk_revealer_set_reveal_child ( 292 | GTK_REVEALER (self->priv->revealer_system), FALSE); 293 | gtk_box_pack_start (GTK_BOX (box), self->priv->revealer_system, 294 | TRUE, TRUE, 0); 295 | 296 | system_box = create_system_box (self); 297 | gtk_container_add (GTK_CONTAINER (self->priv->revealer_system), 298 | system_box); 299 | 300 | /* clock */ 301 | self->priv->revealer_clock = gtk_revealer_new (); 302 | gtk_revealer_set_transition_type ( 303 | GTK_REVEALER (self->priv->revealer_clock), 304 | GTK_REVEALER_TRANSITION_TYPE_SLIDE_LEFT); 305 | gtk_revealer_set_reveal_child ( 306 | GTK_REVEALER (self->priv->revealer_clock), TRUE); 307 | gtk_box_pack_start (GTK_BOX (box), self->priv->revealer_clock, 308 | TRUE, TRUE, 0); 309 | 310 | self->priv->label = gtk_label_new (""); 311 | gtk_label_set_justify (GTK_LABEL (self->priv->label), GTK_JUSTIFY_CENTER); 312 | gtk_container_add (GTK_CONTAINER (self->priv->revealer_clock), 313 | self->priv->label); 314 | 315 | /* TODO: work out how to fix the padding properly. this is added to 316 | * fix the broken alignment where the clock appears to the right. */ 317 | gtk_box_pack_start (GTK_BOX (box), gtk_revealer_new (), TRUE, TRUE, 0); 318 | 319 | setup_mixer (self); 320 | 321 | wall_clock_notify_cb (self->priv->wall_clock, NULL, self); 322 | } 323 | 324 | static void 325 | maynard_clock_dispose (GObject *object) 326 | { 327 | MaynardClock *self = MAYNARD_CLOCK (object); 328 | 329 | g_clear_object (&self->priv->wall_clock); 330 | 331 | if (self->priv->mixer_handle != NULL) 332 | snd_mixer_close (self->priv->mixer_handle); 333 | self->priv->mixer_handle = NULL; 334 | self->priv->mixer = NULL; 335 | 336 | G_OBJECT_CLASS (maynard_clock_parent_class)->dispose (object); 337 | } 338 | 339 | static void 340 | maynard_clock_class_init (MaynardClockClass *klass) 341 | { 342 | GObjectClass *object_class = (GObjectClass *)klass; 343 | 344 | object_class->constructed = maynard_clock_constructed; 345 | object_class->dispose = maynard_clock_dispose; 346 | 347 | signals[VOLUME_CHANGED] = g_signal_new ("volume-changed", 348 | G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, 349 | NULL, G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_STRING); 350 | 351 | g_type_class_add_private (object_class, sizeof (MaynardClockPrivate)); 352 | } 353 | 354 | GtkWidget * 355 | maynard_clock_new (void) 356 | { 357 | return g_object_new (MAYNARD_CLOCK_TYPE, 358 | NULL); 359 | } 360 | 361 | void 362 | maynard_clock_show_section (MaynardClock *self, 363 | MaynardClockSection section) 364 | { 365 | gtk_revealer_set_reveal_child ( 366 | GTK_REVEALER (self->priv->revealer_clock), 367 | section == MAYNARD_CLOCK_SECTION_CLOCK); 368 | 369 | gtk_revealer_set_reveal_child ( 370 | GTK_REVEALER (self->priv->revealer_system), 371 | section == MAYNARD_CLOCK_SECTION_SYSTEM); 372 | 373 | gtk_revealer_set_reveal_child ( 374 | GTK_REVEALER (self->priv->revealer_volume), 375 | section == MAYNARD_CLOCK_SECTION_VOLUME); 376 | } 377 | -------------------------------------------------------------------------------- /shell/clock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Jonny Lamb 20 | */ 21 | 22 | #ifndef __MAYNARD_CLOCK_H__ 23 | #define __MAYNARD_CLOCK_H__ 24 | 25 | #include 26 | 27 | #include "panel.h" 28 | 29 | #define MAYNARD_CLOCK_TYPE (maynard_clock_get_type ()) 30 | #define MAYNARD_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAYNARD_CLOCK_TYPE, MaynardClock)) 31 | #define MAYNARD_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAYNARD_CLOCK_TYPE, MaynardClockClass)) 32 | #define MAYNARD_IS_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAYNARD_CLOCK_TYPE)) 33 | #define MAYNARD_IS_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAYNARD_CLOCK_TYPE)) 34 | #define MAYNARD_CLOCK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAYNARD_CLOCK_TYPE, MaynardClockClass)) 35 | 36 | typedef struct MaynardClock MaynardClock; 37 | typedef struct MaynardClockClass MaynardClockClass; 38 | typedef struct MaynardClockPrivate MaynardClockPrivate; 39 | 40 | struct MaynardClock 41 | { 42 | GtkWindow parent; 43 | 44 | MaynardClockPrivate *priv; 45 | }; 46 | 47 | struct MaynardClockClass 48 | { 49 | GtkWindowClass parent_class; 50 | }; 51 | 52 | #define MAYNARD_CLOCK_WIDTH (MAYNARD_PANEL_WIDTH * 2.6) 53 | #define MAYNARD_CLOCK_HEIGHT (MAYNARD_PANEL_WIDTH * 2) 54 | 55 | typedef enum { 56 | MAYNARD_CLOCK_SECTION_CLOCK, 57 | MAYNARD_CLOCK_SECTION_SYSTEM, 58 | MAYNARD_CLOCK_SECTION_VOLUME 59 | } MaynardClockSection; 60 | 61 | GType maynard_clock_get_type (void) G_GNUC_CONST; 62 | 63 | GtkWidget * maynard_clock_new (void); 64 | 65 | void maynard_clock_show_section (MaynardClock *self, MaynardClockSection section); 66 | 67 | #endif /* __MAYNARD_CLOCK_H__ */ 68 | -------------------------------------------------------------------------------- /shell/favorites.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Emilio Pozuelo Monfort 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "favorites.h" 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include "app-icon.h" 31 | 32 | enum { 33 | APP_LAUNCHED, 34 | N_SIGNALS 35 | }; 36 | static guint signals[N_SIGNALS] = { 0 }; 37 | 38 | struct MaynardFavoritesPrivate { 39 | GSettings *settings; 40 | }; 41 | 42 | G_DEFINE_TYPE(MaynardFavorites, maynard_favorites, GTK_TYPE_BOX) 43 | 44 | static void 45 | favorite_clicked (GtkButton *button, 46 | MaynardFavorites *self) 47 | { 48 | GAppInfo *info = g_object_get_data (G_OBJECT(button), "info"); 49 | GError *error = NULL; 50 | 51 | g_app_info_launch (info, NULL, NULL, &error); 52 | if (error) 53 | { 54 | g_warning ("Could not launch app %s: %s", 55 | g_app_info_get_name (info), 56 | error->message); 57 | g_clear_error (&error); 58 | } 59 | 60 | g_signal_emit (self, signals[APP_LAUNCHED], 0); 61 | } 62 | 63 | static void 64 | add_favorite (MaynardFavorites *self, 65 | const gchar *favorite) 66 | { 67 | GDesktopAppInfo *info; 68 | GtkWidget *button, *image; 69 | GIcon *icon; 70 | 71 | info = g_desktop_app_info_new (favorite); 72 | 73 | if (!info) 74 | return; 75 | 76 | icon = g_app_info_get_icon (G_APP_INFO (info)); 77 | 78 | button = maynard_app_icon_new_from_gicon (icon); 79 | 80 | g_object_set_data_full (G_OBJECT (button), "info", info, g_object_unref); 81 | 82 | g_signal_connect (button, "clicked", G_CALLBACK (favorite_clicked), self); 83 | 84 | gtk_box_pack_end (GTK_BOX (self), button, FALSE, FALSE, 0); 85 | } 86 | 87 | static void 88 | remove_favorite (GtkWidget *favorite, 89 | gpointer user_data) 90 | { 91 | gtk_widget_destroy (favorite); 92 | } 93 | 94 | static void 95 | favorites_changed (GSettings *settings, 96 | const gchar *key, 97 | MaynardFavorites *self) 98 | { 99 | gchar **favorites = g_settings_get_strv (settings, key); 100 | gint i; 101 | 102 | /* Remove all favorites first */ 103 | gtk_container_foreach (GTK_CONTAINER (self), remove_favorite, NULL); 104 | 105 | for (i = 0; i < g_strv_length (favorites); i++) 106 | { 107 | gchar *fav = favorites[i]; 108 | 109 | add_favorite (self, fav); 110 | } 111 | 112 | g_strfreev (favorites); 113 | } 114 | 115 | static void 116 | maynard_favorites_dispose (GObject *object) 117 | { 118 | MaynardFavorites *self = MAYNARD_FAVORITES (object); 119 | 120 | g_clear_object (&self->priv->settings); 121 | 122 | G_OBJECT_CLASS (maynard_favorites_parent_class)->dispose (object); 123 | } 124 | 125 | static void 126 | maynard_favorites_init (MaynardFavorites *self) 127 | { 128 | self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, 129 | MAYNARD_TYPE_FAVORITES, 130 | MaynardFavoritesPrivate); 131 | 132 | self->priv->settings = g_settings_new ("org.raspberrypi.maynard"); 133 | g_signal_connect (self->priv->settings, "changed::favorites", 134 | G_CALLBACK (favorites_changed), self); 135 | favorites_changed (self->priv->settings, "favorites", self); 136 | 137 | gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL); 138 | } 139 | 140 | static void 141 | maynard_favorites_class_init (MaynardFavoritesClass *klass) 142 | { 143 | GObjectClass *object_class = (GObjectClass *)klass; 144 | 145 | object_class->dispose = maynard_favorites_dispose; 146 | 147 | signals[APP_LAUNCHED] = g_signal_new ("app-launched", 148 | G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, 149 | NULL, G_TYPE_NONE, 0); 150 | 151 | g_type_class_add_private (object_class, sizeof (MaynardFavoritesPrivate)); 152 | } 153 | 154 | GtkWidget * 155 | maynard_favorites_new (void) 156 | { 157 | return g_object_new (MAYNARD_TYPE_FAVORITES, 158 | "orientation", GTK_ORIENTATION_VERTICAL, 159 | NULL); 160 | } 161 | -------------------------------------------------------------------------------- /shell/favorites.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Emilio Pozuelo Monfort 20 | */ 21 | 22 | #ifndef __MAYNARD_FAVORITES_H__ 23 | #define __MAYNARD_FAVORITES_H__ 24 | 25 | #include 26 | 27 | #define MAYNARD_TYPE_FAVORITES (maynard_favorites_get_type ()) 28 | #define MAYNARD_FAVORITES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAYNARD_TYPE_FAVORITES, MaynardFavorites)) 29 | #define MAYNARD_FAVORITES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAYNARD_TYPE_FAVORITES, MaynardFavoritesClass)) 30 | #define MAYNARD_IS_FAVORITES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAYNARD_TYPE_FAVORITES)) 31 | #define MAYNARD_IS_FAVORITES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAYNARD_TYPE_FAVORITES)) 32 | #define MAYNARD_FAVORITES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAYNARD_TYPE_FAVORITES, MaynardFavoritesClass)) 33 | 34 | typedef struct MaynardFavorites MaynardFavorites; 35 | typedef struct MaynardFavoritesClass MaynardFavoritesClass; 36 | typedef struct MaynardFavoritesPrivate MaynardFavoritesPrivate; 37 | 38 | struct MaynardFavorites 39 | { 40 | GtkBox parent; 41 | 42 | MaynardFavoritesPrivate *priv; 43 | }; 44 | 45 | struct MaynardFavoritesClass 46 | { 47 | GtkBoxClass parent_class; 48 | }; 49 | 50 | GType maynard_favorites_get_type (void) G_GNUC_CONST; 51 | GtkWidget *maynard_favorites_new (void); 52 | 53 | #endif /* __MAYNARD_FAVORITES_H__ */ 54 | -------------------------------------------------------------------------------- /shell/launcher.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013-2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authors: Emilio Pozuelo Monfort 20 | * Jonny Lamb 21 | */ 22 | 23 | #include "config.h" 24 | 25 | #include "launcher.h" 26 | 27 | #include "clock.h" 28 | #include "panel.h" 29 | #include "shell-app-system.h" 30 | 31 | enum { 32 | PROP_0, 33 | PROP_BACKGROUND, 34 | }; 35 | 36 | enum { 37 | APP_LAUNCHED, 38 | N_SIGNALS 39 | }; 40 | static guint signals[N_SIGNALS] = { 0 }; 41 | 42 | struct MaynardLauncherPrivate { 43 | /* background widget so we know the output size */ 44 | GtkWidget *background; 45 | ShellAppSystem *app_system; 46 | GtkWidget *scrolled_window; 47 | GtkWidget *grid; 48 | }; 49 | 50 | G_DEFINE_TYPE(MaynardLauncher, maynard_launcher, GTK_TYPE_WINDOW) 51 | 52 | /* each grid item is 114x114 */ 53 | #define GRID_ITEM_WIDTH 114 54 | #define GRID_ITEM_HEIGHT 114 55 | 56 | static void 57 | maynard_launcher_init (MaynardLauncher *self) 58 | { 59 | self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, 60 | MAYNARD_LAUNCHER_TYPE, 61 | MaynardLauncherPrivate); 62 | } 63 | 64 | static gint 65 | sort_apps (gconstpointer a, 66 | gconstpointer b) 67 | { 68 | GAppInfo *info1 = G_APP_INFO (a); 69 | GAppInfo *info2 = G_APP_INFO (b); 70 | gchar *s1, *s2; 71 | gint ret; 72 | 73 | s1 = g_utf8_casefold (g_app_info_get_display_name (info1), -1); 74 | s2 = g_utf8_casefold (g_app_info_get_display_name (info2), -1); 75 | 76 | ret = g_strcmp0 (s1, s2); 77 | 78 | g_free (s1); 79 | g_free (s2); 80 | 81 | return ret; 82 | } 83 | 84 | static gboolean 85 | get_child_position_cb (GtkOverlay *overlay, 86 | GtkWidget *widget, 87 | GdkRectangle *allocation, 88 | gpointer user_data) 89 | { 90 | GtkOverlayClass *klass = GTK_OVERLAY_GET_CLASS (overlay); 91 | 92 | klass->get_child_position (overlay, widget, allocation); 93 | 94 | /* use the same valign and halign properties, but given we have a 95 | * border of 1px, respect it and don't draw the overlay widget over 96 | * the border. */ 97 | allocation->x += 1; 98 | allocation->y -= 1; 99 | allocation->width -= 2; 100 | 101 | return TRUE; 102 | } 103 | 104 | static gboolean 105 | app_launched_idle_cb (gpointer data) 106 | { 107 | MaynardLauncher *self = data; 108 | GtkAdjustment *adjustment; 109 | 110 | /* make the scrolled window go back to the top */ 111 | 112 | adjustment = gtk_scrolled_window_get_vadjustment ( 113 | GTK_SCROLLED_WINDOW (self->priv->scrolled_window)); 114 | 115 | gtk_adjustment_set_value (adjustment, 0.0); 116 | 117 | return G_SOURCE_REMOVE; 118 | } 119 | 120 | static void 121 | clicked_cb (GtkWidget *widget, 122 | GDesktopAppInfo *info) 123 | { 124 | MaynardLauncher *self; 125 | 126 | g_app_info_launch (G_APP_INFO (info), NULL, NULL, NULL); 127 | 128 | self = g_object_get_data (G_OBJECT (widget), "launcher"); 129 | g_assert (self); 130 | g_signal_emit (self, signals[APP_LAUNCHED], 0); 131 | 132 | /* do this in an idle so it's not done so obviously onscreen */ 133 | g_idle_add (app_launched_idle_cb, self); 134 | } 135 | 136 | static gboolean 137 | app_enter_cb (GtkWidget *widget, 138 | GdkEvent *event, 139 | GtkWidget *revealer) 140 | { 141 | gtk_revealer_set_reveal_child (GTK_REVEALER (revealer), TRUE); 142 | return FALSE; 143 | } 144 | 145 | static gboolean 146 | app_leave_cb (GtkWidget *widget, 147 | GdkEvent *event, 148 | GtkWidget *revealer) 149 | { 150 | gtk_revealer_set_reveal_child (GTK_REVEALER (revealer), FALSE); 151 | return FALSE; 152 | } 153 | 154 | static GtkWidget * 155 | app_launcher_new_from_desktop_info (MaynardLauncher *self, 156 | GDesktopAppInfo *info) 157 | { 158 | GIcon *icon; 159 | GtkWidget *alignment; 160 | GtkWidget *image; 161 | GtkWidget *button; 162 | GtkWidget *overlay; 163 | GtkWidget *revealer; 164 | GtkWidget *label; 165 | GtkWidget *ebox; 166 | 167 | /* we need an ebox to catch enter and leave events */ 168 | ebox = gtk_event_box_new (); 169 | gtk_style_context_add_class (gtk_widget_get_style_context (ebox), 170 | "maynard-grid-item"); 171 | 172 | /* we use an overlay so we can have the app icon showing but use a 173 | * GtkRevealer to show a label of the app's name. */ 174 | overlay = gtk_overlay_new (); 175 | gtk_container_add (GTK_CONTAINER (ebox), overlay); 176 | 177 | /* ...but each item has a border of 1px and we don't want the 178 | * revealer to paint into the border, so overload this function to 179 | * know where to put it. */ 180 | g_signal_connect (overlay, "get-child-position", 181 | G_CALLBACK (get_child_position_cb), NULL); 182 | 183 | revealer = gtk_revealer_new (); 184 | g_object_set (revealer, 185 | "halign", GTK_ALIGN_FILL, /* all the width */ 186 | "valign", GTK_ALIGN_END, /* only at the bottom */ 187 | NULL); 188 | gtk_revealer_set_transition_type (GTK_REVEALER (revealer), 189 | GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP); 190 | gtk_revealer_set_reveal_child (GTK_REVEALER (revealer), FALSE); 191 | gtk_overlay_add_overlay (GTK_OVERLAY (overlay), revealer); 192 | 193 | /* app name */ 194 | label = gtk_label_new (g_app_info_get_display_name (G_APP_INFO (info))); 195 | gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); 196 | gtk_style_context_add_class (gtk_widget_get_style_context (label), "maynard-grid-label"); 197 | gtk_container_add (GTK_CONTAINER (revealer), label); 198 | 199 | /* icon button to load the app */ 200 | alignment = gtk_alignment_new (0.5, 0.5, 1, 1); 201 | gtk_container_add (GTK_CONTAINER (overlay), alignment); 202 | 203 | icon = g_app_info_get_icon (G_APP_INFO (info)); 204 | image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG); 205 | button = gtk_button_new (); 206 | gtk_style_context_remove_class ( 207 | gtk_widget_get_style_context (button), 208 | "button"); 209 | gtk_style_context_remove_class ( 210 | gtk_widget_get_style_context (button), 211 | "image-button"); 212 | gtk_button_set_image (GTK_BUTTON (button), image); 213 | g_object_set (image, 214 | "margin", 30, 215 | NULL); 216 | gtk_container_add (GTK_CONTAINER (alignment), button); 217 | 218 | /* TODO: a bit ugly */ 219 | g_object_set_data (G_OBJECT (button), "launcher", self); 220 | g_signal_connect (button, "clicked", G_CALLBACK (clicked_cb), info); 221 | 222 | /* now we have set everything up, we can refernce the ebox and the 223 | * revealer. enter will show the label and leave will hide the label. */ 224 | g_signal_connect (ebox, "enter-notify-event", G_CALLBACK (app_enter_cb), revealer); 225 | g_signal_connect (ebox, "leave-notify-event", G_CALLBACK (app_leave_cb), revealer); 226 | 227 | return ebox; 228 | } 229 | 230 | static void 231 | installed_changed_cb (ShellAppSystem *app_system, 232 | MaynardLauncher *self) 233 | { 234 | GHashTable *entries = shell_app_system_get_entries (app_system); 235 | GList *l, *values; 236 | 237 | gint output_width, output_height; 238 | guint cols; 239 | guint left, top; 240 | 241 | /* remove all children first */ 242 | gtk_container_foreach (GTK_CONTAINER (self->priv->grid), 243 | (GtkCallback) gtk_widget_destroy, NULL); 244 | 245 | values = g_hash_table_get_values (entries); 246 | values = g_list_sort (values, sort_apps); 247 | 248 | maynard_launcher_calculate (self, NULL, NULL, &cols); 249 | cols--; /* because we start from zero here */ 250 | 251 | left = top = 0; 252 | for (l = values; l; l = l->next) 253 | { 254 | GDesktopAppInfo *info = G_DESKTOP_APP_INFO (l->data); 255 | GtkWidget *app = app_launcher_new_from_desktop_info (self, info); 256 | 257 | gtk_grid_attach (GTK_GRID (self->priv->grid), app, left++, top, 1, 1); 258 | 259 | if (left > cols) 260 | { 261 | left = 0; 262 | top++; 263 | } 264 | } 265 | 266 | g_list_free (values); 267 | 268 | gtk_widget_show_all (self->priv->grid); 269 | } 270 | 271 | static void 272 | background_size_allocate_cb (GtkWidget *widget, 273 | GdkRectangle *allocation, 274 | MaynardLauncher *self) 275 | { 276 | installed_changed_cb (self->priv->app_system, self); 277 | } 278 | 279 | static void 280 | maynard_launcher_constructed (GObject *object) 281 | { 282 | MaynardLauncher *self = MAYNARD_LAUNCHER (object); 283 | 284 | G_OBJECT_CLASS (maynard_launcher_parent_class)->constructed (object); 285 | 286 | /* window properties */ 287 | gtk_window_set_title (GTK_WINDOW (self), "maynard"); 288 | gtk_window_set_decorated (GTK_WINDOW (self), FALSE); 289 | gtk_widget_realize (GTK_WIDGET (self)); 290 | 291 | /* make it black and slightly alpha */ 292 | gtk_style_context_add_class ( 293 | gtk_widget_get_style_context (GTK_WIDGET (self)), 294 | "maynard-grid"); 295 | 296 | /* scroll it */ 297 | self->priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL); 298 | gtk_container_add (GTK_CONTAINER (self), self->priv->scrolled_window); 299 | 300 | /* main grid for apps */ 301 | self->priv->grid = gtk_grid_new (); 302 | gtk_container_add (GTK_CONTAINER (self->priv->scrolled_window), 303 | self->priv->grid); 304 | 305 | /* fill the grid with apps */ 306 | self->priv->app_system = shell_app_system_get_default (); 307 | g_signal_connect (self->priv->app_system, "installed-changed", 308 | G_CALLBACK (installed_changed_cb), self); 309 | 310 | /* refill the grid if the background is changed */ 311 | g_assert (self->priv->background != NULL); 312 | g_signal_connect (self->priv->background, "size-allocate", 313 | G_CALLBACK (background_size_allocate_cb), self); 314 | 315 | /* now actually fill the grid */ 316 | installed_changed_cb (self->priv->app_system, self); 317 | } 318 | 319 | static void 320 | maynard_launcher_get_property (GObject *object, 321 | guint param_id, 322 | GValue *value, 323 | GParamSpec *pspec) 324 | { 325 | MaynardLauncher *self = MAYNARD_LAUNCHER (object); 326 | 327 | switch (param_id) 328 | { 329 | case PROP_BACKGROUND: 330 | g_value_set_object (value, self->priv->background); 331 | break; 332 | default: 333 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); 334 | break; 335 | } 336 | } 337 | 338 | static void 339 | maynard_launcher_set_property (GObject *object, 340 | guint param_id, 341 | const GValue *value, 342 | GParamSpec *pspec) 343 | { 344 | MaynardLauncher *self = MAYNARD_LAUNCHER (object); 345 | 346 | switch (param_id) 347 | { 348 | case PROP_BACKGROUND: 349 | self->priv->background = g_value_get_object (value); 350 | break; 351 | default: 352 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); 353 | break; 354 | } 355 | } 356 | 357 | static void 358 | maynard_launcher_class_init (MaynardLauncherClass *klass) 359 | { 360 | GObjectClass *object_class = (GObjectClass *)klass; 361 | 362 | object_class->constructed = maynard_launcher_constructed; 363 | object_class->get_property = maynard_launcher_get_property; 364 | object_class->set_property = maynard_launcher_set_property; 365 | 366 | g_object_class_install_property (object_class, PROP_BACKGROUND, 367 | g_param_spec_object ("background", 368 | "background", 369 | "The #GtkWidget of the background of the output", 370 | GTK_TYPE_WIDGET, 371 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); 372 | 373 | signals[APP_LAUNCHED] = g_signal_new ("app-launched", 374 | G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, 375 | NULL, G_TYPE_NONE, 0); 376 | 377 | g_type_class_add_private (object_class, sizeof (MaynardLauncherPrivate)); 378 | } 379 | 380 | GtkWidget * 381 | maynard_launcher_new (GtkWidget *background_widget) 382 | { 383 | return g_object_new (MAYNARD_LAUNCHER_TYPE, 384 | "background", background_widget, 385 | NULL); 386 | } 387 | 388 | void 389 | maynard_launcher_calculate (MaynardLauncher *self, 390 | gint *grid_window_width, 391 | gint *grid_window_height, 392 | gint *grid_cols) 393 | { 394 | gint output_width, output_height, panel_height; 395 | gint usable_width, usable_height; 396 | guint cols, rows; 397 | guint num_apps; 398 | guint scrollbar_width = 13; 399 | 400 | gtk_widget_get_size_request (self->priv->background, 401 | &output_width, &output_height); 402 | panel_height = output_height * MAYNARD_PANEL_HEIGHT_RATIO; 403 | 404 | usable_width = output_width - MAYNARD_PANEL_WIDTH - scrollbar_width; 405 | /* don't go further down than the panel */ 406 | usable_height = panel_height - MAYNARD_CLOCK_HEIGHT; 407 | 408 | /* try and fill half the screen, otherwise round down */ 409 | cols = (int) ((usable_width / 2.0) / GRID_ITEM_WIDTH); 410 | /* try to fit as many rows as possible in the panel height we have */ 411 | rows = (int) (usable_height / GRID_ITEM_HEIGHT); 412 | 413 | /* we don't need to include the scrollbar if we already have enough 414 | * space for all the apps. */ 415 | num_apps = g_hash_table_size ( 416 | shell_app_system_get_entries (self->priv->app_system)); 417 | if ((cols * rows) >= num_apps) 418 | scrollbar_width = 0; 419 | 420 | /* done! */ 421 | 422 | if (grid_window_width) 423 | *grid_window_width = (cols * GRID_ITEM_WIDTH) + scrollbar_width; 424 | 425 | if (grid_window_height) 426 | *grid_window_height = (rows * GRID_ITEM_HEIGHT); 427 | 428 | if (grid_cols) 429 | *grid_cols = cols; 430 | } 431 | -------------------------------------------------------------------------------- /shell/launcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013-2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authors: Emilio Pozuelo Monfort 20 | * Jonny Lamb 21 | */ 22 | 23 | #ifndef __MAYNARD_LAUNCHER_H__ 24 | #define __MAYNARD_LAUNCHER_H__ 25 | 26 | #include 27 | 28 | #define MAYNARD_LAUNCHER_TYPE (maynard_launcher_get_type ()) 29 | #define MAYNARD_LAUNCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAYNARD_LAUNCHER_TYPE, MaynardLauncher)) 30 | #define MAYNARD_LAUNCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAYNARD_LAUNCHER_TYPE, MaynardLauncherClass)) 31 | #define MAYNARD_IS_LAUNCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAYNARD_LAUNCHER_TYPE)) 32 | #define MAYNARD_IS_LAUNCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAYNARD_LAUNCHER_TYPE)) 33 | #define MAYNARD_LAUNCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAYNARD_LAUNCHER_TYPE, MaynardLauncherClass)) 34 | 35 | typedef struct MaynardLauncher MaynardLauncher; 36 | typedef struct MaynardLauncherClass MaynardLauncherClass; 37 | typedef struct MaynardLauncherPrivate MaynardLauncherPrivate; 38 | 39 | struct MaynardLauncher 40 | { 41 | GtkWindow parent; 42 | 43 | MaynardLauncherPrivate *priv; 44 | }; 45 | 46 | struct MaynardLauncherClass 47 | { 48 | GtkWindowClass parent_class; 49 | }; 50 | 51 | GType maynard_launcher_get_type (void) G_GNUC_CONST; 52 | 53 | GtkWidget * maynard_launcher_new (GtkWidget *background_widget); 54 | 55 | void maynard_launcher_calculate (MaynardLauncher *self, 56 | gint *grid_window_width, gint *grid_window_height, 57 | gint *grid_cols); 58 | 59 | #endif /* __MAYNARD_LAUNCHER_H__ */ 60 | -------------------------------------------------------------------------------- /shell/maynard.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Tiago Vignatti 3 | * Copyright (c) 2013-2014 Collabora Ltd. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to 7 | * deal in the Software without restriction, including without limitation the 8 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9 | * sell copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | * IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include "desktop-shell-client-protocol.h" 32 | #include "weston-desktop-shell-client-protocol.h" 33 | #include "shell-helper-client-protocol.h" 34 | 35 | #include "maynard-resources.h" 36 | 37 | #include "app-icon.h" 38 | #include "clock.h" 39 | #include "favorites.h" 40 | #include "launcher.h" 41 | #include "panel.h" 42 | #include "vertical-clock.h" 43 | 44 | extern char **environ; /* defined by libc */ 45 | 46 | struct element { 47 | GtkWidget *window; 48 | GdkPixbuf *pixbuf; 49 | struct wl_surface *surface; 50 | }; 51 | 52 | struct desktop { 53 | struct wl_display *display; 54 | struct wl_registry *registry; 55 | struct desktop_shell *shell; 56 | struct weston_desktop_shell *wshell; 57 | struct wl_output *output; 58 | struct shell_helper *helper; 59 | 60 | struct wl_seat *seat; 61 | struct wl_pointer *pointer; 62 | 63 | GdkDisplay *gdk_display; 64 | 65 | struct element *background; 66 | struct element *panel; 67 | struct element *curtain; 68 | struct element *launcher_grid; 69 | struct element *clock; 70 | 71 | guint initial_panel_timeout_id; 72 | guint hide_panel_idle_id; 73 | 74 | gboolean grid_visible; 75 | gboolean system_visible; 76 | gboolean volume_visible; 77 | gboolean pointer_out_of_panel; 78 | }; 79 | 80 | static gboolean panel_window_enter_cb (GtkWidget *widget, 81 | GdkEventCrossing *event, struct desktop *desktop); 82 | static gboolean panel_window_leave_cb (GtkWidget *widget, 83 | GdkEventCrossing *event, struct desktop *desktop); 84 | 85 | static gboolean 86 | connect_enter_leave_signals (gpointer data) 87 | { 88 | struct desktop *desktop = data; 89 | GList *l; 90 | 91 | g_signal_connect (desktop->panel->window, "enter-notify-event", 92 | G_CALLBACK (panel_window_enter_cb), desktop); 93 | g_signal_connect (desktop->panel->window, "leave-notify-event", 94 | G_CALLBACK (panel_window_leave_cb), desktop); 95 | 96 | g_signal_connect (desktop->clock->window, "enter-notify-event", 97 | G_CALLBACK (panel_window_enter_cb), desktop); 98 | g_signal_connect (desktop->clock->window, "leave-notify-event", 99 | G_CALLBACK (panel_window_leave_cb), desktop); 100 | 101 | g_signal_connect (desktop->launcher_grid->window, "enter-notify-event", 102 | G_CALLBACK (panel_window_enter_cb), desktop); 103 | g_signal_connect (desktop->launcher_grid->window, "leave-notify-event", 104 | G_CALLBACK (panel_window_leave_cb), desktop); 105 | 106 | return G_SOURCE_REMOVE; 107 | } 108 | 109 | static void 110 | shell_configure (struct desktop *desktop, 111 | uint32_t edges, 112 | struct wl_surface *surface, 113 | int32_t width, int32_t height) 114 | { 115 | int window_height; 116 | int grid_width, grid_height; 117 | 118 | gtk_widget_set_size_request (desktop->background->window, 119 | width, height); 120 | 121 | /* TODO: make this height a little nicer */ 122 | window_height = height * MAYNARD_PANEL_HEIGHT_RATIO; 123 | gtk_window_resize (GTK_WINDOW (desktop->panel->window), 124 | MAYNARD_PANEL_WIDTH, window_height); 125 | 126 | maynard_launcher_calculate (MAYNARD_LAUNCHER (desktop->launcher_grid->window), 127 | &grid_width, &grid_height, NULL); 128 | gtk_widget_set_size_request (desktop->launcher_grid->window, 129 | grid_width, grid_height); 130 | 131 | shell_helper_move_surface (desktop->helper, desktop->panel->surface, 132 | 0, (height - window_height) / 2); 133 | 134 | gtk_window_resize (GTK_WINDOW (desktop->clock->window), 135 | MAYNARD_CLOCK_WIDTH, MAYNARD_CLOCK_HEIGHT); 136 | 137 | shell_helper_move_surface (desktop->helper, desktop->clock->surface, 138 | MAYNARD_PANEL_WIDTH, (height - window_height) / 2); 139 | 140 | shell_helper_move_surface (desktop->helper, 141 | desktop->launcher_grid->surface, 142 | - grid_width, 143 | ((height - window_height) / 2) + MAYNARD_CLOCK_HEIGHT); 144 | 145 | if (desktop->shell) 146 | desktop_shell_desktop_ready (desktop->shell); 147 | else 148 | weston_desktop_shell_desktop_ready (desktop->wshell); 149 | 150 | /* TODO: why does the panel signal leave on drawing for 151 | * startup? we don't want to have to have this silly 152 | * timeout. */ 153 | g_timeout_add_seconds (1, connect_enter_leave_signals, desktop); 154 | } 155 | 156 | static void 157 | desktop_shell_configure (void *data, 158 | struct desktop_shell *desktop_shell, 159 | uint32_t edges, 160 | struct wl_surface *surface, 161 | int32_t width, int32_t height) 162 | { 163 | shell_configure(data, edges, surface, width, height); 164 | } 165 | 166 | static void 167 | weston_desktop_shell_configure (void *data, 168 | struct weston_desktop_shell *weston_desktop_shell, 169 | uint32_t edges, 170 | struct wl_surface *surface, 171 | int32_t width, int32_t height) 172 | { 173 | shell_configure(data, edges, surface, width, height); 174 | } 175 | 176 | static void 177 | desktop_shell_prepare_lock_surface (void *data, 178 | struct desktop_shell *desktop_shell) 179 | { 180 | desktop_shell_unlock (desktop_shell); 181 | } 182 | 183 | static void 184 | weston_desktop_shell_prepare_lock_surface (void *data, 185 | struct weston_desktop_shell *weston_desktop_shell) 186 | { 187 | weston_desktop_shell_unlock (weston_desktop_shell); 188 | } 189 | 190 | static void 191 | desktop_shell_grab_cursor (void *data, 192 | struct desktop_shell *desktop_shell, 193 | uint32_t cursor) 194 | { 195 | } 196 | 197 | static void 198 | weston_desktop_shell_grab_cursor (void *data, 199 | struct weston_desktop_shell *weston_desktop_shell, 200 | uint32_t cursor) 201 | { 202 | } 203 | 204 | static const struct desktop_shell_listener shell_listener = { 205 | desktop_shell_configure, 206 | desktop_shell_prepare_lock_surface, 207 | desktop_shell_grab_cursor 208 | }; 209 | 210 | static const struct weston_desktop_shell_listener wshell_listener = { 211 | weston_desktop_shell_configure, 212 | weston_desktop_shell_prepare_lock_surface, 213 | weston_desktop_shell_grab_cursor 214 | }; 215 | 216 | static void 217 | launcher_grid_toggle (GtkWidget *widget, 218 | struct desktop *desktop) 219 | { 220 | if (desktop->grid_visible) 221 | { 222 | shell_helper_slide_surface_back (desktop->helper, 223 | desktop->launcher_grid->surface); 224 | 225 | shell_helper_curtain (desktop->helper, desktop->curtain->surface, 0); 226 | } 227 | else 228 | { 229 | int width; 230 | 231 | gtk_widget_get_size_request (desktop->launcher_grid->window, 232 | &width, NULL); 233 | 234 | shell_helper_slide_surface (desktop->helper, 235 | desktop->launcher_grid->surface, 236 | width + MAYNARD_PANEL_WIDTH, 0); 237 | 238 | shell_helper_curtain (desktop->helper, desktop->curtain->surface, 1); 239 | } 240 | 241 | desktop->grid_visible = !desktop->grid_visible; 242 | } 243 | 244 | static void 245 | launcher_grid_create (struct desktop *desktop) 246 | { 247 | struct element *launcher_grid; 248 | GdkWindow *gdk_window; 249 | 250 | launcher_grid = malloc (sizeof *launcher_grid); 251 | memset (launcher_grid, 0, sizeof *launcher_grid); 252 | 253 | launcher_grid->window = maynard_launcher_new (desktop->background->window); 254 | gdk_window = gtk_widget_get_window (launcher_grid->window); 255 | launcher_grid->surface = gdk_wayland_window_get_wl_surface (gdk_window); 256 | 257 | gdk_wayland_window_set_use_custom_surface (gdk_window); 258 | shell_helper_add_surface_to_layer (desktop->helper, 259 | launcher_grid->surface, 260 | desktop->panel->surface); 261 | 262 | g_signal_connect (launcher_grid->window, "app-launched", 263 | G_CALLBACK (launcher_grid_toggle), desktop); 264 | 265 | gtk_widget_show_all (launcher_grid->window); 266 | 267 | desktop->launcher_grid = launcher_grid; 268 | } 269 | 270 | static void 271 | volume_changed_cb (MaynardClock *clock, 272 | gdouble value, 273 | const gchar *icon_name, 274 | struct desktop *desktop) 275 | { 276 | maynard_panel_set_volume_icon_name ( 277 | MAYNARD_PANEL (desktop->panel->window), icon_name); 278 | } 279 | 280 | static GtkWidget * 281 | clock_create (struct desktop *desktop) 282 | { 283 | struct element *clock; 284 | GdkWindow *gdk_window; 285 | 286 | clock = malloc (sizeof *clock); 287 | memset (clock, 0, sizeof *clock); 288 | 289 | clock->window = maynard_clock_new (); 290 | 291 | g_signal_connect (clock->window, "volume-changed", 292 | G_CALLBACK (volume_changed_cb), desktop); 293 | 294 | gdk_window = gtk_widget_get_window (clock->window); 295 | clock->surface = gdk_wayland_window_get_wl_surface (gdk_window); 296 | 297 | gdk_wayland_window_set_use_custom_surface (gdk_window); 298 | shell_helper_add_surface_to_layer (desktop->helper, clock->surface, 299 | desktop->panel->surface); 300 | 301 | gtk_widget_show_all (clock->window); 302 | 303 | desktop->clock = clock; 304 | } 305 | 306 | static void 307 | button_toggled_cb (struct desktop *desktop, 308 | gboolean *visible, 309 | gboolean *not_visible) 310 | { 311 | *visible = !*visible; 312 | *not_visible = FALSE; 313 | 314 | if (desktop->system_visible) 315 | { 316 | maynard_clock_show_section (MAYNARD_CLOCK (desktop->clock->window), 317 | MAYNARD_CLOCK_SECTION_SYSTEM); 318 | maynard_panel_show_previous (MAYNARD_PANEL (desktop->panel->window), 319 | MAYNARD_PANEL_BUTTON_SYSTEM); 320 | } 321 | else if (desktop->volume_visible) 322 | { 323 | maynard_clock_show_section (MAYNARD_CLOCK (desktop->clock->window), 324 | MAYNARD_CLOCK_SECTION_VOLUME); 325 | maynard_panel_show_previous (MAYNARD_PANEL (desktop->panel->window), 326 | MAYNARD_PANEL_BUTTON_VOLUME); 327 | } 328 | else 329 | { 330 | maynard_clock_show_section (MAYNARD_CLOCK (desktop->clock->window), 331 | MAYNARD_CLOCK_SECTION_CLOCK); 332 | maynard_panel_show_previous (MAYNARD_PANEL (desktop->panel->window), 333 | MAYNARD_PANEL_BUTTON_NONE); 334 | } 335 | } 336 | 337 | static void 338 | system_toggled_cb (GtkWidget *widget, 339 | struct desktop *desktop) 340 | { 341 | button_toggled_cb (desktop, 342 | &desktop->system_visible, 343 | &desktop->volume_visible); 344 | } 345 | 346 | static void 347 | volume_toggled_cb (GtkWidget *widget, 348 | struct desktop *desktop) 349 | { 350 | button_toggled_cb (desktop, 351 | &desktop->volume_visible, 352 | &desktop->system_visible); 353 | } 354 | 355 | static gboolean 356 | panel_window_enter_cb (GtkWidget *widget, 357 | GdkEventCrossing *event, 358 | struct desktop *desktop) 359 | { 360 | if (desktop->initial_panel_timeout_id > 0) 361 | { 362 | g_source_remove (desktop->initial_panel_timeout_id); 363 | desktop->initial_panel_timeout_id = 0; 364 | } 365 | 366 | if (desktop->hide_panel_idle_id > 0) 367 | { 368 | g_source_remove (desktop->hide_panel_idle_id); 369 | desktop->hide_panel_idle_id = 0; 370 | return FALSE; 371 | } 372 | 373 | if (desktop->pointer_out_of_panel) 374 | { 375 | desktop->pointer_out_of_panel = FALSE; 376 | return FALSE; 377 | } 378 | 379 | shell_helper_slide_surface_back (desktop->helper, 380 | desktop->panel->surface); 381 | shell_helper_slide_surface_back (desktop->helper, 382 | desktop->clock->surface); 383 | 384 | maynard_panel_set_expand (MAYNARD_PANEL (desktop->panel->window), TRUE); 385 | 386 | return FALSE; 387 | } 388 | 389 | static gboolean 390 | leave_panel_idle_cb (gpointer data) 391 | { 392 | struct desktop *desktop = data; 393 | gint width; 394 | 395 | desktop->hide_panel_idle_id = 0; 396 | 397 | gtk_window_get_size (GTK_WINDOW (desktop->clock->window), 398 | &width, NULL); 399 | 400 | shell_helper_slide_surface (desktop->helper, 401 | desktop->panel->surface, 402 | MAYNARD_VERTICAL_CLOCK_WIDTH - MAYNARD_PANEL_WIDTH, 0); 403 | shell_helper_slide_surface (desktop->helper, 404 | desktop->clock->surface, 405 | MAYNARD_VERTICAL_CLOCK_WIDTH - MAYNARD_PANEL_WIDTH - width, 0); 406 | 407 | maynard_panel_set_expand (MAYNARD_PANEL (desktop->panel->window), FALSE); 408 | 409 | maynard_clock_show_section (MAYNARD_CLOCK (desktop->clock->window), 410 | MAYNARD_CLOCK_SECTION_CLOCK); 411 | maynard_panel_show_previous (MAYNARD_PANEL (desktop->panel->window), 412 | MAYNARD_PANEL_BUTTON_NONE); 413 | desktop->system_visible = FALSE; 414 | desktop->volume_visible = FALSE; 415 | desktop->pointer_out_of_panel = FALSE; 416 | 417 | return G_SOURCE_REMOVE; 418 | } 419 | 420 | static gboolean 421 | panel_window_leave_cb (GtkWidget *widget, 422 | GdkEventCrossing *event, 423 | struct desktop *desktop) 424 | { 425 | if (desktop->initial_panel_timeout_id > 0) 426 | { 427 | g_source_remove (desktop->initial_panel_timeout_id); 428 | desktop->initial_panel_timeout_id = 0; 429 | } 430 | 431 | if (desktop->hide_panel_idle_id > 0) 432 | return FALSE; 433 | 434 | if (desktop->grid_visible) 435 | { 436 | desktop->pointer_out_of_panel = TRUE; 437 | return FALSE; 438 | } 439 | 440 | desktop->hide_panel_idle_id = g_idle_add (leave_panel_idle_cb, desktop); 441 | 442 | return FALSE; 443 | } 444 | 445 | static gboolean 446 | panel_hide_timeout_cb (gpointer data) 447 | { 448 | struct desktop *desktop = data; 449 | 450 | panel_window_leave_cb (NULL, NULL, desktop); 451 | 452 | return G_SOURCE_REMOVE; 453 | } 454 | 455 | static void 456 | favorite_launched_cb (MaynardPanel *panel, 457 | struct desktop *desktop) 458 | { 459 | if (desktop->grid_visible) 460 | launcher_grid_toggle (desktop->launcher_grid->window, desktop); 461 | 462 | panel_window_leave_cb (NULL, NULL, desktop); 463 | } 464 | 465 | static void 466 | panel_create (struct desktop *desktop) 467 | { 468 | struct element *panel; 469 | GdkWindow *gdk_window; 470 | 471 | panel = malloc (sizeof *panel); 472 | memset (panel, 0, sizeof *panel); 473 | 474 | panel->window = maynard_panel_new (); 475 | 476 | g_signal_connect (panel->window, "app-menu-toggled", 477 | G_CALLBACK (launcher_grid_toggle), desktop); 478 | g_signal_connect (panel->window, "system-toggled", 479 | G_CALLBACK (system_toggled_cb), desktop); 480 | g_signal_connect (panel->window, "volume-toggled", 481 | G_CALLBACK (volume_toggled_cb), desktop); 482 | g_signal_connect (panel->window, "favorite-launched", 483 | G_CALLBACK (favorite_launched_cb), desktop); 484 | 485 | desktop->initial_panel_timeout_id = 486 | g_timeout_add_seconds (2, panel_hide_timeout_cb, desktop); 487 | 488 | /* set it up as the panel */ 489 | gdk_window = gtk_widget_get_window (panel->window); 490 | gdk_wayland_window_set_use_custom_surface (gdk_window); 491 | 492 | panel->surface = gdk_wayland_window_get_wl_surface (gdk_window); 493 | if (desktop->shell) 494 | { 495 | desktop_shell_set_user_data (desktop->shell, desktop); 496 | desktop_shell_set_panel (desktop->shell, desktop->output, panel->surface); 497 | desktop_shell_set_panel_position (desktop->shell, 498 | DESKTOP_SHELL_PANEL_POSITION_LEFT); 499 | } 500 | else 501 | { 502 | weston_desktop_shell_set_user_data (desktop->wshell, desktop); 503 | weston_desktop_shell_set_panel (desktop->wshell, desktop->output, 504 | panel->surface); 505 | weston_desktop_shell_set_panel_position (desktop->wshell, 506 | DESKTOP_SHELL_PANEL_POSITION_LEFT); 507 | } 508 | shell_helper_set_panel (desktop->helper, panel->surface); 509 | 510 | gtk_widget_show_all (panel->window); 511 | 512 | desktop->panel = panel; 513 | } 514 | 515 | /* Expose callback for the drawing area */ 516 | static gboolean 517 | draw_cb (GtkWidget *widget, 518 | cairo_t *cr, 519 | gpointer data) 520 | { 521 | struct desktop *desktop = data; 522 | 523 | gdk_cairo_set_source_pixbuf (cr, desktop->background->pixbuf, 0, 0); 524 | cairo_paint (cr); 525 | 526 | return TRUE; 527 | } 528 | 529 | /* Destroy handler for the window */ 530 | static void 531 | destroy_cb (GObject *object, 532 | gpointer data) 533 | { 534 | gtk_main_quit (); 535 | } 536 | 537 | static GdkPixbuf * 538 | scale_background (GdkPixbuf *original_pixbuf) 539 | { 540 | /* Scale original_pixbuf so it mostly fits on the screen. 541 | * If the aspect ratio is different than a bit on the right or on the 542 | * bottom could be cropped out. */ 543 | GdkScreen *screen = gdk_screen_get_default (); 544 | gint screen_width, screen_height; 545 | gint original_width, original_height; 546 | gint final_width, final_height; 547 | gdouble ratio_horizontal, ratio_vertical, ratio; 548 | 549 | screen_width = gdk_screen_get_width (screen); 550 | screen_height = gdk_screen_get_height (screen); 551 | original_width = gdk_pixbuf_get_width (original_pixbuf); 552 | original_height = gdk_pixbuf_get_height (original_pixbuf); 553 | 554 | ratio_horizontal = (double) screen_width / original_width; 555 | ratio_vertical = (double) screen_height / original_height; 556 | ratio = MAX (ratio_horizontal, ratio_vertical); 557 | 558 | final_width = ceil (ratio * original_width); 559 | final_height = ceil (ratio * original_height); 560 | 561 | return gdk_pixbuf_scale_simple (original_pixbuf, 562 | final_width, final_height, GDK_INTERP_BILINEAR); 563 | } 564 | 565 | static void 566 | background_create (struct desktop *desktop) 567 | { 568 | GdkWindow *gdk_window; 569 | struct element *background; 570 | const gchar *filename; 571 | GdkPixbuf *unscaled_background; 572 | const gchar *xpm_data[] = {"1 1 1 1", "_ c SteelBlue", "_"}; 573 | 574 | background = malloc (sizeof *background); 575 | memset (background, 0, sizeof *background); 576 | 577 | filename = g_getenv ("MAYNARD_BACKGROUND"); 578 | if (filename && filename[0] != '\0') 579 | unscaled_background = gdk_pixbuf_new_from_file (filename, NULL); 580 | else 581 | unscaled_background = gdk_pixbuf_new_from_xpm_data (xpm_data); 582 | 583 | if (!unscaled_background) 584 | { 585 | g_message ("Could not load background (%s).", 586 | filename ? filename : "built-in"); 587 | exit (EXIT_FAILURE); 588 | } 589 | 590 | background->pixbuf = scale_background (unscaled_background); 591 | g_object_unref (unscaled_background); 592 | 593 | background->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 594 | 595 | g_signal_connect (background->window, "destroy", 596 | G_CALLBACK (destroy_cb), NULL); 597 | 598 | g_signal_connect (background->window, "draw", 599 | G_CALLBACK (draw_cb), desktop); 600 | 601 | gtk_window_set_title (GTK_WINDOW (background->window), "maynard"); 602 | gtk_window_set_decorated (GTK_WINDOW (background->window), FALSE); 603 | gtk_widget_realize (background->window); 604 | 605 | gdk_window = gtk_widget_get_window (background->window); 606 | gdk_wayland_window_set_use_custom_surface (gdk_window); 607 | 608 | background->surface = gdk_wayland_window_get_wl_surface (gdk_window); 609 | if (desktop->shell) 610 | { 611 | desktop_shell_set_user_data (desktop->shell, desktop); 612 | desktop_shell_set_background (desktop->shell, desktop->output, 613 | background->surface); 614 | } 615 | else 616 | { 617 | weston_desktop_shell_set_user_data (desktop->wshell, desktop); 618 | weston_desktop_shell_set_background (desktop->wshell, desktop->output, 619 | background->surface); 620 | } 621 | 622 | desktop->background = background; 623 | 624 | gtk_widget_show_all (background->window); 625 | } 626 | 627 | static void 628 | curtain_create (struct desktop *desktop) 629 | { 630 | GdkWindow *gdk_window; 631 | struct element *curtain; 632 | 633 | curtain = malloc (sizeof *curtain); 634 | memset (curtain, 0, sizeof *curtain); 635 | 636 | curtain->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 637 | 638 | gtk_window_set_title (GTK_WINDOW (curtain->window), "maynard"); 639 | gtk_window_set_decorated (GTK_WINDOW (curtain->window), FALSE); 640 | gtk_widget_set_size_request (curtain->window, 8192, 8192); 641 | gtk_widget_realize (curtain->window); 642 | 643 | gdk_window = gtk_widget_get_window (curtain->window); 644 | gdk_wayland_window_set_use_custom_surface (gdk_window); 645 | 646 | curtain->surface = gdk_wayland_window_get_wl_surface (gdk_window); 647 | 648 | desktop->curtain = curtain; 649 | 650 | gtk_widget_show_all (curtain->window); 651 | } 652 | 653 | static void 654 | css_setup (struct desktop *desktop) 655 | { 656 | GtkCssProvider *provider; 657 | GFile *file; 658 | GError *error = NULL; 659 | 660 | provider = gtk_css_provider_new (); 661 | 662 | file = g_file_new_for_uri ("resource:///org/raspberry-pi/maynard/style.css"); 663 | 664 | if (!gtk_css_provider_load_from_file (provider, file, &error)) 665 | { 666 | g_warning ("Failed to load CSS file: %s", error->message); 667 | g_clear_error (&error); 668 | g_object_unref (file); 669 | return; 670 | } 671 | 672 | gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), 673 | GTK_STYLE_PROVIDER (provider), 600); 674 | 675 | g_object_unref (file); 676 | } 677 | 678 | 679 | static void 680 | pointer_handle_enter (void *data, 681 | struct wl_pointer *pointer, 682 | uint32_t serial, 683 | struct wl_surface *surface, 684 | wl_fixed_t sx_w, 685 | wl_fixed_t sy_w) 686 | { 687 | } 688 | 689 | static void 690 | pointer_handle_leave (void *data, 691 | struct wl_pointer *pointer, 692 | uint32_t serial, 693 | struct wl_surface *surface) 694 | { 695 | } 696 | 697 | static void 698 | pointer_handle_motion (void *data, 699 | struct wl_pointer *pointer, 700 | uint32_t time, 701 | wl_fixed_t sx_w, 702 | wl_fixed_t sy_w) 703 | { 704 | } 705 | 706 | static void 707 | pointer_handle_button (void *data, 708 | struct wl_pointer *pointer, 709 | uint32_t serial, 710 | uint32_t time, 711 | uint32_t button, 712 | uint32_t state_w) 713 | { 714 | struct desktop *desktop = data; 715 | 716 | if (state_w != WL_POINTER_BUTTON_STATE_RELEASED) 717 | return; 718 | 719 | if (!desktop->pointer_out_of_panel) 720 | return; 721 | 722 | if (desktop->grid_visible) 723 | launcher_grid_toggle (desktop->launcher_grid->window, desktop); 724 | 725 | panel_window_leave_cb (NULL, NULL, desktop); 726 | } 727 | 728 | static void 729 | pointer_handle_axis (void *data, 730 | struct wl_pointer *pointer, 731 | uint32_t time, 732 | uint32_t axis, 733 | wl_fixed_t value) 734 | { 735 | } 736 | 737 | static const struct wl_pointer_listener pointer_listener = { 738 | pointer_handle_enter, 739 | pointer_handle_leave, 740 | pointer_handle_motion, 741 | pointer_handle_button, 742 | pointer_handle_axis, 743 | }; 744 | 745 | static void 746 | seat_handle_capabilities (void *data, 747 | struct wl_seat *seat, 748 | enum wl_seat_capability caps) 749 | { 750 | struct desktop *desktop = data; 751 | 752 | if ((caps & WL_SEAT_CAPABILITY_POINTER) && !desktop->pointer) { 753 | desktop->pointer = wl_seat_get_pointer(seat); 754 | wl_pointer_set_user_data (desktop->pointer, desktop); 755 | wl_pointer_add_listener(desktop->pointer, &pointer_listener, 756 | desktop); 757 | } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && desktop->pointer) { 758 | wl_pointer_destroy(desktop->pointer); 759 | desktop->pointer = NULL; 760 | } 761 | 762 | /* TODO: keyboard and touch */ 763 | } 764 | 765 | static void 766 | seat_handle_name (void *data, 767 | struct wl_seat *seat, 768 | const char *name) 769 | { 770 | } 771 | 772 | static const struct wl_seat_listener seat_listener = { 773 | seat_handle_capabilities, 774 | seat_handle_name 775 | }; 776 | 777 | static void 778 | registry_handle_global (void *data, 779 | struct wl_registry *registry, 780 | uint32_t name, 781 | const char *interface, 782 | uint32_t version) 783 | { 784 | struct desktop *d = data; 785 | 786 | if (!strcmp (interface, "desktop_shell")) 787 | { 788 | d->shell = wl_registry_bind (registry, name, 789 | &desktop_shell_interface, MIN(version, 3)); 790 | desktop_shell_add_listener (d->shell, &shell_listener, d); 791 | desktop_shell_set_user_data (d->shell, d); 792 | } 793 | else if (!strcmp (interface, "weston_desktop_shell")) 794 | { 795 | d->wshell = wl_registry_bind (registry, name, 796 | &weston_desktop_shell_interface, MIN(version, 1)); 797 | weston_desktop_shell_add_listener (d->wshell, &wshell_listener, d); 798 | weston_desktop_shell_set_user_data (d->wshell, d); 799 | } 800 | else if (!strcmp (interface, "wl_output")) 801 | { 802 | /* TODO: create multiple outputs */ 803 | d->output = wl_registry_bind (registry, name, 804 | &wl_output_interface, 1); 805 | } 806 | else if (!strcmp (interface, "wl_seat")) 807 | { 808 | d->seat = wl_registry_bind (registry, name, 809 | &wl_seat_interface, 1); 810 | wl_seat_add_listener (d->seat, &seat_listener, d); 811 | } 812 | else if (!strcmp (interface, "shell_helper")) 813 | { 814 | d->helper = wl_registry_bind (registry, name, 815 | &shell_helper_interface, 1); 816 | } 817 | } 818 | 819 | static void 820 | registry_handle_global_remove (void *data, 821 | struct wl_registry *registry, 822 | uint32_t name) 823 | { 824 | } 825 | 826 | static const struct wl_registry_listener registry_listener = { 827 | registry_handle_global, 828 | registry_handle_global_remove 829 | }; 830 | 831 | static void grab_surface_create(struct desktop *desktop) 832 | { 833 | 834 | struct wl_surface *s; 835 | 836 | GdkWindow *gdk_window; 837 | struct element *curtain; 838 | 839 | curtain = malloc (sizeof *curtain); 840 | memset (curtain, 0, sizeof *curtain); 841 | 842 | curtain->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 843 | 844 | gtk_window_set_title (GTK_WINDOW (curtain->window), "maynard2"); 845 | gtk_window_set_decorated (GTK_WINDOW (curtain->window), FALSE); 846 | gtk_widget_set_size_request (curtain->window, 8192, 8192); 847 | gtk_widget_realize (curtain->window); 848 | 849 | gdk_window = gtk_widget_get_window (curtain->window); 850 | gdk_wayland_window_set_use_custom_surface (gdk_window); 851 | 852 | curtain->surface = gdk_wayland_window_get_wl_surface (gdk_window); 853 | 854 | desktop->curtain = curtain; 855 | 856 | gtk_widget_show_all (curtain->window); 857 | weston_desktop_shell_set_grab_surface(desktop->wshell, curtain->surface); 858 | 859 | 860 | } 861 | 862 | int 863 | main (int argc, 864 | char *argv[]) 865 | { 866 | struct desktop *desktop; 867 | 868 | gdk_set_allowed_backends ("wayland"); 869 | 870 | gtk_init (&argc, &argv); 871 | 872 | g_resources_register (maynard_get_resource ()); 873 | 874 | desktop = malloc (sizeof *desktop); 875 | desktop->output = NULL; 876 | desktop->shell = NULL; 877 | desktop->helper = NULL; 878 | desktop->seat = NULL; 879 | desktop->pointer = NULL; 880 | 881 | desktop->gdk_display = gdk_display_get_default (); 882 | desktop->display = 883 | gdk_wayland_display_get_wl_display (desktop->gdk_display); 884 | if (desktop->display == NULL) 885 | { 886 | fprintf (stderr, "failed to get display: %m\n"); 887 | return -1; 888 | } 889 | 890 | desktop->registry = wl_display_get_registry (desktop->display); 891 | wl_registry_add_listener (desktop->registry, 892 | ®istry_listener, desktop); 893 | 894 | /* Wait until we have been notified about the compositor, 895 | * shell, and shell helper objects */ 896 | if (!desktop->output || (!desktop->shell && !desktop->wshell) || 897 | !desktop->helper) 898 | wl_display_roundtrip (desktop->display); 899 | if (!desktop->output || (!desktop->shell && !desktop->wshell) || 900 | !desktop->helper) 901 | { 902 | fprintf (stderr, "could not find output, shell or helper modules\n"); 903 | return -1; 904 | } 905 | 906 | desktop->grid_visible = FALSE; 907 | desktop->system_visible = FALSE; 908 | desktop->volume_visible = FALSE; 909 | desktop->pointer_out_of_panel = FALSE; 910 | 911 | css_setup (desktop); 912 | background_create (desktop); 913 | curtain_create (desktop); 914 | 915 | /* panel needs to be first so the clock and launcher grid can 916 | * be added to its layer */ 917 | panel_create (desktop); 918 | clock_create (desktop); 919 | launcher_grid_create (desktop); 920 | grab_surface_create (desktop); 921 | 922 | gtk_main (); 923 | 924 | /* TODO cleanup */ 925 | return EXIT_SUCCESS; 926 | } 927 | -------------------------------------------------------------------------------- /shell/maynard.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | style.css 5 | 6 | 7 | -------------------------------------------------------------------------------- /shell/panel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Jonny Lamb 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "panel.h" 25 | 26 | #include "app-icon.h" 27 | #include "favorites.h" 28 | #include "vertical-clock.h" 29 | 30 | enum { 31 | APP_MENU_TOGGLED, 32 | SYSTEM_TOGGLED, 33 | VOLUME_TOGGLED, 34 | FAVORITE_LAUNCHED, 35 | N_SIGNALS 36 | }; 37 | static guint signals[N_SIGNALS] = { 0 }; 38 | 39 | struct MaynardPanelPrivate { 40 | gboolean hidden; 41 | 42 | GtkWidget *revealer_buttons; /* for the top buttons */ 43 | GtkWidget *revealer_clock; /* for the vertical clock */ 44 | 45 | GtkWidget *system_button; 46 | 47 | gboolean volume_showing; 48 | GtkWidget *volume_button; 49 | gchar *volume_icon_name; 50 | }; 51 | 52 | G_DEFINE_TYPE(MaynardPanel, maynard_panel, GTK_TYPE_WINDOW) 53 | 54 | static void 55 | maynard_panel_init (MaynardPanel *self) 56 | { 57 | self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, 58 | MAYNARD_PANEL_TYPE, 59 | MaynardPanelPrivate); 60 | 61 | self->priv->volume_icon_name = g_strdup ("audio-volume-high-symbolic"); 62 | } 63 | 64 | static gboolean 65 | widget_enter_notify_event_cb (GtkWidget *widget, 66 | GdkEventCrossing *event, 67 | MaynardPanel *self) 68 | { 69 | gboolean handled; 70 | g_signal_emit_by_name (self, "enter-notify-event", event, &handled); 71 | return handled; 72 | } 73 | 74 | static void 75 | widget_connect_enter_signal (MaynardPanel *self, 76 | GtkWidget *widget) 77 | { 78 | g_signal_connect (widget, "enter-notify-event", 79 | G_CALLBACK (widget_enter_notify_event_cb), self); 80 | } 81 | 82 | static void 83 | app_menu_button_clicked_cb (GtkButton *button, 84 | MaynardPanel *self) 85 | { 86 | g_signal_emit (self, signals[APP_MENU_TOGGLED], 0); 87 | } 88 | 89 | static void 90 | system_button_clicked_cb (GtkButton *button, 91 | MaynardPanel *self) 92 | { 93 | g_signal_emit (self, signals[SYSTEM_TOGGLED], 0); 94 | } 95 | 96 | static void 97 | volume_button_clicked_cb (GtkButton *button, 98 | MaynardPanel *self) 99 | { 100 | g_signal_emit (self, signals[VOLUME_TOGGLED], 0); 101 | } 102 | 103 | static void 104 | favorite_launched_cb (MaynardFavorites *favorites, 105 | MaynardPanel *self) 106 | { 107 | g_signal_emit (self, signals[FAVORITE_LAUNCHED], 0); 108 | } 109 | 110 | static void 111 | maynard_panel_constructed (GObject *object) 112 | { 113 | MaynardPanel *self = MAYNARD_PANEL (object); 114 | GtkWidget *main_box, *menu_box, *buttons_box; 115 | GtkWidget *ebox; 116 | GtkWidget *image; 117 | GtkWidget *button; 118 | GtkWidget *favorites; 119 | 120 | G_OBJECT_CLASS (maynard_panel_parent_class)->constructed (object); 121 | 122 | /* window properties */ 123 | gtk_window_set_title (GTK_WINDOW (self), "maynard"); 124 | gtk_window_set_decorated (GTK_WINDOW (self), FALSE); 125 | gtk_widget_realize(GTK_WIDGET (self)); 126 | 127 | /* make it black and slightly alpha */ 128 | gtk_style_context_add_class ( 129 | gtk_widget_get_style_context (GTK_WIDGET (self)), 130 | "maynard-panel"); 131 | 132 | /* main vbox */ 133 | main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); 134 | gtk_container_add (GTK_CONTAINER (self), main_box); 135 | 136 | /* for the top buttons and vertical clock we have a few more 137 | * boxes. the hbox has two cells. in each cell there is a 138 | * GtkRevealer for hiding and showing the content. only one revealer 139 | * is ever visibile at one point and transitions happen at the same 140 | * time so the width stays constant (the animation duration is the 141 | * same). the first revealer contains another box which has the two 142 | * wifi and sound buttons. the second revealer has the vertical 143 | * clock widget. 144 | */ 145 | 146 | /* GtkBoxes seem to eat up enter/leave events, so let's use an event 147 | * box for the entire thing. */ 148 | ebox = gtk_event_box_new (); 149 | gtk_box_pack_start (GTK_BOX (main_box), ebox, FALSE, FALSE, 0); 150 | widget_connect_enter_signal (self, ebox); 151 | 152 | menu_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); 153 | gtk_container_add (GTK_CONTAINER (ebox), menu_box); 154 | 155 | /* revealer for the top buttons */ 156 | self->priv->revealer_buttons = gtk_revealer_new (); 157 | gtk_revealer_set_transition_type (GTK_REVEALER (self->priv->revealer_buttons), 158 | GTK_REVEALER_TRANSITION_TYPE_SLIDE_LEFT); 159 | gtk_revealer_set_reveal_child (GTK_REVEALER (self->priv->revealer_buttons), 160 | TRUE); 161 | gtk_box_pack_start (GTK_BOX (menu_box), 162 | self->priv->revealer_buttons, FALSE, FALSE, 0); 163 | 164 | /* the box for the top buttons */ 165 | buttons_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); 166 | gtk_container_add (GTK_CONTAINER (self->priv->revealer_buttons), buttons_box); 167 | 168 | /* system button */ 169 | ebox = gtk_event_box_new (); 170 | gtk_box_pack_start (GTK_BOX (buttons_box), ebox, FALSE, FALSE, 0); 171 | button = gtk_button_new_from_icon_name ("emblem-system-symbolic", 172 | GTK_ICON_SIZE_LARGE_TOOLBAR); 173 | gtk_style_context_add_class (gtk_widget_get_style_context (button), 174 | "maynard-system"); 175 | gtk_style_context_remove_class (gtk_widget_get_style_context (button), 176 | "button"); 177 | gtk_style_context_remove_class (gtk_widget_get_style_context (button), 178 | "image-button"); 179 | g_signal_connect (button, "clicked", 180 | G_CALLBACK (system_button_clicked_cb), self); 181 | gtk_container_add (GTK_CONTAINER (ebox), button); 182 | widget_connect_enter_signal (self, ebox); 183 | self->priv->system_button = button; 184 | 185 | /* sound button */ 186 | ebox = gtk_event_box_new (); 187 | gtk_box_pack_start (GTK_BOX (buttons_box), ebox, FALSE, FALSE, 0); 188 | button = gtk_button_new_from_icon_name (self->priv->volume_icon_name, 189 | GTK_ICON_SIZE_LARGE_TOOLBAR); 190 | gtk_style_context_add_class (gtk_widget_get_style_context (button), 191 | "maynard-audio"); 192 | gtk_style_context_remove_class (gtk_widget_get_style_context (button), 193 | "button"); 194 | gtk_style_context_remove_class (gtk_widget_get_style_context (button), 195 | "image-button"); 196 | g_signal_connect (button, "clicked", 197 | G_CALLBACK (volume_button_clicked_cb), self); 198 | gtk_container_add (GTK_CONTAINER (ebox), button); 199 | widget_connect_enter_signal (self, ebox); 200 | self->priv->volume_button = button; 201 | 202 | /* revealer for the vertical clock */ 203 | self->priv->revealer_clock = gtk_revealer_new (); 204 | gtk_revealer_set_transition_type (GTK_REVEALER (self->priv->revealer_clock), 205 | GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT); 206 | gtk_revealer_set_reveal_child (GTK_REVEALER (self->priv->revealer_clock), 207 | FALSE); 208 | gtk_box_pack_start (GTK_BOX (menu_box), 209 | self->priv->revealer_clock, FALSE, FALSE, 0); 210 | 211 | /* vertical clock */ 212 | gtk_container_add (GTK_CONTAINER (self->priv->revealer_clock), 213 | maynard_vertical_clock_new ()); 214 | 215 | /* end of the menu buttons and vertical clock */ 216 | 217 | /* favorites */ 218 | ebox = gtk_event_box_new (); 219 | gtk_box_pack_start (GTK_BOX (main_box), ebox, FALSE, FALSE, 0); 220 | favorites = maynard_favorites_new (); 221 | gtk_container_add (GTK_CONTAINER (ebox), favorites); 222 | widget_connect_enter_signal (self, ebox); 223 | 224 | g_signal_connect (favorites, "app-launched", 225 | G_CALLBACK (favorite_launched_cb), self); 226 | 227 | /* bottom app menu button */ 228 | ebox = gtk_event_box_new (); 229 | gtk_box_pack_end (GTK_BOX (main_box), ebox, FALSE, FALSE, 0); 230 | button = maynard_app_icon_new ("view-grid-symbolic"); 231 | g_signal_connect (button, "clicked", 232 | G_CALLBACK (app_menu_button_clicked_cb), self); 233 | gtk_container_add (GTK_CONTAINER (ebox), button); 234 | widget_connect_enter_signal (self, ebox); 235 | 236 | /* done */ 237 | self->priv->hidden = FALSE; 238 | self->priv->volume_showing = FALSE; 239 | } 240 | 241 | static void 242 | maynard_panel_dispose (GObject *object) 243 | { 244 | MaynardPanel *self = MAYNARD_PANEL (object); 245 | 246 | g_free (self->priv->volume_icon_name); 247 | self->priv->volume_icon_name = NULL; 248 | 249 | G_OBJECT_CLASS (maynard_panel_parent_class)->dispose (object); 250 | } 251 | 252 | static void 253 | maynard_panel_class_init (MaynardPanelClass *klass) 254 | { 255 | GObjectClass *object_class = (GObjectClass *)klass; 256 | GParamSpec *param_spec; 257 | 258 | object_class->constructed = maynard_panel_constructed; 259 | object_class->dispose = maynard_panel_dispose; 260 | 261 | signals[APP_MENU_TOGGLED] = g_signal_new ("app-menu-toggled", 262 | G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, 263 | NULL, G_TYPE_NONE, 0); 264 | 265 | signals[SYSTEM_TOGGLED] = g_signal_new ("system-toggled", 266 | G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, 267 | NULL, G_TYPE_NONE, 0); 268 | 269 | signals[VOLUME_TOGGLED] = g_signal_new ("volume-toggled", 270 | G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, 271 | NULL, G_TYPE_NONE, 0); 272 | 273 | signals[FAVORITE_LAUNCHED] = g_signal_new ("favorite-launched", 274 | G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, 275 | NULL, G_TYPE_NONE, 0); 276 | 277 | g_type_class_add_private (object_class, sizeof (MaynardPanelPrivate)); 278 | } 279 | 280 | GtkWidget * 281 | maynard_panel_new (void) 282 | { 283 | return g_object_new (MAYNARD_PANEL_TYPE, 284 | NULL); 285 | } 286 | 287 | void 288 | maynard_panel_set_expand (MaynardPanel *self, 289 | gboolean expand) 290 | { 291 | gtk_revealer_set_reveal_child (GTK_REVEALER (self->priv->revealer_buttons), expand); 292 | gtk_revealer_set_reveal_child (GTK_REVEALER (self->priv->revealer_clock), !expand); 293 | } 294 | 295 | static void 296 | set_icon (GtkWidget *button, 297 | const gchar *icon_name) 298 | { 299 | GtkWidget *image; 300 | 301 | image = gtk_image_new_from_icon_name (icon_name, 302 | GTK_ICON_SIZE_LARGE_TOOLBAR); 303 | gtk_button_set_image (GTK_BUTTON (button), 304 | image); 305 | } 306 | 307 | void 308 | maynard_panel_show_previous (MaynardPanel *self, 309 | MaynardPanelButton button) 310 | { 311 | switch (button) 312 | { 313 | case MAYNARD_PANEL_BUTTON_SYSTEM: 314 | set_icon (self->priv->system_button, "go-previous-symbolic"); 315 | set_icon (self->priv->volume_button, self->priv->volume_icon_name); 316 | self->priv->volume_showing = FALSE; 317 | break; 318 | case MAYNARD_PANEL_BUTTON_VOLUME: 319 | set_icon (self->priv->system_button, "emblem-system-symbolic"); 320 | set_icon (self->priv->volume_button, "go-previous-symbolic"); 321 | self->priv->volume_showing = TRUE; 322 | break; 323 | case MAYNARD_PANEL_BUTTON_NONE: 324 | default: 325 | set_icon (self->priv->system_button, "emblem-system-symbolic"); 326 | set_icon (self->priv->volume_button, self->priv->volume_icon_name); 327 | self->priv->volume_showing = FALSE; 328 | } 329 | } 330 | 331 | void 332 | maynard_panel_set_volume_icon_name (MaynardPanel *self, 333 | const gchar *icon_name) 334 | { 335 | g_free (self->priv->volume_icon_name); 336 | self->priv->volume_icon_name = g_strdup (icon_name); 337 | 338 | if (!self->priv->volume_showing) 339 | set_icon (self->priv->volume_button, icon_name); 340 | } 341 | -------------------------------------------------------------------------------- /shell/panel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Jonny Lamb 20 | */ 21 | 22 | #ifndef __MAYNARD_PANEL_H__ 23 | #define __MAYNARD_PANEL_H__ 24 | 25 | #include 26 | 27 | #define MAYNARD_PANEL_TYPE (maynard_panel_get_type ()) 28 | #define MAYNARD_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAYNARD_PANEL_TYPE, MaynardPanel)) 29 | #define MAYNARD_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAYNARD_PANEL_TYPE, MaynardPanelClass)) 30 | #define MAYNARD_IS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAYNARD_PANEL_TYPE)) 31 | #define MAYNARD_IS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAYNARD_PANEL_TYPE)) 32 | #define MAYNARD_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAYNARD_PANEL_TYPE, MaynardPanelClass)) 33 | 34 | typedef struct MaynardPanel MaynardPanel; 35 | typedef struct MaynardPanelClass MaynardPanelClass; 36 | typedef struct MaynardPanelPrivate MaynardPanelPrivate; 37 | 38 | struct MaynardPanel 39 | { 40 | GtkWindow parent; 41 | 42 | MaynardPanelPrivate *priv; 43 | }; 44 | 45 | struct MaynardPanelClass 46 | { 47 | GtkWindowClass parent_class; 48 | }; 49 | 50 | #define MAYNARD_PANEL_WIDTH 56 51 | #define MAYNARD_PANEL_HEIGHT_RATIO 0.73 52 | 53 | typedef enum { 54 | MAYNARD_PANEL_BUTTON_NONE, 55 | MAYNARD_PANEL_BUTTON_SYSTEM, 56 | MAYNARD_PANEL_BUTTON_VOLUME 57 | } MaynardPanelButton; 58 | 59 | GType maynard_panel_get_type (void) G_GNUC_CONST; 60 | 61 | GtkWidget * maynard_panel_new (void); 62 | 63 | void maynard_panel_set_expand (MaynardPanel *self, gboolean expand); 64 | 65 | void maynard_panel_show_previous (MaynardPanel *self, MaynardPanelButton button); 66 | 67 | void maynard_panel_set_volume_icon_name (MaynardPanel *self, 68 | const gchar *icon_name); 69 | 70 | #endif /* __MAYNARD_PANEL_H__ */ 71 | -------------------------------------------------------------------------------- /shell/shell-app-system.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2 | /* Original code taken from gnome-shell */ 3 | #include "config.h" 4 | 5 | #include "shell-app-system.h" 6 | #include 7 | 8 | #include 9 | 10 | enum { 11 | INSTALLED_CHANGED, 12 | LAST_SIGNAL 13 | }; 14 | 15 | static guint signals[LAST_SIGNAL] = { 0 }; 16 | 17 | struct _ShellAppSystemPrivate { 18 | GMenuTree *apps_tree; 19 | 20 | GHashTable *id_to_info; 21 | }; 22 | 23 | static void shell_app_system_finalize (GObject *object); 24 | static void on_apps_tree_changed_cb (GMenuTree *tree, gpointer user_data); 25 | 26 | G_DEFINE_TYPE(ShellAppSystem, shell_app_system, G_TYPE_OBJECT); 27 | 28 | static void shell_app_system_class_init(ShellAppSystemClass *klass) 29 | { 30 | GObjectClass *gobject_class = (GObjectClass *)klass; 31 | 32 | gobject_class->finalize = shell_app_system_finalize; 33 | 34 | signals[INSTALLED_CHANGED] = 35 | g_signal_new ("installed-changed", 36 | SHELL_TYPE_APP_SYSTEM, 37 | G_SIGNAL_RUN_LAST, 38 | G_STRUCT_OFFSET (ShellAppSystemClass, installed_changed), 39 | NULL, NULL, NULL, 40 | G_TYPE_NONE, 0); 41 | 42 | g_type_class_add_private (gobject_class, sizeof (ShellAppSystemPrivate)); 43 | } 44 | 45 | static void 46 | shell_app_system_init (ShellAppSystem *self) 47 | { 48 | ShellAppSystemPrivate *priv; 49 | 50 | self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (self, 51 | SHELL_TYPE_APP_SYSTEM, 52 | ShellAppSystemPrivate); 53 | 54 | priv->id_to_info = g_hash_table_new_full (g_str_hash, g_str_equal, 55 | (GDestroyNotify)g_free, 56 | (GDestroyNotify)g_object_unref); 57 | 58 | priv->apps_tree = gmenu_tree_new ("applications.menu", GMENU_TREE_FLAGS_NONE); 59 | g_signal_connect (priv->apps_tree, "changed", G_CALLBACK (on_apps_tree_changed_cb), self); 60 | 61 | on_apps_tree_changed_cb (priv->apps_tree, self); 62 | } 63 | 64 | static void 65 | shell_app_system_finalize (GObject *object) 66 | { 67 | ShellAppSystem *self = SHELL_APP_SYSTEM (object); 68 | ShellAppSystemPrivate *priv = self->priv; 69 | 70 | g_object_unref (priv->apps_tree); 71 | 72 | g_hash_table_destroy (priv->id_to_info); 73 | 74 | G_OBJECT_CLASS (shell_app_system_parent_class)->finalize (object); 75 | } 76 | 77 | static void 78 | get_flattened_entries_recurse (GMenuTreeDirectory *dir, 79 | GHashTable *entry_set) 80 | { 81 | GMenuTreeIter *iter = gmenu_tree_directory_iter (dir); 82 | GMenuTreeItemType next_type; 83 | 84 | while ((next_type = gmenu_tree_iter_next (iter)) != GMENU_TREE_ITEM_INVALID) 85 | { 86 | gpointer item = NULL; 87 | 88 | switch (next_type) 89 | { 90 | case GMENU_TREE_ITEM_ENTRY: 91 | { 92 | GMenuTreeEntry *entry; 93 | item = entry = gmenu_tree_iter_get_entry (iter); 94 | /* Key is owned by entry */ 95 | g_hash_table_replace (entry_set, 96 | (char*)gmenu_tree_entry_get_desktop_file_id (entry), 97 | gmenu_tree_item_ref (entry)); 98 | } 99 | break; 100 | case GMENU_TREE_ITEM_DIRECTORY: 101 | { 102 | item = gmenu_tree_iter_get_directory (iter); 103 | get_flattened_entries_recurse ((GMenuTreeDirectory*)item, entry_set); 104 | } 105 | break; 106 | default: 107 | break; 108 | } 109 | if (item != NULL) 110 | gmenu_tree_item_unref (item); 111 | } 112 | 113 | gmenu_tree_iter_unref (iter); 114 | } 115 | 116 | static GHashTable * 117 | get_flattened_entries_from_tree (GMenuTree *tree) 118 | { 119 | GHashTable *table; 120 | GMenuTreeDirectory *root; 121 | 122 | table = g_hash_table_new_full (g_str_hash, g_str_equal, 123 | (GDestroyNotify) NULL, 124 | (GDestroyNotify) gmenu_tree_item_unref); 125 | 126 | root = gmenu_tree_get_root_directory (tree); 127 | 128 | if (root != NULL) 129 | get_flattened_entries_recurse (root, table); 130 | 131 | gmenu_tree_item_unref (root); 132 | 133 | return table; 134 | } 135 | 136 | static void 137 | on_apps_tree_changed_cb (GMenuTree *tree, 138 | gpointer user_data) 139 | { 140 | ShellAppSystem *self = SHELL_APP_SYSTEM (user_data); 141 | GError *error = NULL; 142 | GHashTable *new_apps; 143 | GHashTableIter iter; 144 | gpointer key, value; 145 | 146 | g_assert (tree == self->priv->apps_tree); 147 | 148 | if (!gmenu_tree_load_sync (self->priv->apps_tree, &error)) 149 | { 150 | if (error) 151 | { 152 | g_warning ("Failed to load apps: %s", error->message); 153 | g_error_free (error); 154 | } 155 | else 156 | { 157 | g_warning ("Failed to load apps"); 158 | } 159 | return; 160 | } 161 | 162 | /* FIXME: Is this 'replace info, then removed those that are gone from 163 | * the menu tree' vs. 'empty hash table, add everything that's still here' 164 | * still useful (from a performance POV) ? 165 | */ 166 | 167 | new_apps = get_flattened_entries_from_tree (self->priv->apps_tree); 168 | g_hash_table_iter_init (&iter, new_apps); 169 | while (g_hash_table_iter_next (&iter, &key, &value)) 170 | { 171 | const char *id = key; 172 | GMenuTreeEntry *entry = value; 173 | GDesktopAppInfo *info; 174 | 175 | info = gmenu_tree_entry_get_app_info (entry); 176 | 177 | g_hash_table_insert (self->priv->id_to_info, g_strdup (id), g_object_ref (info)); 178 | } 179 | 180 | g_hash_table_iter_init (&iter, self->priv->id_to_info); 181 | while (g_hash_table_iter_next (&iter, &key, &value)) 182 | { 183 | const char *id = key; 184 | 185 | if (!g_hash_table_lookup (new_apps, id)) 186 | g_hash_table_iter_remove (&iter); 187 | } 188 | 189 | g_hash_table_destroy (new_apps); 190 | 191 | g_signal_emit (self, signals[INSTALLED_CHANGED], 0); 192 | } 193 | 194 | /** 195 | * shell_app_system_get_default: 196 | * 197 | * Return Value: (transfer none): The global #ShellAppSystem singleton 198 | */ 199 | ShellAppSystem * 200 | shell_app_system_get_default () 201 | { 202 | static ShellAppSystem *instance = NULL; 203 | 204 | if (instance == NULL) 205 | instance = g_object_new (SHELL_TYPE_APP_SYSTEM, NULL); 206 | 207 | return instance; 208 | } 209 | 210 | GHashTable * 211 | shell_app_system_get_entries (ShellAppSystem *self) 212 | { 213 | return self->priv->id_to_info; 214 | } 215 | -------------------------------------------------------------------------------- /shell/shell-app-system.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2 | #ifndef __SHELL_APP_SYSTEM_H__ 3 | #define __SHELL_APP_SYSTEM_H__ 4 | 5 | #include 6 | #define GMENU_I_KNOW_THIS_IS_UNSTABLE 7 | #include 8 | 9 | #define SHELL_TYPE_APP_SYSTEM (shell_app_system_get_type ()) 10 | #define SHELL_APP_SYSTEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_APP_SYSTEM, ShellAppSystem)) 11 | #define SHELL_APP_SYSTEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_APP_SYSTEM, ShellAppSystemClass)) 12 | #define SHELL_IS_APP_SYSTEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_APP_SYSTEM)) 13 | #define SHELL_IS_APP_SYSTEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_APP_SYSTEM)) 14 | #define SHELL_APP_SYSTEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_APP_SYSTEM, ShellAppSystemClass)) 15 | 16 | typedef struct _ShellAppSystem ShellAppSystem; 17 | typedef struct _ShellAppSystemClass ShellAppSystemClass; 18 | typedef struct _ShellAppSystemPrivate ShellAppSystemPrivate; 19 | 20 | struct _ShellAppSystem 21 | { 22 | GObject parent; 23 | 24 | ShellAppSystemPrivate *priv; 25 | }; 26 | 27 | struct _ShellAppSystemClass 28 | { 29 | GObjectClass parent_class; 30 | 31 | void (*installed_changed)(ShellAppSystem *appsys, gpointer user_data); 32 | void (*favorites_changed)(ShellAppSystem *appsys, gpointer user_data); 33 | }; 34 | 35 | GType shell_app_system_get_type (void) G_GNUC_CONST; 36 | ShellAppSystem *shell_app_system_get_default (void); 37 | 38 | GHashTable *shell_app_system_get_entries (ShellAppSystem *self); 39 | 40 | #endif /* __SHELL_APP_SYSTEM_H__ */ 41 | -------------------------------------------------------------------------------- /shell/shell-helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Jonny Lamb 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #include "config.h" 26 | #ifdef HAVE_NEW_WESTON 27 | #include 28 | #else 29 | #include 30 | #endif 31 | 32 | #include "shell-helper-server-protocol.h" 33 | 34 | #ifndef container_of 35 | #define container_of(ptr, type, member) ({ \ 36 | const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ 37 | (type *)( (char *)__mptr - offsetof(type,member) );}) 38 | #endif 39 | 40 | struct shell_helper { 41 | struct weston_compositor *compositor; 42 | 43 | struct wl_listener destroy_listener; 44 | 45 | struct weston_layer *panel_layer; 46 | 47 | struct weston_layer curtain_layer; 48 | struct weston_view *curtain_view; 49 | struct weston_view_animation *curtain_animation; 50 | uint32_t curtain_show; 51 | 52 | struct wl_list slide_list; 53 | }; 54 | 55 | static void 56 | shell_helper_move_surface(struct wl_client *client, 57 | struct wl_resource *resource, 58 | struct wl_resource *surface_resource, 59 | int32_t x, 60 | int32_t y) 61 | { 62 | struct shell_helper *helper = wl_resource_get_user_data(resource); 63 | struct weston_surface *surface = 64 | wl_resource_get_user_data(surface_resource); 65 | struct weston_view *view; 66 | 67 | view = container_of(surface->views.next, struct weston_view, surface_link); 68 | 69 | if (!view) 70 | return; 71 | 72 | weston_view_set_position(view, x, y); 73 | weston_view_update_transform(view); 74 | } 75 | 76 | static void 77 | configure_surface(struct weston_surface *es, int32_t sx, int32_t sy) 78 | { 79 | #ifdef HAVE_NEW_WESTON 80 | struct weston_view *existing_view = es->committed_private; 81 | #else 82 | struct weston_view *existing_view = es->configure_private; 83 | #endif 84 | struct weston_view *new_view; 85 | 86 | new_view = container_of(es->views.next, struct weston_view, surface_link); 87 | 88 | if (wl_list_empty(&new_view->layer_link.link)) { 89 | /* be sure to append to the list, not insert */ 90 | weston_layer_entry_insert(&existing_view->layer_link, &new_view->layer_link); 91 | weston_compositor_schedule_repaint(es->compositor); 92 | } 93 | } 94 | 95 | static void 96 | shell_helper_add_surface_to_layer(struct wl_client *client, 97 | struct wl_resource *resource, 98 | struct wl_resource *new_surface_resource, 99 | struct wl_resource *existing_surface_resource) 100 | { 101 | struct shell_helper *helper = wl_resource_get_user_data(resource); 102 | struct weston_surface *new_surface = 103 | wl_resource_get_user_data(new_surface_resource); 104 | struct weston_surface *existing_surface = 105 | wl_resource_get_user_data(existing_surface_resource); 106 | struct weston_view *new_view, *existing_view, *next; 107 | struct wl_layer *layer; 108 | 109 | #ifdef HAVE_NEW_WESTON 110 | if (new_surface->committed) { 111 | wl_resource_post_error(new_surface_resource, 112 | WL_DISPLAY_ERROR_INVALID_OBJECT, 113 | "surface role already assigned"); 114 | return; 115 | } 116 | #else 117 | if (new_surface->configure) { 118 | wl_resource_post_error(new_surface_resource, 119 | WL_DISPLAY_ERROR_INVALID_OBJECT, 120 | "surface role already assigned"); 121 | return; 122 | } 123 | #endif 124 | 125 | existing_view = container_of(existing_surface->views.next, 126 | struct weston_view, 127 | surface_link); 128 | 129 | wl_list_for_each_safe(new_view, next, &new_surface->views, surface_link) 130 | weston_view_destroy(new_view); 131 | new_view = weston_view_create(new_surface); 132 | 133 | #ifdef HAVE_NEW_WESTON 134 | new_surface->committed = configure_surface; 135 | new_surface->committed_private = existing_view; 136 | #else 137 | new_surface->configure = configure_surface; 138 | new_surface->configure_private = existing_view; 139 | #endif 140 | new_surface->output = existing_view->output; 141 | } 142 | 143 | static void 144 | configure_panel(struct weston_surface *es, int32_t sx, int32_t sy) 145 | { 146 | #ifdef HAVE_NEW_WESTON 147 | struct shell_helper *helper = es->committed_private; 148 | #else 149 | struct shell_helper *helper = es->configure_private; 150 | #endif 151 | struct weston_view *view; 152 | 153 | view = container_of(es->views.next, struct weston_view, surface_link); 154 | 155 | if (wl_list_empty(&view->layer_link.link)) { 156 | weston_layer_entry_insert(&helper->panel_layer->view_list, &view->layer_link); 157 | weston_compositor_schedule_repaint(es->compositor); 158 | } 159 | } 160 | 161 | static void 162 | shell_helper_set_panel(struct wl_client *client, 163 | struct wl_resource *resource, 164 | struct wl_resource *surface_resource) 165 | { 166 | struct shell_helper *helper = wl_resource_get_user_data(resource); 167 | struct weston_surface *surface = 168 | wl_resource_get_user_data(surface_resource); 169 | struct weston_view *view = container_of(surface->views.next, 170 | struct weston_view, 171 | surface_link); 172 | 173 | /* we need to save the panel's layer so we can use it later on, but 174 | * it hasn't yet been defined because the original surface configure 175 | * function hasn't yet been called. if we call it here we will have 176 | * access to the layer. */ 177 | #ifdef HAVE_NEW_WESTON 178 | surface->committed(surface, 0, 0); 179 | #else 180 | surface->configure(surface, 0, 0); 181 | #endif 182 | 183 | helper->panel_layer = container_of(view->layer_link.link.next, 184 | struct weston_layer, 185 | view_list.link); 186 | 187 | /* set new configure functions that only ensure the surface is in the 188 | * correct layer. */ 189 | #ifdef HAVE_NEW_WESTON 190 | surface->committed = configure_panel; 191 | surface->committed_private = helper; 192 | #else 193 | surface->configure = configure_panel; 194 | surface->configure_private = helper; 195 | #endif 196 | } 197 | 198 | enum SlideState { 199 | SLIDE_STATE_NONE, 200 | SLIDE_STATE_SLIDING_OUT, 201 | SLIDE_STATE_OUT, 202 | SLIDE_STATE_SLIDING_BACK, 203 | SLIDE_STATE_BACK 204 | }; 205 | 206 | enum SlideRequest { 207 | SLIDE_REQUEST_NONE, 208 | SLIDE_REQUEST_OUT, 209 | SLIDE_REQUEST_BACK 210 | }; 211 | 212 | struct slide { 213 | struct weston_surface *surface; 214 | struct weston_view *view; 215 | int x; 216 | int y; 217 | 218 | enum SlideState state; 219 | enum SlideRequest request; 220 | 221 | struct weston_transform transform; 222 | 223 | struct wl_list link; 224 | }; 225 | 226 | static void slide_back(struct slide *slide); 227 | 228 | static void 229 | slide_done_cb(struct weston_view_animation *animation, void *data) 230 | { 231 | struct slide *slide = data; 232 | 233 | slide->state = SLIDE_STATE_OUT; 234 | 235 | wl_list_insert(&slide->view->transform.position.link, 236 | &slide->transform.link); 237 | weston_matrix_init(&slide->transform.matrix); 238 | weston_matrix_translate(&slide->transform.matrix, 239 | slide->x, 240 | slide->y, 241 | 0); 242 | 243 | weston_view_geometry_dirty(slide->view); 244 | weston_compositor_schedule_repaint(slide->surface->compositor); 245 | 246 | if (slide->request == SLIDE_REQUEST_BACK) { 247 | slide->request = SLIDE_REQUEST_NONE; 248 | slide_back(slide); 249 | } 250 | } 251 | 252 | static void 253 | slide_out(struct slide *slide) 254 | { 255 | assert(slide->state == SLIDE_STATE_NONE || slide->state == SLIDE_STATE_BACK); 256 | 257 | slide->state = SLIDE_STATE_SLIDING_OUT; 258 | 259 | weston_move_scale_run(slide->view, slide->x, slide->y, 260 | 1.0, 1.0, 0, 261 | slide_done_cb, slide); 262 | } 263 | 264 | static void 265 | slide_back_done_cb(struct weston_view_animation *animation, void *data) 266 | { 267 | struct slide *slide = data; 268 | 269 | slide->state = SLIDE_STATE_BACK; 270 | 271 | wl_list_remove(&slide->transform.link); 272 | weston_view_geometry_dirty(slide->view); 273 | 274 | if (slide->request == SLIDE_REQUEST_OUT) { 275 | slide->request = SLIDE_REQUEST_NONE; 276 | slide_out(slide); 277 | } else { 278 | wl_list_remove(&slide->link); 279 | free(slide); 280 | } 281 | } 282 | 283 | static void 284 | slide_back(struct slide *slide) 285 | { 286 | assert(slide->state == SLIDE_STATE_OUT); 287 | 288 | slide->state = SLIDE_STATE_SLIDING_BACK; 289 | 290 | weston_move_scale_run(slide->view, -slide->x, -slide->y, 291 | 1.0, 1.0, 0, 292 | slide_back_done_cb, slide); 293 | } 294 | 295 | static void 296 | shell_helper_slide_surface(struct wl_client *client, 297 | struct wl_resource *resource, 298 | struct wl_resource *surface_resource, 299 | int32_t x, 300 | int32_t y) 301 | { 302 | struct shell_helper *helper = wl_resource_get_user_data(resource); 303 | struct weston_surface *surface = 304 | wl_resource_get_user_data(surface_resource); 305 | struct weston_view *view; 306 | struct slide *slide; 307 | 308 | wl_list_for_each(slide, &helper->slide_list, link) { 309 | if (slide->surface == surface) { 310 | if (slide->state == SLIDE_STATE_SLIDING_BACK) 311 | slide->request = SLIDE_REQUEST_OUT; 312 | return; 313 | } 314 | } 315 | 316 | view = container_of(surface->views.next, struct weston_view, surface_link); 317 | 318 | if (!view) 319 | return; 320 | 321 | slide = malloc(sizeof *slide); 322 | if (!slide) 323 | return; 324 | 325 | slide->surface = surface; 326 | slide->view = view; 327 | slide->x = x; 328 | slide->y = y; 329 | 330 | slide->state = SLIDE_STATE_NONE; 331 | slide->request = SLIDE_REQUEST_NONE; 332 | 333 | wl_list_insert(&helper->slide_list, 334 | &slide->link); 335 | 336 | slide_out(slide); 337 | } 338 | 339 | static void 340 | shell_helper_slide_surface_back(struct wl_client *client, 341 | struct wl_resource *resource, 342 | struct wl_resource *surface_resource) 343 | { 344 | struct shell_helper *helper = wl_resource_get_user_data(resource); 345 | struct weston_surface *surface = 346 | wl_resource_get_user_data(surface_resource); 347 | struct weston_view *view; 348 | int found = 0; 349 | struct slide *slide; 350 | 351 | wl_list_for_each(slide, &helper->slide_list, link) { 352 | if (slide->surface == surface) { 353 | found = 1; 354 | break; 355 | } 356 | } 357 | 358 | if (!found || slide->state == SLIDE_STATE_SLIDING_BACK) 359 | return; 360 | 361 | if (slide->state == SLIDE_STATE_SLIDING_OUT) 362 | slide->request = SLIDE_REQUEST_BACK; 363 | else 364 | slide_back(slide); 365 | } 366 | 367 | /* mostly copied from weston's desktop-shell/shell.c */ 368 | static struct weston_view * 369 | shell_curtain_create_view(struct shell_helper *helper, 370 | struct weston_surface *surface) 371 | { 372 | struct weston_view *view; 373 | 374 | if (!surface) 375 | return NULL; 376 | 377 | view = weston_view_create(surface); 378 | if (!view) { 379 | return NULL; 380 | } 381 | 382 | weston_view_set_position(view, 0, 0); 383 | weston_surface_set_color(surface, 0.0, 0.0, 0.0, 0.7); 384 | weston_layer_entry_insert(&helper->curtain_layer.view_list, 385 | &view->layer_link); 386 | pixman_region32_init_rect(&surface->input, 0, 0, 387 | surface->width, 388 | surface->height); 389 | 390 | return view; 391 | } 392 | 393 | static void 394 | curtain_done_hide(struct weston_view_animation *animation, 395 | void *data); 396 | 397 | static void 398 | curtain_fade_done(struct weston_view_animation *animation, 399 | void *data) 400 | { 401 | struct shell_helper *helper = data; 402 | 403 | if (!helper->curtain_show) 404 | wl_list_remove(&helper->curtain_layer.link); 405 | 406 | helper->curtain_animation = NULL; 407 | } 408 | 409 | static void 410 | shell_helper_curtain(struct wl_client *client, 411 | struct wl_resource *resource, 412 | struct wl_resource *surface_resource, 413 | int32_t show) 414 | { 415 | struct shell_helper *helper = wl_resource_get_user_data(resource); 416 | struct weston_surface *surface = 417 | wl_resource_get_user_data(surface_resource); 418 | 419 | helper->curtain_show = show; 420 | 421 | if (show) { 422 | if (helper->curtain_animation) { 423 | weston_fade_update(helper->curtain_animation, 0.7); 424 | return; 425 | } 426 | 427 | if (!helper->curtain_view) { 428 | weston_layer_init(&helper->curtain_layer, 429 | &helper->panel_layer->link); 430 | 431 | helper->curtain_view = shell_curtain_create_view(helper, surface); 432 | 433 | /* we need to assign an output to the view before we can 434 | * fade it in */ 435 | weston_view_geometry_dirty(helper->curtain_view); 436 | weston_view_update_transform(helper->curtain_view); 437 | } else { 438 | wl_list_insert(&helper->panel_layer->link, &helper->curtain_layer.link); 439 | } 440 | 441 | helper->curtain_animation = weston_fade_run( 442 | helper->curtain_view, 443 | 0.0, 0.7, 400, 444 | curtain_fade_done, helper); 445 | 446 | } else { 447 | if (helper->curtain_animation) { 448 | weston_fade_update(helper->curtain_animation, 0.0); 449 | return; 450 | } 451 | 452 | /* should never happen in theory */ 453 | if (!helper->curtain_view) 454 | return; 455 | 456 | helper->curtain_animation = weston_fade_run( 457 | helper->curtain_view, 458 | 0.7, 0.0, 400, 459 | curtain_fade_done, helper); 460 | } 461 | } 462 | 463 | static const struct shell_helper_interface helper_implementation = { 464 | shell_helper_move_surface, 465 | shell_helper_add_surface_to_layer, 466 | shell_helper_set_panel, 467 | shell_helper_slide_surface, 468 | shell_helper_slide_surface_back, 469 | shell_helper_curtain 470 | }; 471 | 472 | static void 473 | bind_helper(struct wl_client *client, void *data, uint32_t version, uint32_t id) 474 | { 475 | struct shell_helper *helper = data; 476 | struct wl_resource *resource; 477 | 478 | resource = wl_resource_create(client, &shell_helper_interface, 1, id); 479 | if (resource) 480 | wl_resource_set_implementation(resource, &helper_implementation, 481 | helper, NULL); 482 | } 483 | 484 | static void 485 | helper_destroy(struct wl_listener *listener, void *data) 486 | { 487 | struct shell_helper *helper = 488 | container_of(listener, struct shell_helper, destroy_listener); 489 | 490 | free(helper); 491 | } 492 | 493 | WL_EXPORT int 494 | module_init(struct weston_compositor *ec, 495 | int *argc, char *argv[]) 496 | { 497 | struct shell_helper *helper; 498 | 499 | helper = zalloc(sizeof *helper); 500 | if (helper == NULL) 501 | return -1; 502 | 503 | helper->compositor = ec; 504 | helper->panel_layer = NULL; 505 | helper->curtain_view = NULL; 506 | helper->curtain_show = 0; 507 | 508 | wl_list_init(&helper->slide_list); 509 | 510 | helper->destroy_listener.notify = helper_destroy; 511 | wl_signal_add(&ec->destroy_signal, &helper->destroy_listener); 512 | 513 | if (wl_global_create(ec->wl_display, &shell_helper_interface, 1, 514 | helper, bind_helper) == NULL) 515 | return -1; 516 | 517 | return 0; 518 | } 519 | -------------------------------------------------------------------------------- /shell/style.css: -------------------------------------------------------------------------------- 1 | .maynard-panel { 2 | background-color: alpha(black, 0.7); 3 | } 4 | 5 | .maynard-system { 6 | background-color: #6d6d6d; 7 | padding: 13px; 8 | color: #fcfcfc; 9 | } 10 | 11 | .maynard-system:hover { 12 | background-color: alpha(#6d6d6d, 0.8); 13 | color: white; 14 | } 15 | 16 | .maynard-audio { 17 | background-color: #b4b4b4; 18 | color: #fcfcfc; 19 | padding: 13px; 20 | } 21 | 22 | .maynard-audio:hover { 23 | background-color: alpha(#b4b4b4, 0.8); 24 | color: white; 25 | } 26 | 27 | .maynard-apps { 28 | color: #bebebe; 29 | } 30 | 31 | .maynard-apps:hover { 32 | background-color: alpha(black, 0.2); 33 | color: white; 34 | } 35 | 36 | .maynard-clock { 37 | background-color: #929292; 38 | color: white; 39 | } 40 | 41 | .maynard-grid { 42 | background-color: alpha(black, 0.6); 43 | } 44 | 45 | .maynard-grid-item { 46 | background-color: alpha(black, 0.6); 47 | color: white; 48 | font: Droid Sans 12; 49 | border-style: solid; 50 | border-color: #6d6d6d; 51 | border-width: 1px; 52 | border-radius: 1px; 53 | } 54 | 55 | .maynard-grid-label { 56 | background-color: #929292; 57 | } -------------------------------------------------------------------------------- /shell/vertical-clock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Jonny Lamb 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "vertical-clock.h" 25 | 26 | #define GNOME_DESKTOP_USE_UNSTABLE_API 27 | #include 28 | 29 | #include "panel.h" 30 | 31 | struct MaynardVerticalClockPrivate { 32 | GtkWidget *label; 33 | 34 | GnomeWallClock *wall_clock; 35 | }; 36 | 37 | G_DEFINE_TYPE(MaynardVerticalClock, maynard_vertical_clock, GTK_TYPE_BOX) 38 | 39 | /* this widget takes up the entire width of the panel and displays 40 | * padding for the first (panel width - vertical clock width) pixels, 41 | * then shows the vertical clock itself. the idea is to put this into 42 | * a GtkRevealer and only show it when appropriate. */ 43 | 44 | static void 45 | maynard_vertical_clock_init (MaynardVerticalClock *self) 46 | { 47 | self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, 48 | MAYNARD_VERTICAL_CLOCK_TYPE, 49 | MaynardVerticalClockPrivate); 50 | } 51 | 52 | static void 53 | wall_clock_notify_cb (GnomeWallClock *wall_clock, 54 | GParamSpec *pspec, 55 | MaynardVerticalClock *self) 56 | { 57 | GDateTime *datetime; 58 | gchar *str; 59 | 60 | datetime = g_date_time_new_now_local (); 61 | 62 | str = g_date_time_format (datetime, 63 | "%H\n" 64 | ":\n" 65 | "%M"); 66 | gtk_label_set_markup (GTK_LABEL (self->priv->label), str); 67 | 68 | g_free (str); 69 | g_date_time_unref (datetime); 70 | } 71 | 72 | static void 73 | maynard_vertical_clock_constructed (GObject *object) 74 | { 75 | MaynardVerticalClock *self = MAYNARD_VERTICAL_CLOCK (object); 76 | GtkWidget *padding; 77 | gint width; 78 | 79 | G_OBJECT_CLASS (maynard_vertical_clock_parent_class)->constructed (object); 80 | 81 | self->priv->wall_clock = g_object_new (GNOME_TYPE_WALL_CLOCK, NULL); 82 | g_signal_connect (self->priv->wall_clock, "notify::clock", 83 | G_CALLBACK (wall_clock_notify_cb), self); 84 | 85 | gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL); 86 | 87 | /* a label just to pad things out to the correct width */ 88 | width = MAYNARD_PANEL_WIDTH - MAYNARD_VERTICAL_CLOCK_WIDTH; 89 | 90 | padding = gtk_label_new (""); 91 | gtk_style_context_add_class (gtk_widget_get_style_context (padding), 92 | "maynard-clock"); 93 | gtk_widget_set_size_request (padding, width, -1); 94 | gtk_box_pack_start (GTK_BOX (self), padding, FALSE, FALSE, 0); 95 | 96 | /* the actual clock label */ 97 | self->priv->label = gtk_label_new (""); 98 | gtk_style_context_add_class (gtk_widget_get_style_context (self->priv->label), 99 | "maynard-clock"); 100 | gtk_label_set_justify (GTK_LABEL (self->priv->label), GTK_JUSTIFY_CENTER); 101 | gtk_widget_set_size_request (self->priv->label, 102 | MAYNARD_VERTICAL_CLOCK_WIDTH, -1); 103 | gtk_box_pack_start (GTK_BOX (self), self->priv->label, FALSE, FALSE, 0); 104 | 105 | wall_clock_notify_cb (self->priv->wall_clock, NULL, self); 106 | } 107 | 108 | static void 109 | maynard_vertical_clock_dispose (GObject *object) 110 | { 111 | MaynardVerticalClock *self = MAYNARD_VERTICAL_CLOCK (object); 112 | 113 | G_OBJECT_CLASS (maynard_vertical_clock_parent_class)->dispose (object); 114 | } 115 | 116 | static void 117 | maynard_vertical_clock_class_init (MaynardVerticalClockClass *klass) 118 | { 119 | GObjectClass *object_class = (GObjectClass *)klass; 120 | 121 | object_class->constructed = maynard_vertical_clock_constructed; 122 | object_class->dispose = maynard_vertical_clock_dispose; 123 | 124 | g_type_class_add_private (object_class, sizeof (MaynardVerticalClockPrivate)); 125 | } 126 | 127 | GtkWidget * 128 | maynard_vertical_clock_new (void) 129 | { 130 | return g_object_new (MAYNARD_VERTICAL_CLOCK_TYPE, 131 | NULL); 132 | } 133 | -------------------------------------------------------------------------------- /shell/vertical-clock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Collabora Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of the 7 | * License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Author: Jonny Lamb 20 | */ 21 | 22 | #ifndef __MAYNARD_VERTICAL_CLOCK_H__ 23 | #define __MAYNARD_VERTICAL_CLOCK_H__ 24 | 25 | #include 26 | 27 | #define MAYNARD_VERTICAL_CLOCK_TYPE (maynard_vertical_clock_get_type ()) 28 | #define MAYNARD_VERTICAL_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAYNARD_VERTICAL_CLOCK_TYPE, MaynardVerticalClock)) 29 | #define MAYNARD_VERTICAL_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAYNARD_VERTICAL_CLOCK_TYPE, MaynardVerticalClockClass)) 30 | #define MAYNARD_IS_VERTICAL_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAYNARD_VERTICAL_CLOCK_TYPE)) 31 | #define MAYNARD_IS_VERTICAL_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAYNARD_VERTICAL_CLOCK_TYPE)) 32 | #define MAYNARD_VERTICAL_CLOCK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAYNARD_VERTICAL_CLOCK_TYPE, MaynardVerticalClockClass)) 33 | 34 | typedef struct MaynardVerticalClock MaynardVerticalClock; 35 | typedef struct MaynardVerticalClockClass MaynardVerticalClockClass; 36 | typedef struct MaynardVerticalClockPrivate MaynardVerticalClockPrivate; 37 | 38 | struct MaynardVerticalClock 39 | { 40 | GtkBox parent; 41 | 42 | MaynardVerticalClockPrivate *priv; 43 | }; 44 | 45 | struct MaynardVerticalClockClass 46 | { 47 | GtkBoxClass parent_class; 48 | }; 49 | 50 | #define MAYNARD_VERTICAL_CLOCK_WIDTH 25 51 | 52 | GType maynard_vertical_clock_get_type (void) G_GNUC_CONST; 53 | 54 | GtkWidget * maynard_vertical_clock_new (void); 55 | 56 | #endif /* __MAYNARD_VERTICAL_CLOCK_H__ */ 57 | --------------------------------------------------------------------------------