summaryrefslogtreecommitdiff
path: root/libs/gtkmm2ext
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2008-06-02 21:41:35 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2008-06-02 21:41:35 +0000
commit449aab3c465bbbf66d221fac3d7ea559f1720357 (patch)
tree6843cc40c88250a132acac701271f1504cd2df04 /libs/gtkmm2ext
parent9c0d7d72d70082a54f823cd44c0ccda5da64bb6f (diff)
rollback to 3428, before the mysterious removal of libs/* at 3431/3432
git-svn-id: svn://localhost/ardour2/branches/3.0@3435 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/gtkmm2ext')
-rw-r--r--libs/gtkmm2ext/.cvsignore7
-rw-r--r--libs/gtkmm2ext/AUTHORS2
-rw-r--r--libs/gtkmm2ext/COPYING340
-rw-r--r--libs/gtkmm2ext/ChangeLog0
-rw-r--r--libs/gtkmm2ext/NEWS0
-rw-r--r--libs/gtkmm2ext/README0
-rw-r--r--libs/gtkmm2ext/SConscript97
-rw-r--r--libs/gtkmm2ext/auto_spin.cc268
-rw-r--r--libs/gtkmm2ext/barcontroller.cc469
-rw-r--r--libs/gtkmm2ext/bindable_button.cc139
-rw-r--r--libs/gtkmm2ext/binding_proxy.cc101
-rw-r--r--libs/gtkmm2ext/choice.cc70
-rw-r--r--libs/gtkmm2ext/click_box.cc153
-rw-r--r--libs/gtkmm2ext/dndtreeview.cc71
-rw-r--r--libs/gtkmm2ext/fastmeter.cc567
-rw-r--r--libs/gtkmm2ext/focus_entry.cc50
-rw-r--r--libs/gtkmm2ext/gettext.h82
-rw-r--r--libs/gtkmm2ext/grouped_buttons.cc96
-rw-r--r--libs/gtkmm2ext/gtk_ui.cc656
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/.cvsignore1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/auto_spin.h71
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/barcontroller.h104
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/bindable_button.h81
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/binding_proxy.h55
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/choice.h44
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/click_box.h65
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/dndtreeview.h165
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/doi.h36
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/fastmeter.h92
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/focus_entry.h41
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h48
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/gtk_ui.h177
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/gtkutils.h33
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/hexentry.h58
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/idle_adjustment.h45
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/pathlist.h63
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/pixfader.h78
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/pixscroller.h64
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/popup.h59
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/prompter.h72
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/scroomer.h88
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/selector.h110
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/slider_controller.h83
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/stateful_button.h83
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/stop_signal.h33
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/sync-menu.h44
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/tearoff.h70
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/textviewer.h57
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/utils.h58
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/window_title.h63
-rw-r--r--libs/gtkmm2ext/gtkutils.cc22
-rw-r--r--libs/gtkmm2ext/hexentry.cc111
-rw-r--r--libs/gtkmm2ext/i18n.h11
-rw-r--r--libs/gtkmm2ext/idle_adjustment.cc73
-rw-r--r--libs/gtkmm2ext/libgtkmm2ext.pc.in11
-rw-r--r--libs/gtkmm2ext/libgtkmm2ext.spec.in68
-rw-r--r--libs/gtkmm2ext/pathlist.cc124
-rw-r--r--libs/gtkmm2ext/pixfader.cc309
-rw-r--r--libs/gtkmm2ext/pixscroller.cc265
-rw-r--r--libs/gtkmm2ext/po/el_GR.po59
-rw-r--r--libs/gtkmm2ext/po/es_ES.po58
-rw-r--r--libs/gtkmm2ext/po/pl_PL.po53
-rw-r--r--libs/gtkmm2ext/po/pt_BR.po59
-rw-r--r--libs/gtkmm2ext/po/ru_RU.po58
-rw-r--r--libs/gtkmm2ext/popup.cc139
-rw-r--r--libs/gtkmm2ext/prompter.cc109
-rw-r--r--libs/gtkmm2ext/scroomer.cc389
-rw-r--r--libs/gtkmm2ext/selector.cc234
-rw-r--r--libs/gtkmm2ext/slider_controller.cc91
-rw-r--r--libs/gtkmm2ext/stateful_button.cc102
-rw-r--r--libs/gtkmm2ext/sync-menu.c977
-rw-r--r--libs/gtkmm2ext/tearoff.cc197
-rw-r--r--libs/gtkmm2ext/textviewer.cc127
-rw-r--r--libs/gtkmm2ext/utils.cc93
-rw-r--r--libs/gtkmm2ext/window_title.cc45
75 files changed, 9093 insertions, 0 deletions
diff --git a/libs/gtkmm2ext/.cvsignore b/libs/gtkmm2ext/.cvsignore
new file mode 100644
index 0000000000..d7120405dc
--- /dev/null
+++ b/libs/gtkmm2ext/.cvsignore
@@ -0,0 +1,7 @@
+libgtkmmext.pc
+libgtkmmext.spec
+version.cc
+*.mo
+*.pot
+*.os
+*.dylib
diff --git a/libs/gtkmm2ext/AUTHORS b/libs/gtkmm2ext/AUTHORS
new file mode 100644
index 0000000000..396f223e8c
--- /dev/null
+++ b/libs/gtkmm2ext/AUTHORS
@@ -0,0 +1,2 @@
+Written primarily by Paul Davis.
+Porting to gtkmm2 and sigc++2 work done by Taybin Rutkin.
diff --git a/libs/gtkmm2ext/COPYING b/libs/gtkmm2ext/COPYING
new file mode 100644
index 0000000000..d60c31a97a
--- /dev/null
+++ b/libs/gtkmm2ext/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/libs/gtkmm2ext/ChangeLog b/libs/gtkmm2ext/ChangeLog
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/libs/gtkmm2ext/ChangeLog
diff --git a/libs/gtkmm2ext/NEWS b/libs/gtkmm2ext/NEWS
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/libs/gtkmm2ext/NEWS
diff --git a/libs/gtkmm2ext/README b/libs/gtkmm2ext/README
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/libs/gtkmm2ext/README
diff --git a/libs/gtkmm2ext/SConscript b/libs/gtkmm2ext/SConscript
new file mode 100644
index 0000000000..a0ef88e6d1
--- /dev/null
+++ b/libs/gtkmm2ext/SConscript
@@ -0,0 +1,97 @@
+# -*- python -*-
+
+import os
+import os.path
+import glob
+
+Import('env final_prefix install_prefix libraries i18n')
+
+gtkmm2ext = env.Copy()
+gtkmm2ext.Merge ([
+ libraries['sigc2'],
+ libraries['pbd'],
+ libraries['gtk2'],
+ libraries['glibmm2'],
+ libraries['pangomm'],
+ libraries['atkmm'],
+ libraries['gdkmm2'],
+ libraries['gtkmm2'],
+ libraries['cairomm']
+ ])
+
+#
+# this defines the version number of libgtkmm2ext
+#
+
+domain = 'libgtkmm2ext'
+
+gtkmm2ext.Append(DOMAIN=domain,MAJOR=0,MINOR=8,MICRO=3)
+gtkmm2ext.Append(CXXFLAGS="-DPACKAGE=\\\"" + domain + "\\\"")
+gtkmm2ext.Append(CXXFLAGS=["-DLIBSIGC_DISABLE_DEPRECATED", "-DGLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED", "-DGLIBMM_PROPERTIES_ENABLED"])
+#gtkmm2ext.Append(CPPPATH='#libs/surfaces/control_protocol')
+gtkmm2ext.Append(PACKAGE=domain)
+gtkmm2ext.Append(POTFILE=domain + '.pot')
+
+if gtkmm2ext['IS_OSX']:
+ gtkmm2ext.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
+
+extra_sources = []
+
+gtkmm2ext_files = Split("""
+auto_spin.cc
+barcontroller.cc
+binding_proxy.cc
+choice.cc
+click_box.cc
+dndtreeview.cc
+fastmeter.cc
+focus_entry.cc
+grouped_buttons.cc
+gtk_ui.cc
+hexentry.cc
+idle_adjustment.cc
+pathlist.cc
+pixfader.cc
+pixscroller.cc
+popup.cc
+prompter.cc
+scroomer.cc
+selector.cc
+slider_controller.cc
+stateful_button.cc
+tearoff.cc
+textviewer.cc
+utils.cc
+version.cc
+window_title.cc
+""")
+
+gtkosx_files=Split("""
+sync-menu.c
+""")
+
+if gtkmm2ext['GTKOSX']:
+ extra_sources += gtkosx_files
+ gtkmm2ext.Append (CCFLAGS="-DTOP_MENUBAR -DGTKOSX")
+ gtkmm2ext.Append (LINKFLAGS="-framework Carbon")
+
+gtkmm2ext.VersionBuild(['version.cc','gtkmm2ext/version.h'], [])
+
+gtkmm2ext.Append(CCFLAGS="-D_REENTRANT")
+gtkmm2ext.Append(CCFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
+
+libgtkmm2ext = gtkmm2ext.SharedLibrary('gtkmm2ext', gtkmm2ext_files + extra_sources)
+
+Default(libgtkmm2ext)
+
+if env['NLS']:
+ i18n (gtkmm2ext, gtkmm2ext_files, env)
+
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour3'), libgtkmm2ext))
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript', 'i18n.h', 'gettext.h'] +
+ gtkmm2ext_files +
+ gtkosx_files +
+ glob.glob('po/*.po') +
+ glob.glob('gtkmm2ext/*.h')))
diff --git a/libs/gtkmm2ext/auto_spin.cc b/libs/gtkmm2ext/auto_spin.cc
new file mode 100644
index 0000000000..2e051b5be8
--- /dev/null
+++ b/libs/gtkmm2ext/auto_spin.cc
@@ -0,0 +1,268 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <gtkmm2ext/auto_spin.h>
+#include <cmath>
+
+using namespace Gtkmm2ext;
+using namespace std;
+
+#define upper adjustment.get_upper()
+#define lower adjustment.get_lower()
+#define step_increment adjustment.get_step_increment()
+#define page_increment adjustment.get_page_increment()
+
+const unsigned int AutoSpin::initial_timer_interval = 500; /* msecs */
+const unsigned int AutoSpin::timer_interval = 20; /* msecs */
+const unsigned int AutoSpin::climb_timer_calls = 5; /* between climbing */
+
+AutoSpin::AutoSpin (Gtk::Adjustment &adjr, gfloat cr, bool round_to_steps_yn)
+ : adjustment (adjr),
+ climb_rate (cr)
+
+{
+ initial = adjustment.get_value();
+ left_is_decrement = true;
+ wrap = false;
+ have_timer = false;
+ need_timer = false;
+ timer_calls = 0;
+ round_to_steps = round_to_steps_yn;
+}
+
+void
+AutoSpin::stop_timer ()
+{
+ if (have_timer) {
+ g_source_remove (timeout_tag);
+ have_timer = false;
+ }
+}
+
+gint
+AutoSpin::stop_spinning (GdkEventButton *ev)
+{
+ need_timer = false;
+ stop_timer ();
+ return FALSE;
+}
+
+gint
+AutoSpin::button_press (GdkEventButton *ev)
+{
+ bool shifted = false;
+ bool control = false;
+ bool with_decrement = false;
+
+ stop_spinning (0);
+
+ if (ev->state & GDK_SHIFT_MASK) {
+ /* use page shift */
+
+ shifted = true;
+ }
+
+ if (ev->state & GDK_CONTROL_MASK) {
+ /* go to upper/lower bound on button1/button2 */
+
+ control = true;
+ }
+
+ /* XXX should figure out which button is left/right */
+
+ switch (ev->button) {
+ case 1:
+ if (control) {
+ set_value (left_is_decrement ? lower : upper);
+ return TRUE;
+ } else {
+ if (left_is_decrement) {
+ with_decrement = true;
+ } else {
+ with_decrement = false;
+ }
+ }
+ break;
+
+ case 2:
+ if (!control) {
+ set_value (initial);
+ }
+ return TRUE;
+ break;
+
+ case 3:
+ if (control) {
+ set_value (left_is_decrement ? upper : lower);
+ return TRUE;
+ }
+ break;
+
+ case 4:
+ if (!control) {
+ adjust_value (shifted ? page_increment : step_increment);
+ } else {
+ set_value (upper);
+ }
+ return TRUE;
+ break;
+
+ case 5:
+ if (!control) {
+ adjust_value (shifted ? -page_increment : -step_increment);
+ } else {
+ set_value (lower);
+ }
+ return TRUE;
+ break;
+ }
+
+ start_spinning (with_decrement, shifted);
+ return TRUE;
+}
+
+void
+AutoSpin::start_spinning (bool decrement, bool page)
+{
+ timer_increment = page ? page_increment : step_increment;
+
+ if (decrement) {
+ timer_increment = -timer_increment;
+ }
+
+ adjust_value (timer_increment);
+
+ have_timer = true;
+ timer_calls = 0;
+ timeout_tag = g_timeout_add (initial_timer_interval,
+ AutoSpin::_timer,
+ this);
+}
+
+gint
+AutoSpin::_timer (void *arg)
+{
+ return ((AutoSpin *) arg)->timer ();
+}
+
+void
+AutoSpin::set_value (gfloat value)
+{
+ if (round_to_steps)
+ adjustment.set_value (floor((value / step_increment) + 0.5f) * step_increment);
+ else
+ adjustment.set_value (value);
+}
+
+bool
+AutoSpin::adjust_value (gfloat increment)
+{
+ gfloat val;
+ bool done = false;
+
+ val = adjustment.get_value();
+
+ val += increment;
+
+ if (val > upper) {
+ if (wrap) {
+ val = lower;
+ } else {
+ val = upper;
+ done = true;
+ }
+ } else if (val < lower) {
+ if (wrap) {
+ val = upper;
+ } else {
+ val = lower;
+ done = true;
+ }
+ }
+
+ set_value(val);
+ return done;
+}
+
+gint
+AutoSpin::timer ()
+{
+ bool done;
+ int retval = FALSE;
+
+ done = adjust_value (timer_increment);
+
+ if (need_timer) {
+
+ /* we're in the initial call, which happened
+ after initial_timer_interval msecs. Now
+ request a much more frequent update.
+ */
+
+ timeout_tag = g_timeout_add (timer_interval,
+ _timer,
+ this);
+ have_timer = true;
+ need_timer = false;
+
+ /* cancel this initial timeout */
+
+ retval = FALSE;
+
+ } else {
+ /* this is the regular "fast" call after each
+ timer_interval msecs.
+ */
+
+ if (timer_calls < climb_timer_calls) {
+ timer_calls++;
+ } else {
+ if (climb_rate > 0.0) {
+ if (timer_increment > 0) {
+ timer_increment += climb_rate;
+ } else {
+ timer_increment -= climb_rate;
+ }
+ }
+ timer_calls = 0;
+ }
+
+ if (!done) {
+ retval = TRUE;
+ }
+ }
+
+ return retval;
+}
+
+void
+AutoSpin::set_bounds (gfloat init, gfloat up, gfloat down, bool with_reset)
+{
+ adjustment.set_upper(up);
+ adjustment.set_lower(down);
+
+ initial = init;
+
+ adjustment.changed ();
+
+ if (with_reset) {
+ adjustment.set_value (init);
+ }
+}
diff --git a/libs/gtkmm2ext/barcontroller.cc b/libs/gtkmm2ext/barcontroller.cc
new file mode 100644
index 0000000000..a3b2a13bf5
--- /dev/null
+++ b/libs/gtkmm2ext/barcontroller.cc
@@ -0,0 +1,469 @@
+/*
+ Copyright (C) 2004 Paul Davis
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <string>
+#include <climits>
+#include <cstdio>
+#include <cmath>
+#include <algorithm>
+
+#include <pbd/controllable.h>
+
+#include <gtkmm2ext/gtk_ui.h>
+#include <gtkmm2ext/utils.h>
+#include <gtkmm2ext/barcontroller.h>
+
+#include "i18n.h"
+
+using namespace std;
+using namespace Gtk;
+using namespace Gtkmm2ext;
+
+BarController::BarController (Gtk::Adjustment& adj,
+ PBD::Controllable& mc,
+ sigc::slot<void,char*,unsigned int> lc)
+
+ : adjustment (adj),
+ binding_proxy (mc),
+ label_callback (lc),
+ spinner (adjustment)
+
+{
+ _style = LeftToRight;
+ grabbed = false;
+ switching = false;
+ switch_on_release = false;
+ with_text = true;
+ use_parent = false;
+
+ layout = darea.create_pango_layout("");
+
+ set_shadow_type (SHADOW_NONE);
+
+ initial_value = adjustment.get_value ();
+
+ adjustment.signal_value_changed().connect (mem_fun (*this, &Gtk::Widget::queue_draw));
+ adjustment.signal_changed().connect (mem_fun (*this, &Gtk::Widget::queue_draw));
+
+ darea.add_events (Gdk::BUTTON_RELEASE_MASK|
+ Gdk::BUTTON_PRESS_MASK|
+ Gdk::POINTER_MOTION_MASK|
+ Gdk::ENTER_NOTIFY_MASK|
+ Gdk::LEAVE_NOTIFY_MASK|
+ Gdk::SCROLL_MASK);
+
+ darea.signal_expose_event().connect (mem_fun (*this, &BarController::expose));
+ darea.signal_motion_notify_event().connect (mem_fun (*this, &BarController::motion));
+ darea.signal_button_press_event().connect (mem_fun (*this, &BarController::button_press), false);
+ darea.signal_button_release_event().connect (mem_fun (*this, &BarController::button_release), false);
+ darea.signal_scroll_event().connect (mem_fun (*this, &BarController::scroll));
+
+ spinner.signal_activate().connect (mem_fun (*this, &BarController::entry_activated));
+ spinner.signal_focus_out_event().connect (mem_fun (*this, &BarController::entry_focus_out));
+ spinner.set_digits (3);
+
+ add (darea);
+ show_all ();
+}
+
+void
+BarController::drop_grab ()
+{
+ if (grabbed) {
+ grabbed = false;
+ darea.remove_modal_grab();
+ StopGesture ();
+ }
+}
+
+bool
+BarController::button_press (GdkEventButton* ev)
+{
+ double fract;
+
+ if (binding_proxy.button_press_handler (ev)) {
+ return true;
+ }
+
+ switch (ev->button) {
+ case 1:
+ if (ev->type == GDK_2BUTTON_PRESS) {
+ switch_on_release = true;
+ drop_grab ();
+ } else {
+ switch_on_release = false;
+ darea.add_modal_grab();
+ grabbed = true;
+ grab_x = ev->x;
+ grab_window = ev->window;
+ StartGesture ();
+ }
+ return true;
+ break;
+
+ case 2:
+ fract = ev->x / (darea.get_width() - 2.0);
+ adjustment.set_value (adjustment.get_lower() + fract * (adjustment.get_upper() - adjustment.get_lower()));
+
+ case 3:
+ break;
+
+ case 4:
+ case 5:
+ break;
+ }
+
+ return false;
+}
+
+bool
+BarController::button_release (GdkEventButton* ev)
+{
+ drop_grab ();
+
+ switch (ev->button) {
+ case 1:
+ if (switch_on_release) {
+ Glib::signal_idle().connect (mem_fun (*this, &BarController::switch_to_spinner));
+ return true;
+ }
+
+ if ((ev->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)) == GDK_SHIFT_MASK) {
+ adjustment.set_value (initial_value);
+ } else {
+ double scale;
+
+ if ((ev->state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) {
+ scale = 0.01;
+ } else if (ev->state & GDK_CONTROL_MASK) {
+ scale = 0.1;
+ } else {
+ scale = 1.0;
+ }
+
+ mouse_control (ev->x, ev->window, scale);
+ }
+ break;
+
+ case 2:
+ break;
+
+ case 3:
+ return false;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool
+BarController::scroll (GdkEventScroll* ev)
+{
+ double scale;
+
+ if ((ev->state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) {
+ scale = 0.01;
+ } else if (ev->state & GDK_CONTROL_MASK) {
+ scale = 0.1;
+ } else {
+ scale = 1.0;
+ }
+
+ switch (ev->direction) {
+ case GDK_SCROLL_UP:
+ case GDK_SCROLL_RIGHT:
+ adjustment.set_value (adjustment.get_value() + (scale * adjustment.get_step_increment()));
+ break;
+
+ case GDK_SCROLL_DOWN:
+ case GDK_SCROLL_LEFT:
+ adjustment.set_value (adjustment.get_value() - (scale * adjustment.get_step_increment()));
+ break;
+ }
+
+ return true;
+}
+
+bool
+BarController::motion (GdkEventMotion* ev)
+{
+ double scale;
+
+ if (!grabbed) {
+ return true;
+ }
+
+ if ((ev->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)) == GDK_SHIFT_MASK) {
+ return TRUE;
+ }
+
+ if ((ev->state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) {
+ scale = 0.01;
+ } else if (ev->state & GDK_CONTROL_MASK) {
+ scale = 0.1;
+ } else {
+ scale = 1.0;
+ }
+
+ return mouse_control (ev->x, ev->window, scale);
+}
+
+gint
+BarController::mouse_control (double x, GdkWindow* window, double scaling)
+{
+ double fract = 0.0;
+ double delta;
+
+ if (window != grab_window) {
+ grab_x = x;
+ grab_window = window;
+ return TRUE;
+ }
+
+ delta = x - grab_x;
+ grab_x = x;
+
+ switch (_style) {
+ case Line:
+ case LeftToRight:
+ fract = scaling * (delta / (darea.get_width() - 2));
+ fract = min (1.0, fract);
+ fract = max (-1.0, fract);
+ adjustment.set_value (adjustment.get_value() + fract * (adjustment.get_upper() - adjustment.get_lower()));
+ break;
+
+ default:
+ fract = 0.0;
+ }
+
+
+ return TRUE;
+}
+
+bool
+BarController::expose (GdkEventExpose* event)
+{
+ Glib::RefPtr<Gdk::Window> win (darea.get_window());
+ Widget* parent;
+ gint x1=0, x2=0, y1=0, y2=0;
+ gint w, h;
+ double fract;
+
+ fract = ((adjustment.get_value() - adjustment.get_lower()) /
+ (adjustment.get_upper() - adjustment.get_lower()));
+
+ switch (_style) {
+ case Line:
+ w = darea.get_width() - 1;
+ h = darea.get_height();
+ x1 = (gint) floor (w * fract);
+ x2 = x1;
+ y1 = 0;
+ y2 = h - 1;
+
+ if (use_parent) {
+ parent = get_parent();
+
+ if (parent) {
+ win->draw_rectangle (parent->get_style()->get_fg_gc (parent->get_state()),
+ true,
+ 0, 0, darea.get_width(), darea.get_height());
+ }
+
+ } else {
+
+ win->draw_rectangle (get_style()->get_bg_gc (get_state()),
+ true,
+ 0, 0, darea.get_width() - ((darea.get_width()+1) % 2), darea.get_height());
+ }
+
+ win->draw_line (get_style()->get_fg_gc (get_state()), x1, 0, x1, h);
+ break;
+
+ case CenterOut:
+ break;
+
+ case LeftToRight:
+
+ w = darea.get_width() - 2;
+ h = darea.get_height() - 2;
+
+ x1 = 0;
+ x2 = (gint) floor (w * fract);
+ y1 = 0;
+ y2 = h - 1;
+
+ win->draw_rectangle (get_style()->get_bg_gc (get_state()),
+ false,
+ 0, 0, darea.get_width() - 1, darea.get_height() - 1);
+
+ /* draw active box */
+
+ win->draw_rectangle (get_style()->get_fg_gc (get_state()),
+ true,
+ 1 + x1,
+ 1 + y1,
+ x2,
+ 1 + y2);
+
+ /* draw inactive box */
+
+ win->draw_rectangle (get_style()->get_fg_gc (STATE_INSENSITIVE),
+ true,
+ 1 + x2,
+ 1 + y1,
+ w - x2,
+ 1 + y2);
+
+ break;
+
+ case RightToLeft:
+ break;
+ case TopToBottom:
+ break;
+ case BottomToTop:
+ break;
+ }
+
+ if (with_text) {
+ /* draw label */
+
+ char buf[64];
+ buf[0] = '\0';
+
+ if (label_callback)
+ label_callback (buf, 64);
+
+ if (buf[0] != '\0') {
+
+ layout->set_text (buf);
+
+ int width, height;
+ layout->get_pixel_size (width, height);
+
+ int xpos;
+
+ xpos = max (3, 1 + (x2 - (width/2)));
+ xpos = min (darea.get_width() - width - 3, xpos);
+
+ win->draw_layout (get_style()->get_text_gc (get_state()),
+ xpos,
+ (darea.get_height()/2) - (height/2),
+ layout);
+ }
+ }
+
+ return true;
+}
+
+void
+BarController::set_with_text (bool yn)
+{
+ if (with_text != yn) {
+ with_text = yn;
+ queue_draw ();
+ }
+}
+
+void
+BarController::set_style (Style s)
+{
+ _style = s;
+ darea.queue_draw ();
+}
+
+gint
+BarController::switch_to_bar ()
+{
+ if (switching) {
+ return FALSE;
+ }
+
+ switching = true;
+
+ if (get_child() == &darea) {
+ return FALSE;
+ }
+
+ remove ();
+ add (darea);
+ darea.show ();
+
+ switching = false;
+ return FALSE;
+}
+
+gint
+BarController::switch_to_spinner ()
+{
+ if (switching) {
+ return FALSE;
+ }
+
+ switching = true;
+
+ if (get_child() == &spinner) {
+ return FALSE;
+ }
+
+ remove ();
+ add (spinner);
+ spinner.show ();
+ spinner.select_region (0, spinner.get_text_length());
+ spinner.grab_focus ();
+
+ switching = false;
+ return FALSE;
+}
+
+void
+BarController::entry_activated ()
+{
+ string text = spinner.get_text ();
+ float val;
+
+ if (sscanf (text.c_str(), "%f", &val) == 1) {
+ adjustment.set_value (val);
+ }
+
+ switch_to_bar ();
+}
+
+bool
+BarController::entry_focus_out (GdkEventFocus* ev)
+{
+ entry_activated ();
+ return true;
+}
+
+void
+BarController::set_use_parent (bool yn)
+{
+ use_parent = yn;
+ queue_draw ();
+}
+
+void
+BarController::set_sensitive (bool yn)
+{
+ Frame::set_sensitive (yn);
+ darea.set_sensitive (yn);
+}
diff --git a/libs/gtkmm2ext/bindable_button.cc b/libs/gtkmm2ext/bindable_button.cc
new file mode 100644
index 0000000000..3c3cad6e46
--- /dev/null
+++ b/libs/gtkmm2ext/bindable_button.cc
@@ -0,0 +1,139 @@
+/*
+ Copyright (C) 2004 Paul Davis
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <string>
+#include <climits>
+#include <iostream>
+
+#include <midi++/controllable.h>
+
+#include <gtkmm2ext/gtk_ui.h>
+#include <gtkmm2ext/bindable_button.h>
+
+#include "i18n.h"
+
+using namespace Gtkmm2ext;
+using namespace std;
+
+BindableToggleButton::BindableToggleButton (MIDI::Controllable *mc)
+ : prompter (Gtk::WIN_POS_MOUSE, 30000, false),
+ midi_control (mc),
+ bind_button (2),
+ bind_statemask (Gdk::CONTROL_MASK)
+
+{
+ init_events ();
+}
+
+BindableToggleButton::BindableToggleButton(MIDI::Controllable *mc, const string &label)
+ : StatefulButton (label),
+ prompter (Gtk::WIN_POS_MOUSE, 30000, false),
+ midi_control (mc),
+ bind_button (2),
+ bind_statemask (Gdk::CONTROL_MASK)
+{
+ init_events ();
+}
+
+
+void
+BindableToggleButton::init_events ()
+{
+ prompter.signal_unmap_event().connect (mem_fun (*this, &BindableToggleButton::prompter_hiding));
+
+ prompting = false;
+ unprompting = false;
+
+ if (midi_control) {
+ midi_control->learning_started.connect (mem_fun (*this, &BindableToggleButton::midicontrol_prompt));
+ midi_control->learning_stopped.connect (mem_fun (*this, &BindableToggleButton::midicontrol_unprompt));
+ }
+}
+
+void
+BindableToggleButton::set_bind_button_state (guint button, guint statemask)
+{
+ bind_button = button;
+ bind_statemask = statemask;
+}
+
+void
+BindableToggleButton::get_bind_button_state (guint &button, guint &statemask)
+{
+ button = bind_button;
+ statemask = bind_statemask;
+}
+
+void
+BindableToggleButton::midi_learn()
+{
+ if (midi_control) {
+ prompting = true;
+ midi_control->learn_about_external_control ();
+ }
+}
+
+bool
+BindableToggleButton::prompter_hiding (GdkEventAny *ev)
+{
+ if (unprompting) {
+ if (midi_control) {
+ midi_control->stop_learning();
+ }
+ unprompting = false;
+ }
+
+ return false;
+}
+
+
+void
+BindableToggleButton::midicontrol_set_tip ()
+
+{
+ if (midi_control) {
+ // Gtkmm2ext::UI::instance()->set_tip (evbox, midi_control->control_description());
+ }
+}
+
+void
+BindableToggleButton::midicontrol_prompt ()
+
+{
+ if (prompting) {
+ string prompt = _("operate MIDI controller now");
+ prompter.set_text (prompt);
+ Gtkmm2ext::UI::instance()->touch_display (&prompter);
+
+ unprompting = true;
+ prompting = false;
+ }
+}
+
+void
+BindableToggleButton::midicontrol_unprompt ()
+
+{
+ if (unprompting) {
+ Gtkmm2ext::UI::instance()->touch_display (&prompter);
+ unprompting = false;
+ }
+}
+
+
diff --git a/libs/gtkmm2ext/binding_proxy.cc b/libs/gtkmm2ext/binding_proxy.cc
new file mode 100644
index 0000000000..90f95f82ef
--- /dev/null
+++ b/libs/gtkmm2ext/binding_proxy.cc
@@ -0,0 +1,101 @@
+/*
+ Copyright (C) 2006 Paul Davis
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <string>
+#include <climits>
+#include <iostream>
+
+#include <pbd/controllable.h>
+
+#include <gtkmm2ext/binding_proxy.h>
+
+#include "i18n.h"
+
+using namespace Gtkmm2ext;
+using namespace std;
+using namespace PBD;
+
+BindingProxy::BindingProxy (Controllable& c)
+ : prompter (0),
+ controllable (c),
+ bind_button (2),
+ bind_statemask (Gdk::CONTROL_MASK)
+
+{
+}
+
+BindingProxy::~BindingProxy ()
+{
+ if (prompter) {
+ delete prompter;
+ }
+}
+
+void
+BindingProxy::set_bind_button_state (guint button, guint statemask)
+{
+ bind_button = button;
+ bind_statemask = statemask;
+}
+
+void
+BindingProxy::get_bind_button_state (guint &button, guint &statemask)
+{
+ button = bind_button;
+ statemask = bind_statemask;
+}
+
+bool
+BindingProxy::button_press_handler (GdkEventButton *ev)
+{
+ if ((ev->state & bind_statemask) && ev->button == bind_button) {
+ if (Controllable::StartLearning (&controllable)) {
+ string prompt = _("operate controller now");
+ if (prompter == 0) {
+ prompter = new PopUp (Gtk::WIN_POS_MOUSE, 30000, false);
+ prompter->signal_unmap_event().connect (mem_fun (*this, &BindingProxy::prompter_hiding));
+ }
+ prompter->set_text (prompt);
+ prompter->touch (); // shows popup
+ learning_connection = controllable.LearningFinished.connect (mem_fun (*this, &BindingProxy::learning_finished));
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void
+BindingProxy::learning_finished ()
+{
+ learning_connection.disconnect ();
+ if (prompter) {
+ prompter->touch (); // hides popup
+ }
+}
+
+
+bool
+BindingProxy::prompter_hiding (GdkEventAny *ev)
+{
+ learning_connection.disconnect ();
+ Controllable::StopLearning (&controllable);
+ return false;
+}
+
diff --git a/libs/gtkmm2ext/choice.cc b/libs/gtkmm2ext/choice.cc
new file mode 100644
index 0000000000..7f5f869ada
--- /dev/null
+++ b/libs/gtkmm2ext/choice.cc
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <gtkmm/label.h>
+#include <gtkmm2ext/choice.h>
+
+using namespace std;
+using namespace Gtkmm2ext;
+using namespace sigc;
+using namespace Gtk;
+
+Choice::Choice (string prompt, vector<string> choices, bool center)
+{
+ int n;
+ vector<string>::iterator i;
+
+ if (center) {
+ set_position (Gtk::WIN_POS_CENTER);
+ } else {
+ set_position (Gtk::WIN_POS_MOUSE);
+ }
+
+ set_name ("ChoiceWindow");
+
+ HBox* dhbox = manage (new HBox());
+ Image* dimage = manage (new Gtk::Image(Stock::DIALOG_QUESTION, Gtk::ICON_SIZE_DIALOG));
+ Label* label = manage (new Label (prompt));
+
+ dhbox->pack_start (*dimage, true, false, 10);
+ dhbox->pack_start (*label, true, false, 10);
+
+ get_vbox()->set_border_width (12);
+ get_vbox()->pack_start (*dhbox, true, false);
+
+ set_has_separator (false);
+ set_resizable (false);
+ show_all_children ();
+
+ for (n = 0, i = choices.begin(); i != choices.end(); ++i, ++n) {
+ add_button (*i, n);
+ }
+}
+
+void
+Choice::on_realize ()
+{
+ Gtk::Window::on_realize();
+ get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
+}
+
+Choice::~Choice ()
+{
+}
diff --git a/libs/gtkmm2ext/click_box.cc b/libs/gtkmm2ext/click_box.cc
new file mode 100644
index 0000000000..3ab7ea883c
--- /dev/null
+++ b/libs/gtkmm2ext/click_box.cc
@@ -0,0 +1,153 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <iostream>
+#include <cstdio> /* for sprintf, sigh ... */
+
+#include <gtkmm2ext/utils.h>
+#include <gtkmm2ext/click_box.h>
+
+using namespace std;
+using namespace Gtk;
+using namespace Gtkmm2ext;
+using namespace sigc;
+
+ClickBox::ClickBox (Gtk::Adjustment *adjp, const string &name, bool round_to_steps)
+ : AutoSpin (*adjp,0,round_to_steps)
+{
+ print_func = default_printer;
+ print_arg = 0;
+ layout = create_pango_layout ("");
+ twidth = 0;
+ theight = 0;
+
+
+ add_events (Gdk::BUTTON_RELEASE_MASK|
+ Gdk::BUTTON_PRESS_MASK|
+ Gdk::ENTER_NOTIFY_MASK|
+ Gdk::LEAVE_NOTIFY_MASK);
+
+ get_adjustment().signal_value_changed().connect (mem_fun (*this, &ClickBox::set_label));
+ signal_style_changed().connect (mem_fun (*this, &ClickBox::style_changed));
+ signal_button_press_event().connect (mem_fun (*this, &ClickBox::button_press_handler));
+ signal_button_release_event().connect (mem_fun (*this, &ClickBox::button_release_handler));
+ set_name (name);
+ set_label ();
+}
+
+ClickBox::~ClickBox ()
+{
+}
+
+bool
+ClickBox::button_press_handler (GdkEventButton* ev)
+{
+ add_modal_grab();
+ AutoSpin::button_press (ev);
+ return true;
+}
+
+bool
+ClickBox::button_release_handler (GdkEventButton* ev)
+{
+ switch (ev->button) {
+ case 1:
+ case 2:
+ case 3:
+ stop_spinning (0);
+ default:
+ remove_modal_grab();
+ break;
+ }
+ return true;
+}
+
+void
+ClickBox::default_printer (char buf[32], Gtk::Adjustment &adj,
+ void *ignored)
+{
+ sprintf (buf, "%.2f", adj.get_value());
+}
+
+void
+ClickBox::set_label ()
+{
+ if (!print_func) {
+ return;
+ }
+
+ char buf[32];
+
+ print_func (buf, get_adjustment(), print_arg);
+
+ layout->set_text (buf);
+ layout->get_pixel_size (twidth, theight);
+
+ queue_draw ();
+}
+
+void
+ClickBox::style_changed (const Glib::RefPtr<Gtk::Style>& ignored)
+{
+
+ layout->context_changed ();
+ layout->get_pixel_size (twidth, theight);
+}
+
+bool
+ClickBox::on_expose_event (GdkEventExpose *ev)
+{
+ /* Why do we do things like this rather than use a Gtk::Label?
+ Because whenever Gtk::Label::set_label() is called, it
+ triggers a recomputation of its own size, along with that
+ of its container and on up the tree. That's intended
+ to be unnecessary here.
+ */
+
+ Gtk::DrawingArea::on_expose_event (ev);
+
+ if (print_func) {
+
+ Glib::RefPtr<Gtk::Style> style (get_style());
+ Glib::RefPtr<Gdk::GC> fg_gc (style->get_fg_gc (Gtk::STATE_NORMAL));
+ Glib::RefPtr<Gdk::GC> bg_gc (style->get_bg_gc (Gtk::STATE_NORMAL));
+ Glib::RefPtr<Gdk::Window> win (get_window());
+
+ GdkRectangle base_rect;
+ GdkRectangle draw_rect;
+ gint x, y, width, height, depth;
+
+ win->get_geometry (x, y, width, height, depth);
+
+ base_rect.width = width;
+ base_rect.height = height;
+ base_rect.x = 0;
+ base_rect.y = 0;
+
+ gdk_rectangle_intersect (&ev->area, &base_rect, &draw_rect);
+ win->draw_rectangle (bg_gc, true, draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height);
+
+ if (twidth && theight) {
+ win->draw_layout (fg_gc, (width - twidth) / 2, (height - theight) / 2, layout);
+ }
+ }
+
+ return true;
+}
diff --git a/libs/gtkmm2ext/dndtreeview.cc b/libs/gtkmm2ext/dndtreeview.cc
new file mode 100644
index 0000000000..2c2e69f6b6
--- /dev/null
+++ b/libs/gtkmm2ext/dndtreeview.cc
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <cstdio>
+#include <iostream>
+
+#include <gtkmm2ext/dndtreeview.h>
+
+using namespace std;
+using namespace sigc;
+using namespace Gdk;
+using namespace Gtk;
+using namespace Glib;
+using namespace Gtkmm2ext;
+
+DnDTreeViewBase::DnDTreeViewBase ()
+ : TreeView ()
+{
+ draggable.push_back (TargetEntry ("GTK_TREE_MODEL_ROW", TARGET_SAME_WIDGET));
+ data_column = -1;
+
+ enable_model_drag_source (draggable);
+ enable_model_drag_dest (draggable);
+
+ suggested_action = Gdk::DragAction (0);
+}
+
+void
+DnDTreeViewBase::add_drop_targets (list<TargetEntry>& targets)
+{
+ for (list<TargetEntry>::iterator i = targets.begin(); i != targets.end(); ++i) {
+ draggable.push_back (*i);
+ }
+ enable_model_drag_source (draggable);
+ enable_model_drag_dest (draggable);
+}
+
+void
+DnDTreeViewBase::add_object_drag (int column, string type_name)
+{
+ draggable.push_back (TargetEntry (type_name, TargetFlags(0)));
+ data_column = column;
+
+ enable_model_drag_source (draggable);
+ enable_model_drag_dest (draggable);
+}
+
+bool
+DnDTreeViewBase::on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time)
+{
+ suggested_action = Gdk::DragAction (0);
+ return TreeView::on_drag_drop (context, x, y, time);
+}
+
+
diff --git a/libs/gtkmm2ext/fastmeter.cc b/libs/gtkmm2ext/fastmeter.cc
new file mode 100644
index 0000000000..63c36558f1
--- /dev/null
+++ b/libs/gtkmm2ext/fastmeter.cc
@@ -0,0 +1,567 @@
+/*
+ Copyright (C) 2003-2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <iostream>
+#include <cmath>
+#include <algorithm>
+#include <gdkmm/rectangle.h>
+#include <gtkmm2ext/fastmeter.h>
+#include <gtkmm2ext/utils.h>
+#include <gtkmm/style.h>
+#include <string.h>
+
+#define UINT_TO_RGB(u,r,g,b) { (*(r)) = ((u)>>16)&0xff; (*(g)) = ((u)>>8)&0xff; (*(b)) = (u)&0xff; }
+#define UINT_TO_RGBA(u,r,g,b,a) { UINT_TO_RGB(((u)>>8),r,g,b); (*(a)) = (u)&0xff; }
+using namespace Gtk;
+using namespace Gdk;
+using namespace Glib;
+using namespace Gtkmm2ext;
+using namespace std;
+
+
+int FastMeter::min_v_pixbuf_size = 10;
+int FastMeter::max_v_pixbuf_size = 1024;
+Glib::RefPtr<Gdk::Pixbuf>* FastMeter::v_pixbuf_cache = 0;
+
+int FastMeter::min_h_pixbuf_size = 10;
+int FastMeter::max_h_pixbuf_size = 1024;
+Glib::RefPtr<Gdk::Pixbuf>* FastMeter::h_pixbuf_cache = 0;
+
+int FastMeter::_clr0 = 0;
+int FastMeter::_clr1 = 0;
+int FastMeter::_clr2 = 0;
+int FastMeter::_clr3 = 0;
+
+FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o, int len, int clr0, int clr1, int clr2, int clr3)
+{
+ orientation = o;
+ hold_cnt = hold;
+ hold_state = 0;
+ current_peak = 0;
+ current_level = 0;
+ last_peak_rect.width = 0;
+ last_peak_rect.height = 0;
+ _clr0 = clr0;
+ _clr1 = clr1;
+ _clr2 = clr2;
+ _clr3 = clr3;
+
+ set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK);
+
+ pixrect.x = 0;
+ pixrect.y = 0;
+
+ if (orientation == Vertical) {
+ if (!len)
+ len = 250;
+ pixbuf = request_vertical_meter(dimen, len);
+ } else {
+ if (!len)
+ len = 186;
+ pixbuf = request_horizontal_meter(len, dimen);
+ }
+
+ pixheight = pixbuf->get_height();
+ pixwidth = pixbuf->get_width();
+
+ if (orientation == Vertical) {
+ pixrect.width = min (pixwidth, (gint) dimen);
+ pixrect.height = pixheight;
+ } else {
+ pixrect.width = pixwidth;
+ pixrect.height = min (pixheight, (gint) dimen);
+ }
+
+ request_width = pixrect.width;
+ request_height= pixrect.height;
+}
+
+Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_vertical_meter(int width, int height)
+{
+ if (height < min_v_pixbuf_size)
+ height = min_v_pixbuf_size;
+ if (height > max_v_pixbuf_size)
+ height = max_v_pixbuf_size;
+
+ //int index = height - 1;
+
+ //if (v_pixbuf_cache == 0) {
+ // v_pixbuf_cache = (Glib::RefPtr<Gdk::Pixbuf>*) malloc(sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_v_pixbuf_size);
+ // memset(v_pixbuf_cache,0,sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_v_pixbuf_size);
+ //}
+ Glib::RefPtr<Gdk::Pixbuf> ret;// = v_pixbuf_cache[index];
+ //if (ret)
+ // return ret;
+
+ guint8* data;
+
+ data = (guint8*) malloc(width*height * 3);
+
+ guint8 r,g,b,r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3,a;
+
+ UINT_TO_RGBA (_clr0, &r0, &g0, &b0, &a);
+ UINT_TO_RGBA (_clr1, &r1, &g1, &b1, &a);
+ UINT_TO_RGBA (_clr2, &r2, &g2, &b2, &a);
+ UINT_TO_RGBA (_clr3, &r3, &g3, &b3, &a);
+ // fake log calculation copied from log_meter.h
+ // actual calculation:
+ // log_meter(0.0f) =
+ // def = (0.0f + 20.0f) * 2.5f + 50f
+ // return def / 115.0f
+ int knee = (int)floor((float)height * 100.0f / 115.0f);
+ int y;
+
+ for (y = 0; y < knee/2; y++) {
+
+ r = (guint8)floor((float)abs(r1 - r0) * (float)y / (float)(knee/2));
+ (r0 >= r1) ? r = r0 - r : r += r0;
+
+ g = (guint8)floor((float)abs(g1 - g0) * (float)y / (float)(knee/2));
+ (g0 >= g1) ? g = g0 - g : g += g0;
+
+ b = (guint8)floor((float)abs(b1 - b0) * (float)y / (float)(knee/2));
+ (b0 >= b1) ? b = b0 - b : b += b0;
+
+ for (int x = 0; x < width; x++) {
+ data[ (x+(height-y-1)*width) * 3 + 0 ] = r;
+ data[ (x+(height-y-1)*width) * 3 + 1 ] = g;
+ data[ (x+(height-y-1)*width) * 3 + 2 ] = b;
+ }
+ }
+
+ int offset = knee - y;
+ for (int i=0; i < offset; i++,y++) {
+
+ r = (guint8)floor((float)abs(r2 - r1) * (float)i / (float)offset);
+ (r1 >= r2) ? r = r1 - r : r += r1;
+
+ g = (guint8)floor((float)abs(g2 - g1) * (float)i / (float)offset);
+ (g1 >= g2) ? g = g1 - g : g += g1;
+
+ b = (guint8)floor((float)abs(b2 - b1) * (float)i / (float)offset);
+ (b1 >= b2) ? b = b1 - b : b += b1;
+
+ for (int x = 0; x < width; x++) {
+ data[ (x+(height-y-1)*width) * 3 + 0 ] = r;
+ data[ (x+(height-y-1)*width) * 3 + 1 ] = g;
+ data[ (x+(height-y-1)*width) * 3 + 2 ] = b;
+ }
+ }
+ y--;
+ for (; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ data[ (x+(height-y-1)*width) * 3 + 0 ] = r3;
+ data[ (x+(height-y-1)*width) * 3 + 1 ] = g3;
+ data[ (x+(height-y-1)*width) * 3 + 2 ] = b3;
+ }
+ }
+
+ ret = Pixbuf::create_from_data(data, COLORSPACE_RGB, false, 8, width, height, width * 3);
+ //v_pixbuf_cache[index] = ret;
+
+ return ret;
+}
+
+Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_horizontal_meter(int width, int height)
+{
+ if (width < min_h_pixbuf_size)
+ width = min_h_pixbuf_size;
+ if (width > max_h_pixbuf_size)
+ width = max_h_pixbuf_size;
+
+ int index = width - 1;
+
+ if (h_pixbuf_cache == 0) {
+ h_pixbuf_cache = (Glib::RefPtr<Gdk::Pixbuf>*) malloc(sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_h_pixbuf_size);
+ memset(h_pixbuf_cache,0,sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_h_pixbuf_size);
+ }
+ Glib::RefPtr<Gdk::Pixbuf> ret = h_pixbuf_cache[index];
+ if (ret)
+ return ret;
+
+ guint8* data;
+
+ data = (guint8*) malloc(width*height * 3);
+
+ guint8 r,g,b;
+ r=0;
+ g=255;
+ b=0;
+
+ // fake log calculation copied from log_meter.h
+ // actual calculation:
+ // log_meter(0.0f) =
+ // def = (0.0f + 20.0f) * 2.5f + 50f
+ // return def / 115.0f
+ int knee = (int)floor((float)width * 100.0f / 115.0f);
+
+ int x;
+
+ for (x = 0; x < knee / 2; x++) {
+
+ r = (guint8)floor(255.0 * (float)x/(float)(knee / 2));
+
+ for (int y = 0; y < height; y++) {
+ data[ (x+(height-y-1)*width) * 3 + 0 ] = r;
+ data[ (x+(height-y-1)*width) * 3 + 1 ] = g;
+ data[ (x+(height-y-1)*width) * 3 + 2 ] = b;
+ }
+ }
+
+ for (; x < knee; x++) {
+
+ g = 255 - (guint8)floor(170.0 * (float)(x - knee/ 2)/(float)(knee / 2));
+
+ for (int y = 0; y < height; y++) {
+ data[ (x+(height-y-1)*width) * 3 + 0 ] = r;
+ data[ (x+(height-y-1)*width) * 3 + 1 ] = g;
+ data[ (x+(height-y-1)*width) * 3 + 2 ] = b;
+ }
+ }
+
+ r=255;
+ g=0;
+ b=0;
+ for (; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ data[ (x+(height-y-1)*width) * 3 + 0 ] = r;
+ data[ (x+(height-y-1)*width) * 3 + 1 ] = g;
+ data[ (x+(height-y-1)*width) * 3 + 2 ] = b;
+ }
+ }
+
+ ret = Pixbuf::create_from_data(data, COLORSPACE_RGB, false, 8, width, height, width * 3);
+ h_pixbuf_cache[index] = ret;
+
+ return ret;
+}
+
+FastMeter::~FastMeter ()
+{
+}
+
+void
+FastMeter::set_hold_count (long val)
+{
+ if (val < 1) {
+ val = 1;
+ }
+
+ hold_cnt = val;
+ hold_state = 0;
+ current_peak = 0;
+
+ queue_draw ();
+}
+
+void
+FastMeter::on_size_request (GtkRequisition* req)
+{
+ if (orientation == Vertical) {
+
+ req->height = request_height;
+ req->height = max(req->height, min_v_pixbuf_size);
+ req->height = min(req->height, max_v_pixbuf_size);
+
+ req->width = request_width;
+
+ } else {
+
+ req->width = request_width;
+ req->width = max(req->width, min_h_pixbuf_size);
+ req->width = min(req->width, max_h_pixbuf_size);
+
+ req->height = request_height;
+ }
+
+}
+
+void
+FastMeter::on_size_allocate (Gtk::Allocation &alloc)
+{
+ if (orientation == Vertical) {
+
+ if (alloc.get_width() != request_width) {
+ alloc.set_width (request_width);
+ }
+
+ int h = alloc.get_height();
+ h = max(h, min_v_pixbuf_size);
+ h = min(h, max_v_pixbuf_size);
+
+ if ( h != alloc.get_height())
+ alloc.set_height(h);
+
+ if (pixheight != h) {
+ pixbuf = request_vertical_meter(request_width, h);
+ }
+
+ } else {
+
+ if (alloc.get_height() != request_height) {
+ alloc.set_height(request_height);
+ }
+
+ int w = alloc.get_width();
+ w = max(w, min_h_pixbuf_size);
+ w = min(w, max_h_pixbuf_size);
+
+ if ( w != alloc.get_width())
+ alloc.set_width(w);
+
+ if (pixwidth != w) {
+ pixbuf = request_horizontal_meter(w, request_height);
+ }
+ }
+
+ pixheight = pixbuf->get_height();
+ pixwidth = pixbuf->get_width();
+
+ DrawingArea::on_size_allocate(alloc);
+}
+
+bool
+FastMeter::on_expose_event (GdkEventExpose* ev)
+{
+ if (orientation == Vertical) {
+ return vertical_expose (ev);
+ } else {
+ return horizontal_expose (ev);
+ }
+}
+
+bool
+FastMeter::vertical_expose (GdkEventExpose* ev)
+{
+ gint top_of_meter;
+ GdkRectangle intersection;
+ GdkRectangle background;
+
+ top_of_meter = (gint) floor (pixheight * current_level);
+
+ /* reset the height & origin of the rect that needs to show the pixbuf
+ */
+
+ pixrect.height = top_of_meter;
+ pixrect.y = pixheight - top_of_meter;
+
+ background.x = 0;
+ background.y = 0;
+ background.width = pixrect.width;
+ background.height = pixheight - top_of_meter;
+
+ if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) {
+ get_window()->draw_rectangle (get_style()->get_black_gc(), true,
+ intersection.x, intersection.y,
+ intersection.width, intersection.height);
+ }
+
+ if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) {
+ // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
+ get_window()->draw_pixbuf(get_style()->get_fg_gc(get_state()), pixbuf,
+ intersection.x, intersection.y,
+ intersection.x, intersection.y,
+ intersection.width, intersection.height,
+ Gdk::RGB_DITHER_NONE, 0, 0);
+ }
+
+ // draw peak bar
+
+ if (hold_state) {
+ last_peak_rect.x = 0;
+ last_peak_rect.width = pixwidth;
+ last_peak_rect.y = pixheight - (gint) floor (pixheight * current_peak);
+ last_peak_rect.height = min(3, pixheight - last_peak_rect.y);
+
+ get_window()->draw_pixbuf (get_style()->get_fg_gc(get_state()), pixbuf,
+ 0, last_peak_rect.y,
+ 0, last_peak_rect.y,
+ pixwidth, last_peak_rect.height,
+ Gdk::RGB_DITHER_NONE, 0, 0);
+ } else {
+ last_peak_rect.width = 0;
+ last_peak_rect.height = 0;
+ }
+
+ return TRUE;
+}
+
+bool
+FastMeter::horizontal_expose (GdkEventExpose* ev)
+{
+ gint right_of_meter;
+ GdkRectangle intersection;
+ GdkRectangle background;
+
+ right_of_meter = (gint) floor (pixwidth * current_level);
+ pixrect.width = right_of_meter;
+
+ background.x = 0;
+ background.y = 0;
+ background.width = pixwidth - right_of_meter;
+ background.height = pixrect.height;
+
+ if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) {
+ get_window()->draw_rectangle (get_style()->get_black_gc(), true,
+ intersection.x + right_of_meter, intersection.y,
+ intersection.width, intersection.height);
+ }
+
+ if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) {
+ // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
+ get_window()->draw_pixbuf(get_style()->get_fg_gc(get_state()), pixbuf,
+ intersection.x, intersection.y,
+ intersection.x, intersection.y,
+ pixrect.width, intersection.height,
+ Gdk::RGB_DITHER_NONE, 0, 0);
+ }
+
+ // draw peak bar
+ // XXX: peaks don't work properly
+ /*
+ if (hold_state && intersection.height > 0) {
+ gint x = (gint) floor(pixwidth * current_peak);
+
+ get_window()->draw_pixbuf (get_style()->get_fg_gc(get_state()), pixbuf,
+ x, intersection.y,
+ x, intersection.y,
+ 3, intersection.height,
+ Gdk::RGB_DITHER_NONE, 0, 0);
+ }
+ */
+
+ return true;
+}
+
+void
+FastMeter::set (float lvl)
+{
+ float old_level = current_level;
+ float old_peak = current_peak;
+
+ current_level = lvl;
+
+ if (lvl > current_peak) {
+ current_peak = lvl;
+ hold_state = hold_cnt;
+ }
+
+ if (hold_state > 0) {
+ if (--hold_state == 0) {
+ current_peak = lvl;
+ }
+ }
+
+ if (current_level == old_level && current_peak == old_peak && hold_state == 0) {
+ return;
+ }
+
+
+ Glib::RefPtr<Gdk::Window> win;
+
+ if ((win = get_window()) == 0) {
+ queue_draw ();
+ return;
+ }
+
+ if (orientation == Vertical) {
+ queue_vertical_redraw (win, old_level);
+ } else {
+ queue_horizontal_redraw (win, old_level);
+ }
+}
+
+void
+FastMeter::queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
+{
+ GdkRectangle rect;
+
+ gint new_top = (gint) floor (pixheight * current_level);
+
+ rect.x = 0;
+ rect.width = pixwidth;
+ rect.height = new_top;
+ rect.y = pixheight - new_top;
+
+ if (current_level > old_level) {
+ /* colored/pixbuf got larger, just draw the new section */
+ /* rect.y stays where it is because of X coordinates */
+ /* height of invalidated area is between new.y (smaller) and old.y
+ (larger).
+ X coordinates just make my brain hurt.
+ */
+ rect.height = pixrect.y - rect.y;
+ } else {
+ /* it got smaller, compute the difference */
+ /* rect.y becomes old.y (the smaller value) */
+ rect.y = pixrect.y;
+ /* rect.height is the old.y (smaller) minus the new.y (larger)
+ */
+ rect.height = pixrect.height - rect.height;
+ }
+
+ GdkRegion* region = 0;
+ bool queue = false;
+
+ if (rect.height != 0) {
+
+ /* ok, first region to draw ... */
+
+ region = gdk_region_rectangle (&rect);
+ queue = true;
+ }
+
+ /* redraw the last place where the last peak hold bar was;
+ the next expose will draw the new one whether its part of
+ expose region or not.
+ */
+
+ if (last_peak_rect.width * last_peak_rect.height != 0) {
+ if (!queue) {
+ region = gdk_region_new ();
+ queue = true;
+ }
+ gdk_region_union_with_rect (region, &last_peak_rect);
+ }
+
+ if (queue) {
+ gdk_window_invalidate_region (win->gobj(), region, true);
+ }
+ if (region) {
+ gdk_region_destroy(region);
+ region = 0;
+ }
+}
+
+void
+FastMeter::queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
+{
+ /* XXX OPTIMIZE (when we have some horizontal meters) */
+ queue_draw ();
+}
+
+void
+FastMeter::clear ()
+{
+ current_level = 0;
+ current_peak = 0;
+ hold_state = 0;
+ queue_draw ();
+}
diff --git a/libs/gtkmm2ext/focus_entry.cc b/libs/gtkmm2ext/focus_entry.cc
new file mode 100644
index 0000000000..706fc28e2f
--- /dev/null
+++ b/libs/gtkmm2ext/focus_entry.cc
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <gtkmm2ext/focus_entry.h>
+
+using namespace Gtkmm2ext;
+
+FocusEntry::FocusEntry ()
+{
+ next_release_selects = false;
+}
+
+bool
+FocusEntry::on_button_press_event (GdkEventButton* ev)
+{
+ if (!has_focus()) {
+ next_release_selects = true;
+ }
+ return Entry::on_button_press_event (ev);
+}
+
+bool
+FocusEntry::on_button_release_event (GdkEventButton* ev)
+{
+ if (next_release_selects) {
+ bool ret = Entry::on_button_release_event (ev);
+ select_region (0, -1);
+ next_release_selects = false;
+ return ret;
+ }
+
+ return Entry::on_button_release_event (ev);
+}
+
diff --git a/libs/gtkmm2ext/gettext.h b/libs/gtkmm2ext/gettext.h
new file mode 100644
index 0000000000..339c74ffe7
--- /dev/null
+++ b/libs/gtkmm2ext/gettext.h
@@ -0,0 +1,82 @@
+/* Convenience header for conditional use of GNU <libintl.h>.
+ Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+/* NLS can be disabled through the configure --disable-nls option. */
+#if ENABLE_NLS
+
+/* Get declarations of GNU message catalog functions. */
+# include <libintl.h>
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+ chokes if dcgettext is defined as a macro. So include it now, to make
+ later inclusions of <locale.h> a NOP. We don't include <libintl.h>
+ as well because people using "gettext.h" will not include <libintl.h>,
+ and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+ is OK. */
+#if defined(__sun)
+# include <locale.h>
+#endif
+
+/* Disabled NLS.
+ The casts to 'const char *' serve the purpose of producing warnings
+ for invalid uses of the value returned from these functions.
+ On pre-ANSI systems without 'const', the config.h file is supposed to
+ contain "#define const". */
+
+/* other headers may have included libintl.h */
+
+# undef gettext
+# undef dgettext
+# undef dcgettext
+# undef ngettext
+# undef dngettext
+# undef dcngettext
+# undef textdomain
+# undef bindtextdomain
+# undef bind_textdomain_codeset
+
+# define gettext(Msgid) ((const char *) (Msgid))
+# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
+# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
+# define ngettext(Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
+
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+ extraction of messages, but does not call gettext(). The run-time
+ translation is done at a different place in the code.
+ The argument, String, should be a literal string. Concatenated strings
+ and other string expressions won't work.
+ The macro's expansion is not parenthesized, so that it is suitable as
+ initializer for static 'char[]' or 'const char[]' variables. */
+#define gettext_noop(String) String
+
+#endif /* _LIBGETTEXT_H */
diff --git a/libs/gtkmm2ext/grouped_buttons.cc b/libs/gtkmm2ext/grouped_buttons.cc
new file mode 100644
index 0000000000..b16b983d02
--- /dev/null
+++ b/libs/gtkmm2ext/grouped_buttons.cc
@@ -0,0 +1,96 @@
+/*
+ Copyright (C) 2001 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <gtkmm.h>
+
+#include <gtkmm2ext/grouped_buttons.h>
+
+using namespace std;
+
+GroupedButtons::GroupedButtons (vector<Gtk::ToggleButton *>& buttonset)
+{
+ uint32_t n = 0;
+
+ buttons = buttonset;
+
+ for (vector<Gtk::ToggleButton *>::iterator i = buttons.begin(); i != buttons.end(); ++i, ++n) {
+ if ((*i)->get_active()) {
+ current_active = n;
+ }
+ (*i)->signal_clicked().connect (sigc::bind (mem_fun (*this, &GroupedButtons::one_clicked), n));
+ }
+}
+
+GroupedButtons::GroupedButtons (uint32_t nbuttons, uint32_t first_active)
+{
+ buttons.reserve (nbuttons);
+ current_active = first_active;
+
+ for (uint32_t n = 0; n < nbuttons; ++n) {
+
+ Gtk::ToggleButton *button;
+
+ button = manage (new (Gtk::ToggleButton));
+
+ if (n == current_active) {
+ button->set_active (true);
+ }
+
+ button->signal_clicked().connect (sigc::bind (mem_fun (*this, &GroupedButtons::one_clicked), n));
+ buttons.push_back (button);
+ }
+}
+
+static gint
+reactivate_button (void *arg)
+{
+ Gtk::ToggleButton *b = (Gtk::ToggleButton *) arg;
+ b->set_active (true);
+ return FALSE;
+}
+
+void
+GroupedButtons::one_clicked (uint32_t which)
+{
+ if (buttons[which]->get_active()) {
+
+ if (which != current_active) {
+ uint32_t old = current_active;
+ current_active = which;
+ buttons[old]->set_active (false);
+ }
+
+ } else if (which == current_active) {
+
+ /* Someobody tried to unset the current active
+ button by clicking on it. This caused
+ set_active (false) to be called. We don't
+ allow that, so just reactivate it.
+
+ Don't try this right here, because of some
+ design glitches with GTK+ toggle buttons.
+ Setting the button back to active from
+ within the signal emission that marked
+ it as inactive causes a segfault ...
+ */
+
+ gtk_idle_add (reactivate_button, buttons[which]);
+ }
+}
diff --git a/libs/gtkmm2ext/gtk_ui.cc b/libs/gtkmm2ext/gtk_ui.cc
new file mode 100644
index 0000000000..f00c6cd1e1
--- /dev/null
+++ b/libs/gtkmm2ext/gtk_ui.cc
@@ -0,0 +1,656 @@
+/*
+ Copyright (C) 1999-2005 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <cmath>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <cerrno>
+#include <climits>
+#include <cctype>
+
+#include <gtkmm.h>
+#include <pbd/error.h>
+#include <pbd/touchable.h>
+#include <pbd/failed_constructor.h>
+#include <pbd/pthread_utils.h>
+#include <pbd/stacktrace.h>
+
+#include <gtkmm2ext/gtk_ui.h>
+#include <gtkmm2ext/textviewer.h>
+#include <gtkmm2ext/popup.h>
+#include <gtkmm2ext/utils.h>
+#include <gtkmm2ext/window_title.h>
+
+#include "i18n.h"
+
+using namespace Gtkmm2ext;
+using namespace Gtk;
+using namespace Glib;
+using namespace PBD;
+using std::map;
+
+pthread_t UI::gui_thread;
+UI *UI::theGtkUI = 0;
+
+BaseUI::RequestType Gtkmm2ext::ErrorMessage = BaseUI::new_request_type();
+BaseUI::RequestType Gtkmm2ext::Quit = BaseUI::new_request_type();
+BaseUI::RequestType Gtkmm2ext::TouchDisplay = BaseUI::new_request_type();
+BaseUI::RequestType Gtkmm2ext::StateChange = BaseUI::new_request_type();
+BaseUI::RequestType Gtkmm2ext::SetTip = BaseUI::new_request_type();
+BaseUI::RequestType Gtkmm2ext::AddIdle = BaseUI::new_request_type();
+BaseUI::RequestType Gtkmm2ext::AddTimeout = BaseUI::new_request_type();
+
+#include <pbd/abstract_ui.cc> /* instantiate the template */
+
+
+UI::UI (string namestr, int *argc, char ***argv)
+ : AbstractUI<UIRequest> (namestr, true)
+{
+ theMain = new Main (argc, argv);
+ tips = new Tooltips;
+
+ _active = false;
+
+ if (!theGtkUI) {
+ theGtkUI = this;
+ gui_thread = pthread_self ();
+ } else {
+ fatal << "duplicate UI requested" << endmsg;
+ /* NOTREACHED */
+ }
+
+ /* add the pipe to the select/poll loop that GDK does */
+
+ gdk_input_add (signal_pipe[0],
+ GDK_INPUT_READ,
+ UI::signal_pipe_callback,
+ this);
+
+ errors = new TextViewer (850,100);
+ errors->text().set_editable (false);
+ errors->text().set_name ("ErrorText");
+
+ Glib::set_application_name(namestr);
+
+ WindowTitle title(Glib::get_application_name());
+ title += _("Log");
+ errors->set_title (title.get_string());
+
+ errors->dismiss_button().set_name ("ErrorLogCloseButton");
+ errors->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), (Window *) errors));
+
+ register_thread (pthread_self(), X_("GUI"));
+
+ //load_rcfile (rcfile);
+}
+
+UI::~UI ()
+{
+}
+
+
+bool
+UI::caller_is_ui_thread ()
+{
+ return pthread_equal (gui_thread, pthread_self());
+}
+
+int
+UI::load_rcfile (string path, bool themechange)
+{
+ if (path.length() == 0) {
+ return -1;
+ }
+
+ if (access (path.c_str(), R_OK)) {
+ error << "UI: couldn't find rc file \""
+ << path
+ << '"'
+ << endmsg;
+ return -1;
+ }
+
+ RC rc (path.c_str());
+ // RC::reset_styles (Gtk::Settings::get_default());
+ gtk_rc_reset_styles (gtk_settings_get_default());
+ theme_changed.emit();
+
+ if (themechange) {
+ return 0; //Don't continue on every time there is a theme change
+ }
+
+ /* have to pack widgets into a toplevel window so that styles will stick */
+
+ Window temp_window (WINDOW_TOPLEVEL);
+ HBox box;
+ Label a_widget1;
+ Label a_widget2;
+ Label a_widget3;
+ Label a_widget4;
+ RefPtr<Gtk::Style> style;
+ RefPtr<TextBuffer> buffer (errors->text().get_buffer());
+
+ box.pack_start (a_widget1);
+ box.pack_start (a_widget2);
+ box.pack_start (a_widget3);
+ box.pack_start (a_widget4);
+
+ error_ptag = buffer->create_tag();
+ error_mtag = buffer->create_tag();
+ fatal_ptag = buffer->create_tag();
+ fatal_mtag = buffer->create_tag();
+ warning_ptag = buffer->create_tag();
+ warning_mtag = buffer->create_tag();
+ info_ptag = buffer->create_tag();
+ info_mtag = buffer->create_tag();
+
+ a_widget1.set_name ("FatalMessage");
+ a_widget1.ensure_style ();
+ style = a_widget1.get_style();
+
+ fatal_ptag->property_font_desc().set_value(style->get_font());
+ fatal_ptag->property_foreground_gdk().set_value(style->get_fg(STATE_ACTIVE));
+ fatal_ptag->property_background_gdk().set_value(style->get_bg(STATE_ACTIVE));
+ fatal_mtag->property_font_desc().set_value(style->get_font());
+ fatal_mtag->property_foreground_gdk().set_value(style->get_fg(STATE_NORMAL));
+ fatal_mtag->property_background_gdk().set_value(style->get_bg(STATE_NORMAL));
+
+ a_widget2.set_name ("ErrorMessage");
+ a_widget2.ensure_style ();
+ style = a_widget2.get_style();
+
+ error_ptag->property_font_desc().set_value(style->get_font());
+ error_ptag->property_foreground_gdk().set_value(style->get_fg(STATE_ACTIVE));
+ error_ptag->property_background_gdk().set_value(style->get_bg(STATE_ACTIVE));
+ error_mtag->property_font_desc().set_value(style->get_font());
+ error_mtag->property_foreground_gdk().set_value(style->get_fg(STATE_NORMAL));
+ error_mtag->property_background_gdk().set_value(style->get_bg(STATE_NORMAL));
+
+ a_widget3.set_name ("WarningMessage");
+ a_widget3.ensure_style ();
+ style = a_widget3.get_style();
+
+ warning_ptag->property_font_desc().set_value(style->get_font());
+ warning_ptag->property_foreground_gdk().set_value(style->get_fg(STATE_ACTIVE));
+ warning_ptag->property_background_gdk().set_value(style->get_bg(STATE_ACTIVE));
+ warning_mtag->property_font_desc().set_value(style->get_font());
+ warning_mtag->property_foreground_gdk().set_value(style->get_fg(STATE_NORMAL));
+ warning_mtag->property_background_gdk().set_value(style->get_bg(STATE_NORMAL));
+
+ a_widget4.set_name ("InfoMessage");
+ a_widget4.ensure_style ();
+ style = a_widget4.get_style();
+
+ info_ptag->property_font_desc().set_value(style->get_font());
+ info_ptag->property_foreground_gdk().set_value(style->get_fg(STATE_ACTIVE));
+ info_ptag->property_background_gdk().set_value(style->get_bg(STATE_ACTIVE));
+ info_mtag->property_font_desc().set_value(style->get_font());
+ info_mtag->property_foreground_gdk().set_value(style->get_fg(STATE_NORMAL));
+ info_mtag->property_background_gdk().set_value(style->get_bg(STATE_NORMAL));
+
+ return 0;
+}
+
+void
+UI::run (Receiver &old_receiver)
+{
+ listen_to (error);
+ listen_to (info);
+ listen_to (warning);
+ listen_to (fatal);
+
+ old_receiver.hangup ();
+ starting ();
+ _active = true;
+ theMain->run ();
+ _active = false;
+ stopping ();
+ hangup ();
+ return;
+}
+
+bool
+UI::running ()
+{
+ return _active;
+}
+
+void
+UI::kill ()
+{
+ if (_active) {
+ pthread_kill (gui_thread, SIGKILL);
+ }
+}
+
+void
+UI::quit ()
+{
+ UIRequest *req = get_request (Quit);
+
+ if (req == 0) {
+ return;
+ }
+
+ send_request (req);
+}
+
+static bool idle_quit ()
+{
+ Main::quit ();
+ return true;
+}
+
+void
+UI::do_quit ()
+{
+ if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
+ Main::quit ();
+ } else {
+ Glib::signal_idle().connect (sigc::ptr_fun (idle_quit));
+ }
+}
+
+void
+UI::touch_display (Touchable *display)
+{
+ UIRequest *req = get_request (TouchDisplay);
+
+ if (req == 0) {
+ return;
+ }
+
+ req->display = display;
+
+ send_request (req);
+}
+
+void
+UI::set_tip (Widget *w, const gchar *tip, const gchar *hlp)
+{
+ UIRequest *req = get_request (SetTip);
+
+ if (req == 0) {
+ return;
+ }
+
+ req->widget = w;
+ req->msg = tip;
+ req->msg2 = hlp;
+
+ send_request (req);
+}
+
+void
+UI::set_state (Widget *w, StateType state)
+{
+ UIRequest *req = get_request (StateChange);
+
+ if (req == 0) {
+ return;
+ }
+
+ req->new_state = state;
+ req->widget = w;
+
+ send_request (req);
+}
+
+void
+UI::idle_add (int (*func)(void *), void *arg)
+{
+ UIRequest *req = get_request (AddIdle);
+
+ if (req == 0) {
+ return;
+ }
+
+ req->function = func;
+ req->arg = arg;
+
+ send_request (req);
+}
+
+/* END abstract_ui interfaces */
+
+void
+UI::signal_pipe_callback (void *arg, int fd, GdkInputCondition cond)
+{
+ char buf[256];
+
+ /* flush (nonblocking) pipe */
+
+ while (read (fd, buf, 256) > 0);
+
+ ((UI *) arg)->handle_ui_requests ();
+}
+
+void
+UI::do_request (UIRequest* req)
+{
+ if (req->type == ErrorMessage) {
+
+ process_error_message (req->chn, req->msg);
+ free (const_cast<char*>(req->msg)); /* it was strdup'ed */
+ req->msg = 0; /* don't free it again in the destructor */
+
+ } else if (req->type == Quit) {
+
+ do_quit ();
+
+ } else if (req->type == CallSlot) {
+
+ req->slot ();
+
+ } else if (req->type == TouchDisplay) {
+
+ req->display->touch ();
+ if (req->display->delete_after_touch()) {
+ delete req->display;
+ }
+
+ } else if (req->type == StateChange) {
+
+ req->widget->set_state (req->new_state);
+
+ } else if (req->type == SetTip) {
+
+ /* XXX need to figure out how this works */
+
+ } else {
+
+ error << "GtkUI: unknown request type "
+ << (int) req->type
+ << endmsg;
+ }
+}
+
+/*======================================================================
+ Error Display
+ ======================================================================*/
+
+void
+UI::receive (Transmitter::Channel chn, const char *str)
+{
+ if (caller_is_ui_thread()) {
+ process_error_message (chn, str);
+ } else {
+ UIRequest* req = get_request (ErrorMessage);
+
+ if (req == 0) {
+ return;
+ }
+
+ req->chn = chn;
+ req->msg = strdup (str);
+
+ send_request (req);
+ }
+}
+
+#define OLD_STYLE_ERRORS 1
+
+void
+UI::process_error_message (Transmitter::Channel chn, const char *str)
+{
+ RefPtr<Style> style;
+ RefPtr<TextBuffer::Tag> ptag;
+ RefPtr<TextBuffer::Tag> mtag;
+ const char *prefix;
+ size_t prefix_len;
+ bool fatal_received = false;
+#ifndef OLD_STYLE_ERRORS
+ PopUp* popup = new PopUp (WIN_POS_CENTER, 0, true);
+#endif
+
+ switch (chn) {
+ case Transmitter::Fatal:
+ prefix = "[FATAL]: ";
+ ptag = fatal_ptag;
+ mtag = fatal_mtag;
+ prefix_len = 9;
+ fatal_received = true;
+ break;
+ case Transmitter::Error:
+#if OLD_STYLE_ERRORS
+ prefix = "[ERROR]: ";
+ ptag = error_ptag;
+ mtag = error_mtag;
+ prefix_len = 9;
+#else
+ popup->set_name ("ErrorMessage");
+ popup->set_text (str);
+ popup->touch ();
+ return;
+#endif
+ break;
+ case Transmitter::Info:
+#if OLD_STYLE_ERRORS
+ prefix = "[INFO]: ";
+ ptag = info_ptag;
+ mtag = info_mtag;
+ prefix_len = 8;
+#else
+ popup->set_name ("InfoMessage");
+ popup->set_text (str);
+ popup->touch ();
+ return;
+#endif
+
+ break;
+ case Transmitter::Warning:
+#if OLD_STYLE_ERRORS
+ prefix = "[WARNING]: ";
+ ptag = warning_ptag;
+ mtag = warning_mtag;
+ prefix_len = 11;
+#else
+ popup->set_name ("WarningMessage");
+ popup->set_text (str);
+ popup->touch ();
+ return;
+#endif
+ break;
+ default:
+ /* no choice but to use text/console output here */
+ cerr << "programmer error in UI::check_error_messages (channel = " << chn << ")\n";
+ ::exit (1);
+ }
+
+ errors->text().get_buffer()->begin_user_action();
+
+ if (fatal_received) {
+ handle_fatal (str);
+ } else {
+
+ display_message (prefix, prefix_len, ptag, mtag, str);
+
+ if (!errors->is_visible()) {
+ toggle_errors();
+ }
+ }
+
+ errors->text().get_buffer()->end_user_action();
+}
+
+void
+UI::toggle_errors ()
+{
+ if (!errors->is_visible()) {
+ errors->set_position (WIN_POS_MOUSE);
+ errors->show ();
+ } else {
+ errors->hide ();
+ }
+}
+
+void
+UI::display_message (const char *prefix, gint prefix_len, RefPtr<TextBuffer::Tag> ptag, RefPtr<TextBuffer::Tag> mtag, const char *msg)
+{
+ RefPtr<TextBuffer> buffer (errors->text().get_buffer());
+
+ buffer->insert_with_tag(buffer->end(), prefix, ptag);
+ buffer->insert_with_tag(buffer->end(), msg, mtag);
+ buffer->insert_with_tag(buffer->end(), "\n", mtag);
+
+ errors->scroll_to_bottom ();
+}
+
+void
+UI::handle_fatal (const char *message)
+{
+ Window win (WINDOW_POPUP);
+ VBox packer;
+ Label label (message);
+ Button quit (_("Press To Exit"));
+
+ win.set_default_size (400, 100);
+
+ string title;
+ title = name();
+ title += ": Fatal Error";
+ win.set_title (title);
+
+ win.set_position (WIN_POS_MOUSE);
+ win.add (packer);
+
+ packer.pack_start (label, true, true);
+ packer.pack_start (quit, false, false);
+ quit.signal_clicked().connect(mem_fun(*this,&UI::quit));
+
+ win.show_all ();
+ win.set_modal (true);
+
+ theMain->run ();
+
+ exit (1);
+}
+
+void
+UI::popup_error (const char *text)
+{
+ PopUp *pup;
+
+ if (!caller_is_ui_thread()) {
+ error << "non-UI threads can't use UI::popup_error"
+ << endmsg;
+ return;
+ }
+
+ pup = new PopUp (WIN_POS_MOUSE, 0, true);
+ pup->set_text (text);
+ pup->touch ();
+}
+
+#ifdef GTKOSX
+extern "C" {
+ int gdk_quartz_in_carbon_menu_event_handler ();
+}
+#endif
+
+void
+UI::flush_pending ()
+{
+#ifdef GTKOSX
+ /* as of february 11th 2008, gtk/osx has a problem in that mac menu events
+ are handled using Carbon with an "internal" event handling system that
+ doesn't pass things back to the glib/gtk main loop. this makes
+ gtk_main_iteration() block if we call it while in a menu event handler
+ because glib gets confused and thinks there are two threads running
+ g_main_poll_func().
+
+ this hack (relies on code in gtk2_ardour/sync-menu.c) works
+ around that.
+ */
+
+ if (gdk_quartz_in_carbon_menu_event_handler()) {
+ return;
+ }
+#endif
+ if (!caller_is_ui_thread()) {
+ error << "non-UI threads cannot call UI::flush_pending()"
+ << endmsg;
+ return;
+ }
+
+ gtk_main_iteration();
+
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+}
+
+bool
+UI::just_hide_it (GdkEventAny *ev, Window *win)
+{
+ win->hide ();
+ return true;
+}
+
+Gdk::Color
+UI::get_color (const string& prompt, bool& picked, const Gdk::Color* initial)
+{
+ Gdk::Color color;
+
+ ColorSelectionDialog color_dialog (prompt);
+
+ color_dialog.set_modal (true);
+ color_dialog.get_cancel_button()->signal_clicked().connect (bind (mem_fun (*this, &UI::color_selection_done), false));
+ color_dialog.get_ok_button()->signal_clicked().connect (bind (mem_fun (*this, &UI::color_selection_done), true));
+ color_dialog.signal_delete_event().connect (mem_fun (*this, &UI::color_selection_deleted));
+
+ if (initial) {
+ color_dialog.get_colorsel()->set_current_color (*initial);
+ }
+
+ color_dialog.show_all ();
+ color_picked = false;
+ picked = false;
+
+ Main::run();
+
+ color_dialog.hide_all ();
+
+ if (color_picked) {
+ Gdk::Color f_rgba = color_dialog.get_colorsel()->get_current_color ();
+ color.set_red(f_rgba.get_red());
+ color.set_green(f_rgba.get_green());
+ color.set_blue(f_rgba.get_blue());
+
+ picked = true;
+ }
+
+ return color;
+}
+
+void
+UI::color_selection_done (bool status)
+{
+ color_picked = status;
+ Main::quit ();
+}
+
+bool
+UI::color_selection_deleted (GdkEventAny *ev)
+{
+ Main::quit ();
+ return true;
+}
diff --git a/libs/gtkmm2ext/gtkmm2ext/.cvsignore b/libs/gtkmm2ext/gtkmm2ext/.cvsignore
new file mode 100644
index 0000000000..67020331ba
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/.cvsignore
@@ -0,0 +1 @@
+version.h
diff --git a/libs/gtkmm2ext/gtkmm2ext/auto_spin.h b/libs/gtkmm2ext/gtkmm2ext/auto_spin.h
new file mode 100644
index 0000000000..b692a7ccdc
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/auto_spin.h
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) 2000 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_auto_spin_h__
+#define __gtkmm2ext_auto_spin_h__
+
+#include <gtkmm.h>
+
+namespace Gtkmm2ext {
+
+class AutoSpin
+
+{
+ public:
+ AutoSpin (Gtk::Adjustment &adj, gfloat cr = 0, bool round_to_steps_yn = false);
+
+ Gtk::Adjustment &get_adjustment() { return adjustment; }
+
+ void use_left_as_decrement (bool yn) { left_is_decrement = yn; }
+ void set_wrap (bool yn) { wrap = yn; }
+ void set_climb_rate (gfloat cr) { climb_rate = cr; }
+ void set_bounds (gfloat initial, gfloat low, gfloat high,
+ bool with_reset = true);
+
+ gint button_press (GdkEventButton *);
+ gint stop_spinning (GdkEventButton *ignored_but_here_for_clicked);
+ void start_spinning (bool decrementing, bool use_page);
+
+ private:
+ Gtk::Adjustment &adjustment;
+ gfloat climb_rate;
+ gfloat timer_increment;
+ gfloat initial;
+ unsigned int timer_calls;
+ bool have_timer;
+ bool need_timer;
+ bool wrap;
+ gint timeout_tag;
+ bool left_is_decrement;
+ bool round_to_steps;
+
+ static const unsigned int initial_timer_interval;
+ static const unsigned int timer_interval;
+ static const unsigned int climb_timer_calls;
+
+ void stop_timer ();
+ static gint _timer (void *arg);
+ gint timer ();
+ bool adjust_value (gfloat increment);
+ void set_value (gfloat value);
+};
+
+} /* namespace */
+
+#endif /* __gtkmm2ext_auto_spin_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h
new file mode 100644
index 0000000000..fe67e9ecec
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h
@@ -0,0 +1,104 @@
+/*
+ Copyright (C) 2004 Paul Davis
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_bar_controller_h__
+#define __gtkmm2ext_bar_controller_h__
+
+#include <gtkmm/frame.h>
+#include <gtkmm/drawingarea.h>
+#include <gtkmm2ext/binding_proxy.h>
+
+namespace ARDOUR {
+ class Controllable;
+}
+
+namespace Gtkmm2ext {
+
+class BarController : public Gtk::Frame
+{
+ public:
+ typedef sigc::slot<void,char*,unsigned int> LabelCallback;
+
+ BarController (Gtk::Adjustment& adj, PBD::Controllable&, LabelCallback lc = LabelCallback());
+
+ virtual ~BarController () {}
+
+ enum Style {
+ LeftToRight,
+ RightToLeft,
+ Line,
+ CenterOut,
+
+ TopToBottom,
+ BottomToTop
+ };
+
+ Style style() const { return _style; }
+ void set_style (Style);
+ void set_with_text (bool yn);
+ void set_use_parent (bool yn);
+
+ void set_sensitive (bool yn);
+
+ Gtk::SpinButton& get_spin_button() { return spinner; }
+
+ sigc::signal<void> StartGesture;
+ sigc::signal<void> StopGesture;
+
+ /* export this to allow direct connection to button events */
+
+ Gtk::Widget& event_widget() { return darea; }
+ PBD::Controllable* get_controllable() { return binding_proxy.get_controllable(); }
+
+ protected:
+ Gtk::Adjustment& adjustment;
+ BindingProxy binding_proxy;
+ Gtk::DrawingArea darea;
+ LabelCallback label_callback;
+ Glib::RefPtr<Pango::Layout> layout;
+ Style _style;
+ bool grabbed;
+ bool switching;
+ bool switch_on_release;
+ bool with_text;
+ double initial_value;
+ double grab_x;
+ GdkWindow* grab_window;
+ Gtk::SpinButton spinner;
+ bool use_parent;
+
+ virtual bool button_press (GdkEventButton *);
+ virtual bool button_release (GdkEventButton *);
+ virtual bool motion (GdkEventMotion *);
+ virtual bool expose (GdkEventExpose *);
+ virtual bool scroll (GdkEventScroll *);
+ virtual bool entry_focus_out (GdkEventFocus*);
+
+ gint mouse_control (double x, GdkWindow* w, double scaling);
+
+ gint switch_to_bar ();
+ gint switch_to_spinner ();
+
+ void entry_activated ();
+ void drop_grab ();
+};
+
+
+}; /* namespace */
+
+#endif // __gtkmm2ext_bar_controller_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h
new file mode 100644
index 0000000000..1cde32c5ba
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2004 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __bindable_button_h__
+#define __bindable_button_h__
+
+#include <string>
+
+#include <gtkmm2ext/stateful_button.h>
+#include "binding_proxy.h"
+
+namespace PBD {
+ class Controllable;
+}
+
+class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton
+{
+ public:
+ BindableToggleButton (PBD::Controllable& c) : binding_proxy (c) {}
+
+ explicit BindableToggleButton (PBD::Controllable& c, const std::string &label)
+ : Gtkmm2ext::StatefulToggleButton (label), binding_proxy (c) {}
+
+ virtual ~BindableToggleButton() {}
+
+ bool on_button_press_event (GdkEventButton *ev) {
+ if (!binding_proxy.button_press_handler (ev)) {
+ StatefulToggleButton::on_button_press_event (ev);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ PBD::Controllable* get_controllable() { return binding_proxy.get_controllable(); }
+ private:
+ BindingProxy binding_proxy;
+};
+
+class BindableButton : public Gtkmm2ext::StatefulButton
+{
+ public:
+ BindableButton (PBD::Controllable& c) : binding_proxy (c) {}
+
+ explicit BindableButton (PBD::Controllable& c, const std::string &label)
+ : Gtkmm2ext::StatefulButton (label), binding_proxy (c) {}
+
+ ~BindableButton() {}
+
+ bool on_button_press_event (GdkEventButton *ev) {
+ if (!binding_proxy.button_press_handler (ev)) {
+ StatefulButton::on_button_press_event (ev);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ PBD::Controllable* get_controllable() { return binding_proxy.get_controllable(); }
+
+ private:
+ BindingProxy binding_proxy;
+};
+
+#endif
diff --git a/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h
new file mode 100644
index 0000000000..dd9b94319d
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __binding_proxy__
+#define __binding_proxy__
+
+#include <string>
+
+#include <gtkmm2ext/popup.h>
+
+namespace PBD {
+ class Controllable;
+}
+
+class BindingProxy : public sigc::trackable
+{
+ public:
+ BindingProxy (PBD::Controllable&);
+ virtual ~BindingProxy();
+
+ void set_bind_button_state (guint button, guint statemask);
+ void get_bind_button_state (guint &button, guint &statemask);
+
+ bool button_press_handler (GdkEventButton *);
+
+ PBD::Controllable* get_controllable() { return &controllable; }
+ protected:
+
+ Gtkmm2ext::PopUp* prompter;
+ PBD::Controllable& controllable;
+ guint bind_button;
+ guint bind_statemask;
+ sigc::connection learning_connection;
+ void learning_finished ();
+ bool prompter_hiding (GdkEventAny *);
+};
+
+#endif
diff --git a/libs/gtkmm2ext/gtkmm2ext/choice.h b/libs/gtkmm2ext/gtkmm2ext/choice.h
new file mode 100644
index 0000000000..b6dcdc05c1
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/choice.h
@@ -0,0 +1,44 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __pbd_gtkmm_choice_h__
+#define __pbd_gtkmm_choice_h__
+
+#include <gtkmm/dialog.h>
+#include <gtkmm/image.h>
+#include <gtkmm/stock.h>
+#include <gtkmm/box.h>
+#include <string>
+#include <vector>
+
+namespace Gtkmm2ext {
+
+class Choice : public Gtk::Dialog
+{
+ public:
+ Choice (std::string prompt, std::vector<std::string> choices, bool center = true);
+ virtual ~Choice ();
+
+ protected:
+ void on_realize ();
+};
+
+} /* namespace */
+
+#endif // __pbd_gtkmm_choice_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/click_box.h b/libs/gtkmm2ext/gtkmm2ext/click_box.h
new file mode 100644
index 0000000000..8f9fb55717
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/click_box.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_click_box_h__
+#define __gtkmm2ext_click_box_h__
+
+#include <string>
+#include <gtkmm.h>
+
+#include <gtkmm2ext/auto_spin.h>
+
+namespace Gtkmm2ext {
+
+class ClickBox : public Gtk::DrawingArea, public AutoSpin
+{
+ public:
+ ClickBox (Gtk::Adjustment *adj, const std::string &name, bool round_to_steps = false);
+ ~ClickBox ();
+
+ void set_print_func(void (*pf)(char buf[32], Gtk::Adjustment &, void *),
+ void *arg) {
+ print_func = pf;
+ print_arg = arg;
+ set_label ();
+ }
+
+
+ protected:
+ bool on_expose_event (GdkEventExpose*);
+
+ private:
+ void (*print_func) (char buf[32], Gtk::Adjustment &, void *);
+ void *print_arg;
+
+ Glib::RefPtr<Pango::Layout> layout;
+ int twidth;
+ int theight;
+
+ void set_label ();
+ void style_changed (const Glib::RefPtr<Gtk::Style> &);
+ bool button_press_handler (GdkEventButton *);
+ bool button_release_handler (GdkEventButton *);
+
+ static void default_printer (char buf[32], Gtk::Adjustment &, void *);
+};
+
+} /* namespace */
+
+#endif /* __gtkmm2ext_click_box_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h b/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h
new file mode 100644
index 0000000000..fbc5ea90ef
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h
@@ -0,0 +1,165 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_dndtreeview_h__
+#define __gtkmm2ext_dndtreeview_h__
+
+#include <stdint.h>
+#include <string>
+#include <gtkmm/treeview.h>
+#include <gtkmm/treeselection.h>
+#include <gtkmm/selectiondata.h>
+
+namespace Gtkmm2ext {
+
+template<class DataType>
+struct SerializedObjectPointers {
+ uint32_t size;
+ uint32_t cnt;
+ char type[32];
+ DataType data[0];
+};
+
+class DnDTreeViewBase : public Gtk::TreeView
+{
+ private:
+ public:
+ DnDTreeViewBase ();
+ ~DnDTreeViewBase() {}
+
+ void add_drop_targets (std::list<Gtk::TargetEntry>&);
+ void add_object_drag (int column, std::string type_name);
+
+ void on_drag_leave(const Glib::RefPtr<Gdk::DragContext>& context, guint time) {
+ suggested_action = context->get_suggested_action();
+ TreeView::on_drag_leave (context, time);
+ }
+
+ bool on_drag_motion(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time) {
+ suggested_action = context->get_suggested_action();
+ return TreeView::on_drag_motion (context, x, y, time);
+ }
+
+ bool on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time);
+
+ protected:
+ std::list<Gtk::TargetEntry> draggable;
+ Gdk::DragAction suggested_action;
+ int data_column;
+};
+
+template<class DataType>
+class DnDTreeView : public DnDTreeViewBase
+{
+ public:
+ DnDTreeView() {}
+ ~DnDTreeView() {}
+
+ sigc::signal<void,std::string,uint32_t,const DataType*> signal_object_drop;
+
+ void on_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& context, Gtk::SelectionData& selection_data, guint info, guint time) {
+ if (selection_data.get_target() == "GTK_TREE_MODEL_ROW") {
+
+ TreeView::on_drag_data_get (context, selection_data, info, time);
+
+ } else if (data_column >= 0) {
+
+ Gtk::TreeSelection::ListHandle_Path selection = get_selection()->get_selected_rows ();
+ SerializedObjectPointers<DataType>* sr = serialize_pointers (get_model(), &selection, selection_data.get_target());
+ selection_data.set (8, (guchar*)sr, sr->size);
+ }
+ }
+
+ void on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time) {
+ if (suggested_action) {
+ /* this is a drag motion callback. just update the status to
+ say that we are still dragging, and that's it.
+ */
+ suggested_action = Gdk::DragAction (0);
+ TreeView::on_drag_data_received (context, x, y, selection_data, info, time);
+ return;
+ }
+
+ if (selection_data.get_target() == "GTK_TREE_MODEL_ROW") {
+
+ TreeView::on_drag_data_received (context, x, y, selection_data, info, time);
+
+ } else if (data_column >= 0) {
+
+ /* object D-n-D */
+
+ const void* data = selection_data.get_data();
+ const SerializedObjectPointers<DataType>* sr = reinterpret_cast<const SerializedObjectPointers<DataType> *>(data);
+
+ if (sr) {
+ signal_object_drop (sr->type, sr->cnt, sr->data);
+ }
+
+ } else {
+ /* some kind of target type added by the app, which will be handled by a signal handler */
+ }
+ }
+
+ private:
+
+ SerializedObjectPointers<DataType>* serialize_pointers (Glib::RefPtr<Gtk::TreeModel> model,
+ Gtk::TreeSelection::ListHandle_Path* selection,
+ Glib::ustring type) {
+
+ /* this nasty chunk of code is here because X's DnD protocol (probably other graphics UI's too)
+ requires that we package up the entire data collection for DnD in a single contiguous region
+ (so that it can be trivially copied between address spaces). We don't know the type of DataType so
+ we have to mix-and-match C and C++ programming techniques here to get the right result.
+
+ The C trick is to use the "someType foo[0];" declaration trick to create a zero-sized array at the
+ end of a SerializedObjectPointers<DataType object. Then we allocate a raw memory buffer that extends
+ past that array and thus provides space for however many DataType items we actually want to pass
+ around.
+
+ The C++ trick is to use the placement operator new() syntax to initialize that extra
+ memory properly.
+ */
+
+ uint32_t cnt = selection->size();
+ uint32_t sz = (sizeof (DataType) * cnt) + sizeof (SerializedObjectPointers<DataType>);
+
+ char* buf = new char[sz];
+ SerializedObjectPointers<DataType>* sr = (SerializedObjectPointers<DataType>*) buf;
+
+ for (uint32_t i = 0; i < cnt; ++i) {
+ new ((void *) &sr->data[i]) DataType ();
+ }
+
+ sr->cnt = cnt;
+ sr->size = sz;
+ snprintf (sr->type, sizeof (sr->type), "%s", type.c_str());
+
+ cnt = 0;
+
+ for (Gtk::TreeSelection::ListHandle_Path::iterator x = selection->begin(); x != selection->end(); ++x, ++cnt) {
+ model->get_iter (*x)->get_value (data_column, sr->data[cnt]);
+ }
+
+ return sr;
+ }
+};
+
+} // namespace
+
+#endif /* __gtkmm2ext_dndtreeview_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/doi.h b/libs/gtkmm2ext/gtkmm2ext/doi.h
new file mode 100644
index 0000000000..6ad1f7dd94
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/doi.h
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) 2002 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_gtk_doi_h__
+#define __ardour_gtk_doi_h__
+
+#include <gtkmm.h>
+
+/* XXX g++ 2.95 can't compile this as pair of member function templates */
+
+template<typename T> gint idle_delete (T *obj) { delete obj; return FALSE; }
+template<typename T> void delete_when_idle (T *obj) {
+ Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (idle_delete<T>), obj));
+}
+template<typename T> gint delete_on_unmap (GdkEventAny *ignored, T *obj) {
+ Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (idle_delete<T>), obj));
+ return FALSE;
+}
+
+#endif /* __ardour_gtk_doi_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/fastmeter.h b/libs/gtkmm2ext/gtkmm2ext/fastmeter.h
new file mode 100644
index 0000000000..2bf4539d87
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/fastmeter.h
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2003 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_fastmeter_h__
+#define __gtkmm2ext_fastmeter_h__
+
+#include <gtkmm/drawingarea.h>
+#include <gdkmm/pixbuf.h>
+
+namespace Gtkmm2ext {
+
+class FastMeter : public Gtk::DrawingArea {
+ public:
+ enum Orientation {
+ Horizontal,
+ Vertical
+ };
+
+ FastMeter (long hold_cnt, unsigned long width, Orientation, int len=0, int clrb0=0x00ff00, int clr1=0xffff00, int clr2=0xffaa00, int clr3=0xff0000);
+ virtual ~FastMeter ();
+
+ void set (float level);
+ void clear ();
+
+ float get_level() { return current_level; }
+ float get_user_level() { return current_user_level; }
+ float get_peak() { return current_peak; }
+
+ long hold_count() { return hold_cnt; }
+ void set_hold_count (long);
+
+ protected:
+ bool on_expose_event (GdkEventExpose*);
+ void on_size_request (GtkRequisition*);
+ void on_size_allocate (Gtk::Allocation&);
+
+ private:
+
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf;
+ gint pixheight;
+ gint pixwidth;
+ static int _clr0, _clr1, _clr2, _clr3;
+
+ Orientation orientation;
+ GdkRectangle pixrect;
+ GdkRectangle last_peak_rect;
+ gint request_width;
+ gint request_height;
+ unsigned long hold_cnt;
+ unsigned long hold_state;
+ float current_level;
+ float current_peak;
+ float current_user_level;
+
+ bool vertical_expose (GdkEventExpose*);
+ bool horizontal_expose (GdkEventExpose*);
+ void queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>&, float);
+ void queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>&, float);
+
+ static Glib::RefPtr<Gdk::Pixbuf> request_vertical_meter(int w, int h);
+
+ static Glib::RefPtr<Gdk::Pixbuf> *v_pixbuf_cache;
+ static int min_v_pixbuf_size;
+ static int max_v_pixbuf_size;
+
+ static Glib::RefPtr<Gdk::Pixbuf> request_horizontal_meter(int w, int h);
+
+ static Glib::RefPtr<Gdk::Pixbuf> *h_pixbuf_cache;
+ static int min_h_pixbuf_size;
+ static int max_h_pixbuf_size;
+};
+
+
+} /* namespace */
+
+ #endif /* __gtkmm2ext_fastmeter_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/focus_entry.h b/libs/gtkmm2ext/gtkmm2ext/focus_entry.h
new file mode 100644
index 0000000000..3fb57b433d
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/focus_entry.h
@@ -0,0 +1,41 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_focus_entry_h__
+#define __gtkmm2ext_focus_entry_h__
+
+#include <gtkmm/entry.h>
+
+namespace Gtkmm2ext {
+
+class FocusEntry : public Gtk::Entry
+{
+ public:
+ FocusEntry ();
+
+ protected:
+ bool on_button_press_event (GdkEventButton*);
+ bool on_button_release_event (GdkEventButton*);
+ private:
+ bool next_release_selects;
+};
+
+}
+
+#endif /* __gtkmm2ext_focus_entry_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h b/libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h
new file mode 100644
index 0000000000..99d9f8ffc4
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2001 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_grouped_buttons_h__
+#define __gtkmm2ext_grouped_buttons_h__
+
+#include <stdint.h>
+
+#include <vector>
+#include <sigc++/signal.h>
+
+namespace Gtk {
+ class ToggleButton;
+};
+
+class GroupedButtons : public sigc::trackable
+{
+ public:
+ GroupedButtons (uint32_t nbuttons, uint32_t first_active);
+ GroupedButtons (std::vector<Gtk::ToggleButton *>&);
+
+ Gtk::ToggleButton& button (uint32_t which) {
+ return *buttons[which];
+ }
+
+ private:
+ std::vector<Gtk::ToggleButton *> buttons;
+ uint32_t current_active;
+ void one_clicked (uint32_t which);
+};
+
+#endif /* __gtkmm2ext_grouped_buttons_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
new file mode 100644
index 0000000000..0c2ff0d798
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
@@ -0,0 +1,177 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __pbd_gtk_ui_h__
+#define __pbd_gtk_ui_h__
+
+#include <string>
+#include <queue>
+#include <map>
+
+#include <stdint.h>
+#include <setjmp.h>
+#include <pthread.h>
+#include <gtkmm/widget.h>
+#include <gtkmm/style.h>
+#include <gtkmm/textbuffer.h>
+#include <gtkmm/main.h>
+#include <gtkmm/tooltips.h>
+#include <gdkmm/color.h>
+#include <pbd/abstract_ui.h>
+#include <pbd/ringbufferNPT.h>
+
+#include <pbd/pool.h>
+#include <pbd/error.h>
+#include <pbd/receiver.h>
+
+using std::string;
+using std::queue;
+
+class Touchable;
+
+namespace Gtkmm2ext {
+
+class TextViewer;
+
+extern BaseUI::RequestType ErrorMessage;
+extern BaseUI::RequestType Quit;
+extern BaseUI::RequestType CallSlot;
+extern BaseUI::RequestType TouchDisplay;
+extern BaseUI::RequestType StateChange;
+extern BaseUI::RequestType SetTip;
+extern BaseUI::RequestType AddIdle;
+extern BaseUI::RequestType AddTimeout;
+
+struct UIRequest : public BaseUI::BaseRequestObject {
+
+ /* this once used anonymous unions to merge elements
+ that are never part of the same request. that makes
+ the creation of a legal copy constructor difficult
+ because of the semantics of the slot member.
+ */
+
+ Touchable *display;
+ const char *msg;
+ Gtk::StateType new_state;
+ int (*function)(void *);
+ Gtk::Widget *widget;
+ Transmitter::Channel chn;
+ void *arg;
+ const char *msg2;
+ sigc::slot<void> slot;
+
+ ~UIRequest () {
+ if (type == ErrorMessage && msg) {
+ /* msg was strdup()'ed */
+ free ((char *)msg);
+ }
+ }
+ };
+
+class UI : public Receiver, public AbstractUI<UIRequest>
+{
+ public:
+ UI (string name, int *argc, char **argv[]);
+ virtual ~UI ();
+
+ static UI *instance() { return theGtkUI; }
+
+ /* receiver interface */
+
+ void receive (Transmitter::Channel, const char *);
+
+ /* Abstract UI interfaces */
+
+ bool caller_is_ui_thread ();
+
+ static pthread_t thread_id() { return gui_thread; }
+
+ /* Gtk-UI specific interfaces */
+
+ bool running ();
+ void quit ();
+ void kill ();
+ int load_rcfile (string, bool themechange = false);
+ void run (Receiver &old_receiver);
+
+ void set_state (Gtk::Widget *w, Gtk::StateType state);
+ void popup_error (const char *text);
+ void flush_pending ();
+ void toggle_errors ();
+ void touch_display (Touchable *);
+ void set_tip (Gtk::Widget *w, const gchar *tip, const gchar *hlp);
+ void idle_add (int (*func)(void *), void *arg);
+
+ template<class T> static bool idle_delete (T *obj) { delete obj; return false; }
+ template<class T> static void delete_when_idle (T *obj) {
+ Glib::signal_idle().connect (bind (slot (&UI::idle_delete<T>), obj));
+ }
+
+ Gdk::Color get_color (const string& prompt, bool& picked, const Gdk::Color *initial = 0);
+
+ /* starting is sent just before we enter the main loop,
+ stopping just after we return from it (at the top level)
+ */
+
+ sigc::signal<void> starting;
+ sigc::signal<void> stopping;
+
+ sigc::signal<void> theme_changed;
+
+ static bool just_hide_it (GdkEventAny *, Gtk::Window *);
+
+ static pthread_t the_gui_thread() { return gui_thread; }
+
+ protected:
+ virtual void handle_fatal (const char *);
+ virtual void display_message (const char *prefix, gint prefix_len,
+ Glib::RefPtr<Gtk::TextBuffer::Tag> ptag,
+ Glib::RefPtr<Gtk::TextBuffer::Tag> mtag,
+ const char *msg);
+
+ private:
+ static UI *theGtkUI;
+ static pthread_t gui_thread;
+ bool _active;
+ Gtk::Main *theMain;
+ Gtk::Tooltips *tips;
+ TextViewer *errors;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> error_ptag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> error_mtag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> fatal_ptag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> fatal_mtag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> info_ptag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> info_mtag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> warning_ptag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> warning_mtag;
+
+ static void signal_pipe_callback (void *, gint, GdkInputCondition);
+ void process_error_message (Transmitter::Channel, const char *);
+ void do_quit ();
+
+ void color_selection_done (bool status);
+ bool color_selection_deleted (GdkEventAny *);
+ bool color_picked;
+
+ void do_request (UIRequest*);
+};
+
+} /* namespace */
+
+#endif /* __pbd_gtk_ui_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/gtkutils.h b/libs/gtkmm2ext/gtkmm2ext/gtkutils.h
new file mode 100644
index 0000000000..832423f31d
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/gtkutils.h
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkutils_h__
+#define __gtkutils_h__
+
+#include <string>
+
+namespace Gtk {
+ class Widget;
+}
+
+void gtk_set_size_request_to_display_given_text (Gtk::Widget& w,
+ const std::string& text,
+ gint hpadding = 0,
+ gint vpadding = 0);
+#endif /* __gtkutils_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/hexentry.h b/libs/gtkmm2ext/gtkmm2ext/hexentry.h
new file mode 100644
index 0000000000..410f54274e
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/hexentry.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_hexentry_h__
+#define __gtkmm2ext_hexentry_h__
+
+#include <gtkmm.h>
+
+namespace Gtkmm2ext {
+
+class HexEntry : public Gtk::Entry
+
+{
+ public:
+ /* Take a byte-level representation of a series of hexadecimal
+ values and use them to set the displayed text of the entry.
+ Eg. if hexbuf[0] = 0xff and hexbuf[1] = 0xa1 and buflen = 2,
+ then the text will be set to "ff a1".
+ */
+
+ void set_hex (unsigned char *hexbuf, unsigned int buflen);
+
+ /* puts byte-level representation of current entry text
+ into hexbuf, and returns number of bytes written there.
+
+ NOTE: this will release the existing memory pointed to
+ by hexbuf if buflen indicates that it is not long enough
+ to hold the new representation, and hexbuf is not zero.
+
+ If the returned length is zero, the contents of hexbuf
+ are undefined.
+ */
+
+ unsigned int get_hex (unsigned char *hexbuf, size_t buflen);
+
+ private:
+ bool on_key_press_event (GdkEventKey *);
+};
+
+} /* namespace */
+
+#endif /* __gtkmm2ext_hexentry_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/idle_adjustment.h b/libs/gtkmm2ext/gtkmm2ext/idle_adjustment.h
new file mode 100644
index 0000000000..d8bda35cb5
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/idle_adjustment.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_idle_adjustment_h__
+#define __gtkmm2ext_idle_adjustment_h__
+
+#include <sys/time.h>
+#include <gtkmm/adjustment.h>
+
+namespace Gtkmm2ext {
+
+class IdleAdjustment : public sigc::trackable
+{
+ public:
+ IdleAdjustment (Gtk::Adjustment& adj);
+ ~IdleAdjustment ();
+
+ sigc::signal<void> value_changed;
+
+ private:
+ void underlying_adjustment_value_changed();
+ struct timeval last_vc;
+ gint timeout_handler();
+ bool timeout_queued;
+};
+
+}
+
+#endif /* __gtkmm2ext_idle_adjustment_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/pathlist.h b/libs/gtkmm2ext/gtkmm2ext/pathlist.h
new file mode 100644
index 0000000000..f4a5973d5a
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/pathlist.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_pathlist_h__
+#define __gtkmm2ext_pathlist_h__
+
+#include <vector>
+#include <string>
+
+#include <gtkmm.h>
+
+namespace Gtkmm2ext {
+
+class PathList : public Gtk::VBox
+{
+ public:
+ PathList ();
+ ~PathList () {};
+
+ std::vector<std::string> get_paths ();
+ void set_paths (std::vector<std::string> paths);
+
+ sigc::signal<void> PathsUpdated;
+
+ protected:
+ Gtk::Button add_btn;
+ Gtk::Button subtract_btn;
+
+ void add_btn_clicked ();
+ void subtract_btn_clicked ();
+
+ private:
+ struct PathColumns : public Gtk::TreeModel::ColumnRecord {
+ PathColumns() { add (paths); }
+ Gtk::TreeModelColumn<std::string> paths;
+ };
+ PathColumns path_columns;
+
+ Glib::RefPtr<Gtk::ListStore> _store;
+ Gtk::TreeView _view;
+
+ void selection_changed ();
+};
+
+} // namespace Gtkmm2ext
+
+#endif // __gtkmm2ext_pathlist_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/pixfader.h b/libs/gtkmm2ext/gtkmm2ext/pixfader.h
new file mode 100644
index 0000000000..519e1c9e1e
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/pixfader.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_pixfader_h__
+#define __gtkmm2ext_pixfader_h__
+
+#include <cmath>
+
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/adjustment.h>
+#include <gdkmm/pixbuf.h>
+
+namespace Gtkmm2ext {
+
+class PixFader : public Gtk::DrawingArea {
+ public:
+ PixFader (Glib::RefPtr<Gdk::Pixbuf> belt_image, Gtk::Adjustment& adjustment, int orientation);
+ virtual ~PixFader ();
+
+ protected:
+ Gtk::Adjustment& adjustment;
+
+ void on_size_request (GtkRequisition*);
+
+ bool on_expose_event (GdkEventExpose*);
+ bool on_button_press_event (GdkEventButton*);
+ bool on_button_release_event (GdkEventButton*);
+ bool on_motion_notify_event (GdkEventMotion*);
+ bool on_scroll_event (GdkEventScroll* ev);
+
+ enum Orientation {
+ VERT=1,
+ HORIZ=2,
+ };
+
+ private:
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf;
+ int span, girth;
+ int _orien;
+
+ GdkRectangle view;
+
+ GdkWindow* grab_window;
+ double grab_loc;
+ double grab_start;
+ int last_drawn;
+ bool dragging;
+ float default_value;
+ int unity_loc;
+
+ void adjustment_changed ();
+
+ int display_span ();
+
+ static int fine_scale_modifier;
+ static int extra_fine_scale_modifier;
+};
+
+
+} /* namespace */
+
+ #endif /* __gtkmm2ext_pixfader_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/pixscroller.h b/libs/gtkmm2ext/gtkmm2ext/pixscroller.h
new file mode 100644
index 0000000000..ea33359a25
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/pixscroller.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_pixscroller_h__
+#define __gtkmm2ext_pixscroller_h__
+
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/adjustment.h>
+#include <gdkmm.h>
+
+namespace Gtkmm2ext {
+
+class PixScroller : public Gtk::DrawingArea
+{
+ public:
+ PixScroller(Gtk::Adjustment& adjustment,
+ Glib::RefPtr<Gdk::Pixbuf> slider,
+ Glib::RefPtr<Gdk::Pixbuf> rail);
+
+ bool on_expose_event (GdkEventExpose*);
+ bool on_motion_notify_event (GdkEventMotion*);
+ bool on_button_press_event (GdkEventButton*);
+ bool on_button_release_event (GdkEventButton*);
+ bool on_scroll_event (GdkEventScroll*);
+ void on_size_request (GtkRequisition*);
+
+ protected:
+ Gtk::Adjustment& adj;
+
+ private:
+ Glib::RefPtr<Gdk::Pixbuf> rail;
+ Glib::RefPtr<Gdk::Pixbuf> slider;
+ Gdk::Rectangle sliderrect;
+ Gdk::Rectangle railrect;
+ GdkWindow* grab_window;
+ double grab_y;
+ double grab_start;
+ int overall_height;
+ bool dragging;
+
+ float default_value;
+
+ void adjustment_changed ();
+};
+
+} // namespace
+
+#endif /* __gtkmm2ext_pixscroller_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/popup.h b/libs/gtkmm2ext/gtkmm2ext/popup.h
new file mode 100644
index 0000000000..1db357341d
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/popup.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __qui_popup_h__
+#define __qui_popup_h__
+
+#include <string>
+#include <gtkmm.h>
+
+#include <pbd/touchable.h>
+
+namespace Gtkmm2ext {
+
+class PopUp : public Gtk::Window, public Touchable
+{
+ public:
+ PopUp (Gtk::WindowPosition pos, unsigned int show_for_msecs = 0,
+ bool delete_on_hide = false);
+ virtual ~PopUp ();
+ void touch ();
+ void remove ();
+ void set_text (std::string);
+ void set_name (std::string);
+ gint button_click (GdkEventButton *);
+
+ bool on_delete_event (GdkEventAny* );
+
+ protected:
+ void on_realize ();
+
+ private:
+ Gtk::Label label;
+ std::string my_text;
+ gint timeout;
+ static gint remove_prompt_timeout (void *);
+ bool delete_on_hide;
+ unsigned int popdown_time;
+
+};
+
+} /* namespace */
+
+#endif // __qui_popup_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/prompter.h b/libs/gtkmm2ext/gtkmm2ext/prompter.h
new file mode 100644
index 0000000000..5f71463288
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/prompter.h
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_prompter_h__
+#define __gtkmm2ext_prompter_h__
+
+#include <string>
+#include <gtkmm/box.h>
+#include <gtkmm/entry.h>
+#include <gtkmm/label.h>
+#include <gtkmm/dialog.h>
+#include <sigc++/sigc++.h>
+
+namespace Gtk {
+ class Window;
+}
+
+namespace Gtkmm2ext {
+
+class Prompter : public Gtk::Dialog
+
+{
+ public:
+ Prompter (bool modal = false);
+ Prompter (Gtk::Window& parent, bool modal = false);
+ ~Prompter () {};
+
+ void set_prompt (std::string prompt) {
+ entryLabel.set_label (prompt);
+ }
+
+ void set_initial_text (std::string txt) {
+ entry.set_text (txt);
+ entry.select_region (0, entry.get_text_length());
+ }
+
+ void change_labels (std::string ok, std::string cancel);
+
+ void get_result (std::string &str, bool strip=true);
+
+ protected:
+ Gtk::Entry& the_entry() { return entry; }
+
+ void on_entry_changed ();
+
+ private:
+ Gtk::Entry entry;
+ Gtk::HBox entryBox;
+ Gtk::Label entryLabel;
+
+ void init ();
+};
+
+} /* namespace */
+
+#endif /* __gtkmm2ext_prompter_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/scroomer.h b/libs/gtkmm2ext/gtkmm2ext/scroomer.h
new file mode 100644
index 0000000000..d4f2ce6aa3
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/scroomer.h
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2008 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_scroomer_h__
+#define __gtkmm2ext_scroomer_h__
+
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/adjustment.h>
+#include <gdkmm.h>
+
+namespace Gtkmm2ext {
+
+class Scroomer : public Gtk::DrawingArea
+{
+public:
+ enum Component {
+ TopBase = 0,
+ Handle1 = 1,
+ Slider = 2,
+ Handle2 = 3,
+ BottomBase = 4,
+ Total = 5,
+ None = 6
+ };
+
+ Scroomer(Gtk::Adjustment& adjustment);
+ ~Scroomer();
+
+ bool on_motion_notify_event (GdkEventMotion*);
+ bool on_button_press_event (GdkEventButton*);
+ bool on_button_release_event (GdkEventButton*);
+ bool on_scroll_event (GdkEventScroll*);
+ virtual void on_size_allocate (Gtk::Allocation&);
+
+ void set_comp_rect(GdkRectangle&, Component) const;
+
+ Component point_in(double point) const;
+
+ void set_min_page_size(double page_size);
+ int get_handle_size() { return handle_size; }
+
+ inline int position_of(Component comp) { return position[comp]; }
+
+ // debug
+ std::string get_comp_name(Component);
+
+protected:
+ Gtk::Adjustment& adj;
+
+private:
+ struct UpdateRect {
+ GdkRectangle rect;
+ Component first_comp;
+ };
+
+ void update();
+ void adjustment_changed ();
+
+ int position[6];
+ int old_pos[6];
+ int handle_size;
+ double min_page_size;
+ GdkWindow* grab_window;
+ Component grab_comp;
+ double grab_y;
+ double unzoomed_val;
+ double unzoomed_page;
+};
+
+} // namespace
+
+#endif /* __gtkmm2ext_scroomer_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/selector.h b/libs/gtkmm2ext/gtkmm2ext/selector.h
new file mode 100644
index 0000000000..841742db03
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/selector.h
@@ -0,0 +1,110 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkselector_h__
+#define __gtkselector_h__
+
+#include <string>
+#include <vector>
+
+#include <gtkmm.h>
+
+namespace Gtkmm2ext {
+
+class TreeView_Selector : public Gtk::TreeView
+{
+public:
+ TreeView_Selector() {}
+ virtual ~TreeView_Selector() {}
+
+protected:
+ virtual bool on_button_press_event(GdkEventButton *ev);
+};
+
+typedef void (SelectorRefillFunction)(Glib::RefPtr<Gtk::ListStore>, void *);
+
+class Selector : public Gtk::VBox
+{
+ friend class Gtkmm2ext::TreeView_Selector;
+
+public:
+ Selector (SelectorRefillFunction, void *arg,
+ std::vector<std::string> titles);
+
+ virtual ~Selector ();
+ Glib::RefPtr<Gtk::ListStore> liststore () { return lstore; }
+ void reset (void (*refiller)(Glib::RefPtr<Gtk::ListStore>, void *), void *arg);
+ void set_size (unsigned int w, unsigned int h) {
+ scroll.set_size_request (w, h);
+ tview.columns_autosize ();
+ }
+
+ struct Result {
+ Gtk::TreeView& view;
+ Glib::RefPtr<Gtk::TreeSelection> selection;
+
+ Result (Gtk::TreeView& v, Glib::RefPtr<Gtk::TreeSelection> sel)
+ : view (v), selection (sel) {}
+ };
+
+ /* selection is activated via a double click, choice via
+ a single click.
+ */
+ sigc::signal<void,Result*> selection_made;
+ sigc::signal<void,Result*> choice_made;
+ sigc::signal<void,Result*> shift_made;
+ sigc::signal<void,Result*> control_made;
+
+ sigc::signal<void> update_contents;
+
+ void accept();
+ void cancel();
+ void rescan();
+
+
+ protected:
+ virtual void on_map ();
+ virtual void on_show ();
+
+ private:
+ Gtk::ScrolledWindow scroll;
+ Gtk::TreeModel::ColumnRecord column_records;
+ Glib::RefPtr<Gtk::ListStore> lstore;
+ Gtkmm2ext::TreeView_Selector tview;
+ void (*refiller)(Glib::RefPtr<Gtk::ListStore>, void *);
+ void *refill_arg;
+ gint selected_row;
+ gint selected_column;
+ gint chosen_row;
+ gint chosen_column;
+
+ void refill ();
+ void chosen ();
+ void shift_clicked ();
+ void control_clicked ();
+
+ static gint _accept (gpointer);
+ static gint _chosen (gpointer);
+ static gint _shift_clicked (gpointer);
+ static gint _control_clicked (gpointer);
+
+};
+
+} /* namespace */
+
+#endif // __gtkselector_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
new file mode 100644
index 0000000000..60c8eef660
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 1998-2006 Paul Davis
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_slider_controller_h__
+#define __gtkmm2ext_slider_controller_h__
+
+#include <gtkmm.h>
+#include <gtkmm2ext/popup.h>
+#include <gtkmm2ext/pixfader.h>
+#include <gtkmm2ext/binding_proxy.h>
+
+namespace Gtkmm2ext {
+ class Pix;
+}
+
+namespace PBD {
+ class Controllable;
+}
+
+namespace Gtkmm2ext {
+
+class SliderController : public Gtkmm2ext::PixFader
+{
+ public:
+ SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
+ Gtk::Adjustment* adj, int orientation,
+ PBD::Controllable&,
+ bool with_numeric = true);
+
+ virtual ~SliderController () {}
+
+ void set_value (float);
+
+ Gtk::SpinButton& get_spin_button () { return spin; }
+
+ bool on_button_press_event (GdkEventButton *ev);
+
+ protected:
+ BindingProxy binding_proxy;
+ Glib::RefPtr<Gdk::Pixbuf> slider;
+ Glib::RefPtr<Gdk::Pixbuf> rail;
+ Gtk::SpinButton spin;
+ Gtk::Frame spin_frame;
+ Gtk::HBox spin_hbox;
+};
+
+class VSliderController : public SliderController
+{
+ public:
+ VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
+ Gtk::Adjustment *adj,
+ PBD::Controllable&,
+ bool with_numeric = true);
+};
+
+class HSliderController : public SliderController
+{
+ public:
+ HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
+ Gtk::Adjustment *adj,
+ PBD::Controllable&,
+ bool with_numeric = true);
+};
+
+
+}; /* namespace */
+
+#endif // __gtkmm2ext_slider_controller_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/stateful_button.h b/libs/gtkmm2ext/gtkmm2ext/stateful_button.h
new file mode 100644
index 0000000000..c86402e54e
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/stateful_button.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2005 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __pbd_gtkmm_abutton_h__
+#define __pbd_gtkmm_abutton_h__
+
+#include <vector>
+
+#include <gtkmm/togglebutton.h>
+
+namespace Gtkmm2ext {
+
+class StateButton
+{
+ public:
+ StateButton();
+ virtual ~StateButton() {}
+
+ void set_visual_state (int);
+ int get_visual_state () { return visual_state; }
+ void set_self_managed (bool yn) { _self_managed = yn; }
+
+ protected:
+ int visual_state;
+ bool _self_managed;
+ bool _is_realized;
+
+ virtual std::string get_widget_name() const = 0;
+ virtual void set_widget_name (std::string) = 0;
+ virtual int get_widget_state() = 0;
+};
+
+
+class StatefulToggleButton : public StateButton, public Gtk::ToggleButton
+{
+ public:
+ StatefulToggleButton() {}
+ explicit StatefulToggleButton(const std::string &label) : Gtk::ToggleButton (label) {}
+ ~StatefulToggleButton() {}
+
+ protected:
+ void on_realize ();
+ void on_toggled ();
+
+ std::string get_widget_name() const { return get_name(); }
+ void set_widget_name (std::string name) { set_name (name); get_child()->set_name (name); }
+ int get_widget_state() { return get_state(); }
+};
+
+class StatefulButton : public StateButton, public Gtk::Button
+{
+ public:
+ StatefulButton() {}
+ explicit StatefulButton(const std::string &label) : Gtk::Button (label) {}
+ virtual ~StatefulButton() {}
+
+ protected:
+ void on_realize ();
+
+ std::string get_widget_name() const { return get_name(); }
+ void set_widget_name (std::string name) { set_name (name); get_child()->set_name (name); }
+ int get_widget_state() { return get_state(); }
+};
+
+};
+
+#endif
diff --git a/libs/gtkmm2ext/gtkmm2ext/stop_signal.h b/libs/gtkmm2ext/gtkmm2ext/stop_signal.h
new file mode 100644
index 0000000000..cb8dedca12
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/stop_signal.h
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_gtk_stop_signal_h__
+#define __ardour_gtk_stop_signal_h__
+
+#include <gtkmm.h>
+#include <gtk/gtksignal.h>
+
+static inline gint
+stop_signal (Gtk::Widget& widget, const char *signal_name)
+{
+ gtk_signal_emit_stop_by_name (GTK_OBJECT(widget.gobj()), signal_name);
+ return TRUE;
+}
+
+#endif /* __ardour_gtk_stop_signal_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/sync-menu.h b/libs/gtkmm2ext/gtkmm2ext/sync-menu.h
new file mode 100644
index 0000000000..2be5e71d02
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/sync-menu.h
@@ -0,0 +1,44 @@
+/* GTK+ Integration for the Mac OS X Menubar.
+ *
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * Copyright (C) 2007 Imendio AB
+ *
+ * For further information, see:
+ * http://developer.imendio.com/projects/gtk-macosx/menubar
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __IGE_MAC_MENU_H__
+#define __IGE_MAC_MENU_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _IgeMacMenuGroup IgeMacMenuGroup;
+
+void ige_mac_menu_set_menu_bar (GtkMenuShell *menu_shell);
+void ige_mac_menu_set_quit_menu_item (GtkMenuItem *menu_item);
+
+IgeMacMenuGroup * ige_mac_menu_add_app_menu_group (void);
+void ige_mac_menu_add_app_menu_item (IgeMacMenuGroup *group,
+ GtkMenuItem *menu_item,
+ const gchar *label);
+
+G_END_DECLS
+
+#endif /* __IGE_MAC_MENU_H__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/tearoff.h b/libs/gtkmm2ext/gtkmm2ext/tearoff.h
new file mode 100644
index 0000000000..5e80892b98
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/tearoff.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2003 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_tearoff_h__
+#define __gtkmm2ext_tearoff_h__
+
+#include <gtkmm/window.h>
+#include <gtkmm/arrow.h>
+#include <gtkmm/box.h>
+#include <gtkmm/eventbox.h>
+
+namespace Gtkmm2ext {
+
+class TearOff : public Gtk::HBox
+{
+ public:
+ TearOff (Gtk::Widget& contents, bool allow_resize = false);
+ virtual ~TearOff ();
+
+ void set_visible (bool yn);
+
+ sigc::signal<void> Detach;
+ sigc::signal<void> Attach;
+ sigc::signal<void> Visible;
+ sigc::signal<void> Hidden;
+
+ Gtk::Window& tearoff_window() { return own_window; }
+ bool torn_off() const;
+
+ private:
+ Gtk::Widget& contents;
+ Gtk::Window own_window;
+ Gtk::Arrow tearoff_arrow;
+ Gtk::Arrow close_arrow;
+ Gtk::HBox window_box;
+ Gtk::EventBox tearoff_event_box;
+ Gtk::EventBox close_event_box;
+ double drag_x;
+ double drag_y;
+ bool dragging;
+ bool _visible;
+
+ gint tearoff_click (GdkEventButton*);
+ gint close_click (GdkEventButton*);
+
+ gint window_motion (GdkEventMotion*);
+ gint window_button_press (GdkEventButton*);
+ gint window_button_release (GdkEventButton*);
+ gint window_delete_event (GdkEventAny*);
+};
+
+} /* namespace */
+
+#endif // __gtkmm2ext_tearoff_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/textviewer.h b/libs/gtkmm2ext/gtkmm2ext/textviewer.h
new file mode 100644
index 0000000000..9cc639cd75
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/textviewer.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __pbd_gtkmm_textviewer_h__
+#define __pbd_gtkmm_textviewer_h__
+
+#include <string>
+#include <gtkmm.h>
+
+#include <pbd/transmitter.h>
+
+using std::string;
+
+namespace Gtkmm2ext {
+
+class TextViewer : public Gtk::Window, public Transmitter
+{
+ Gtk::TextView etext;
+ Gtk::VBox vbox1;
+ Gtk::VBox vbox2;
+ Gtk::ScrolledWindow scrollwin;
+ Gtk::Button dismiss;
+ bool _editable;
+
+ void toggle_edit ();
+ void toggle_word_wrap ();
+ void signal_released_handler ();
+
+ public:
+ TextViewer (size_t width, size_t height);
+ Gtk::TextView& text() { return etext; }
+ Gtk::Button& dismiss_button() { return dismiss; }
+
+ void insert_file (const string &);
+ void scroll_to_bottom ();
+
+ void deliver ();
+};
+
+} /* namespace */
+
+#endif // __pbd_gtkmm_textviewer_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/utils.h b/libs/gtkmm2ext/gtkmm2ext/utils.h
new file mode 100644
index 0000000000..ca1b88abba
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/utils.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtkmm2ext_utils_h__
+#define __gtkmm2ext_utils_h__
+
+#include <vector>
+#include <string>
+
+#include <gtkmm/treeview.h>
+#include <gdkmm/window.h> /* for WMDecoration */
+
+namespace Gtk {
+ class ComboBoxText;
+ class Widget;
+ class Window;
+ class Paned;
+}
+
+namespace Gtkmm2ext {
+ void init ();
+
+ void get_ink_pixel_size (Glib::RefPtr<Pango::Layout>, int& width, int& height);
+
+ void set_size_request_to_display_given_text (Gtk::Widget &w,
+ const gchar *text,
+ gint hpadding,
+ gint vpadding);
+
+ void set_popdown_strings (Gtk::ComboBoxText&, const std::vector<std::string>&);
+
+ template<class T> void deferred_delete (void *ptr) {
+ delete static_cast<T *> (ptr);
+ }
+
+ GdkWindow* get_paned_handle (Gtk::Paned& paned);
+ void set_decoration (Gtk::Window* win, Gdk::WMDecoration decor);
+ void set_treeview_header_as_default_label(Gtk::TreeViewColumn *c);
+ Glib::RefPtr<Gdk::Drawable> get_bogus_drawable();
+};
+
+#endif /* __gtkmm2ext_utils_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/window_title.h b/libs/gtkmm2ext/gtkmm2ext/window_title.h
new file mode 100644
index 0000000000..93b47d9d45
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/window_title.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef WINDOW_TITLE_INCLUDED
+#define WINDOW_TITLE_INCLUDED
+
+#include <string>
+
+namespace Gtkmm2ext {
+
+using std::string;
+
+/**
+ * \class The WindowTitle class can be used to maintain the
+ * consistancy of window titles between windows and dialogs.
+ *
+ * Each string element that is added to the window title will
+ * be separated by a hyphen.
+ */
+class WindowTitle
+{
+public:
+
+ /**
+ * \param title The first string/element of the window title
+ * which will may be the application name or the document
+ * name in a document based application.
+ */
+ WindowTitle(const string& title);
+
+ /**
+ * Add an string element to the window title.
+ */
+ void operator+= (const string&);
+
+ /// @return The window title string.
+ const string& get_string () { return m_title;}
+
+private:
+
+ string m_title;
+
+};
+
+} // Gtkmm2ext
+
+#endif // WINDOW_TITLE_INCLUDED
diff --git a/libs/gtkmm2ext/gtkutils.cc b/libs/gtkmm2ext/gtkutils.cc
new file mode 100644
index 0000000000..23bf4d6b2f
--- /dev/null
+++ b/libs/gtkmm2ext/gtkutils.cc
@@ -0,0 +1,22 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <gtkmm2ext/gtkutils.h>
+
diff --git a/libs/gtkmm2ext/hexentry.cc b/libs/gtkmm2ext/hexentry.cc
new file mode 100644
index 0000000000..9862cac435
--- /dev/null
+++ b/libs/gtkmm2ext/hexentry.cc
@@ -0,0 +1,111 @@
+/*
+ Copyright (C) 2000 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <stdio.h> /* for sprintf, sigh ... */
+#include <string>
+#include <ctype.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtkmm2ext/hexentry.h>
+
+using namespace std;
+using namespace Gtkmm2ext;
+
+bool
+HexEntry::on_key_press_event (GdkEventKey *ev)
+
+{
+ if ((ev->keyval >= GDK_a && ev->keyval <= GDK_f) ||
+ (ev->keyval >= GDK_A && ev->keyval <= GDK_A) ||
+ (ev->keyval >= GDK_0 && ev->keyval <= GDK_9) ||
+ ev->keyval == GDK_space ||
+ ev->keyval == GDK_Tab ||
+ ev->keyval == GDK_Return ||
+ ev->keyval == GDK_BackSpace ||
+ ev->keyval == GDK_Delete) {
+ return Gtk::Entry::on_key_press_event (ev);
+ } else {
+ gdk_beep ();
+ return FALSE;
+ }
+}
+
+
+void
+HexEntry::set_hex (unsigned char *msg, unsigned int len)
+
+{
+ /* create a textual representation of the MIDI message */
+
+ if (msg && len) {
+ char *rep;
+
+ rep = new char[(len * 3) + 1];
+ for (size_t i = 0; i < len; i++) {
+ sprintf (&rep[i*3], "%02x ", msg[i]);
+ }
+ rep[len * 3] = '\0';
+ set_text (rep);
+ delete [] rep;
+ } else {
+ set_text ("");
+ }
+}
+
+unsigned int
+HexEntry::get_hex (unsigned char *hexbuf, size_t buflen)
+
+{
+ int fetched_len;
+ char buf[3];
+ string text = get_text();
+ string::size_type length = text.length ();
+ string::size_type offset;
+
+ fetched_len = 0;
+ buf[2] = '\0';
+ offset = 0;
+
+ while (1) {
+ offset = text.find_first_of ("abcdef0123456789", offset);
+
+ if (offset == string::npos) {
+ break;
+ }
+
+ /* grab two characters, but no more */
+
+ buf[0] = text[offset];
+
+ if (offset < length - 1) {
+ buf[1] = text[offset+1];
+ offset += 2;
+ } else {
+ buf[1] = '\0';
+ offset += 1;
+ }
+
+ hexbuf[fetched_len++] = (char) strtol (buf, 0, 16);
+ }
+
+ return fetched_len;
+}
+
+
diff --git a/libs/gtkmm2ext/i18n.h b/libs/gtkmm2ext/i18n.h
new file mode 100644
index 0000000000..7c79d2eb53
--- /dev/null
+++ b/libs/gtkmm2ext/i18n.h
@@ -0,0 +1,11 @@
+#ifndef __i18n_h__
+#define __i18n_h__
+
+#include <pbd/compose.h>
+#include "gettext.h"
+
+#define _(Text) dgettext (PACKAGE, Text)
+#define N_(Text) gettext_noop (Text)
+#define X_(Text) (Text)
+
+#endif // __i18n_h__
diff --git a/libs/gtkmm2ext/idle_adjustment.cc b/libs/gtkmm2ext/idle_adjustment.cc
new file mode 100644
index 0000000000..3e3a3da566
--- /dev/null
+++ b/libs/gtkmm2ext/idle_adjustment.cc
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#define _BSD_SOURCE
+#include <gtkmm2ext/idle_adjustment.h>
+#include <gtkmm/main.h>
+#include <iostream>
+
+using namespace Gtk;
+using namespace sigc;
+using namespace Gtkmm2ext;
+
+IdleAdjustment::IdleAdjustment (Gtk::Adjustment& adj)
+{
+ adj.signal_value_changed().connect (mem_fun (*this, &IdleAdjustment::underlying_adjustment_value_changed));
+ timeout_queued = 0;
+ gettimeofday (&last_vc, 0);
+}
+
+IdleAdjustment::~IdleAdjustment ()
+{
+}
+
+void
+IdleAdjustment::underlying_adjustment_value_changed ()
+{
+ gettimeofday (&last_vc, 0);
+
+ if (timeout_queued) {
+ return;
+ }
+
+ Glib::signal_timeout().connect(mem_fun(*this, &IdleAdjustment::timeout_handler), 250);
+ timeout_queued = true;
+}
+
+gint
+IdleAdjustment::timeout_handler ()
+{
+ struct timeval now;
+ struct timeval tdiff;
+
+ gettimeofday (&now, 0);
+
+ timersub (&now, &last_vc, &tdiff);
+
+ std::cerr << "timer elapsed, diff = " << tdiff.tv_sec << " + " << tdiff.tv_usec << std::endl;
+
+ if (tdiff.tv_sec > 0 || tdiff.tv_usec > 250000) {
+ std::cerr << "send signal\n";
+ value_changed ();
+ timeout_queued = false;
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
diff --git a/libs/gtkmm2ext/libgtkmm2ext.pc.in b/libs/gtkmm2ext/libgtkmm2ext.pc.in
new file mode 100644
index 0000000000..ee87973e2b
--- /dev/null
+++ b/libs/gtkmm2ext/libgtkmm2ext.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/gtkmm2ext
+
+Name: libgtkmm2ext
+Version: @VERSION@
+Description: libgtkmm2ext, a library of useful new C++ and C widgets for gtkmm users
+Requires: libpbd, libmidi++
+Libs: -L${libdir} -lgtkmm2ext @NON_PKG_LIBS@
+Cflags: -I${includedir} @NON_PKG_CFLAGS@
diff --git a/libs/gtkmm2ext/libgtkmm2ext.spec.in b/libs/gtkmm2ext/libgtkmm2ext.spec.in
new file mode 100644
index 0000000000..19657721ef
--- /dev/null
+++ b/libs/gtkmm2ext/libgtkmm2ext.spec.in
@@ -0,0 +1,68 @@
+Summary: extensions to the libgtkmm library
+%define lib_name gtkmm2ext
+Name: lib%{lib_name}
+Version: @VERSION@
+Release: 2
+Copyright: GPL
+Source: ftp://ftp.quasimodo.org/pub/libs/gtkmm2ext/current/%{name}-%{version}.tar.gz
+Url: http://www.quasimodo.org
+Vendor: Paul Barton Davis <pbd@op.net>
+Packager: jfm3 <jfm3@acm.org>
+Group: System Environment/Libraries
+Prefix: %{_prefix}
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+
+%description
+
+libgtkmm2ext provides extensions to Gtk-- useful for audio
+applications. These include ShapedWindow, MotionFeedback,
+PixmapButton and several more. It also includes the useful Pix class
+for managing sets of pixmaps, with reference counting etc.
+
+%prep
+%setup -q
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure $ARCH_FLAGS --prefix=%{prefix}
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+install -d -m 755 $RPM_BUILD_ROOT%{prefix}/{{include,lib}/%{lib_name}}
+make install INSTALL="%(which install) -p" prefix=$RPM_BUILD_ROOT%{prefix}
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%doc README AUTHORS NEWS COPYING*
+%{prefix}/lib/libgtkmm2ext.so*
+
+%package devel
+Summary: extensions to the libgtkmm library -- developer package
+Group: System Environment/Libraries
+
+%description devel
+
+libgtkmm2ext provides extensions to Gtk-- useful for audio
+applications. These include ShapedWindow, MotionFeedback,
+PixmapButton and several more. It also includes the useful Pix class
+for managing sets of pixmaps, with reference counting etc.
+
+This package holds static libraries and headers needed by developers
+who wish to use libgtkmm2ext in their programs.
+
+%files devel
+%defattr(-,root,root)
+%{prefix}/include/gtkmm2ext/*
+%{prefix}/lib/libgtkmm2ext.a
+%{prefix}/lib/libgtkmm2ext.la
+%{prefix}/bin/gtkmm2ext-config
+%{prefix}/share/aclocal/gtkmm2ext.m4
diff --git a/libs/gtkmm2ext/pathlist.cc b/libs/gtkmm2ext/pathlist.cc
new file mode 100644
index 0000000000..7b3448ed5f
--- /dev/null
+++ b/libs/gtkmm2ext/pathlist.cc
@@ -0,0 +1,124 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <gtkmm2ext/pathlist.h>
+
+#include "i18n.h"
+
+using namespace std;
+using namespace Gtkmm2ext;
+
+PathList::PathList ()
+ :
+ add_btn(_("+")),
+ subtract_btn(_("-")),
+ path_columns(),
+ _store(Gtk::ListStore::create(path_columns)),
+ _view(_store)
+{
+ _view.append_column(_("Paths"), path_columns.paths);
+ _view.set_size_request(-1, 100);
+ _view.set_headers_visible (false);
+
+ Gtk::ScrolledWindow* scroll = manage(new Gtk::ScrolledWindow);
+ scroll->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+ scroll->add(_view);
+
+ add (*scroll);
+
+ Gtk::HBox* btn_box = manage(new Gtk::HBox);
+ btn_box->add(add_btn);
+ btn_box->add(subtract_btn);
+
+ add (*btn_box);
+
+ add_btn.signal_clicked().connect (mem_fun(*this, &PathList::add_btn_clicked));
+ subtract_btn.signal_clicked().connect (mem_fun(*this, &PathList::subtract_btn_clicked));
+ _view.get_selection()->signal_changed().connect (mem_fun(*this, &PathList::selection_changed));
+}
+
+vector<string>
+PathList::get_paths ()
+{
+ vector<string> paths;
+
+ Gtk::TreeModel::Children children(_store->children());
+
+ for (Gtk::TreeIter iter = children.begin(); iter != children.end(); ++iter) {
+ Gtk::ListStore::Row row = *iter;
+
+ paths.push_back(row[path_columns.paths]);
+ }
+
+ return paths;
+}
+
+void
+PathList::set_paths (vector<string> paths)
+{
+ _store->clear();
+
+ for (vector<string>::iterator i = paths.begin(); i != paths.end(); ++i) {
+ Gtk::ListStore::iterator iter = _store->append();
+ Gtk::ListStore::Row row = *iter;
+ row[path_columns.paths] = *i;
+ }
+}
+
+void
+PathList::add_btn_clicked ()
+{
+ Gtk::FileChooserDialog path_chooser (_("Path Chooser"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
+
+ path_chooser.add_button (Gtk::Stock::ADD, Gtk::RESPONSE_OK);
+ path_chooser.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+
+ int result = path_chooser.run ();
+
+ if (result == Gtk::RESPONSE_OK) {
+ string pathname = path_chooser.get_filename();
+
+ if (pathname.length ()) {
+ Gtk::ListStore::iterator iter = _store->append ();
+ Gtk::ListStore::Row row = *iter;
+ row[path_columns.paths] = pathname;
+
+ PathsUpdated (); // EMIT_SIGNAL
+ }
+ }
+}
+
+void
+PathList::subtract_btn_clicked ()
+{
+ Gtk::ListStore::iterator iter = _view.get_selection()->get_selected();
+ _store->erase (iter);
+
+ PathsUpdated (); // EMIT_SIGNAL
+}
+
+void
+PathList::selection_changed ()
+{
+ if (_view.get_selection()->count_selected_rows ()) {
+ subtract_btn.set_sensitive (true);
+ } else {
+ subtract_btn.set_sensitive (false);
+ }
+}
diff --git a/libs/gtkmm2ext/pixfader.cc b/libs/gtkmm2ext/pixfader.cc
new file mode 100644
index 0000000000..521a6cb9ca
--- /dev/null
+++ b/libs/gtkmm2ext/pixfader.cc
@@ -0,0 +1,309 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id: fastmeter.h 570 2006-06-07 21:21:21Z sampo $
+*/
+
+
+#include <iostream>
+#include <gtkmm2ext/pixfader.h>
+
+using namespace Gtkmm2ext;
+using namespace Gtk;
+using namespace Gdk;
+using namespace std;
+
+#ifdef GTKOSX
+int PixFader::fine_scale_modifier = GDK_META_MASK;
+#else
+int PixFader::fine_scale_modifier = GDK_CONTROL_MASK;
+#endif
+
+int PixFader::extra_fine_scale_modifier = GDK_MOD1_MASK;
+
+PixFader::PixFader (Glib::RefPtr<Pixbuf> belt, Gtk::Adjustment& adj, int orientation)
+
+ : adjustment (adj),
+ pixbuf (belt),
+ _orien(orientation)
+{
+ dragging = false;
+ default_value = adjustment.get_value();
+ last_drawn = -1;
+
+ view.x = 0;
+ view.y = 0;
+
+ if (orientation == VERT) {
+ view.width = girth = pixbuf->get_width();
+ view.height = span = pixbuf->get_height() / 2;
+ unity_loc = (int) rint (view.height - (default_value * view.height)) - 1;
+ } else {
+ view.width = span = pixbuf->get_width () / 2;
+ view.height = girth = pixbuf->get_height();
+ unity_loc = (int) rint (default_value * view.width) - 1;
+ }
+
+ add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
+
+ adjustment.signal_value_changed().connect (mem_fun (*this, &PixFader::adjustment_changed));
+ adjustment.signal_changed().connect (mem_fun (*this, &PixFader::adjustment_changed));
+}
+
+PixFader::~PixFader ()
+{
+}
+
+bool
+PixFader::on_expose_event (GdkEventExpose* ev)
+{
+ GdkRectangle intersection;
+ int srcx, srcy, ds = display_span ();
+ int offset_into_pixbuf = (int) floor (span / ((float) span / ds));
+ Glib::RefPtr<Gdk::GC> fg_gc (get_style()->get_fg_gc(get_state()));
+
+ if (gdk_rectangle_intersect (&view, &ev->area, &intersection)) {
+ if (_orien == VERT) {
+ srcx = intersection.x;
+ srcy = offset_into_pixbuf + intersection.y;
+ } else {
+ srcx = offset_into_pixbuf + intersection.x;
+ srcy = intersection.y;
+ }
+ get_window()->draw_pixbuf (fg_gc, pixbuf,
+ srcx, srcy,
+ intersection.x, intersection.y,
+ intersection.width, intersection.height,
+ Gdk::RGB_DITHER_NONE, 0, 0);
+
+ get_window()->draw_line (get_style()->get_bg_gc(STATE_ACTIVE), 0, 0, view.width - 1, 0); /* top */
+ get_window()->draw_line (get_style()->get_bg_gc(STATE_ACTIVE), 0, 0, 0, view.height - 1); /* left */
+ get_window()->draw_line (get_style()->get_bg_gc(STATE_NORMAL), view.width - 1, 0, view.width - 1, view.height - 1); /* right */
+ get_window()->draw_line (get_style()->get_bg_gc(STATE_NORMAL), 0, view.height - 1, view.width - 1, view.height - 1); /* bottom */
+ }
+
+ /* always draw the line */
+ if (_orien == VERT) {
+ get_window()->draw_line (fg_gc, 1, unity_loc, girth - 2, unity_loc);
+ } else {
+ get_window()->draw_line (fg_gc, unity_loc, 1, unity_loc, girth - 2);
+ }
+ last_drawn = ds;
+ return true;
+}
+
+void
+PixFader::on_size_request (GtkRequisition* req)
+{
+ req->width = view.width;
+ req->height = view.height;
+}
+
+bool
+PixFader::on_button_press_event (GdkEventButton* ev)
+{
+ switch (ev->button) {
+ case 1:
+ case 2:
+ add_modal_grab();
+ grab_loc = (_orien == VERT) ? ev->y : ev->x;
+ grab_start = (_orien == VERT) ? ev->y : ev->x;
+ grab_window = ev->window;
+ dragging = true;
+ break;
+ default:
+ break;
+ }
+
+
+ return false;
+}
+
+bool
+PixFader::on_button_release_event (GdkEventButton* ev)
+{
+ double fract, ev_pos;
+
+ ev_pos = (_orien == VERT) ? ev->y : ev->x;
+
+ switch (ev->button) {
+ case 1:
+ if (dragging) {
+ remove_modal_grab();
+ dragging = false;
+
+ if (ev_pos == grab_start) {
+
+ /* no motion - just a click */
+
+ if (ev->state & Gdk::SHIFT_MASK) {
+ adjustment.set_value (default_value);
+ } else if (ev->state & fine_scale_modifier) {
+ adjustment.set_value (adjustment.get_lower());
+ } else if ((_orien == VERT && ev_pos < span - display_span()) || (_orien == HORIZ && ev_pos > span - display_span())) {
+ /* above the current display height, remember X Window coords */
+ adjustment.set_value (adjustment.get_value() + adjustment.get_step_increment());
+ } else {
+ adjustment.set_value (adjustment.get_value() - adjustment.get_step_increment());
+ }
+ }
+
+ }
+ break;
+
+ case 2:
+ if (dragging) {
+ remove_modal_grab();
+ dragging = false;
+
+ fract = 1.0 - (ev_pos / span); // inverted X Window coordinates, grrr
+
+ fract = min (1.0, fract);
+ fract = max (0.0, fract);
+
+ adjustment.set_value (fract * (adjustment.get_upper() - adjustment.get_lower()));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool
+PixFader::on_scroll_event (GdkEventScroll* ev)
+{
+ double scale;
+ bool ret = false;
+
+ if (ev->state & fine_scale_modifier) {
+ if (ev->state & extra_fine_scale_modifier) {
+ scale = 0.01;
+ } else {
+ scale = 0.05;
+ }
+ } else {
+ scale = 0.25;
+ }
+
+ if (_orien == VERT) {
+
+ /* should left/right scroll affect vertical faders ? */
+
+ switch (ev->direction) {
+
+ case GDK_SCROLL_UP:
+ /* wheel up */
+ adjustment.set_value (adjustment.get_value() + (adjustment.get_page_increment() * scale));
+ ret = true;
+ break;
+ case GDK_SCROLL_DOWN:
+ /* wheel down */
+ adjustment.set_value (adjustment.get_value() - (adjustment.get_page_increment() * scale));
+ ret = true;
+ break;
+ default:
+ break;
+ }
+ } else {
+
+ /* up/down scrolls should definitely affect horizontal faders
+ because they are so much easier to use
+ */
+
+ switch (ev->direction) {
+
+ case GDK_SCROLL_RIGHT:
+ case GDK_SCROLL_UP:
+ /* wheel right */
+ adjustment.set_value (adjustment.get_value() + (adjustment.get_page_increment() * scale));
+ ret = true;
+ break;
+ case GDK_SCROLL_LEFT:
+ case GDK_SCROLL_DOWN:
+ /* wheel left */
+ adjustment.set_value (adjustment.get_value() - (adjustment.get_page_increment() * scale));
+ ret = true;
+ break;
+ default:
+ break;
+ }
+ }
+ return ret;
+}
+
+bool
+PixFader::on_motion_notify_event (GdkEventMotion* ev)
+{
+ if (dragging) {
+ double fract, delta, scale, ev_pos;
+ ev_pos = (_orien == VERT) ? ev->y : ev->x;
+ //cerr << "PixFader::on_motion_notify_event() called x:y = " << ev->x << ":" << ev->y;
+ if (ev->window != grab_window) {
+ grab_loc = ev_pos;
+ grab_window = ev->window;
+ return true;
+ }
+
+ if (ev->state & fine_scale_modifier) {
+ if (ev->state & extra_fine_scale_modifier) {
+ scale = 0.05;
+ } else {
+ scale = 0.1;
+ }
+ } else {
+ scale = 1.0;
+ }
+ //cerr << " ev_pos=" << ev_pos << " grab_loc=" << grab_loc;
+ delta = ev_pos - grab_loc;
+ grab_loc = ev_pos;
+
+ fract = (delta / span);
+
+ fract = min (1.0, fract);
+ fract = max (-1.0, fract);
+
+ // X Window is top->bottom for 0..Y
+
+ if (_orien == VERT) {
+ fract = -fract;
+ }
+
+ adjustment.set_value (adjustment.get_value() + scale * fract * (adjustment.get_upper() - adjustment.get_lower()));
+ //cerr << " adj=" << adjustment.get_value() << " fract=" << fract << " delta=" << delta << " scale=" << scale << endl;
+ }
+
+ return true;
+}
+
+void
+PixFader::adjustment_changed ()
+{
+ if (display_span() != last_drawn) {
+ queue_draw ();
+ }
+}
+
+int
+PixFader::display_span ()
+{
+ float fract = (adjustment.get_upper() - adjustment.get_value ()) / ((adjustment.get_upper() - adjustment.get_lower()));
+ return (_orien == VERT) ? (int)floor (span * (1.0 - fract)) : (int)floor (span * fract);
+}
+
diff --git a/libs/gtkmm2ext/pixscroller.cc b/libs/gtkmm2ext/pixscroller.cc
new file mode 100644
index 0000000000..f459726f27
--- /dev/null
+++ b/libs/gtkmm2ext/pixscroller.cc
@@ -0,0 +1,265 @@
+/*
+ Copyright (C) 2005 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+#include <iostream>
+#include <algorithm>
+#include <cmath>
+
+#include <gtkmm.h>
+
+#include <gtkmm2ext/pixscroller.h>
+
+using namespace std;
+using namespace Gtk;
+using namespace Gtkmm2ext;
+
+PixScroller::PixScroller (Adjustment& a,
+ Glib::RefPtr<Gdk::Pixbuf> s,
+ Glib::RefPtr<Gdk::Pixbuf> r)
+ : adj (a),
+ rail (r),
+ slider (s)
+{
+ dragging = false;
+ add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
+
+ adj.signal_value_changed().connect (mem_fun (*this, &PixScroller::adjustment_changed));
+ default_value = adj.get_value();
+
+ sliderrect.set_width(slider->get_width());
+ sliderrect.set_height(slider->get_height());
+ railrect.set_width(rail->get_width());
+ railrect.set_height(rail->get_height());
+
+ railrect.set_y(sliderrect.get_height() / 2);
+ sliderrect.set_x(0);
+
+ overall_height = railrect.get_height() + sliderrect.get_height();
+
+ sliderrect.set_y((int) rint ((overall_height - sliderrect.get_height()) * (adj.get_upper() - adj.get_value())));
+ railrect.set_x((sliderrect.get_width() / 2) - 2);
+}
+
+void
+PixScroller::on_size_request (GtkRequisition* requisition)
+{
+ requisition->width = sliderrect.get_width();
+ requisition->height = overall_height;
+}
+
+bool
+PixScroller::on_expose_event (GdkEventExpose* ev)
+{
+ GdkRectangle intersect;
+ Glib::RefPtr<Gdk::Window> win (get_window());
+
+ win->draw_rectangle (get_style()->get_bg_gc(get_state()), TRUE,
+ ev->area.x,
+ ev->area.y,
+ ev->area.width,
+ ev->area.height);
+
+ if (gdk_rectangle_intersect (railrect.gobj(), &ev->area, &intersect)) {
+ Glib::RefPtr<Gdk::GC> gc(get_style()->get_bg_gc(get_state()));
+ win->draw_pixbuf (gc, rail,
+ intersect.x - railrect.get_x(),
+ intersect.y - railrect.get_y(),
+ intersect.x,
+ intersect.y,
+ intersect.width,
+ intersect.height,
+ Gdk::RGB_DITHER_NONE, 0, 0);
+ }
+
+ if (gdk_rectangle_intersect (sliderrect.gobj(), &ev->area, &intersect)) {
+ Glib::RefPtr<Gdk::GC> gc(get_style()->get_fg_gc(get_state()));
+ // Glib::RefPtr<Gdk::Bitmap> mask (slider_mask);
+
+ GdkGCValues values;
+ gdk_gc_get_values(gc->gobj(), &values);
+ gc->set_clip_origin (sliderrect.get_x(), sliderrect.get_y());
+ // gc->set_clip_mask (mask);
+ win->draw_pixbuf (gc, slider,
+ intersect.x - sliderrect.get_x(),
+ intersect.y - sliderrect.get_y(),
+ intersect.x,
+ intersect.y,
+ intersect.width,
+ intersect.height,
+ Gdk::RGB_DITHER_NONE, 0, 0);
+ gc->set_clip_origin (values.clip_x_origin, values.clip_y_origin);
+ // gdk_gc_set_clip_mask (gc->gobj(), values.clip_mask);
+ }
+
+
+ return true;
+}
+
+bool
+PixScroller::on_button_press_event (GdkEventButton* ev)
+{
+ switch (ev->button) {
+ case 1:
+ if (!(ev->state & Gdk::SHIFT_MASK)) {
+ add_modal_grab();
+ grab_y = ev->y;
+ grab_start = ev->y;
+ grab_window = ev->window;
+ dragging = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+
+ return false;
+}
+
+bool
+PixScroller::on_button_release_event (GdkEventButton* ev)
+{
+ double scale;
+
+ if (ev->state & GDK_CONTROL_MASK) {
+ if (ev->state & GDK_MOD1_MASK) {
+ scale = 0.05;
+ } else {
+ scale = 0.1;
+ }
+ } else {
+ scale = 1.0;
+ }
+
+ switch (ev->button) {
+ case 1:
+ if (dragging) {
+ remove_modal_grab();
+ dragging = false;
+
+ if (ev->y == grab_start) {
+ /* no motion - just a click */
+ double fract;
+
+ if (ev->y < sliderrect.get_height()/2) {
+ /* near the top */
+ fract = 1.0;
+ } else {
+ fract = 1.0 - (ev->y - sliderrect.get_height()/2) / railrect.get_height();
+ }
+
+ fract = min (1.0, fract);
+ fract = max (0.0, fract);
+
+ adj.set_value (scale * fract * (adj.get_upper() - adj.get_lower()));
+ }
+ } else {
+ if (ev->state & Gdk::SHIFT_MASK) {
+ adj.set_value (default_value);
+ cerr << "default value = " << default_value << endl;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+PixScroller::on_scroll_event (GdkEventScroll* ev)
+{
+ double scale;
+
+ if (ev->state & GDK_CONTROL_MASK) {
+ if (ev->state & GDK_MOD1_MASK) {
+ scale = 0.05;
+ } else {
+ scale = 0.1;
+ }
+ } else {
+ scale = 0.5;
+ }
+
+ switch (ev->direction) {
+
+ case GDK_SCROLL_UP:
+ /* wheel up */
+ adj.set_value (adj.get_value() + (adj.get_page_increment() * scale));
+ break;
+ case GDK_SCROLL_DOWN:
+ /* wheel down */
+ adj.set_value (adj.get_value() - (adj.get_page_increment() * scale));
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+PixScroller::on_motion_notify_event (GdkEventMotion* ev)
+{
+ if (dragging) {
+ double fract;
+ double delta;
+ double scale;
+
+ if (ev->window != grab_window) {
+ grab_y = ev->y;
+ grab_window = ev->window;
+ return true;
+ }
+
+ if (ev->state & GDK_CONTROL_MASK) {
+ if (ev->state & GDK_MOD1_MASK) {
+ scale = 0.05;
+ } else {
+ scale = 0.1;
+ }
+ } else {
+ scale = 1.0;
+ }
+
+ delta = ev->y - grab_y;
+ grab_y = ev->y;
+
+ fract = (delta / railrect.get_height());
+
+ fract = min (1.0, fract);
+ fract = max (-1.0, fract);
+
+ fract = -fract;
+
+ adj.set_value (adj.get_value() + scale * fract * (adj.get_upper() - adj.get_lower()));
+ }
+
+ return true;
+}
+
+void
+PixScroller::adjustment_changed ()
+{
+ int y = (int) rint ((overall_height - sliderrect.get_height()) * (adj.get_upper() - adj.get_value()));
+
+ if (y != sliderrect.get_y()) {
+ sliderrect.set_y(y);
+ queue_draw ();
+ }
+}
diff --git a/libs/gtkmm2ext/po/el_GR.po b/libs/gtkmm2ext/po/el_GR.po
new file mode 100644
index 0000000000..cc10981aa8
--- /dev/null
+++ b/libs/gtkmm2ext/po/el_GR.po
@@ -0,0 +1,59 @@
+# Σχολιαστικός Τίτλος.
+# Πνευματικά Δικαιώματα (C) YEAR Paul Davis
+# Το παÏόν αÏχείο διανέμεται υπό της ιδίας αδείας με του PACKAGE πακέτου.
+# ΠΡΩΤΟΣ ΔΗΜΙΟΥΡΓΟΣ <muadib@in.gr>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: 0.99beta23\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-06-21 15:09-0400\n"
+"PO-Revision-Date: 2005-01-11\n"
+"Last-Translator: Muadibas\n"
+"Language-Team: Hellenic(Greek) <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: libs/gtkmm2ext/barcontroller.cc:432 libs/gtkmm2ext/bindable_button.cc:131
+#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:132
+msgid "operate MIDI controller now"
+msgstr "λειτουÏγία ελεγκτή MIDI Ï„ÏŽÏα"
+
+#: libs/gtkmm2ext/gtk_ui.cc:510
+msgid "Press To Exit"
+msgstr ""
+
+#: libs/gtkmm2ext/textviewer.cc:34
+msgid "Close"
+msgstr "Κλείσιμο"
+
+#~ msgid "OK"
+#~ msgstr "OK"
+
+#~ msgid "Location:"
+#~ msgstr "Τοποθεσία:"
+
+#~ msgid "Browse ..."
+#~ msgstr "Αναζήτηση ..."
+
+#~ msgid "Cancel"
+#~ msgstr "ΑκÏÏωση"
+
+#~ msgid "New folder"
+#~ msgstr "Îέος φάκελος"
+
+#~ msgid "Add to favorites"
+#~ msgstr "ΠÏόσθεση στα 'Αγαπημένα'"
+
+#~ msgid "Remove from favorites"
+#~ msgstr "Απαλοιφή από τα 'Αγαπημένα'"
+
+#~ msgid "Show Hidden"
+#~ msgstr "Ανάδειξη κÏυμμένων"
+
+#~ msgid "Hide browser"
+#~ msgstr "ΑπόκÏυψη browser"
+
+#~ msgid "Rescan"
+#~ msgstr "Ανανέωση"
diff --git a/libs/gtkmm2ext/po/es_ES.po b/libs/gtkmm2ext/po/es_ES.po
new file mode 100644
index 0000000000..8b7dc8804d
--- /dev/null
+++ b/libs/gtkmm2ext/po/es_ES.po
@@ -0,0 +1,58 @@
+# Copyright (C) 2004 Paul Davis
+# This file is distributed under the same license as the gtkmm2ext package.
+# Author: Alex Krohn <alexkrohn@fastmail.fm>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gtkmm2ext\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-06-21 15:09-0400\n"
+"PO-Revision-Date: 2004-02-13 00:35+0300\n"
+"Last-Translator: Alex Krohn alexkrohn@fastmail.fm\n"
+"Language-Team: Spanish\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: libs/gtkmm2ext/barcontroller.cc:432 libs/gtkmm2ext/bindable_button.cc:131
+#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:132
+msgid "operate MIDI controller now"
+msgstr "Operar controladora de MIDI ahora"
+
+#: libs/gtkmm2ext/gtk_ui.cc:510
+msgid "Press To Exit"
+msgstr ""
+
+#: libs/gtkmm2ext/textviewer.cc:34
+msgid "Close"
+msgstr "Cerrar"
+
+#~ msgid "OK"
+#~ msgstr "ACEPTAR"
+
+#~ msgid "Location:"
+#~ msgstr "Localización:"
+
+#~ msgid "Browse ..."
+#~ msgstr "Seleccionar ..."
+
+#~ msgid "Cancel"
+#~ msgstr "Cancelar"
+
+#~ msgid "New folder"
+#~ msgstr "Nueva carpeta"
+
+#~ msgid "Add to favorites"
+#~ msgstr "Agregar a favoritos"
+
+#~ msgid "Remove from favorites"
+#~ msgstr "Quitar de favoritos"
+
+#~ msgid "Show Hidden"
+#~ msgstr "Mostrar ocultos"
+
+#~ msgid "Hide browser"
+#~ msgstr "Ocultar explorador"
+
+#~ msgid "Rescan"
+#~ msgstr "Buscar de nuevo"
diff --git a/libs/gtkmm2ext/po/pl_PL.po b/libs/gtkmm2ext/po/pl_PL.po
new file mode 100644
index 0000000000..df2414d7ba
--- /dev/null
+++ b/libs/gtkmm2ext/po/pl_PL.po
@@ -0,0 +1,53 @@
+# translation of libgtkmm2ext.po to Polish
+# Copyright (C) YEAR "Paul Davis"
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Piotr Zaryk <pzaryk@gmail.com>, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: libgtkmm2ext\n"
+"Report-Msgid-Bugs-To: Piotr Zaryk <pzaryk@gmail.com>\n"
+"POT-Creation-Date: 2008-04-03 16:17+0200\n"
+"PO-Revision-Date: 2008-04-10 10:54+0100\n"
+"Last-Translator: Piotr Zaryk <pzaryk@gmail.com>\n"
+"Language-Team: Polish <pl@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: libs/gtkmm2ext/binding_proxy.cc:69
+msgid "operate controller now"
+msgstr "Teraz operuj kontrolerem"
+
+#: libs/gtkmm2ext/gtk_ui.cc:95
+msgid "Log"
+msgstr "Log"
+
+#: libs/gtkmm2ext/gtk_ui.cc:536
+msgid "Press To Exit"
+msgstr "Wciśnij by zakończyć"
+
+#: libs/gtkmm2ext/gtk_ui.cc:570
+msgid "Error"
+msgstr "BÅ‚Ä…d"
+
+#: libs/gtkmm2ext/pathlist.cc:29
+msgid "+"
+msgstr "+"
+
+#: libs/gtkmm2ext/pathlist.cc:30
+msgid "-"
+msgstr "-"
+
+#: libs/gtkmm2ext/pathlist.cc:35
+msgid "Paths"
+msgstr "Położenia"
+
+#: libs/gtkmm2ext/pathlist.cc:87
+msgid "Path Chooser"
+msgstr "Wybór położenia"
+
+#: libs/gtkmm2ext/textviewer.cc:34
+msgid "Close"
+msgstr "Zamknij"
+
diff --git a/libs/gtkmm2ext/po/pt_BR.po b/libs/gtkmm2ext/po/pt_BR.po
new file mode 100644
index 0000000000..66381c2d37
--- /dev/null
+++ b/libs/gtkmm2ext/po/pt_BR.po
@@ -0,0 +1,59 @@
+# Copyright (C) 2004 Paul Davis
+# This file is distributed under the same license as the gtkmm2ext package.
+# Authors: Alexander Franca <alexander@nautae.eti.br>
+# Chris Ross <chris.ross@tebibyte.org>
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gtkmm2ext\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-06-21 15:09-0400\n"
+"PO-Revision-Date: 2004-05-17 20:36+0200\n"
+"Last-Translator: Chris Ross <chris.ross@tebibyte.org>\n"
+"Language-Team: Portuguese\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: libs/gtkmm2ext/barcontroller.cc:432 libs/gtkmm2ext/bindable_button.cc:131
+#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:132
+msgid "operate MIDI controller now"
+msgstr "Operar controladora de MIDI agora"
+
+#: libs/gtkmm2ext/gtk_ui.cc:510
+msgid "Press To Exit"
+msgstr ""
+
+#: libs/gtkmm2ext/textviewer.cc:34
+msgid "Close"
+msgstr "Fechar"
+
+#~ msgid "OK"
+#~ msgstr "OK"
+
+#~ msgid "Location:"
+#~ msgstr "localização:"
+
+#~ msgid "Browse ..."
+#~ msgstr "Localizar ..."
+
+#~ msgid "Cancel"
+#~ msgstr "Cancelar"
+
+#~ msgid "New folder"
+#~ msgstr "Novo diretório"
+
+#~ msgid "Add to favorites"
+#~ msgstr "Adicionar a favoritos"
+
+#~ msgid "Remove from favorites"
+#~ msgstr "Remover de favoritos"
+
+#~ msgid "Show Hidden"
+#~ msgstr "Mostrar ocultos"
+
+#~ msgid "Hide browser"
+#~ msgstr "Ocultar explorador"
+
+#~ msgid "Rescan"
+#~ msgstr "Buscar de novo"
diff --git a/libs/gtkmm2ext/po/ru_RU.po b/libs/gtkmm2ext/po/ru_RU.po
new file mode 100644
index 0000000000..4a3edcef5c
--- /dev/null
+++ b/libs/gtkmm2ext/po/ru_RU.po
@@ -0,0 +1,58 @@
+# Copyright (C) 2004 Paul Davis
+# This file is distributed under the same license as the gtkmm2ext package.
+# Igor Blinov pitstop@nm.ru, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gtkmm2ext\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-06-21 15:09-0400\n"
+"PO-Revision-Date: 2004-02-13 00:35+0300\n"
+"Last-Translator: Igor Blinov pitstop@nm.ru\n"
+"Language-Team: Russian\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=koi8-r\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: libs/gtkmm2ext/barcontroller.cc:432 libs/gtkmm2ext/bindable_button.cc:131
+#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:132
+msgid "operate MIDI controller now"
+msgstr "×ËÌÀÞÉÔØ MIDI-ËÏÎÔÒÏÌÌÅÒ"
+
+#: libs/gtkmm2ext/gtk_ui.cc:510
+msgid "Press To Exit"
+msgstr ""
+
+#: libs/gtkmm2ext/textviewer.cc:34
+msgid "Close"
+msgstr "úÁËÒÙÔØ"
+
+#~ msgid "OK"
+#~ msgstr "ïë"
+
+#~ msgid "Location:"
+#~ msgstr "ðÕÔØ:"
+
+#~ msgid "Browse ..."
+#~ msgstr "ïÂÚÏÒ ..."
+
+#~ msgid "Cancel"
+#~ msgstr "ïÔÍÅÎÁ"
+
+#~ msgid "New folder"
+#~ msgstr "îÏ×ÁÑ ÐÁÐËÁ"
+
+#~ msgid "Add to favorites"
+#~ msgstr "äÏÂÁ×ÉÔØ × ÉÚÂÒÁÎÎÏÅ"
+
+#~ msgid "Remove from favorites"
+#~ msgstr "éÓËÌÀÞÉÔØ ÉÚ ÉÚÂÒÁÎÎÏÇÏ"
+
+#~ msgid "Show Hidden"
+#~ msgstr "ðÏËÁÚÙ×ÁÔØ ÓËÒÙÔÙÅ ÆÁÊÌÙ"
+
+#~ msgid "Hide browser"
+#~ msgstr "óËÒÙÔØ ÏÂÌÁÓÔØ ÏÂÚÏÒÁ"
+
+#~ msgid "Rescan"
+#~ msgstr "ïÂÎÏ×ÉÔØ"
diff --git a/libs/gtkmm2ext/popup.cc b/libs/gtkmm2ext/popup.cc
new file mode 100644
index 0000000000..0b150eefe1
--- /dev/null
+++ b/libs/gtkmm2ext/popup.cc
@@ -0,0 +1,139 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <iostream>
+
+#include <gtkmm2ext/popup.h>
+#include <gtkmm2ext/utils.h>
+
+using namespace std;
+using namespace Gtk;
+using namespace Gtkmm2ext;
+
+PopUp::PopUp (Gtk::WindowPosition pos, unsigned int showfor_msecs, bool doh)
+ : Window (WINDOW_POPUP)
+{
+ add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
+ signal_button_press_event().connect(mem_fun(*this,&PopUp::button_click));
+ set_border_width (12);
+ add (label);
+ set_position (pos);
+
+ delete_on_hide = doh;
+ popdown_time = showfor_msecs;
+ timeout = -1;
+}
+
+
+PopUp::~PopUp ()
+{
+}
+
+void
+PopUp::on_realize ()
+{
+ Gtk::Window::on_realize();
+ get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
+}
+
+gint
+PopUp::remove_prompt_timeout (void *arg)
+{
+ PopUp *pup = (PopUp *) arg;
+
+ pup->remove ();
+ return FALSE;
+}
+
+static gint idle_delete (void *arg)
+{
+ delete static_cast<PopUp*> (arg);
+ return FALSE;
+}
+
+void
+PopUp::remove ()
+{
+ hide ();
+
+ if (popdown_time != 0 && timeout != -1) {
+ g_source_remove (timeout);
+ }
+
+ if (delete_on_hide) {
+ std::cerr << "deleting prompter\n";
+ gtk_idle_add (idle_delete, this);
+ }
+}
+
+void
+PopUp::touch ()
+{
+ if (is_visible ()) {
+ remove ();
+ } else {
+ set_size_request_to_display_given_text (label, my_text.c_str(), 25, 10);
+ label.set_text (my_text);
+ show_all ();
+
+ if (popdown_time != 0) {
+ timeout = g_timeout_add (popdown_time,
+ remove_prompt_timeout,
+ this);
+ }
+ }
+}
+
+gint
+PopUp::button_click (GdkEventButton *ev)
+{
+ remove ();
+ return TRUE;
+}
+
+void
+PopUp::set_text (string txt)
+{
+ my_text = txt;
+}
+
+void
+PopUp::set_name (string name)
+{
+ Window::set_name (name);
+ label.set_name (name);
+}
+
+bool
+PopUp::on_delete_event (GdkEventAny* ev)
+{
+ hide();
+
+ if (popdown_time != 0 && timeout != -1) {
+ g_source_remove (timeout);
+ }
+
+ if (delete_on_hide) {
+ std::cerr << "deleting prompter\n" << endl;
+ g_idle_add (idle_delete, this);
+ }
+
+ return true;
+}
diff --git a/libs/gtkmm2ext/prompter.cc b/libs/gtkmm2ext/prompter.cc
new file mode 100644
index 0000000000..0ff9710338
--- /dev/null
+++ b/libs/gtkmm2ext/prompter.cc
@@ -0,0 +1,109 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <string>
+
+#include <pbd/whitespace.h>
+
+#include <gtkmm/stock.h>
+#include <gtkmm2ext/prompter.h>
+
+#include "i18n.h"
+
+using namespace std;
+using namespace Gtkmm2ext;
+
+Prompter::Prompter (Gtk::Window& parent, bool modal)
+ : Gtk::Dialog ("", parent, modal)
+{
+ init ();
+}
+
+Prompter::Prompter (bool modal)
+ : Gtk::Dialog ("", modal)
+{
+ init ();
+}
+
+void
+Prompter::init ()
+{
+ set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
+ set_position (Gtk::WIN_POS_MOUSE);
+ set_name ("Prompter");
+
+ add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+
+ /*
+ Alas a generic 'affirmative' button seems a bit useless sometimes.
+ You will have to add your own.
+ After adding, use :
+ set_response_sensitive (Gtk::RESPONSE_ACCEPT, false)
+ to prevent the RESPONSE_ACCEPT button from permitting blank strings.
+ */
+
+ entryLabel.set_line_wrap (true);
+ entryLabel.set_name ("PrompterLabel");
+
+ entryBox.set_homogeneous (false);
+ entryBox.set_spacing (5);
+ entryBox.set_border_width (10);
+ entryBox.pack_start (entryLabel);
+ entryBox.pack_start (entry, false, false);
+
+ get_vbox()->pack_start (entryBox);
+ show_all_children();
+ entry.signal_changed().connect (mem_fun (*this, &Prompter::on_entry_changed));
+ entry.signal_activate().connect (bind (mem_fun (*this, &Prompter::response), Gtk::RESPONSE_ACCEPT));
+}
+
+void
+Prompter::change_labels (string okstr, string cancelstr)
+{
+ // dynamic_cast<Gtk::Label*>(ok.get_child())->set_text (okstr);
+ // dynamic_cast<Gtk::Label*>(cancel.get_child())->set_text (cancelstr);
+}
+
+void
+Prompter::get_result (string &str, bool strip)
+{
+ str = entry.get_text ();
+ if (strip) {
+ PBD::strip_whitespace_edges (str);
+ }
+}
+
+void
+Prompter::on_entry_changed ()
+{
+ /*
+ This is set up so that entering text in the entry
+ field makes the RESPONSE_ACCEPT button active.
+ Of course if you haven't added a RESPONSE_ACCEPT
+ button, nothing will happen at all.
+ */
+
+ if (entry.get_text() != "") {
+ set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
+ set_default_response (Gtk::RESPONSE_ACCEPT);
+ } else {
+ set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
+ }
+}
diff --git a/libs/gtkmm2ext/scroomer.cc b/libs/gtkmm2ext/scroomer.cc
new file mode 100644
index 0000000000..6572c8b51c
--- /dev/null
+++ b/libs/gtkmm2ext/scroomer.cc
@@ -0,0 +1,389 @@
+/*
+ Copyright (C) 2008 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include <gtkmm2ext/scroomer.h>
+
+using namespace Gtkmm2ext;
+using namespace Gtk;
+using namespace Gdk;
+using namespace std;
+
+Scroomer::Scroomer(Gtk::Adjustment& adjustment)
+ : adj(adjustment)
+ , handle_size(0)
+ , grab_comp(None) {
+
+ position[TopBase] = 0;
+ position[Handle1] = 0;
+ position[Slider] = 0;
+ position[Handle2] = 0;
+ position[BottomBase] = 0;
+ position[Total] = 0;
+
+ add_events (Gdk::BUTTON_PRESS_MASK |
+ Gdk::BUTTON_RELEASE_MASK |
+ Gdk::POINTER_MOTION_MASK |
+ Gdk::SCROLL_MASK);
+
+ adjustment.signal_value_changed().connect (mem_fun (*this, &Scroomer::adjustment_changed));
+ //adjustment.signal_changed().connect (mem_fun (*this, &Scroomer::adjustment_changed));
+}
+
+Scroomer::~Scroomer() {
+}
+
+bool
+Scroomer::on_motion_notify_event (GdkEventMotion* ev) {
+ double range = adj.get_upper() - adj.get_lower();
+ double pixel2val = range / get_height();
+ double val_at_pointer = ((get_height() - ev->y) * pixel2val) + adj.get_lower();
+ double delta_y = ev->y - grab_y;
+ double half_min_page = min_page_size / 2;
+ double fract = delta_y / position[Total];
+ double scale, temp, zoom;
+ double val, page;
+
+ if(grab_comp == None || grab_comp == Total) {
+ return true;
+ }
+
+ if (ev->window != grab_window) {
+ grab_y = ev->y;
+ grab_window = ev->window;
+ return true;
+ }
+
+ grab_y = ev->y;
+
+ if (ev->state & GDK_CONTROL_MASK) {
+ if (ev->state & GDK_MOD1_MASK) {
+ scale = 0.05;
+ } else {
+ scale = 0.1;
+ }
+ } else {
+ scale = 1.0;
+ }
+
+ fract = min (1.0, fract);
+ fract = max (-1.0, fract);
+ fract = -fract;
+
+ switch(grab_comp) {
+ case TopBase:
+ case BottomBase:
+ unzoomed_val += scale * fract * range;
+ unzoomed_val = min(unzoomed_val, adj.get_upper() - unzoomed_page);
+ unzoomed_val = max(unzoomed_val, adj.get_lower());
+ break;
+ case Slider:
+ unzoomed_val += scale * fract * range;
+ unzoomed_val = min(unzoomed_val, adj.get_upper() - unzoomed_page);
+ unzoomed_val = max(unzoomed_val, adj.get_lower());
+ break;
+ case Handle1:
+ unzoomed_page += scale * fract * range;
+ unzoomed_page = min(unzoomed_page, adj.get_upper() - unzoomed_val);
+ unzoomed_page = max(unzoomed_page, min_page_size);
+ break;
+ case Handle2:
+ temp = unzoomed_val + unzoomed_page;
+ unzoomed_val += scale * fract * range;
+ unzoomed_val = min(unzoomed_val, temp - min_page_size);
+ unzoomed_val = max(unzoomed_val, adj.get_lower());
+
+ unzoomed_page = temp - unzoomed_val;
+ unzoomed_page = max(unzoomed_page, min_page_size);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Then we handle zoom, which is dragging horizontally. We zoom around the area that is
+ * the current y pointer value, not from the area that was the start of the drag.
+ * the point of zoom must have the same
+ */
+
+ if(ev->x > get_width()) {
+ zoom = ev->x - get_width();
+
+ double higher = unzoomed_val + unzoomed_page - half_min_page - val_at_pointer;
+ double lower = val_at_pointer - (unzoomed_val + half_min_page);
+
+ higher *= zoom / 128;
+ lower *= zoom / 128;
+
+ val = unzoomed_val + lower;
+ page = unzoomed_page - higher - lower;
+
+ page = max(page, min_page_size);
+
+ if(lower < 0) {
+ val = max(val, val_at_pointer - half_min_page);
+ }
+ else if(lower > 0) {
+ val = min(val, val_at_pointer - half_min_page);
+ }
+
+ val = min(val, adj.get_upper() - min_page_size);
+ page = min(page, adj.get_upper() - val);
+ }
+ else if (ev->x < 0) {
+ /* on zoom out increase the page size as well as moving the range towards the mouse pos*/
+ zoom = abs(ev->x);
+
+ /*double higher = unzoomed_val + unzoomed_page - half_min_page - val_at_pointer;
+ double lower = val_at_pointer - (unzoomed_val + half_min_page);
+
+ higher *= zoom / 128;
+ lower *= zoom / 128;
+
+ val = unzoomed_val + lower;
+ page = unzoomed_page - higher - lower;
+
+ page = max(page, min_page_size);
+
+ if(lower < 0) {
+ val = max(val, val_at_pointer - half_min_page);
+ }
+ else if(lower > 0) {
+ val = min(val, val_at_pointer - half_min_page);
+ }
+
+ val = min(val, adj.get_upper() - min_page_size);
+ page = min(page, adj.get_upper() - val);*/
+
+ val = unzoomed_val;
+ page = unzoomed_page;
+ }
+ else {
+ val = unzoomed_val;
+ page = unzoomed_page;
+ }
+
+ adj.set_page_size(page);
+
+ if(val == adj.get_value()) {
+ adj.value_changed();
+ }
+ if(val < adj.get_lower()) {
+ adj.value_changed();
+ }
+ else if(val > adj.get_upper()) {
+ adj.value_changed();
+ }
+ else {
+ adj.set_value(val);
+ }
+
+ return true;
+}
+
+bool
+Scroomer::on_button_press_event (GdkEventButton* ev) {
+ if(ev->button == 1) {
+ Component comp = point_in(ev->y);
+
+ if(comp == Total || comp == None) {
+ return false;
+ }
+
+ add_modal_grab();
+ grab_comp = comp;
+ grab_y = ev->y;
+ unzoomed_val = adj.get_value();
+ unzoomed_page = adj.get_page_size();
+ grab_window = ev->window;
+ }
+ return false;
+}
+
+bool
+Scroomer::on_button_release_event (GdkEventButton* ev) {
+ if(grab_comp == None || grab_comp == Total) {
+ return true;
+ }
+
+ if (ev->window != grab_window) {
+ grab_y = ev->y;
+ grab_window = ev->window;
+ return true;
+ }
+
+ if (ev->button != 1) {
+ return true;
+ }
+
+ switch(grab_comp) {
+ case TopBase:
+ break;
+ case Handle1:
+ break;
+ case Slider:
+ break;
+ case Handle2:
+ break;
+ case BottomBase:
+ break;
+ default:
+ break;
+ }
+
+ grab_comp = None;
+
+ remove_modal_grab();
+ return true;
+}
+
+bool
+Scroomer::on_scroll_event (GdkEventScroll*) {
+ return true;
+}
+
+void
+Scroomer::on_size_allocate (Allocation& a) {
+ Gtk::DrawingArea::on_size_allocate(a);
+
+ position[Total] = a.get_height();
+ set_min_page_size(min_page_size);
+ update();
+}
+
+/*
+ * assumes that x and width are correct, and they will not be altered
+ */
+void
+Scroomer::set_comp_rect(GdkRectangle& r, Component c) const {
+ int index = (int) c;
+
+ switch(c) {
+ case None:
+ return;
+ case Total:
+ r.y = 0;
+ r.height = position[Total];
+ break;
+ default:
+ r.y = position[index];
+ r.height = position[index+1] - position[index];
+ break;
+ }
+}
+
+Scroomer::Component
+Scroomer::point_in(double point) const {
+ for(int i = 0; i < Total; ++i) {
+ if(position[i+1] >= point) {
+ return (Component) i;
+ }
+ }
+
+ return None;
+}
+
+void
+Scroomer::set_min_page_size(double ps) {
+ double coeff = ((double)position[Total]) / (adj.get_upper() - adj.get_lower());
+
+ min_page_size = ps;
+ handle_size = (int) floor((ps * coeff) / 2);
+}
+
+void
+Scroomer::update() {
+ double range = adj.get_upper() - adj.get_lower();
+ //double value = adj.get_value() - adj.get_lower();
+ int height = position[Total];
+ double coeff = ((double) height) / range;
+
+ /* save the old positions to calculate update regions later*/
+ for(int i = Handle1; i < Total; ++i) {
+ old_pos[i] = position[i];
+ }
+
+ position[BottomBase] = (int) floor(height - (adj.get_value() * coeff));
+ position[Handle2] = position[BottomBase] - handle_size;
+
+ position[Handle1] = (int) floor(height - ((adj.get_value() + adj.get_page_size()) * coeff));
+ position[Slider] = position[Handle1] + handle_size;
+}
+
+void
+Scroomer::adjustment_changed() {
+ //cerr << floor(adj.get_value()) << " " << floor(adj.get_value() + adj.get_page_size()) << endl;
+ Gdk::Rectangle rect;
+ Glib::RefPtr<Gdk::Window> win = get_window();
+
+ update();
+
+ if(!win) {
+ return;
+ }
+
+ rect.set_x(0);
+ rect.set_width(get_width());
+
+ if(position[Handle1] < old_pos[Handle1]) {
+ rect.set_y(position[Handle1]);
+ rect.set_height(old_pos[Slider] - position[Handle1]);
+ win->invalidate_rect(rect, false);
+ }
+ else if(position[Handle1] > old_pos[Handle1]) {
+ rect.set_y(old_pos[Handle1]);
+ rect.set_height(position[Slider] - old_pos[Handle1]);
+ win->invalidate_rect(rect, false);
+ }
+
+ if(position[Handle2] < old_pos[Handle2]) {
+ rect.set_y(position[Handle2]);
+ rect.set_height(old_pos[BottomBase] - position[Handle2]);
+ win->invalidate_rect(rect, false);
+ }
+ else if(position[Handle2] > old_pos[Handle2]) {
+ rect.set_y(old_pos[Handle2]);
+ rect.set_height(position[BottomBase] - old_pos[Handle2]);
+ win->invalidate_rect(rect, false);
+ }
+
+ win->process_updates(false);
+}
+
+std::string
+Scroomer::get_comp_name(Component c) {
+ switch(c) {
+ case TopBase:
+ return "TopBase";
+ case Handle1:
+ return "Handle1";
+ case Slider:
+ return "Slider";
+ case Handle2:
+ return "Handle2";
+ case BottomBase:
+ return "BottomBase";
+ case Total:
+ return "Total";
+ case None:
+ return "None";
+ default:
+ return "ERROR";
+ }
+}
diff --git a/libs/gtkmm2ext/selector.cc b/libs/gtkmm2ext/selector.cc
new file mode 100644
index 0000000000..ee9a5578ba
--- /dev/null
+++ b/libs/gtkmm2ext/selector.cc
@@ -0,0 +1,234 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <string>
+
+#include <gtkmm2ext/selector.h>
+#include <gtkmm2ext/utils.h>
+#include <pbd/pathscanner.h>
+
+using namespace std;
+using namespace Gtkmm2ext;
+
+Selector::Selector (void (*func)(Glib::RefPtr<Gtk::ListStore>, void *), void *arg,
+ vector<string> titles)
+{
+ scroll.add (tview);
+ scroll.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+
+ pack_start (scroll, true, true);
+
+ vector<string>::iterator i;
+ for (i = titles.begin(); i != titles.end(); ++i) {
+ Gtk::TreeModelColumn<Glib::ustring> title;
+ column_records.add(title);
+ }
+
+ lstore = Gtk::ListStore::create(column_records);
+ tview.set_model(lstore);
+
+ update_contents.connect(mem_fun(*this,&Selector::rescan));
+
+ tview.show ();
+
+ refiller = func;
+ refill_arg = arg;
+ selected_row = -1;
+ selected_column = -1;
+}
+
+Selector::~Selector ()
+
+{
+ /* ensure that any row data set with set_row_data_full() is deleted */
+ hide_all ();
+ lstore.clear ();
+}
+
+void
+Selector::on_map()
+
+{
+ Gtk::VBox::on_map ();
+
+ selected_row = -1;
+ selected_column = -1;
+ refill();
+}
+
+void
+Selector::on_show()
+{
+ VBox::on_show();
+
+ rescan();
+}
+
+void
+Selector::reset (void (*func)(Glib::RefPtr<Gtk::ListStore>, void *), void *arg)
+
+{
+ refiller = func;
+ refill_arg = arg;
+ selected_row = -1;
+ selected_column = -1;
+
+ refill();
+}
+
+void
+Selector::refill ()
+
+{
+ if (refiller) {
+ lstore.clear ();
+ refiller (lstore, refill_arg);
+ }
+}
+
+gint
+Selector::_accept (gpointer arg)
+
+{
+ ((Selector *) arg)->accept ();
+ return FALSE;
+}
+
+gint
+Selector::_chosen (gpointer arg)
+
+{
+ ((Selector *) arg)->chosen ();
+ return FALSE;
+}
+
+gint
+Selector::_shift_clicked (gpointer arg)
+{
+ ((Selector *) arg)->shift_clicked ();
+ return FALSE;
+}
+
+gint
+Selector::_control_clicked (gpointer arg)
+{
+ ((Selector *) arg)->control_clicked ();
+ return FALSE;
+}
+
+void
+Selector::accept ()
+{
+ Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection();
+ Gtk::TreeModel::iterator iter = tree_sel->get_selected();
+
+ if (iter) {
+
+ selection_made (new Result (tview, tree_sel));
+ } else {
+ cancel ();
+ }
+}
+
+void
+Selector::chosen ()
+{
+ Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection();
+ Gtk::TreeModel::iterator iter = tree_sel->get_selected();
+
+ if (iter) {
+ choice_made (new Result (tview, tree_sel));
+ } else {
+ cancel ();
+ }
+}
+
+void
+Selector::shift_clicked ()
+{
+ Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection();
+ Gtk::TreeModel::iterator iter = tree_sel->get_selected();
+
+ if (iter) {
+ shift_made (new Result (tview, tree_sel));
+ } else {
+ cancel ();
+ }
+}
+
+void
+Selector::control_clicked ()
+{
+ Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection();
+ Gtk::TreeModel::iterator iter = tree_sel->get_selected();
+
+ if (iter) {
+ control_made (new Result (tview, tree_sel));
+ } else {
+ cancel ();
+ }
+}
+
+void
+Selector::cancel ()
+{
+ Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection();
+ tree_sel->unselect_all();
+
+ selection_made (new Result (tview, tree_sel));
+}
+
+void
+Selector::rescan ()
+
+{
+ selected_row = -1;
+ selected_column = -1;
+ refill ();
+ show_all ();
+}
+
+struct string_cmp {
+ bool operator()(const string* a, const string* b) {
+ return *a < *b;
+ }
+};
+
+bool
+TreeView_Selector::on_button_press_event(GdkEventButton* ev)
+{
+ bool return_value = TreeView::on_button_press_event(ev);
+
+ if (ev && (ev->type == GDK_BUTTON_RELEASE || ev->type == GDK_2BUTTON_PRESS)) {
+ if (ev->state & Gdk::CONTROL_MASK) {
+ g_idle_add (Selector::_control_clicked, this);
+ } else if (ev->state & Gdk::SHIFT_MASK) {
+ g_idle_add (Selector::_shift_clicked, this);
+ } else if (ev->type == GDK_2BUTTON_PRESS) {
+ g_idle_add (Selector::_accept, this);
+ } else {
+ g_idle_add (Selector::_chosen, this);
+ }
+ }
+
+ return return_value;
+}
diff --git a/libs/gtkmm2ext/slider_controller.cc b/libs/gtkmm2ext/slider_controller.cc
new file mode 100644
index 0000000000..93dfb27ae2
--- /dev/null
+++ b/libs/gtkmm2ext/slider_controller.cc
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 1998-99 Paul Davis
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <string>
+
+#include <gtkmm2ext/gtk_ui.h>
+#include <gtkmm2ext/pixfader.h>
+#include <gtkmm2ext/slider_controller.h>
+
+#include "i18n.h"
+
+using namespace Gtkmm2ext;
+using namespace PBD;
+
+SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
+ Gtk::Adjustment *adj, int orientation,
+ Controllable& c,
+ bool with_numeric)
+
+ : PixFader (image, *adj, orientation),
+ binding_proxy (c),
+ spin (*adj, 0, 2)
+{
+ spin.set_name ("SliderControllerValue");
+ spin.set_size_request (70,-1); // should be based on font size somehow
+ spin.set_numeric (true);
+ spin.set_snap_to_ticks (false);
+}
+
+void
+SliderController::set_value (float v)
+{
+ adjustment.set_value (v);
+}
+
+bool
+SliderController::on_button_press_event (GdkEventButton *ev)
+{
+ if (binding_proxy.button_press_handler (ev)) {
+ return true;
+ }
+ return PixFader::on_button_press_event (ev);
+}
+
+VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
+ Gtk::Adjustment *adj,
+ Controllable& control,
+ bool with_numeric)
+
+ : SliderController (image, adj, VERT, control, with_numeric)
+{
+ if (with_numeric) {
+ spin_frame.add (spin);
+ spin_frame.set_shadow_type (Gtk::SHADOW_IN);
+ spin_frame.set_name ("BaseFrame");
+ spin_hbox.pack_start (spin_frame, false, true);
+ // pack_start (spin_hbox, false, false);
+ }
+}
+
+HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
+ Gtk::Adjustment *adj,
+ Controllable& control,
+ bool with_numeric)
+
+ : SliderController (image, adj, HORIZ, control, with_numeric)
+{
+ if (with_numeric) {
+ spin_frame.add (spin);
+ //spin_frame.set_shadow_type (Gtk::SHADOW_IN);
+ spin_frame.set_name ("BaseFrame");
+ spin_hbox.pack_start (spin_frame, false, true);
+ // pack_start (spin_hbox, false, false);
+ }
+}
diff --git a/libs/gtkmm2ext/stateful_button.cc b/libs/gtkmm2ext/stateful_button.cc
new file mode 100644
index 0000000000..949cae958b
--- /dev/null
+++ b/libs/gtkmm2ext/stateful_button.cc
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <string>
+#include <iostream>
+
+#include <gtkmm/main.h>
+
+#include <gtkmm2ext/stateful_button.h>
+
+using namespace Gtk;
+using namespace Glib;
+using namespace Gtkmm2ext;
+using namespace std;
+
+StateButton::StateButton ()
+{
+ _is_realized = false;
+ visual_state = 0;
+}
+
+void
+StateButton::set_visual_state (int n)
+{
+ if (!_is_realized) {
+ /* not yet realized */
+ visual_state = n;
+ return;
+ }
+
+ if (n == visual_state) {
+ return;
+ }
+
+ string name = get_widget_name ();
+ name = name.substr (0, name.find_last_of ('-'));
+
+ switch (n) {
+ case 0:
+ /* relax */
+ break;
+ case 1:
+ name += "-active";
+ break;
+ case 2:
+ name += "-alternate";
+ break;
+ }
+
+ set_widget_name (name);
+ visual_state = n;
+}
+
+/* ----------------------------------------------------------------- */
+
+void
+StatefulToggleButton::on_realize ()
+{
+ ToggleButton::on_realize ();
+
+ _is_realized = true;
+ visual_state++; // to force transition
+ set_visual_state (visual_state - 1);
+}
+
+void
+StatefulButton::on_realize ()
+{
+ Button::on_realize ();
+
+ _is_realized = true;
+ visual_state++; // to force transition
+ set_visual_state (visual_state - 1);
+}
+
+void
+StatefulToggleButton::on_toggled ()
+{
+ if (!_self_managed) {
+ if (get_active()) {
+ set_visual_state (1);
+ } else {
+ set_visual_state (0);
+ }
+ }
+}
diff --git a/libs/gtkmm2ext/sync-menu.c b/libs/gtkmm2ext/sync-menu.c
new file mode 100644
index 0000000000..894446c424
--- /dev/null
+++ b/libs/gtkmm2ext/sync-menu.c
@@ -0,0 +1,977 @@
+/* GTK+ Integration for the Mac OS X Menubar.
+ *
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * Copyright (C) 2007 Imendio AB
+ *
+ * For further information, see:
+ * http://developer.imendio.com/projects/gtk-macosx/menubar
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <Carbon/Carbon.h>
+
+#include <gtkmm2ext/sync-menu.h>
+
+
+/* TODO
+ *
+ * - Sync adding/removing/reordering items
+ * - Create on demand? (can this be done with gtk+? ie fill in menu
+ items when the menu is opened)
+ * - Figure out what to do per app/window...
+ *
+ */
+
+#define IGE_QUARTZ_MENU_CREATOR 'IGEC'
+#define IGE_QUARTZ_ITEM_WIDGET 'IWID'
+
+
+static void sync_menu_shell (GtkMenuShell *menu_shell,
+ MenuRef carbon_menu,
+ gboolean toplevel,
+ gboolean debug);
+
+
+/*
+ * utility functions
+ */
+
+static GtkWidget *
+find_menu_label (GtkWidget *widget)
+{
+ GtkWidget *label = NULL;
+
+ if (GTK_IS_LABEL (widget))
+ return widget;
+
+ if (GTK_IS_CONTAINER (widget))
+ {
+ GList *children;
+ GList *l;
+
+ children = gtk_container_get_children (GTK_CONTAINER (widget));
+
+ for (l = children; l; l = l->next)
+ {
+ label = find_menu_label (l->data);
+ if (label)
+ break;
+ }
+
+ g_list_free (children);
+ }
+
+ return label;
+}
+
+static const gchar *
+get_menu_label_text (GtkWidget *menu_item,
+ GtkWidget **label)
+{
+ GtkWidget *my_label;
+
+ my_label = find_menu_label (menu_item);
+ if (label)
+ *label = my_label;
+
+ if (my_label)
+ return gtk_label_get_text (GTK_LABEL (my_label));
+
+ return NULL;
+}
+
+static gboolean
+accel_find_func (GtkAccelKey *key,
+ GClosure *closure,
+ gpointer data)
+{
+ return (GClosure *) data == closure;
+}
+
+
+/*
+ * CarbonMenu functions
+ */
+
+typedef struct
+{
+ MenuRef menu;
+} CarbonMenu;
+
+static GQuark carbon_menu_quark = 0;
+
+static CarbonMenu *
+carbon_menu_new (void)
+{
+ return g_slice_new0 (CarbonMenu);
+}
+
+static void
+carbon_menu_free (CarbonMenu *menu)
+{
+ g_slice_free (CarbonMenu, menu);
+}
+
+static CarbonMenu *
+carbon_menu_get (GtkWidget *widget)
+{
+ return g_object_get_qdata (G_OBJECT (widget), carbon_menu_quark);
+}
+
+static void
+carbon_menu_connect (GtkWidget *menu,
+ MenuRef menuRef)
+{
+ CarbonMenu *carbon_menu = carbon_menu_get (menu);
+
+ if (!carbon_menu)
+ {
+ carbon_menu = carbon_menu_new ();
+
+ g_object_set_qdata_full (G_OBJECT (menu), carbon_menu_quark,
+ carbon_menu,
+ (GDestroyNotify) carbon_menu_free);
+ }
+
+ carbon_menu->menu = menuRef;
+}
+
+
+/*
+ * CarbonMenuItem functions
+ */
+
+typedef struct
+{
+ MenuRef menu;
+ MenuItemIndex index;
+ MenuRef submenu;
+ GClosure *accel_closure;
+} CarbonMenuItem;
+
+static GQuark carbon_menu_item_quark = 0;
+
+static CarbonMenuItem *
+carbon_menu_item_new (void)
+{
+ return g_slice_new0 (CarbonMenuItem);
+}
+
+static void
+carbon_menu_item_free (CarbonMenuItem *menu_item)
+{
+ if (menu_item->accel_closure)
+ g_closure_unref (menu_item->accel_closure);
+
+ g_slice_free (CarbonMenuItem, menu_item);
+}
+
+static CarbonMenuItem *
+carbon_menu_item_get (GtkWidget *widget)
+{
+ return g_object_get_qdata (G_OBJECT (widget), carbon_menu_item_quark);
+}
+
+static void
+carbon_menu_item_update_state (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ gboolean sensitive;
+ gboolean visible;
+ UInt32 set_attrs = 0;
+ UInt32 clear_attrs = 0;
+
+ g_object_get (widget,
+ "sensitive", &sensitive,
+ "visible", &visible,
+ NULL);
+
+ if (!sensitive)
+ set_attrs |= kMenuItemAttrDisabled;
+ else
+ clear_attrs |= kMenuItemAttrDisabled;
+
+ if (!visible)
+ set_attrs |= kMenuItemAttrHidden;
+ else
+ clear_attrs |= kMenuItemAttrHidden;
+
+ ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index,
+ set_attrs, clear_attrs);
+}
+
+static void
+carbon_menu_item_update_active (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ gboolean active;
+
+ g_object_get (widget,
+ "active", &active,
+ NULL);
+
+ CheckMenuItem (carbon_item->menu, carbon_item->index,
+ active);
+}
+
+static void
+carbon_menu_item_update_submenu (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ GtkWidget *submenu;
+
+ submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+
+ if (submenu)
+ {
+ const gchar *label_text;
+ CFStringRef cfstr = NULL;
+
+ label_text = get_menu_label_text (widget, NULL);
+ if (label_text)
+ cfstr = CFStringCreateWithCString (NULL, label_text,
+ kCFStringEncodingUTF8);
+
+ CreateNewMenu (0, 0, &carbon_item->submenu);
+ SetMenuTitleWithCFString (carbon_item->submenu, cfstr);
+ SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index,
+ carbon_item->submenu);
+
+ sync_menu_shell (GTK_MENU_SHELL (submenu), carbon_item->submenu, FALSE, FALSE);
+
+ if (cfstr)
+ CFRelease (cfstr);
+ }
+ else
+ {
+ SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index,
+ NULL);
+ carbon_item->submenu = NULL;
+ }
+}
+
+static void
+carbon_menu_item_update_label (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ const gchar *label_text;
+ CFStringRef cfstr = NULL;
+
+ label_text = get_menu_label_text (widget, NULL);
+ if (label_text)
+ cfstr = CFStringCreateWithCString (NULL, label_text,
+ kCFStringEncodingUTF8);
+
+ SetMenuItemTextWithCFString (carbon_item->menu, carbon_item->index,
+ cfstr);
+
+ if (cfstr)
+ CFRelease (cfstr);
+}
+
+static void
+carbon_menu_item_update_accelerator (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ GtkWidget *label;
+
+ get_menu_label_text (widget, &label);
+
+ if (GTK_IS_ACCEL_LABEL (label) &&
+ GTK_ACCEL_LABEL (label)->accel_closure)
+ {
+ GtkAccelKey *key;
+
+ key = gtk_accel_group_find (GTK_ACCEL_LABEL (label)->accel_group,
+ accel_find_func,
+ GTK_ACCEL_LABEL (label)->accel_closure);
+
+ if (key &&
+ key->accel_key &&
+ key->accel_flags & GTK_ACCEL_VISIBLE)
+ {
+ GdkDisplay *display = gtk_widget_get_display (widget);
+ GdkKeymap *keymap = gdk_keymap_get_for_display (display);
+ GdkKeymapKey *keys;
+ gint n_keys;
+ gint use_command;
+ gboolean add_modifiers = FALSE;
+
+ if (gdk_keymap_get_entries_for_keyval (keymap, key->accel_key,
+ &keys, &n_keys) == 0)
+ {
+ gint realkey = -1;
+
+ switch (key->accel_key) {
+ case GDK_rightarrow:
+ case GDK_Right:
+ realkey = kRightArrowCharCode;
+ break;
+ case GDK_leftarrow:
+ case GDK_Left:
+ realkey = kLeftArrowCharCode;
+ break;
+ case GDK_uparrow:
+ case GDK_Up:
+ realkey = kUpArrowCharCode;
+ break;
+ case GDK_downarrow:
+ case GDK_Down:
+ realkey = kDownArrowCharCode;
+ break;
+ default:
+ break;
+ }
+
+ if (realkey != -1) {
+ SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
+ false, realkey);
+ add_modifiers = TRUE;
+ }
+
+ } else {
+ SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
+ true, keys[0].keycode);
+ g_free (keys);
+ add_modifiers = TRUE;
+ }
+
+ if (add_modifiers)
+ {
+ UInt8 modifiers = 0; /* implies Command key */
+
+ use_command = 0;
+
+ if (key->accel_mods)
+ {
+ if (key->accel_mods & GDK_SHIFT_MASK) {
+ modifiers |= kMenuShiftModifier;
+ }
+
+ /* gdk/quartz maps Alt/Option to Mod1 */
+
+ if (key->accel_mods & (GDK_MOD1_MASK)) {
+ modifiers |= kMenuOptionModifier;
+ }
+
+ if (key->accel_mods & GDK_CONTROL_MASK) {
+ modifiers |= kMenuControlModifier;
+ }
+
+ /* gdk/quartz maps Command to Meta */
+
+ if (key->accel_mods & GDK_META_MASK) {
+ use_command = 1;
+ }
+ }
+
+ if (!use_command)
+ modifiers |= kMenuNoCommandModifier;
+
+ SetMenuItemModifiers (carbon_item->menu, carbon_item->index,
+ modifiers);
+
+ return;
+ }
+ }
+ }
+
+ /* otherwise, clear the menu shortcut */
+ SetMenuItemModifiers (carbon_item->menu, carbon_item->index,
+ kMenuNoModifiers | kMenuNoCommandModifier);
+ ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index,
+ 0, kMenuItemAttrUseVirtualKey);
+ SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
+ false, 0);
+}
+
+static void
+carbon_menu_item_accel_changed (GtkAccelGroup *accel_group,
+ guint keyval,
+ GdkModifierType modifier,
+ GClosure *accel_closure,
+ GtkWidget *widget)
+{
+ CarbonMenuItem *carbon_item = carbon_menu_item_get (widget);
+ GtkWidget *label;
+
+ get_menu_label_text (widget, &label);
+
+ if (GTK_IS_ACCEL_LABEL (label) &&
+ GTK_ACCEL_LABEL (label)->accel_closure == accel_closure)
+ carbon_menu_item_update_accelerator (carbon_item, widget);
+}
+
+static void
+carbon_menu_item_update_accel_closure (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ GtkAccelGroup *group;
+ GtkWidget *label;
+
+ get_menu_label_text (widget, &label);
+
+ if (carbon_item->accel_closure)
+ {
+ group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure);
+
+ g_signal_handlers_disconnect_by_func (group,
+ carbon_menu_item_accel_changed,
+ widget);
+
+ g_closure_unref (carbon_item->accel_closure);
+ carbon_item->accel_closure = NULL;
+ }
+
+ if (GTK_IS_ACCEL_LABEL (label))
+ carbon_item->accel_closure = GTK_ACCEL_LABEL (label)->accel_closure;
+
+ if (carbon_item->accel_closure)
+ {
+ g_closure_ref (carbon_item->accel_closure);
+
+ group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure);
+
+ g_signal_connect_object (group, "accel-changed",
+ G_CALLBACK (carbon_menu_item_accel_changed),
+ widget, 0);
+ }
+
+ carbon_menu_item_update_accelerator (carbon_item, widget);
+}
+
+static void
+carbon_menu_item_notify (GObject *object,
+ GParamSpec *pspec,
+ CarbonMenuItem *carbon_item)
+{
+ if (!strcmp (pspec->name, "sensitive") ||
+ !strcmp (pspec->name, "visible"))
+ {
+ carbon_menu_item_update_state (carbon_item, GTK_WIDGET (object));
+ }
+ else if (!strcmp (pspec->name, "active"))
+ {
+ carbon_menu_item_update_active (carbon_item, GTK_WIDGET (object));
+ }
+ else if (!strcmp (pspec->name, "submenu"))
+ {
+ carbon_menu_item_update_submenu (carbon_item, GTK_WIDGET (object));
+ }
+}
+
+static void
+carbon_menu_item_notify_label (GObject *object,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ CarbonMenuItem *carbon_item = carbon_menu_item_get (GTK_WIDGET (object));
+
+ if (!strcmp (pspec->name, "label"))
+ {
+ carbon_menu_item_update_label (carbon_item,
+ GTK_WIDGET (object));
+ }
+ else if (!strcmp (pspec->name, "accel-closure"))
+ {
+ carbon_menu_item_update_accel_closure (carbon_item,
+ GTK_WIDGET (object));
+ }
+}
+
+static CarbonMenuItem *
+carbon_menu_item_connect (GtkWidget *menu_item,
+ GtkWidget *label,
+ MenuRef menu,
+ MenuItemIndex index)
+{
+ CarbonMenuItem *carbon_item = carbon_menu_item_get (menu_item);
+
+ if (!carbon_item)
+ {
+ carbon_item = carbon_menu_item_new ();
+
+ g_object_set_qdata_full (G_OBJECT (menu_item), carbon_menu_item_quark,
+ carbon_item,
+ (GDestroyNotify) carbon_menu_item_free);
+
+ g_signal_connect (menu_item, "notify",
+ G_CALLBACK (carbon_menu_item_notify),
+ carbon_item);
+
+ if (label)
+ g_signal_connect_swapped (label, "notify::label",
+ G_CALLBACK (carbon_menu_item_notify_label),
+ menu_item);
+ }
+
+ carbon_item->menu = menu;
+ carbon_item->index = index;
+
+ return carbon_item;
+}
+
+
+/*
+ * carbon event handler
+ */
+
+static int _in_carbon_menu_event_handler = 0;
+
+int
+gdk_quartz_in_carbon_menu_event_handler ()
+{
+ return _in_carbon_menu_event_handler;
+}
+
+static gboolean
+dummy_gtk_menu_item_activate (gpointer *arg)
+{
+ gtk_menu_item_activate (GTK_MENU_ITEM(arg));
+ return FALSE;
+}
+
+static OSStatus
+menu_event_handler_func (EventHandlerCallRef event_handler_call_ref,
+ EventRef event_ref,
+ void *data)
+{
+ UInt32 event_class = GetEventClass (event_ref);
+ UInt32 event_kind = GetEventKind (event_ref);
+ MenuRef menu_ref;
+ OSStatus ret;
+
+ _in_carbon_menu_event_handler = 1;
+
+ switch (event_class)
+ {
+ case kEventClassCommand:
+ /* This is called when activating (is that the right GTK+ term?)
+ * a menu item.
+ */
+ if (event_kind == kEventCommandProcess)
+ {
+ HICommand command;
+ OSStatus err;
+
+ /*g_printerr ("Menu: kEventClassCommand/kEventCommandProcess\n");*/
+
+ err = GetEventParameter (event_ref, kEventParamDirectObject,
+ typeHICommand, 0,
+ sizeof (command), 0, &command);
+
+ if (err == noErr)
+ {
+ GtkWidget *widget = NULL;
+
+ /* Get any GtkWidget associated with the item. */
+ err = GetMenuItemProperty (command.menu.menuRef,
+ command.menu.menuItemIndex,
+ IGE_QUARTZ_MENU_CREATOR,
+ IGE_QUARTZ_ITEM_WIDGET,
+ sizeof (widget), 0, &widget);
+ if (err == noErr && GTK_IS_WIDGET (widget))
+ {
+ g_idle_add (dummy_gtk_menu_item_activate, widget);
+ // gtk_menu_item_activate (GTK_MENU_ITEM (widget));
+ _in_carbon_menu_event_handler = 0;
+ return noErr;
+ }
+ }
+ }
+ break;
+
+ case kEventClassMenu:
+ GetEventParameter (event_ref,
+ kEventParamDirectObject,
+ typeMenuRef,
+ NULL,
+ sizeof (menu_ref),
+ NULL,
+ &menu_ref);
+
+ switch (event_kind)
+ {
+ case kEventMenuTargetItem:
+ /* This is called when an item is selected (what is the
+ * GTK+ term? prelight?)
+ */
+ /*g_printerr ("kEventClassMenu/kEventMenuTargetItem\n");*/
+ break;
+
+ case kEventMenuOpening:
+ /* Is it possible to dynamically build the menu here? We
+ * can at least set visibility/sensitivity.
+ */
+ /*g_printerr ("kEventClassMenu/kEventMenuOpening\n");*/
+ break;
+
+ case kEventMenuClosed:
+ /*g_printerr ("kEventClassMenu/kEventMenuClosed\n");*/
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ ret = CallNextEventHandler (event_handler_call_ref, event_ref);
+ _in_carbon_menu_event_handler = 0;
+ return ret;
+}
+
+static void
+setup_menu_event_handler (void)
+{
+ EventHandlerUPP menu_event_handler_upp;
+ EventHandlerRef menu_event_handler_ref;
+ const EventTypeSpec menu_events[] = {
+ { kEventClassCommand, kEventCommandProcess },
+ { kEventClassMenu, kEventMenuTargetItem },
+ { kEventClassMenu, kEventMenuOpening },
+ { kEventClassMenu, kEventMenuClosed }
+ };
+
+ /* FIXME: We might have to install one per window? */
+
+ menu_event_handler_upp = NewEventHandlerUPP (menu_event_handler_func);
+ InstallEventHandler (GetApplicationEventTarget (), menu_event_handler_upp,
+ GetEventTypeCount (menu_events), menu_events, 0,
+ &menu_event_handler_ref);
+
+#if 0
+ /* FIXME: Remove the handler with: */
+ RemoveEventHandler(menu_event_handler_ref);
+ DisposeEventHandlerUPP(menu_event_handler_upp);
+#endif
+}
+
+static void
+sync_menu_shell (GtkMenuShell *menu_shell,
+ MenuRef carbon_menu,
+ gboolean toplevel,
+ gboolean debug)
+{
+ GList *children;
+ GList *l;
+ MenuItemIndex carbon_index = 1;
+
+ if (debug)
+ g_printerr ("%s: syncing shell %p\n", G_STRFUNC, menu_shell);
+
+ carbon_menu_connect (GTK_WIDGET (menu_shell), carbon_menu);
+
+ children = gtk_container_get_children (GTK_CONTAINER (menu_shell));
+
+ for (l = children; l; l = l->next)
+ {
+ GtkWidget *menu_item = l->data;
+ CarbonMenuItem *carbon_item;
+
+ if (GTK_IS_TEAROFF_MENU_ITEM (menu_item))
+ continue;
+
+ if (toplevel && g_object_get_data (G_OBJECT (menu_item),
+ "gtk-empty-menu-item"))
+ continue;
+
+ carbon_item = carbon_menu_item_get (menu_item);
+
+ if (debug)
+ g_printerr ("%s: carbon_item %d for menu_item %d (%s, %s)\n",
+ G_STRFUNC, carbon_item ? carbon_item->index : -1,
+ carbon_index, get_menu_label_text (menu_item, NULL),
+ g_type_name (G_TYPE_FROM_INSTANCE (menu_item)));
+
+ if (carbon_item && carbon_item->index != carbon_index)
+ {
+ if (debug)
+ g_printerr ("%s: -> not matching, deleting\n", G_STRFUNC);
+
+ DeleteMenuItem (carbon_item->menu, carbon_index);
+ carbon_item = NULL;
+ }
+
+ if (!carbon_item)
+ {
+ GtkWidget *label = NULL;
+ const gchar *label_text;
+ CFStringRef cfstr = NULL;
+ MenuItemAttributes attributes = 0;
+
+ if (debug)
+ g_printerr ("%s: -> creating new\n", G_STRFUNC);
+
+ label_text = get_menu_label_text (menu_item, &label);
+ if (label_text)
+ cfstr = CFStringCreateWithCString (NULL, label_text,
+ kCFStringEncodingUTF8);
+
+ if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item))
+ attributes |= kMenuItemAttrSeparator;
+
+ if (!GTK_WIDGET_IS_SENSITIVE (menu_item))
+ attributes |= kMenuItemAttrDisabled;
+
+ if (!GTK_WIDGET_VISIBLE (menu_item))
+ attributes |= kMenuItemAttrHidden;
+
+ InsertMenuItemTextWithCFString (carbon_menu, cfstr,
+ carbon_index - 1,
+ attributes, 0);
+ SetMenuItemProperty (carbon_menu, carbon_index,
+ IGE_QUARTZ_MENU_CREATOR,
+ IGE_QUARTZ_ITEM_WIDGET,
+ sizeof (menu_item), &menu_item);
+
+ if (cfstr)
+ CFRelease (cfstr);
+
+ carbon_item = carbon_menu_item_connect (menu_item, label,
+ carbon_menu,
+ carbon_index);
+
+ if (GTK_IS_CHECK_MENU_ITEM (menu_item))
+ carbon_menu_item_update_active (carbon_item, menu_item);
+
+ carbon_menu_item_update_accel_closure (carbon_item, menu_item);
+
+ if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item)))
+ carbon_menu_item_update_submenu (carbon_item, menu_item);
+ }
+
+ carbon_index++;
+ }
+
+ g_list_free (children);
+}
+
+
+static gulong emission_hook_id = 0;
+
+static gboolean
+parent_set_emission_hook (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data)
+{
+ GtkWidget *instance = g_value_get_object (param_values);
+
+ if (GTK_IS_MENU_ITEM (instance))
+ {
+ GtkWidget *previous_parent = g_value_get_object (param_values + 1);
+ GtkWidget *menu_shell = NULL;
+
+ if (GTK_IS_MENU_SHELL (previous_parent))
+ {
+ menu_shell = previous_parent;
+ }
+ else if (GTK_IS_MENU_SHELL (instance->parent))
+ {
+ menu_shell = instance->parent;
+ }
+
+ if (menu_shell)
+ {
+ CarbonMenu *carbon_menu = carbon_menu_get (menu_shell);
+
+ if (carbon_menu)
+ {
+#if 0
+ g_printerr ("%s: item %s %p (%s, %s)\n", G_STRFUNC,
+ previous_parent ? "removed from" : "added to",
+ menu_shell,
+ get_menu_label_text (instance, NULL),
+ g_type_name (G_TYPE_FROM_INSTANCE (instance)));
+#endif
+
+ sync_menu_shell (GTK_MENU_SHELL (menu_shell),
+ carbon_menu->menu,
+ carbon_menu->menu == (MenuRef) data,
+ FALSE);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+parent_set_emission_hook_remove (GtkWidget *widget,
+ gpointer data)
+{
+ g_signal_remove_emission_hook (g_signal_lookup ("parent-set",
+ GTK_TYPE_WIDGET),
+ emission_hook_id);
+}
+
+
+/*
+ * public functions
+ */
+
+void
+ige_mac_menu_set_menu_bar (GtkMenuShell *menu_shell)
+{
+ MenuRef carbon_menubar;
+
+ g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+
+ if (carbon_menu_quark == 0)
+ carbon_menu_quark = g_quark_from_static_string ("CarbonMenu");
+
+ if (carbon_menu_item_quark == 0)
+ carbon_menu_item_quark = g_quark_from_static_string ("CarbonMenuItem");
+
+ CreateNewMenu (0 /*id*/, 0 /*options*/, &carbon_menubar);
+ SetRootMenu (carbon_menubar);
+
+ setup_menu_event_handler ();
+
+ emission_hook_id =
+ g_signal_add_emission_hook (g_signal_lookup ("parent-set",
+ GTK_TYPE_WIDGET),
+ 0,
+ parent_set_emission_hook,
+ carbon_menubar, NULL);
+
+ g_signal_connect (menu_shell, "destroy",
+ G_CALLBACK (parent_set_emission_hook_remove),
+ NULL);
+
+ sync_menu_shell (menu_shell, carbon_menubar, TRUE, FALSE);
+}
+
+void
+ige_mac_menu_set_quit_menu_item (GtkMenuItem *menu_item)
+{
+ MenuRef appmenu;
+ MenuItemIndex index;
+
+ g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
+
+ if (GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
+ &appmenu, &index) == noErr)
+ {
+ SetMenuItemCommandID (appmenu, index, 0);
+ SetMenuItemProperty (appmenu, index,
+ IGE_QUARTZ_MENU_CREATOR,
+ IGE_QUARTZ_ITEM_WIDGET,
+ sizeof (menu_item), &menu_item);
+
+ gtk_widget_hide (GTK_WIDGET (menu_item));
+ }
+}
+
+
+struct _IgeMacMenuGroup
+{
+ GList *items;
+};
+
+static GList *app_menu_groups = NULL;
+
+IgeMacMenuGroup *
+ige_mac_menu_add_app_menu_group (void)
+{
+ IgeMacMenuGroup *group = g_slice_new0 (IgeMacMenuGroup);
+
+ app_menu_groups = g_list_append (app_menu_groups, group);
+
+ return group;
+}
+
+void
+ige_mac_menu_add_app_menu_item (IgeMacMenuGroup *group,
+ GtkMenuItem *menu_item,
+ const gchar *label)
+{
+ MenuRef appmenu;
+ GList *list;
+ gint index = 0;
+
+ g_return_if_fail (group != NULL);
+ g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
+
+ if (GetIndMenuItemWithCommandID (NULL, kHICommandHide, 1,
+ &appmenu, NULL) != noErr)
+ {
+ g_warning ("%s: retrieving app menu failed",
+ G_STRFUNC);
+ return;
+ }
+
+ for (list = app_menu_groups; list; list = g_list_next (list))
+ {
+ IgeMacMenuGroup *list_group = list->data;
+
+ index += g_list_length (list_group->items);
+
+ /* adjust index for the separator between groups, but not
+ * before the first group
+ */
+ if (list_group->items && list->prev)
+ index++;
+
+ if (group == list_group)
+ {
+ CFStringRef cfstr;
+
+ /* add a separator before adding the first item, but not
+ * for the first group
+ */
+ if (!group->items && list->prev)
+ {
+ InsertMenuItemTextWithCFString (appmenu, NULL, index,
+ kMenuItemAttrSeparator, 0);
+ index++;
+ }
+
+ if (!label)
+ label = get_menu_label_text (GTK_WIDGET (menu_item), NULL);
+
+ cfstr = CFStringCreateWithCString (NULL, label,
+ kCFStringEncodingUTF8);
+
+ InsertMenuItemTextWithCFString (appmenu, cfstr, index, 0, 0);
+ SetMenuItemProperty (appmenu, index + 1,
+ IGE_QUARTZ_MENU_CREATOR,
+ IGE_QUARTZ_ITEM_WIDGET,
+ sizeof (menu_item), &menu_item);
+
+ CFRelease (cfstr);
+
+ gtk_widget_hide (GTK_WIDGET (menu_item));
+
+ group->items = g_list_append (group->items, menu_item);
+
+ return;
+ }
+ }
+
+ if (!list)
+ g_warning ("%s: app menu group %p does not exist",
+ G_STRFUNC, group);
+}
diff --git a/libs/gtkmm2ext/tearoff.cc b/libs/gtkmm2ext/tearoff.cc
new file mode 100644
index 0000000000..92bde5541e
--- /dev/null
+++ b/libs/gtkmm2ext/tearoff.cc
@@ -0,0 +1,197 @@
+/*
+ Copyright (C) 2003 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <cmath>
+#include <gtkmm2ext/tearoff.h>
+#include <gtkmm2ext/utils.h>
+
+using namespace Gtkmm2ext;
+using namespace Gtk;
+using namespace Gdk;
+using namespace Glib;
+using namespace std;
+
+TearOff::TearOff (Widget& c, bool allow_resize)
+ : contents (c),
+ own_window (Gtk::WINDOW_TOPLEVEL),
+ tearoff_arrow (ARROW_DOWN, SHADOW_OUT),
+ close_arrow (ARROW_UP, SHADOW_OUT)
+{
+ dragging = false;
+ _visible = true;
+
+ tearoff_event_box.add (tearoff_arrow);
+ tearoff_event_box.set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK);
+ tearoff_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::tearoff_click));
+
+ close_event_box.add (close_arrow);
+ close_event_box.set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK);
+ close_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::close_click));
+
+ own_window.add_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK|POINTER_MOTION_MASK|POINTER_MOTION_HINT_MASK);
+ own_window.set_resizable (allow_resize);
+ own_window.set_type_hint (WINDOW_TYPE_HINT_TOOLBAR);
+
+ VBox* box1;
+ box1 = manage (new VBox);
+ box1->pack_start (close_event_box, false, false, 2);
+
+ window_box.pack_end (*box1, false, false, 2);
+ own_window.add (window_box);
+
+ own_window.signal_button_press_event().connect (mem_fun (*this, &TearOff::window_button_press));
+ own_window.signal_button_release_event().connect (mem_fun (*this, &TearOff::window_button_release));
+ own_window.signal_motion_notify_event().connect (mem_fun (*this, &TearOff::window_motion));
+ own_window.signal_delete_event().connect (mem_fun (*this, &TearOff::window_delete_event));
+ own_window.signal_realize().connect (bind (sigc::ptr_fun (Gtkmm2ext::set_decoration), &own_window, WMDecoration (DECOR_BORDER|DECOR_RESIZEH)));
+
+ tearoff_arrow.set_name ("TearOffArrow");
+ close_arrow.set_name ("TearOffArrow");
+
+ VBox* box2;
+ box2 = manage (new VBox);
+ box2->pack_start (tearoff_event_box, false, false, 2);
+
+ pack_start (contents);
+ pack_start (*box2, false, false, 2);
+
+}
+
+TearOff::~TearOff ()
+{
+}
+
+void
+TearOff::set_visible (bool yn)
+{
+ /* don't change visibility if torn off */
+
+ if (own_window.is_visible()) {
+ return;
+ }
+
+ if (_visible != yn) {
+ _visible = yn;
+ if (yn) {
+ show_all();
+ Visible ();
+ } else {
+ hide ();
+ Hidden ();
+ }
+ }
+}
+
+gint
+TearOff::tearoff_click (GdkEventButton* ev)
+{
+ remove (contents);
+ window_box.pack_start (contents);
+ own_window.set_name (get_name());
+ close_event_box.set_name (get_name());
+ own_window.show_all ();
+ hide ();
+ Detach ();
+ return true;
+}
+
+gint
+TearOff::close_click (GdkEventButton* ev)
+{
+ window_box.remove (contents);
+ pack_start (contents);
+ reorder_child (contents, 0);
+ own_window.hide ();
+ show_all ();
+ Attach ();
+ return true;
+}
+
+gint
+TearOff::window_button_press (GdkEventButton* ev)
+{
+ if (dragging || ev->button != 1) {
+ dragging = false;
+ own_window.remove_modal_grab();
+ return true;
+ }
+
+ dragging = true;
+ drag_x = ev->x_root;
+ drag_y = ev->y_root;
+
+ own_window.add_modal_grab();
+
+ return true;
+}
+
+gint
+TearOff::window_button_release (GdkEventButton* ev)
+{
+ dragging = false;
+ own_window.remove_modal_grab();
+ return true;
+}
+
+gint
+TearOff::window_delete_event (GdkEventAny* ev)
+{
+ return close_click(0);
+}
+
+gint
+TearOff::window_motion (GdkEventMotion* ev)
+{
+ gint x;
+ gint y;
+ gint mx, my;
+ double x_delta;
+ double y_delta;
+ RefPtr<Gdk::Window> win (own_window.get_window());
+
+ own_window.get_pointer (mx, my);
+
+ if (!dragging) {
+ return true;
+ }
+
+ if (!(ev->state & GDK_BUTTON1_MASK)) {
+ dragging = false;
+ own_window.remove_modal_grab();
+ return true;
+ }
+
+ x_delta = ev->x_root - drag_x;
+ y_delta = ev->y_root - drag_y;
+
+ win->get_root_origin (x, y);
+ win->move ((gint) floor (x + x_delta), (gint) floor (y + y_delta));
+
+ drag_x = ev->x_root;
+ drag_y = ev->y_root;
+
+ return true;
+}
+
+bool
+TearOff::torn_off() const
+{
+ return own_window.is_visible();
+}
diff --git a/libs/gtkmm2ext/textviewer.cc b/libs/gtkmm2ext/textviewer.cc
new file mode 100644
index 0000000000..8c89b845b7
--- /dev/null
+++ b/libs/gtkmm2ext/textviewer.cc
@@ -0,0 +1,127 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <string>
+#include <fstream>
+
+#include <gtkmm2ext/textviewer.h>
+
+#include "i18n.h"
+
+using namespace std;
+using namespace Gtkmm2ext;
+using namespace sigc;
+
+TextViewer::TextViewer (size_t xsize, size_t ysize) :
+ Gtk::Window (Gtk::WINDOW_TOPLEVEL),
+ Transmitter (Transmitter::Info), /* channel arg is irrelevant */
+ dismiss (_("Close"))
+{
+ set_size_request (xsize, ysize);
+
+ set_title ("Text Viewer");
+ set_name ("TextViewer");
+ set_resizable (true);
+ set_border_width (0);
+
+ vbox1.set_homogeneous (false);
+ vbox1.set_spacing (0);
+ add (vbox1);
+ vbox1.show ();
+
+ vbox2.set_homogeneous (false);
+ vbox2.set_spacing (10);
+ //vbox2.set_border_width (10);
+
+ vbox1.pack_start (vbox2, true, true, 0);
+ vbox2.show ();
+
+ vbox2.pack_start (scrollwin, TRUE, TRUE, 0);
+ scrollwin.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
+ scrollwin.show ();
+
+ etext.set_editable (false);
+ etext.set_wrap_mode (Gtk::WRAP_WORD);
+ scrollwin.add (etext);
+ etext.show ();
+
+ vbox1.pack_start (dismiss, false, false, 0);
+ dismiss.show ();
+
+ dismiss.signal_clicked().connect(mem_fun (*this, &TextViewer::signal_released_handler));
+}
+
+void
+TextViewer::signal_released_handler()
+{
+ hide();
+}
+
+void
+TextViewer::insert_file (const string &path)
+
+{
+ char buf[1024];
+ ifstream f (path.c_str());
+
+ if (!f) {
+ return;
+ }
+
+ Glib::RefPtr<Gtk::TextBuffer> tb (etext.get_buffer());
+
+ tb->begin_user_action();
+ while (f) {
+ f.read (buf, sizeof (buf));
+
+ if (f.gcount()) {
+ buf[f.gcount()] = '\0';
+ string foo (buf);
+ tb->insert (tb->end(), foo);
+ }
+ }
+ tb->end_user_action();
+}
+
+void
+TextViewer::scroll_to_bottom ()
+
+{
+ Gtk::Adjustment *adj;
+
+ adj = scrollwin.get_vadjustment();
+ adj->set_value (MAX(0,(adj->get_upper() - adj->get_page_size())));
+}
+
+void
+TextViewer::deliver ()
+
+{
+ char buf[1024];
+ Glib::RefPtr<Gtk::TextBuffer> tb (etext.get_buffer());
+
+ while (!eof()) {
+ read (buf, sizeof (buf));
+ buf[gcount()] = '\0';
+ string foo (buf);
+ tb->insert (tb->end(), foo);
+ }
+ scroll_to_bottom ();
+ clear ();
+}
diff --git a/libs/gtkmm2ext/utils.cc b/libs/gtkmm2ext/utils.cc
new file mode 100644
index 0000000000..57661a05af
--- /dev/null
+++ b/libs/gtkmm2ext/utils.cc
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <map>
+
+#include <gtk/gtkpaned.h>
+#include <gtk/gtk.h>
+
+#include <gtkmm2ext/utils.h>
+#include <gtkmm/widget.h>
+#include <gtkmm/button.h>
+#include <gtkmm/window.h>
+#include <gtkmm/paned.h>
+#include <gtkmm/comboboxtext.h>
+
+#include "i18n.h"
+
+using namespace std;
+
+void
+Gtkmm2ext::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
+ int& width,
+ int& height)
+{
+ Pango::Rectangle ink_rect = layout->get_ink_extents ();
+
+ width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
+ height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
+}
+
+void
+Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, const gchar *text,
+ gint hpadding, gint vpadding)
+
+{
+ int width, height;
+ w.ensure_style ();
+
+ get_ink_pixel_size (w.create_pango_layout (text), width, height);
+ w.set_size_request(width + hpadding, height + vpadding);
+}
+
+void
+Gtkmm2ext::init ()
+{
+ // Necessary for gettext
+ (void) bindtextdomain(PACKAGE, LOCALEDIR);
+}
+
+void
+Gtkmm2ext::set_popdown_strings (Gtk::ComboBoxText& cr, const vector<string>& strings)
+{
+ cr.clear ();
+
+ for (vector<string>::const_iterator i = strings.begin(); i != strings.end(); ++i) {
+ cr.append_text (*i);
+ }
+}
+
+GdkWindow*
+Gtkmm2ext::get_paned_handle (Gtk::Paned& paned)
+{
+ return GTK_PANED(paned.gobj())->handle;
+}
+
+void
+Gtkmm2ext::set_decoration (Gtk::Window* win, Gdk::WMDecoration decor)
+{
+ win->get_window()->set_decorations (decor);
+}
+
+void Gtkmm2ext::set_treeview_header_as_default_label(Gtk::TreeViewColumn* c)
+{
+ gtk_tree_view_column_set_widget( c->gobj(), GTK_WIDGET(0) );
+}
+
diff --git a/libs/gtkmm2ext/window_title.cc b/libs/gtkmm2ext/window_title.cc
new file mode 100644
index 0000000000..7c942d7f20
--- /dev/null
+++ b/libs/gtkmm2ext/window_title.cc
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2000-2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "gtkmm2ext/window_title.h"
+
+#include "i18n.h"
+
+namespace {
+
+// I don't know if this should be translated.
+const char* const title_separator = X_(" - ");
+
+} // anonymous namespace
+
+namespace Gtkmm2ext {
+
+WindowTitle::WindowTitle(const string& title)
+ : m_title(title)
+{
+
+}
+
+void
+WindowTitle::operator+= (const string& element)
+{
+ m_title = m_title + title_separator + element;
+}
+
+}