Rosegarden – music editor and MIDI/audio sequencer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.cpp 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. // -*- c-basic-offset: 4 -*-
  2. /*
  3. Rosegarden
  4. A sequencer and musical notation editor.
  5. This program is Copyright 2000-2008
  6. Guillaume Laurent <glaurent@telegraph-road.org>,
  7. Chris Cannam <cannam@all-day-breakfast.com>,
  8. Richard Bown <bownie@bownie.com>
  9. The moral right of the authors to claim authorship of this work
  10. has been asserted.
  11. This program is free software; you can redistribute it and/or
  12. modify it under the terms of the GNU General Public License as
  13. published by the Free Software Foundation; either version 2 of the
  14. License, or (at your option) any later version. See the file
  15. COPYING included with this distribution for more information.
  16. */
  17. #include <tqtimer.h>
  18. #include <tdeapplication.h>
  19. #include <sys/time.h>
  20. #include <unistd.h>
  21. #include "base/RealTime.h"
  22. #include <tdecmdlineargs.h>
  23. #include <tdeaboutdata.h>
  24. #include <tdelocale.h>
  25. #include <dcopclient.h>
  26. #include <tdeconfig.h>
  27. #include <tdemessagebox.h>
  28. #include <kstddirs.h>
  29. #include <ktip.h>
  30. #include <kprocess.h>
  31. #include <tdeglobalsettings.h>
  32. #include <tqstringlist.h>
  33. #include <tqregexp.h>
  34. #include <tqvbox.h>
  35. #include <tqlabel.h>
  36. #include "document/ConfigGroups.h"
  37. #include "misc/Strings.h"
  38. #include "misc/Debug.h"
  39. #include "gui/application/RosegardenGUIApp.h"
  40. #include "gui/widgets/CurrentProgressDialog.h"
  41. #include "document/RosegardenGUIDoc.h"
  42. #include "gui/kdeext/TDEStartupLogo.h"
  43. #include "gui/application/RosegardenApplication.h"
  44. #include "gui/application/RosegardenDCOP.h"
  45. #include "gui/kdeext/klearlook.h"
  46. using namespace Rosegarden;
  47. /*! \mainpage Rosegarden global design
  48. Rosegarden is split into 3 main parts:
  49. \section base Base
  50. The base library holds all of the fundamental "music handling"
  51. structures, of which the primary ones are Event, Segment, Track,
  52. Instrument and Composition. It also contains a selection of utility
  53. and helper classes of a kind that is not specific to any particular
  54. GUI. Everything here is part of the Rosegarden namespace, and there
  55. are no dependencies on KDE or TQt (although it uses the STL heavily).
  56. The keyword for the basic structures in use is "flexibility". Our
  57. Event objects can be extended arbitrarily for the convenience of GUI
  58. or performance code without having to change their declaration or
  59. modify anything in the base library. And most of our assumptions
  60. about the use of the container classes can be violated without
  61. disastrous side-effects.
  62. \subsection musicstructs Music Structures
  63. - \link Event Event\endlink is the basic musical element. It's more or less a
  64. generalization of the MIDI event. Each note or rest, each key
  65. change or tempo change, is an event: there's no "note class" or
  66. "rest class" as such, they are simply represented by events whose
  67. type happens to be "note" or "rest".
  68. Each Event has a type code, absolute time (the moment at which the
  69. Event starts, relative only to the start of the Composition) and
  70. duration (usually non-zero only for notes and rests), together
  71. with an arbitrary set of named and typed properties that can be
  72. assigned and queried dynamically by other parts of the
  73. application. So, for example, a note event is likely to have an
  74. integer property called "pitch", and probably a "velocity", as
  75. well as potentially many others -- but this is not fixed anywhere,
  76. and there's no definition of what exactly a note is: client code
  77. is simply expected to ignore any unrecognised events or properties
  78. and to cope if properties that should be there are not.
  79. - \link Segment Segment\endlink is a series of consecutive Events found on the same Track,
  80. automatically ordered by their absolute time. It's the usual
  81. container for Events. A Segment has a starting time that can be
  82. changed, and a duration that is based solely on the end time of
  83. the last Event it contains. Note that in order to facilitate
  84. musical notation editing, we explicitly store silences as series
  85. of rest Events; thus a Segment really should contain no gaps
  86. between its Events. (This isn't checked anywhere and nothing will
  87. break very badly if there are gaps, but notation won't quite work
  88. correctly.)
  89. - \link Track Track \endlink is much the same thing as on a mixing table, usually
  90. assigned to an instrument, a voice, etc. Although a Track is not
  91. a container of Events and is not strictly a container of Segments
  92. either, it is referred to by a set of Segments that are therefore
  93. mutually associated with the same instruments and parameters. In
  94. GUI terms, the Track is a horizontal row on the main Rosegarden
  95. window, whereas a Segment is a single blue box within that row, of
  96. which there may be any number.
  97. - \link Instrument Instrument \endlink corresponds broadly to a MIDI or Audio channel, and is
  98. the destination for a performed Event. Each Track is mapped to a
  99. single Instrument (although many Tracks may have the same
  100. Instrument), and the Instrument is indicated in the header at the
  101. left of the Track's row in the GUI.
  102. - \link Composition Composition\endlink is the container for the entire piece of music. It
  103. consists of a set of Segments, together with a set of Tracks that
  104. the Segments may or may not be associated with, a set of
  105. Instruments, and some information about time signature and tempo
  106. changes. (The latter are not stored in Segments; they are only
  107. stored in the top-level Composition. You can't have differing
  108. time signatures or tempos in different Segments.) Any code that
  109. wants to know about the locations of bar lines, or request
  110. real-time calculations based on tempo changes, talks to the
  111. Composition.
  112. See also docs/data_struct/units.txt for an explanation of the units we
  113. use for time and pitch values. See docs/discussion/names.txt for some
  114. name-related discussion. See docs/code/creating_events.txt for an
  115. explanation of how to create new Events and add properties to them.
  116. The base directory also contains various music-related helper classes:
  117. - The NotationTypes.[Ch] files contain classes that help with
  118. creating and manipulating events. It's very important to realise
  119. that these classes are not the events themselves: although there
  120. is a Note class in this file, and a TimeSignature class, and Clef
  121. and Key classes, instances of these are rarely stored anywhere.
  122. Instead they're created on-the-fly in order to do calculation
  123. related to note durations or time signatures or whatever, and they
  124. contain getAsEvent() methods that may be used when an event for
  125. storage is required. But the class of a stored event is always
  126. simply Event.
  127. The NotationTypes classes also define important constants for the
  128. names of common properties in Events. For example, the Note class
  129. contains Note::EventType, which is the type of a note Event, and
  130. Note::EventRestType, the type of a rest Event; and Key contains
  131. Key::EventType, the type of a key change Event, KeyPropertyName,
  132. the name of the property that defines the key change, and a set
  133. of the valid strings for key changes.
  134. - BaseProperties.[Ch] contains a set of "standard"-ish Event
  135. property names that are not basic enough to go in NotationTypes.
  136. - \link SegmentNotationHelper SegmentNotationHelper\endlink
  137. and \link SegmentPerformanceHelper SegmentPerformanceHelper\endlink
  138. do tasks that
  139. may be useful to notation-type code and performer code
  140. respectively. For example, SegmentNotationHelper is used to
  141. manage rests when inserting and deleting notes in a score editor,
  142. and to create beamed groups and suchlike; SegmentPerformanceHelper
  143. generally does calculations involving real performance time of
  144. notes (taking into account tied notes, tuplets and tempo changes).
  145. These two lightweight helper classes are also usually constructed
  146. on-the-fly for use on the events in a given Segment and then
  147. discarded after use.
  148. - \link Quantizer Quantizer\endlink is used to quantize event timings and set quantized
  149. timing properties on those events. Note that quantization is
  150. non-destructive, as it takes advantage of the ability to set new
  151. Event properties to simply assign the quantized values as separate
  152. properties from the original absolute time and duration.
  153. \section gui GUI
  154. The GUI directory builds into a KDE/TQt application. Like most KDE
  155. applications, it follows a document/view model. The document (class
  156. RosegardenGUIDoc, which wraps a Composition) can have several views
  157. (class RosegardenGUIView), although at the moment only a single one is
  158. used.
  159. This view is the TrackEditor, which shows all the Composition's
  160. Segments organized in Tracks. Each Segment can be edited in two ways:
  161. notation (score) or matrix (piano roll).
  162. All editor views are derived from EditView. An EditView is the class
  163. dealing with the edition per se of the events. It uses several
  164. components:
  165. - Layout classes, horizontal and vertical: these are the classes
  166. which determine the x and y coordinates of the graphic items
  167. representing the events (notes or piano-roll rectangles). They
  168. are derived from the LayoutEngine base-class in the base library.
  169. - Tools, which implement each editing function at the GUI (such as
  170. insert, erase, cut and paste). These are the tools which appear on
  171. the EditView's toolbar.
  172. - Toolbox, which is a simple string => tool map.
  173. - Commands, which are the fundamental implementations of editing
  174. operations (both menu functions and tool operations) subclassed
  175. from KDE's Command and used for undo and redo.
  176. - a canvas view. Although this isn't a part of the EditView's
  177. definition, both of the existing edit views (notation and matrix)
  178. use one, because they both use a TQCanvas to represent data.
  179. - LinedStaff, a staff with lines. Like the canvas view, this isn't
  180. part of the EditView definition, but both views use one.
  181. There are currently two editor views:
  182. - NotationView, with accompanying classes NotationHLayout,
  183. NotationVLayout, NotationStaff, and all the classes in the
  184. notationtool and notationcommands files. These are also closely
  185. associated with the NotePixmapFactory and NoteFont classes, which
  186. are used to generate notes from component pixmap files.
  187. - MatrixView, with accompanying classes MatrixHLayout,
  188. MatrixVLayout, MatrixStaff and other classes in the matrixview
  189. files.
  190. The editing process works as follows:
  191. [NOTE : in the following, we're talking both about events as UI events
  192. or user events (mouse button clicks, mouse move, keystrokes, etc...)
  193. and Events (our basic music element). To help lift the ambiguity,
  194. "events" is for UI events, Events is for Event.]
  195. -# The canvas view gets the user events (see
  196. NotationCanvasView::contentsMousePressEvent(TQMouseEvent*) for an
  197. example). It locates where the event occured in terms of musical
  198. element: which note or staff line the user clicked on, which pitch
  199. and time this corresponds to, that kind of stuff. (In the
  200. Notation and Matrix views, the LinedStaff calculates mappings
  201. between coordinates and staff lines: the former is especially
  202. complicated because of its support for page layout.)\n
  203. -# The canvas view transmits this kind of info as a signal, which is
  204. connected to a slot in the parent EditView.
  205. -# The EditView delegates action to the current tool.\n
  206. -# The tool performs the actual job (inserting or deleting a note,
  207. etc...).
  208. Since this action is usually complex (merely inserting a note requires
  209. dealing with the surrounding Events, rests or notes), it does it
  210. through a SegmentHelper (for instance, base/SegmentNotationHelper)
  211. which "wraps" the complexity into simple calls and performs all the
  212. hidden tasks.
  213. The EditView also maintains (obviously) its visual appearance with the
  214. layout classes, applying them when appropriate.
  215. \section sequencer Sequencer
  216. The sequencer directory also builds into a KDE/TQt application, but one
  217. which doesn't have a gui. The Sequencer can be started automatically
  218. by the main Rosegarden GUI or manually if testing - it's sometimes
  219. more convenient to do the latter as the Sequencer needs to be connected
  220. up to the underlying sound system every time it is started.
  221. The Sequencer interfaces directly with \link AlsaDriver ALSA\endlink
  222. and provides MIDI "play" and "record" ports which can be connected to
  223. other MIDI clients (MIDI IN and OUT hardware ports or ALSA synth devices)
  224. using any ALSA MIDI Connection Manager. The Sequencer also supports
  225. playing and recording of Audio sample files using \link JackDriver Jack\endlink
  226. The GUI and Sequencer communicate using the KDE DCOP communication framework.
  227. Look in:
  228. - \link rosegardenguiiface.h gui/rosegardenguiiface.h\endlink
  229. - \link rosegardensequenceriface.h sequencer/rosegardensequenceriface.h\endlink
  230. for definitions of the DCOP interfaces pertinent to the Sequencer
  231. and GUI. The main DCOP operations from the GUI involve starting and
  232. stopping the Sequencer, playing and recording, fast forwarding and
  233. rewinding. Once a play or record cycle is enabled it's the Sequencer
  234. that does most of the hard work. Events are read from (or written to, when recording)
  235. a set of mmapped files.
  236. The Sequencer makes use of two libraries libRosegardenSequencer
  237. and libRosegardenSound:
  238. - libRosegardenSequencer holds everything pertinent to sequencing
  239. for Rosegarden including the
  240. Sequencer class itself. This library is only linked into the
  241. Rosegarden Sequencer.
  242. - libRosegardenSound holds the MidiFile class (writing and reading
  243. MIDI files) and the MappedEvent and MappedComposition classes (the
  244. communication class for transferring events back and forth across
  245. DCOP). This library is needed by the GUI as well as the Sequencer.
  246. The main Sequencer state machine is a good starting point and clearly
  247. visible at the bottom of rosegarden/sequencer/main.cpp.
  248. */
  249. static const char *description =
  250. I18N_NOOP("Rosegarden - A sequencer and musical notation editor");
  251. static TDECmdLineOptions options[] =
  252. {
  253. { "nosequencer", I18N_NOOP("Don't use the sequencer (support editing only)"), 0 },
  254. { "nosplash", I18N_NOOP("Don't show the splash screen"), 0 },
  255. { "nofork", I18N_NOOP("Don't automatically run in the background"), 0 },
  256. { "existingsequencer", I18N_NOOP("Attach to a running sequencer process, if found"), 0 },
  257. { "ignoreversion", I18N_NOOP("Ignore installed version - for devs only"), 0 },
  258. { "+[File]", I18N_NOOP("file to open"), 0 },
  259. { 0, 0, 0 }
  260. };
  261. // -----------------------------------------------------------------
  262. #ifdef TQ_WS_X11
  263. #include <X11/Xlib.h>
  264. #include <X11/Xutil.h>
  265. #include <X11/Xatom.h>
  266. #include <X11/SM/SMlib.h>
  267. static int _x_errhandler( Display *dpy, XErrorEvent *err )
  268. {
  269. char errstr[256];
  270. XGetErrorText( dpy, err->error_code, errstr, 256 );
  271. if ( err->error_code != BadWindow )
  272. kdWarning() << "Rosegarden: detected X Error: " << errstr << " " << err->error_code
  273. << "\n Major opcode: " << err->request_code << endl;
  274. return 0;
  275. }
  276. #endif
  277. // NOTE: to get a dump of the stack trace from KDE during program execution:
  278. // std::cerr << kdBacktrace() << std::endl
  279. // (see kdebug.h)
  280. void testInstalledVersion()
  281. {
  282. TQString versionLocation = locate("appdata", "version.txt");
  283. TQString installedVersion;
  284. if (!versionLocation.isNull()) {
  285. TQFile versionFile(versionLocation);
  286. if (versionFile.open(IO_ReadOnly)) {
  287. TQTextStream text(&versionFile);
  288. TQString s = text.readLine().stripWhiteSpace();
  289. versionFile.close();
  290. if (!s.isNull()) {
  291. if (s == VERSION) return;
  292. installedVersion = s;
  293. }
  294. }
  295. }
  296. if (!installedVersion.isNull()) {
  297. KMessageBox::detailedError
  298. (0,
  299. i18n("Installation contains the wrong version of Rosegarden."),
  300. i18n(" The wrong versions of Rosegarden's data files were\n"
  301. " found in the standard TDE installation directories.\n"
  302. " (I am %1, but the installed files are for version %2.)\n\n"
  303. " This may mean one of the following:\n\n"
  304. " 1. This is a new upgrade of Rosegarden, and it has not yet been\n"
  305. " installed. If you compiled it yourself, check that you have\n"
  306. " run \"make install\" and that the procedure completed\n"
  307. " successfully.\n\n"
  308. " 2. The upgrade was installed in a non-standard directory,\n"
  309. " and an old version was found in a standard directory. If so,\n"
  310. " you will need to add the correct directory to your TDEDIRS\n"
  311. " environment variable before you can run it.").arg(VERSION).arg(installedVersion),
  312. i18n("Installation problem"));
  313. } else {
  314. KMessageBox::detailedError
  315. (0,
  316. i18n("Rosegarden does not appear to have been installed."),
  317. i18n(" One or more of Rosegarden's data files could not be\n"
  318. " found in the standard TDE installation directories.\n\n"
  319. " This may mean one of the following:\n\n"
  320. " 1. Rosegarden has not been correctly installed. If you compiled\n"
  321. " it yourself, check that you have run \"make install\" and that\n"
  322. " the procedure completed successfully.\n\n"
  323. " 2. Rosegarden has been installed in a non-standard directory,\n"
  324. " and you need to add this directory to your TDEDIRS environment\n"
  325. " variable before you can run it. This may be the case if you\n"
  326. " installed into $HOME or a local third-party package directory\n"
  327. " like /usr/local or /opt."),
  328. i18n("Installation problem"));
  329. }
  330. exit(1);
  331. }
  332. int main(int argc, char *argv[])
  333. {
  334. setsid(); // acquire shiny new process group
  335. srandom((unsigned int)time(0) * (unsigned int)getpid());
  336. TDEAboutData aboutData( "rosegarden", I18N_NOOP("Rosegarden"),
  337. VERSION, description, TDEAboutData::License_GPL,
  338. I18N_NOOP("Copyright 2000 - 2008 Guillaume Laurent, Chris Cannam, Richard Bown\nParts copyright 1994 - 2004 Chris Cannam, Andy Green, Richard Bown, Guillaume Laurent\nLilyPond fonts copyright 1997 - 2005 Han-Wen Nienhuys and Jan Nieuwenhuizen"),
  339. 0,
  340. "http://www.rosegardenmusic.com/",
  341. "rosegarden-devel@lists.sourceforge.net");
  342. aboutData.addAuthor("Guillaume Laurent (lead)", 0, "glaurent@telegraph-road.org", "http://telegraph-road.org");
  343. aboutData.addAuthor("Chris Cannam (lead)", 0, "cannam@all-day-breakfast.com", "http://all-day-breakfast.com");
  344. aboutData.addAuthor("Richard Bown (lead)", 0, "richard.bown@ferventsoftware.com");
  345. aboutData.addAuthor("D. Michael McIntyre", 0, "dmmcintyr@users.sourceforge.net");
  346. aboutData.addAuthor("Pedro Lopez-Cabanillas", 0, "plcl@users.sourceforge.net");
  347. aboutData.addAuthor("Heikki Johannes Junes", 0, "hjunes@users.sourceforge.net");
  348. aboutData.addCredit("Randall Farmer", I18N_NOOP("Chord labelling code"), " rfarme@simons-rock.edu");
  349. aboutData.addCredit("Hans Kieserman", I18N_NOOP("LilyPond output\nassorted other patches\ni18n-ization"), "hkieserman@mail.com");
  350. aboutData.addCredit("Levi Burton", I18N_NOOP("UI improvements\nbug fixes"), "donburton@sbcglobal.net");
  351. aboutData.addCredit("Mark Hymers", I18N_NOOP("Segment colours\nOther UI and bug fixes"), "<markh@linuxfromscratch.org>");
  352. aboutData.addCredit("Alexandre Prokoudine", I18N_NOOP("Russian translation\ni18n-ization"), "avp@altlinux.ru");
  353. aboutData.addCredit("Jörg Schumann", I18N_NOOP("German translation"), "jrschumann@gmx.de");
  354. aboutData.addCredit("Eckhard Jokisch", I18N_NOOP("German translation"), "e.jokisch@u-code.de");
  355. aboutData.addCredit("Kevin Donnelly", I18N_NOOP("Welsh translation"));
  356. aboutData.addCredit("Didier Burli", I18N_NOOP("French translation"), "didierburli@bluewin.ch");
  357. aboutData.addCredit("Yves Guillemot", I18N_NOOP("French translation\nBug fixes"), "yc.guillemot@wanadoo.fr");
  358. aboutData.addCredit("Daniele Medri", I18N_NOOP("Italian translation"), "madrid@linuxmeeting.net");
  359. aboutData.addCredit("Alessandro Musesti", I18N_NOOP("Italian translation"), "a.musesti@dmf.unicatt.it");
  360. aboutData.addCredit("Stefan Asserhäll", I18N_NOOP("Swedish translation"), "stefan.asserhall@comhem.se");
  361. aboutData.addCredit("Erik Magnus Johansson", I18N_NOOP("Swedish translation"), "erik.magnus.johansson@telia.com");
  362. aboutData.addCredit("Hasso Tepper", I18N_NOOP("Estonian translation"), "hasso@estpak.ee");
  363. aboutData.addCredit("Jelmer Vernooij", I18N_NOOP("Dutch translation"), "jelmer@samba.org");
  364. aboutData.addCredit("Jasper Stein", I18N_NOOP("Dutch translation"), "jasper.stein@12move.nl");
  365. aboutData.addCredit("Kevin Liang", I18N_NOOP("HSpinBox class"), "xkliang@rhpcs.mcmaster.ca");
  366. aboutData.addCredit("Arnout Engelen", I18N_NOOP("Transposition by interval"));
  367. aboutData.addCredit("Thorsten Wilms", I18N_NOOP("Original designs for rotary controllers"), "t_w_@freenet.de");
  368. aboutData.addCredit("Oota Toshiya", I18N_NOOP("Japanese translation"), "ribbon@users.sourceforge.net");
  369. aboutData.addCredit("William", I18N_NOOP("Auto-scroll deceleration\nRests outside staves and other bug fixes"), "rosegarden4p AT orthoset.com");
  370. aboutData.addCredit("Liu Songhe", I18N_NOOP("Simplified Chinese translation"), "jackliu9999@msn.com");
  371. aboutData.addCredit("Toni Arnold", I18N_NOOP("LIRC infrared remote-controller support"), "<toni__arnold@bluewin.ch>");
  372. aboutData.addCredit("Vince Negri", I18N_NOOP("MTC slave timing implementation"), "vince.negri@gmail.com");
  373. aboutData.addCredit("Jan Bína", I18N_NOOP("Czech translation"), "jbina@sky.cz");
  374. aboutData.addCredit("Thomas Nagy", I18N_NOOP("SCons/bksys building system"), "tnagy256@yahoo.fr");
  375. aboutData.addCredit("Vladimir Savic", I18N_NOOP("icons, icons, icons"), "vladimir@vladimirsavic.net");
  376. aboutData.addCredit("Marcos Germán Guglielmetti", I18N_NOOP("Spanish translation"), "marcospcmusica@yahoo.com.ar");
  377. aboutData.addCredit("Lisandro Damián Nicanor Pérez Meyer", I18N_NOOP("Spanish translation"), "perezmeyer@infovia.com.ar");
  378. aboutData.addCredit("Javier Castrillo", I18N_NOOP("Spanish translation"), "riverplatense@gmail.com");
  379. aboutData.addCredit("Lucas Godoy", I18N_NOOP("Spanish translation"), "godoy.lucas@gmail.com");
  380. aboutData.addCredit("Feliu Ferrer", I18N_NOOP("Catalan translation"), "mverge2@pie.xtec.es");
  381. aboutData.addCredit("Quim Perez i Noguer", I18N_NOOP("Catalan translation"), "noguer@osona.com");
  382. aboutData.addCredit("Carolyn McIntyre", I18N_NOOP("1.2.3 splash screen photo\nGave birth to D. Michael McIntyre, bought him a good flute once\nupon a time, and always humored him when he came over to play her\nsome new instrument, even though she really hated his playing.\nBorn October 19, 1951, died September 21, 2007, R. I. P."), "DECEASED");
  383. aboutData.addCredit("Stephen Torri", I18N_NOOP("Initial guitar chord editing code"), "storri@torri.org");
  384. aboutData.addCredit("Piotr Sawicki", I18N_NOOP("Polish translation"), "pelle@plusnet.pl");
  385. aboutData.addCredit("David García-Abad", I18N_NOOP("Basque translation"), "davidgarciabad@telefonica.net");
  386. aboutData.addCredit("Joerg C. Koenig, Craig Drummond, Bernhard Rosenkränzer, Preston Brown, Than Ngo", I18N_NOOP("Klearlook theme"), "jck@gmx.org");
  387. aboutData.setTranslator(I18N_NOOP("_: NAME OF TRANSLATORS\nYour names") , I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails"));
  388. TDECmdLineArgs::init( argc, argv, &aboutData );
  389. TDECmdLineArgs::addCmdLineOptions( options ); // Add our own options.
  390. KUniqueApplication::addCmdLineOptions(); // Add KUniqueApplication options.
  391. if (!RosegardenApplication::start())
  392. return 0;
  393. RosegardenApplication app;
  394. //
  395. // Ensure quit on last window close
  396. // Register main DCOP interface
  397. //
  398. TQObject::connect(&app, TQT_SIGNAL(lastWindowClosed()), &app, TQT_SLOT(quit()));
  399. app.dcopClient()->registerAs(app.name(), false);
  400. app.dcopClient()->setDefaultObject(ROSEGARDEN_GUI_IFACE_NAME);
  401. // Parse cmd line args
  402. //
  403. TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
  404. if (!args->isSet("ignoreversion")) {
  405. // Give up immediately if we haven't been installed or if the
  406. // installation is out of date
  407. //
  408. testInstalledVersion();
  409. }
  410. TDEConfig *config = kapp->config();
  411. config->setGroup(GeneralOptionsConfigGroup);
  412. TQString lastVersion = config->readEntry("lastversion", "");
  413. bool newVersion = (lastVersion != VERSION);
  414. if (newVersion) {
  415. std::cerr << "*** This is the first time running this Rosegarden version" << std::endl;
  416. config->writeEntry("lastversion", VERSION);
  417. }
  418. // If there is no config setting for the startup window size, set
  419. // one now. But base the default on the appropriate desktop size
  420. // (i.e. not the entire desktop, if Xinerama is in use). This is
  421. // obtained from TDEGlobalSettings::desktopGeometry(), but we can't
  422. // give it a meaningful point to measure from at this stage so we
  423. // always use the "leftmost" display (point 0,0).
  424. // The config keys are "Height X" and "Width Y" where X and Y are
  425. // the sizes of the available desktop (i.e. the whole shebang if
  426. // under Xinerama). These are obtained from TQDesktopWidget.
  427. config->setGroup("MainView");
  428. int windowWidth = 0, windowHeight = 0;
  429. TQDesktopWidget *desktop = TDEApplication::desktop();
  430. if (desktop) {
  431. TQRect totalRect(desktop->screenGeometry());
  432. TQRect desktopRect = TDEGlobalSettings::desktopGeometry(TQPoint(0, 0));
  433. TQSize startupSize;
  434. if (desktopRect.height() <= 800) {
  435. startupSize = TQSize((desktopRect.width() * 6) / 7,
  436. (desktopRect.height() * 6) / 7);
  437. } else {
  438. startupSize = TQSize((desktopRect.width() * 4) / 5,
  439. (desktopRect.height() * 4) / 5);
  440. }
  441. TQString widthKey = TQString("Width %1").arg(totalRect.width());
  442. TQString heightKey = TQString("Height %1").arg(totalRect.height());
  443. windowWidth = config->readUnsignedNumEntry
  444. (widthKey, startupSize.width());
  445. windowHeight = config->readUnsignedNumEntry
  446. (heightKey, startupSize.height());
  447. }
  448. config->setGroup("KDE Action Restrictions");
  449. config->writeEntry("action/help_report_bug", false);
  450. config->setGroup(GeneralOptionsConfigGroup);
  451. int install = config->readNumEntry("Install Own Theme", 1);
  452. if (install == 2 || (install == 1 && !getenv("TDE_FULL_SESSION"))) {
  453. kapp->setStyle(new KlearlookStyle);
  454. }
  455. // Show Startup logo
  456. // (this code borrowed from KDevelop 2.0,
  457. // (c) The KDevelop Development Team
  458. //
  459. config->setGroup(GeneralOptionsConfigGroup);
  460. TDEStartupLogo* startLogo = 0L;
  461. // See if the config wants us to control JACK
  462. //
  463. if (config->readBoolEntry("Logo", true) && (!kapp->isRestored() && args->isSet("splash")) ) {
  464. RG_DEBUG << k_funcinfo << "Showing startup logo\n";
  465. startLogo = TDEStartupLogo::getInstance();
  466. startLogo->setShowTip(!newVersion);
  467. startLogo->show();
  468. }
  469. struct timeval logoShowTime;
  470. gettimeofday(&logoShowTime, 0);
  471. //
  472. // Start application
  473. //
  474. RosegardenGUIApp *rosegardengui = 0;
  475. if (app.isRestored()) {
  476. RG_DEBUG << "Restoring from session\n";
  477. // RESTORE(RosegardenGUIApp);
  478. int n = 1;
  479. while (TDEMainWindow::canBeRestored(n)) {
  480. // memory leak if more than one can be restored?
  481. RG_DEBUG << "Restoring from session - restoring app #" << n << endl;
  482. (rosegardengui = new RosegardenGUIApp)->restore(n);
  483. n++;
  484. }
  485. } else {
  486. #ifndef NO_SOUND
  487. app.setNoSequencerMode(!args->isSet("sequencer"));
  488. #else
  489. app.setNoSequencerMode(true);
  490. #endif // NO_SOUND
  491. rosegardengui = new RosegardenGUIApp(!app.noSequencerMode(),
  492. args->isSet("existingsequencer"),
  493. TQT_TQOBJECT(startLogo));
  494. rosegardengui->setIsFirstRun(newVersion);
  495. app.setMainWidget(rosegardengui);
  496. if (windowWidth != 0 && windowHeight != 0) {
  497. rosegardengui->resize(windowWidth, windowHeight);
  498. }
  499. rosegardengui->show();
  500. // raise start logo
  501. //
  502. if (startLogo) {
  503. startLogo->raise();
  504. startLogo->setHideEnabled(true);
  505. TQApplication::flushX();
  506. }
  507. if (args->count()) {
  508. rosegardengui->openFile(TQFile::decodeName(args->arg(0)), RosegardenGUIApp::ImportCheckType);
  509. } else {
  510. // rosegardengui->openDocumentFile();
  511. }
  512. args->clear();
  513. }
  514. TQObject::connect(&app, TQT_SIGNAL(aboutToSaveState()),
  515. rosegardengui, TQT_SLOT(slotDeleteTransport()));
  516. // Now that we've started up, raise start logo
  517. //
  518. if (startLogo) {
  519. startLogo->raise();
  520. startLogo->setHideEnabled(true);
  521. TQApplication::flushX();
  522. }
  523. // Check for sequencer and launch if needed
  524. //
  525. try {
  526. rosegardengui->launchSequencer(args->isSet("existingsequencer"));
  527. } catch (std::string e) {
  528. RG_DEBUG << "RosegardenGUI - " << e << endl;
  529. } catch (TQString e) {
  530. RG_DEBUG << "RosegardenGUI - " << e << endl;
  531. } catch (Exception e) {
  532. RG_DEBUG << "RosegardenGUI - " << e.getMessage() << endl;
  533. }
  534. config->setGroup(SequencerOptionsConfigGroup);
  535. // See if the config wants us to load a soundfont
  536. //
  537. if (config->readBoolEntry("sfxloadenabled", false)) {
  538. TQString sfxLoadPath = config->readEntry("sfxloadpath", "/bin/sfxload");
  539. TQString soundFontPath = config->readEntry("soundfontpath", "");
  540. TQFileInfo sfxLoadInfo(sfxLoadPath), soundFontInfo(soundFontPath);
  541. if (sfxLoadInfo.isExecutable() && soundFontInfo.isReadable()) {
  542. TDEProcess* sfxLoadProcess = new TDEProcess;
  543. (*sfxLoadProcess) << sfxLoadPath << soundFontPath;
  544. RG_DEBUG << "Starting sfxload : " << sfxLoadPath << " " << soundFontPath << endl;
  545. TQObject::connect(sfxLoadProcess, TQT_SIGNAL(processExited(TDEProcess*)),
  546. &app, TQT_SLOT(sfxLoadExited(TDEProcess*)));
  547. sfxLoadProcess->start();
  548. } else {
  549. RG_DEBUG << "sfxload not executable or soundfont not readable : "
  550. << sfxLoadPath << " " << soundFontPath << endl;
  551. }
  552. } else {
  553. RG_DEBUG << "sfxload disabled\n";
  554. }
  555. #ifdef TQ_WS_X11
  556. XSetErrorHandler( _x_errhandler );
  557. #endif
  558. if (startLogo) {
  559. // pause to ensure the logo has been visible for a reasonable
  560. // length of time, just 'cos it looks a bit silly to show it
  561. // and remove it immediately
  562. struct timeval now;
  563. gettimeofday(&now, 0);
  564. RealTime visibleFor =
  565. RealTime(now.tv_sec, now.tv_usec * 1000) -
  566. RealTime(logoShowTime.tv_sec, logoShowTime.tv_usec * 1000);
  567. if (visibleFor < RealTime(2, 0)) {
  568. int waitTime = visibleFor.sec * 1000 + visibleFor.msec();
  569. TQTimer::singleShot(2500 - waitTime, startLogo, TQT_SLOT(close()));
  570. } else {
  571. startLogo->close();
  572. }
  573. } else {
  574. // if the start logo is there, it's responsible for showing this;
  575. // otherwise we have to
  576. if (!newVersion) {
  577. RosegardenGUIApp::self()->awaitDialogClearance();
  578. KTipDialog::showTip(locate("data", "rosegarden/tips"));
  579. }
  580. }
  581. if (newVersion) {
  582. TDEStartupLogo::hideIfStillThere();
  583. CurrentProgressDialog::freeze();
  584. KDialogBase *dialog = new KDialogBase(rosegardengui, "welcome",
  585. true, i18n("Welcome!"),
  586. KDialogBase::Ok,
  587. KDialogBase::Ok, false);
  588. TQVBox *mw = dialog->makeVBoxMainWidget();
  589. TQHBox *hb = new TQHBox(mw);
  590. TQLabel *image = new TQLabel(hb);
  591. image->setAlignment(TQt::AlignTop);
  592. TQString iconFile = locate("appdata", "pixmaps/misc/welcome-icon.png");
  593. if (!iconFile.isNull()) {
  594. image->setPixmap(TQPixmap(iconFile));
  595. }
  596. TQLabel *label = new TQLabel(hb);
  597. label->setText(i18n("<h2>Welcome to Rosegarden!</h2><p>Welcome to the Rosegarden audio and MIDI sequencer and musical notation editor.</p><ul><li>If you have not already done so, you may wish to install some DSSI synth plugins, or a separate synth program such as TQSynth. Rosegarden does not synthesize sounds from MIDI on its own, so without these you will hear nothing.</li><br><br><li>Rosegarden uses the JACK audio server for recording and playback of audio, and for playback from DSSI synth plugins. These features will only be available if the JACK server is running.</li><br><br><li>Rosegarden has comprehensive documentation: see the Help menu for the handbook, tutorials, and other information!</li></ul><p>Rosegarden was brought to you by a team of volunteers across the world. To learn more, go to <a href=\"http://www.rosegardenmusic.com/\">http://www.rosegardenmusic.com/</a>.</p>"));
  598. dialog->showButtonOK(true);
  599. rosegardengui->awaitDialogClearance();
  600. dialog->exec();
  601. CurrentProgressDialog::thaw();
  602. }
  603. return kapp->exec();
  604. }