1 /* utils.c
2  * Functions useful across the different modules of
3  * drawing and non-drawing code.
4  *
5  * for Denemo, a gtk+ frontend to GNU Lilypond
6  * (c) 1999-2005 Matthew Hiller
7  */
8 
9 #include <stdio.h>
10 #include <string.h>             /*for SIGTERM */
11 #include <ctype.h>
12 #include <math.h>
13 #include <fontconfig/fontconfig.h>
14 #include <gtk/gtk.h>
15 #include <gdk/gdk.h>
16 #include <stdlib.h>
17 #include "display/accwidths.h"
18 #include <denemo/denemo.h>
19 #include "display/notewidths.h"
20 #include "core/utils.h"
21 #include "smf.h"
22 #include "export/print.h"
23 #include "core/kbd-custom.h"
24 #include "core/view.h"
25 #include "command/object.h"
26 #include "command/scorelayout.h"
27 #include <signal.h>             /*for SIGTERM */
28 
29 #include "config.h"
30 #ifdef G_OS_WIN32
31 #include "windows.h"
32 #else
33 #include "core/binreloc.h"
34 #endif
35 #include "audio/pitchentry.h"
36 #include "command/measure.h"
37 #ifdef _MACH_O_
38 #include <mach-o/dyld.h>
39 #endif
40 
41 //generated by cairo_svg2path from piano_staff.svg
42 static cairo_path_data_t piano_brace_data[] = {
43   {.header.type = 0,.header.length = 2},
44   {.point.x = 13.694762,.point.y = 15.134294},
45   {.header.type = 0,.header.length = 2},
46   {.point.x = 13.694762,.point.y = 34.647228},
47   {.header.type = 2,.header.length = 4},
48   {.point.x = 13.694745,.point.y = 37.873117},
49   {.point.x = 13.456160,.point.y = 40.450299},
50   {.point.x = 12.979007,.point.y = 42.378764},
51   {.header.type = 2,.header.length = 4},
52   {.point.x = 12.533633,.point.y = 44.307289},
53   {.point.x = 11.849690,.point.y = 45.797498},
54   {.point.x = 10.927179,.point.y = 46.849380},
55   {.header.type = 2,.header.length = 4},
56   {.point.x = 10.036446,.point.y = 47.901323},
57   {.point.x = 8.748092,.point.y = 48.830499},
58   {.point.x = 7.062105,.point.y = 49.636952},
59   {.header.type = 2,.header.length = 4},
60   {.point.x = 9.734241,.point.y = 50.899267},
61   {.point.x = 11.499767,.point.y = 52.722581},
62   {.point.x = 12.358688,.point.y = 55.106874},
63   {.header.type = 2,.header.length = 4},
64   {.point.x = 13.249387,.point.y = 57.491228},
65   {.point.x = 13.694745,.point.y = 61.102772},
66   {.point.x = 13.694762,.point.y = 65.941541},
67   {.header.type = 1,.header.length = 2},
68   {.point.x = 13.694762,.point.y = 83.666226},
69   {.header.type = 2,.header.length = 4},
70   {.point.x = 13.694745,.point.y = 88.119297},
71   {.point.x = 14.251441,.point.y = 91.450330},
72   {.point.x = 15.364854,.point.y = 93.659376},
73   {.header.type = 2,.header.length = 4},
74   {.point.x = 15.937439,.point.y = 94.781380},
75   {.point.x = 16.557760,.point.y = 95.675508},
76   {.point.x = 17.225817,.point.y = 96.341727},
77   {.header.type = 2,.header.length = 4},
78   {.point.x = 17.925643,.point.y = 97.042993},
79   {.point.x = 18.434624,.point.y = 97.463756},
80   {.point.x = 18.752761,.point.y = 97.604034},
81   {.header.type = 2,.header.length = 4},
82   {.point.x = 19.102663,.point.y = 97.744242},
83   {.point.x = 19.532113,.point.y = 97.884511},
84   {.point.x = 20.041117,.point.y = 98.024788},
85   {.header.type = 1,.header.length = 2},
86   {.point.x = 20.041117,.point.y = 99.602655},
87   {.header.type = 2,.header.length = 4},
88   {.point.x = 14.442310,.point.y = 99.427312},
89   {.point.x = 10.815824,.point.y = 98.112447},
90   {.point.x = 9.161650,.point.y = 95.658006},
91   {.header.type = 2,.header.length = 4},
92   {.point.x = 7.412016,.point.y = 93.028214},
93   {.point.x = 6.537207,.point.y = 88.487468},
94   {.point.x = 6.537217,.point.y = 82.035749},
95   {.header.type = 1,.header.length = 2},
96   {.point.x = 6.537217,.point.y = 63.206580},
97   {.header.type = 2,.header.length = 4},
98   {.point.x = 6.537207,.point.y = 60.787187},
99   {.point.x = 6.362244,.point.y = 58.735972},
100   {.point.x = 6.012330,.point.y = 57.052911},
101   {.header.type = 2,.header.length = 4},
102   {.point.x = 5.694207,.point.y = 55.369866},
103   {.point.x = 5.026171,.point.y = 53.879675},
104   {.point.x = 4.008217,.point.y = 52.582286},
105   {.header.type = 2,.header.length = 4},
106   {.point.x = 3.022060,.point.y = 51.249883},
107   {.point.x = 1.685986,.point.y = 50.373300},
108   {.point.x = -0.000008,.point.y = 49.952520},
109   {.header.type = 1,.header.length = 2},
110   {.point.x = -0.000008,.point.y = 49.373968},
111   {.header.type = 2,.header.length = 4},
112   {.point.x = 4.358134,.point.y = 48.006509},
113   {.point.x = 6.537207,.point.y = 43.676162},
114   {.point.x = 6.537217,.point.y = 36.382874},
115   {.header.type = 1,.header.length = 2},
116   {.point.x = 6.537217,.point.y = 15.975830},
117   {.header.type = 2,.header.length = 4},
118   {.point.x = 6.537207,.point.y = 10.120270},
119   {.point.x = 7.443829,.point.y = 5.965213},
120   {.point.x = 9.257083,.point.y = 3.510685},
121   {.header.type = 2,.header.length = 4},
122   {.point.x = 11.102126,.point.y = 1.056314},
123   {.point.x = 14.696800,.point.y = -0.258578},
124   {.point.x = 20.041117,.point.y = -0.433981},
125   {.header.type = 1,.header.length = 2},
126   {.point.x = 20.041117,.point.y = 1.143903},
127   {.header.type = 2,.header.length = 4},
128   {.point.x = 18.068795,.point.y = 1.740052},
129   {.point.x = 16.462326,.point.y = 3.212732},
130   {.point.x = 15.221705,.point.y = 5.561917},
131   {.header.type = 2,.header.length = 4},
132   {.point.x = 14.203726,.point.y = 7.490478},
133   {.point.x = 13.694745,.point.y = 10.681285},
134   {.point.x = 13.694762,.point.y = 15.134294},
135 
136 };
137 
138 static cairo_path_t piano_brace_path = { 0, piano_brace_data, 92 };
139 /**
140  * This checks to see if there's a .denemo/ directory in the user's
141  * home directory,
142  * if create tries to create one if there isn't, and returns the
143  * path to it
144  * else returns NULL
145  *
146  * .denemo/ is used for holding configuration files, templates, and so on.
147  *
148  * On windows the home directory is the one containing the My Documents folder.
149  */
150 
151 const gchar *
get_user_data_dir(gboolean create)152 get_user_data_dir (gboolean create)
153 {
154   static gchar *dotdenemo = NULL;
155 
156   gboolean err;
157   if (!dotdenemo)
158     {
159       dotdenemo = g_build_filename (g_get_home_dir (), ".denemo-" PACKAGE_VERSION, NULL);
160     }
161   if ((!create) && !g_file_test (dotdenemo, G_FILE_TEST_IS_DIR))
162     return NULL;
163   err = g_mkdir_with_parents (dotdenemo, 0770);
164   if (err)
165     {
166       warningdialog (_("Could not create .denemo for you personal settings"));
167       g_free (dotdenemo);
168       dotdenemo = NULL;
169     }
170   return dotdenemo;
171 }
172 
173 /* return a path to a temporary directory to be used for print intermediate files */
174 const gchar *
locateprintdir(void)175 locateprintdir (void)
176 {
177   static gchar *printdir = NULL;
178   if (!printdir)
179     printdir = make_temp_dir ();
180   return printdir;
181 }
182 
183 
184 void
add_font_directory(gchar * fontpath)185 add_font_directory (gchar * fontpath)
186 {
187 #ifdef G_OS_WIN32
188   if (0 == AddFontResource (fontpath))
189     g_warning("Failed to add font dir %s.", fontpath);
190   SendMessage (HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
191 #endif
192   if(FcConfigAppFontAddDir (NULL, (FcChar8*) fontpath) == FcFalse)
193     g_warning("Failed to add font dir %s.", fontpath);
194 }
195 
196 void
add_font_file(gchar * fontname)197 add_font_file (gchar * fontname)
198 {
199 #ifdef G_OS_WIN32
200   if (0 == AddFontResource (fontname))
201     g_warning("Failed to add font file %s.", fontname);
202   SendMessage (HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
203 #endif
204   if(FcConfigAppFontAddFile (NULL, (FcChar8*) fontname) == FcFalse)
205     g_warning("Failed to add font file %s.", fontname);
206 }
207 
208 #ifdef G_OS_WIN32
209 gboolean CoInitializeExCalled = FALSE;
210 #endif
211 
212 // Create a unique temporary directory starting
213 gchar *
make_temp_dir(void)214 make_temp_dir (void)
215 {
216   gchar *ret = NULL;
217 #ifdef G_OS_WIN32
218   gchar buf[1024] = "C:\\TMP\\\0";
219   gint length = 1024;
220   (void) GetTempPath (length, buf);
221   gint integer = 0;             //Windows does not delete the temp directory, use a constant one. g_rand_int(g_rand_new());
222   ret = g_strdup_printf ("%sDenemo%d", buf, integer);
223 
224   gint fail = g_mkdir_with_parents (ret, 0700);
225   if (fail)
226     g_warning ("Could not create temp dir %s", ret);
227   else
228     g_info ("Created temp dir %s\n", ret);
229 #else
230   ret = g_strdup ("/tmp/DenemoXXXXXX");
231   mkdtemp ((char *) ret);
232 #endif
233   return ret;
234 }
235 
236 gboolean
run_file_association(gchar * filename)237 run_file_association (gchar * filename)
238 {
239 #ifdef G_OS_WIN32
240   gint value = 0;
241   if (!CoInitializeExCalled)
242     {
243       value = CoInitializeExCalled = TRUE;
244       CoInitializeEx (NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
245       g_debug ("coinit returned %d\n", value);
246     }
247   g_info ("Running ShellExecute %s \n", filename);
248   return ShellExecute (NULL, NULL, filename, NULL, NULL, 0) > 32 /* value above 32 indicating success */ ;
249 #else
250   g_warning ("No file assoc code - set pref in externals tab of prefs dialog");
251   return 0;
252 #endif
253 
254 }
255 
256 /**
257    Popups up the menu named.
258  */
259 void
popup_menu(gchar * name)260 popup_menu (gchar * name)
261 {
262   GtkWidget *menu = gtk_ui_manager_get_widget (Denemo.ui_manager, name);
263   gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ());
264 }
265 
266 /**
267  * outputs a warning and sounds bell
268  * @return none
269  */
270 void
warningmessage(gchar * msg)271 warningmessage (gchar * msg)
272 {
273   gdk_beep ();
274   g_warning ("%s", msg);
275 }
276 
277 /**
278  * Pops up an info or warning dialog and blocks until it is dismissed
279  *  @param msg warning message to display
280  *  @param info TRUE if informational only
281  * @return none
282  */
283 void
infowarningdialog(gchar * msg,gboolean info)284 infowarningdialog (gchar * msg, gboolean info)
285 {
286   if(Denemo.non_interactive)
287     g_warning("%s", msg);
288   else
289   {
290     GtkWidget *dialog;
291     dialog = gtk_message_dialog_new (GTK_WINDOW (Denemo.window), GTK_DIALOG_DESTROY_WITH_PARENT, info?GTK_MESSAGE_INFO  :GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, "%s", msg);
292     gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
293     gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(Denemo.window));
294     gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
295     gtk_dialog_run (GTK_DIALOG (dialog));
296     gtk_widget_destroy (dialog);
297   }
298 }
299 /**
300  * Pops up a warning dialog and blocks until it is dismissed
301  *  @param msg warning message to display
302  * @return none
303  */
304 void
warningdialog(gchar * msg)305 warningdialog (gchar * msg)
306 {
307  infowarningdialog (msg, FALSE);
308 }
309 
310 /**
311  * Displays information message to screen, not blocking.
312  * User can destroy window when no longer needed.
313  * @param msg message to display
314  * @return dialog
315  */
316 GtkWidget *
infodialog(gchar * msg)317 infodialog (gchar * msg)
318 {
319   if(Denemo.non_interactive){
320     g_info("%s", msg);
321     return NULL;
322   }
323 
324   GtkWidget *dialog;
325   dialog = gtk_message_dialog_new (GTK_WINDOW (Denemo.window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", msg);
326 #ifdef G_OS_WIN32
327   gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE); //needed on windows because of a bug, not all text can be seen.
328 #endif
329   g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_hide), dialog);
330   gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(Denemo.window));
331   gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
332   gtk_widget_show_all (dialog);
333   return dialog;
334 }
335 
336 /* data stucture to contain Progressbar
337  * data
338  */
339 typedef struct _ProgressData
340 {
341   GtkWidget *window;
342   GtkWidget *pbar;
343   int timer;
344   gboolean progressing;
345 } ProgressData;
346 
347 static ProgressData progress_data;
348 
349 
350 /* Update the value of the progress bar so that we get
351  * some movement */
352 static gboolean
progress_timeout(void)353 progress_timeout (void)
354 {
355   if (progress_data.progressing)
356     gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progress_data.pbar));
357   else
358     {
359       gtk_widget_hide (progress_data.window);
360       progress_data.timer = 0;
361       return FALSE;
362     }
363   return TRUE;
364 }
365 
366 
367 
368 
369 /**
370  * Displays progress bar
371  * optionally pass a callback to be run on delete signal
372  * @param msg message to display, callback (can be NULL)
373  */
374 GtkWindow *
progressbar(gchar * msg,gpointer callback)375 progressbar (gchar * msg, gpointer callback)
376 {
377 
378   GtkWidget *vbox;
379   ProgressData *pdata = &progress_data;
380   if (pdata->progressing) pdata->window;
381   if (pdata->window == NULL)
382     {
383       if (callback && Denemo.prefs.progressbardecorations)
384         pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
385       else
386         pdata->window = gtk_window_new (GTK_WINDOW_POPUP);
387       gtk_window_set_accept_focus (GTK_WINDOW (pdata->window), FALSE);  //FIXME this is only a hint; perhaps we should embed the progress bar in the status line...
388       gtk_window_set_title (GTK_WINDOW (pdata->window), _("Progress"));
389       gtk_widget_set_tooltip_text (pdata->window, _("This indicates the the LilyPond typesetter is still working on setting the Denemo score. This can take a long time, particularly for polyphony where voices must not collide. You can continue editing while the typesetting is taking place.\nKill this window if you want to re-start the typesetting e.g. after fixing a mistake you just spotted."));
390       gtk_window_set_transient_for (GTK_WINDOW(pdata->window), GTK_WINDOW(Denemo.window));
391       gtk_window_set_keep_above (GTK_WINDOW (pdata->window), TRUE);
392       vbox = gtk_vbox_new (FALSE, 5);
393       gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
394       pdata->pbar = gtk_progress_bar_new ();
395       gtk_container_add (GTK_CONTAINER (vbox), pdata->pbar);
396       gtk_widget_show_all (vbox);
397     }
398   /* set text inside progress bar */
399   gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata->pbar), msg);
400   if (pdata->timer == 0)
401     pdata->timer = g_timeout_add (100, (GSourceFunc) progress_timeout, pdata);
402   pdata->progressing = TRUE;           /* If this is false the progress bar will stop */
403   gtk_widget_show (pdata->window);
404   /* If widget is destroyed stop the printing */
405   if(callback)
406     g_signal_connect (G_OBJECT (pdata->window), "delete-event", G_CALLBACK (callback /*call_stop_lilypond*/), NULL);
407   else
408     g_signal_connect (G_OBJECT (pdata->window), "delete-event", G_CALLBACK (progressbar_stop), NULL);
409   return GTK_WINDOW (pdata->window);
410 }
411 
412 void
progressbar_stop(void)413 progressbar_stop (void)
414 {
415   progress_data.progressing = FALSE;
416 }
417 
418 
419 void
busy_cursor(GtkWidget * area)420 busy_cursor (GtkWidget *area)
421 {
422   static GdkCursor *busycursor = NULL;
423   if(!busycursor)
424     busycursor = gdk_cursor_new (GDK_WATCH);
425   if (gtk_widget_get_window (Denemo.printarea))
426     gdk_window_set_cursor (gtk_widget_get_window (area), busycursor);
427 }
428 void
normal_cursor(GtkWidget * area)429 normal_cursor (GtkWidget *area)
430 {
431   static GdkCursor *arrowcursor = NULL;
432   if(!arrowcursor)
433     arrowcursor = gdk_cursor_new (GDK_RIGHT_PTR);
434   if (gtk_widget_get_window (area))
435     gdk_window_set_cursor (gtk_widget_get_window (area), arrowcursor);
436 }
437 
438 
439 /**
440  *  Draws the given bitmap mask on to the pixmap using the given
441  *  grahpics context.
442  *
443  * @param pixmap pixmap be drawn on.
444  * @param gc graphics context to use
445  * @param mask  bitmap to be drawn
446  * @param x x position on the pixmap
447  * @param y y position on the pixmap
448  * @param width width of the bitmap mask
449  * @param height height of the bitmap mask
450  *
451  * @return none
452  */
453 
454 
455 #ifdef G_OS_WIN32
456 //this code actually works on GNU/Linux too, it is not clear what to prefer
457 static void
windows_draw_text(cairo_t * cr,const char * font,const char * text,double x,double y,double size,gboolean invert)458 windows_draw_text (cairo_t *cr, const char *font, const char *text, double x, double y, double size, gboolean invert)
459 {
460  y -= size;
461  size *= 0.75;
462   PangoLayout *layout;
463   PangoFontDescription *desc;
464   /* Create a PangoLayout, set the font and text */
465   layout = pango_cairo_create_layout (cr);
466 
467   pango_layout_set_text (layout, text, -1);
468   desc = pango_font_description_from_string (font);
469   pango_font_description_set_size (desc, size*PANGO_SCALE);
470   pango_layout_set_font_description (layout, desc);
471   pango_font_description_free (desc);
472   pango_cairo_update_layout (cr, layout);
473 
474 
475   cairo_move_to (cr, x, y);
476   if (invert)
477           cairo_scale (cr, 1, -1);
478   pango_cairo_show_layout (cr, layout);
479   /* free the layout object */
480   g_object_unref (layout);
481 }
482 #endif
483 
484 void
drawbitmapinverse_cr(cairo_t * cr,DenemoGraphic * mask,gint x,gint y,gboolean invert)485 drawbitmapinverse_cr (cairo_t * cr, DenemoGraphic * mask, gint x, gint y, gboolean invert)
486 {
487   cairo_save (cr);
488   switch (mask->type)
489     {
490     case DENEMO_BITMAP:
491       {
492 #if GTK_MAJOR_VERSION==3
493         gdk_cairo_set_source_window (cr, mask->graphic, x, y);  //??? bitmap???? asks torbenh
494 #else
495         cairo_rectangle (cr, x, y, mask->width, mask->height);
496 #endif
497         cairo_fill (cr);
498         break;
499       }
500     case DENEMO_PATTERN:
501       {
502         cairo_pattern_t *pattern = (cairo_pattern_t *) mask->graphic;
503         cairo_translate (cr, x, y);
504         cairo_mask (cr, pattern);
505         break;
506       }
507     case DENEMO_FONT:
508       {
509         DenemoGlyph *glyph = mask->graphic;
510 #ifdef G_OS_WIN32
511         windows_draw_text (cr, glyph->fontname, glyph->utf, x, y, glyph->size, invert);
512 #else
513         cairo_select_font_face (cr, glyph->fontname, glyph->slant, glyph->weight);
514         cairo_set_font_size (cr, glyph->size);
515         cairo_move_to (cr, x, y);
516 
517         if (invert)
518           cairo_scale (cr, 1, -1);
519         cairo_show_text (cr, glyph->utf);
520 #endif
521         break;
522       }
523     }
524   cairo_restore (cr);
525 }
526 
527 void
drawfetachar_cr(cairo_t * cr,gunichar uc,double x,double y)528 drawfetachar_cr (cairo_t * cr, gunichar uc, double x, double y)
529 {
530   int len;
531   char utf_string[8];
532   len = g_unichar_to_utf8 (uc, utf_string);
533   utf_string[len] = '\0';
534   //    windows_draw_text (cr, "feta26", utf_string, x, y, 35.0, FALSE); this fails to position stuff correctly, but the code below is working on windows anyway.
535   cairo_select_font_face (cr, "feta26", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
536   cairo_set_font_size (cr, 35.0);
537   cairo_move_to (cr, x, y);
538   cairo_show_text (cr, utf_string);
539 
540 }
541 
542 
543 void
drawtext_cr(cairo_t * cr,const char * text,double x,double y,double size)544 drawtext_cr (cairo_t * cr, const char *text, double x, double y, double size)
545 {
546   if (*text)
547     {
548 #ifdef G_OS_WIN32
549       return windows_draw_text (cr, "Denemo", text, x, y, size, FALSE); //these values arrived at by trial and error, to match the previously used code below
550 #else
551       //use the FreeSerif font as it has music symbols - there is no font substitution done by cairo here
552       cairo_select_font_face (cr, "Denemo", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
553       cairo_set_font_size (cr, size);
554       cairo_move_to (cr, x, y);
555       cairo_show_text (cr, text);
556 #endif
557     }
558 }
559 
560 void
drawnormaltext_cr(cairo_t * cr,const char * text,double x,double y)561 drawnormaltext_cr (cairo_t * cr, const char *text, double x, double y)
562 {
563   drawtext_cr (cr, text, x, y, 14.0);
564 }
565 
566 void
drawlargetext_cr(cairo_t * cr,const char * text,double x,double y)567 drawlargetext_cr (cairo_t * cr, const char *text, double x, double y)
568 {
569   drawtext_cr (cr, text, x, y, 24.0);
570 }
571 
572 /* draw display text and or graphics for directives
573  return the widest graphic width*/
574 gint
draw_for_directives(cairo_t * cr,GList * directives,gint x,gint y,gboolean at_cursor)575 draw_for_directives (cairo_t * cr, GList * directives, gint x, gint y, gboolean at_cursor)
576 {
577   gint count = 10;
578   gint maxwidth = 0;
579   for (; directives; directives = directives->next, count += 10)
580     {
581       DenemoDirective *directive = (DenemoDirective *) directives->data;
582       guint layout = selected_layout_id ();
583       gdouble only = directive->y ? ((directive->y == layout) ? 0.5 : 0.0) : 0.0;
584       gdouble exclude = directive->x ? ((directive->x == layout) ? 0.9 : 0.0) : 0.0;
585       if (directive->y && directive->y != layout)
586         exclude = 0.9;
587       if (exclude>0.0 || only >0.0)
588             {
589                 cairo_save (cr);
590                 cairo_set_source_rgba (cr, 0.4 + exclude -only/2, 0.5 + only, 0.4 -only/2, at_cursor ? 1.0 : 0.7);
591             }
592       if (directive->graphic)
593         {
594           gint gwidth, gheight;
595           gwidth = directive->graphic->width;
596           gheight = directive->graphic->height;
597 
598           maxwidth = MAX (gwidth, maxwidth);
599           //g_debug("drawing a graphic at %d %d\n", xx+directive->gx+count-gwidth/2,  y+height+directive->gy-gheight/2);
600           drawbitmapinverse_cr (cr, directive->graphic, x + directive->gx + count - gwidth / 2, y + directive->gy - gheight / 2, FALSE);
601 
602         }
603       if (directive->display)
604         {
605 #define MAXLEN (8)
606           gchar c = 0;          //if it is a long string only show it all when cursor is on it also only display from first line
607           gchar *p;
608           for (p = directive->display->str; *p; p++)
609             {
610               if (*p == '\n' || (!at_cursor && (p - directive->display->str) > MAXLEN))
611                 {
612                   c = *p;
613                   *p = 0;
614                   break;
615                 }
616             }
617           drawnormaltext_cr (cr, directive->display->str, x + directive->tx + count, y + directive->ty);
618           if (c)
619             {
620               *p = c;
621             }
622          if (exclude>0.0 || only >0.0)
623            cairo_restore (cr);
624         }
625     }
626 
627   return maxwidth;
628 }
629 
630 /* draw a brace straight or curly */
draw_staff_brace(cairo_t * cr,gboolean curly,gint x,gint y,gint height)631 void draw_staff_brace (cairo_t *cr, gboolean curly, gint x, gint y, gint height)
632 {
633   cairo_set_source_rgb (cr, 0, 0, 0);
634   if (!curly)
635     {
636       drawfetachar_cr (cr, 0xD8, x, y);
637       cairo_rectangle (cr, x, y+2.0, 3, height - 4.0);
638       cairo_fill (cr);
639       cairo_rectangle (cr, x + 5.0, y + 1.0, 1, height - 2.0);
640       cairo_fill (cr);
641       drawfetachar_cr (cr, 0xD9, x, y + height);
642     }
643   else
644     {
645       //cairo_translate (cr, 0, 10.0);
646       cairo_translate (cr, x-5, y + 2);
647       cairo_scale (cr, 1.0, height / 100.0);
648       cairo_append_path (cr, &piano_brace_path);
649       cairo_fill (cr);
650     }
651   return;
652 }
653 
pretty_name(gchar * lilynote)654 gchar *pretty_name (gchar *lilynote) //display ����♯♭♮ with note name
655 {
656  static gchar *natural = NULL;
657  static gchar *sharp;
658  static gchar *flat;
659  static gchar *double_sharp;
660  static gchar *double_flat;
661  gchar *answer;
662  if (!natural)
663     {
664         natural = g_strdup ("C♮");
665         sharp = g_strdup ("C♯");
666         flat = g_strdup ("C♭");
667         double_sharp = g_strdup ("C��");
668         double_flat = g_strdup ("C��");
669     }
670  answer = natural;
671  if(*(lilynote+1)==0)
672     answer = natural;
673     else if (*(lilynote+1) == 'i')
674         {
675             if (*(lilynote+3) == 'i')
676                 answer = double_sharp;
677             else
678                 answer = sharp;
679         }
680         else if (*(lilynote+1) == 'e')
681             {
682                 if (*(lilynote+3) == 'e')
683                     answer = double_flat;
684                 else
685                     answer = flat;
686             }
687   *answer =  toupper(*lilynote);
688   return answer;
689 }
690 
691 
692 /**
693  * Utility function to set the number of ticks used by the given object
694  * if it is within a given tuplet
695  *
696  * @param theobj DenemoObject to set the number of ticks
697  * @param numerator numerator of the current tuplet
698  * @param denominator denominator of the current tuplet
699  * @return none
700  */
701 void
set_tuplefied_numticks(DenemoObject * theobj,gint numerator,gint denominator)702 set_tuplefied_numticks (DenemoObject * theobj, gint numerator, gint denominator)
703 {
704   theobj->durinticks = theobj->basic_durinticks * numerator / denominator;
705   /* Though WHOLENUMTICKS is chosen strategically so that in common
706    * cases, this division works out evenly, things should also work
707    * out properly if it doesn't; i.e., durinticks_untupletized is
708    * rounded down */
709 }
710 
711 /**
712  * Utility function to set the number of ticks of a mudela object
713  * in a grace note
714  * @param theobj the DenemoObject to set the number of ticks
715  * @param multiplier the grace notes multiplier
716  * @return none
717  */
718 void
set_grace_numticks(DenemoObject * theobj,gint multiplier)719 set_grace_numticks (DenemoObject * theobj, gint multiplier)
720 {
721 
722   theobj->durinticks = theobj->basic_durinticks / multiplier;
723 
724 
725 }
726 
727 
728 /**
729  * Sets the number of ticks taken by the given DenemoObject.
730  *
731  * @param theobj the mudela object to set the number of ticks on
732  * @return none
733  */
734 void
set_basic_numticks(DenemoObject * theobj)735 set_basic_numticks (DenemoObject * theobj)
736 {
737   gint power;
738   gint withoutdots;
739   gint addperdot, i;
740 
741   switch (theobj->type)
742     {
743     case CHORD:
744       if (((chord *) theobj->object)->baseduration < 0)
745         {
746           withoutdots = -((chord *) theobj->object)->baseduration;
747         }
748       else
749         {
750           power = 1 << ((chord *) theobj->object)->baseduration;
751           withoutdots = WHOLE_NUMTICKS / power;
752         }
753       addperdot = withoutdots / 2;
754       theobj->basic_durinticks = withoutdots;
755       for (i = 0; i < ((chord *) theobj->object)->numdots; addperdot /= 2, i++)
756         theobj->basic_durinticks += addperdot;
757 
758       break;
759     default:
760       theobj->basic_durinticks = 0;
761       theobj->durinticks = 0;
762       /* There's no reason not to set that as well */
763       break;
764     }
765 }
766 
767 /**
768  * Returns the amount of space to be left after a note or rest, only
769  * taking the width of the measure into consideration
770  *
771  * @param numticks the number of ticks taken so far
772  * @param wholenotewidth the number of ticks taken be a whole note
773  * @return the amount of space to be left after a note or rest
774  */
775 
776 gint
space_after(gint numticks,gint wholenotewidth)777 space_after (gint numticks, gint wholenotewidth)
778 {
779   return MAX (numticks * wholenotewidth / WHOLE_NUMTICKS, 0);
780 }
781 
782 #define EXTRAWIDTH 5
783 
784 /**
785  * Sets the minimum space that needs to be allocated for drawing a mudela
786  * object based on the type
787  * also sets space_before
788  * @param theobj the DenemoObject to set the minimum space on
789  * @return none
790  */
791 
792 void
setpixelmin(DenemoObject * theobj)793 setpixelmin (DenemoObject * theobj)
794 {
795   gint i, baseduration, headtype;
796   chord chordval;
797   GList *tnode;
798   note *thetone;
799   /* And these static declaration are copied right out of drawnotes.c
800    * and drawaccidentals.c */
801 
802   switch (theobj->type)
803     {
804     case CHORD:
805       chordval = *(chord *) theobj->object;
806       baseduration = chordval.baseduration;
807       baseduration = MAX (baseduration, 0);
808       headtype = MIN (baseduration, 2);
809       if (headtype < 0)
810         headtype = 0;           //-ve values of baseduration are for specials
811       gint directive_pixels = 0;        // the largest amount of extra space asked for by any directive
812       GList *g = chordval.directives;
813       for (; g; g = g->next)
814         directive_pixels = MAX (directive_pixels, ((DenemoDirective *) g->data)->minpixels);
815       if (chordval.notes)
816         {
817           theobj->minpixelsalloted = headwidths[headtype];
818           //search through notes and their attached directives, find max display space requested
819           //use this below
820 
821           g = chordval.notes;
822           for (; g; g = g->next)
823             {
824               GList *h = ((note *) g->data)->directives;
825               for (; h; h = h->next)
826                 directive_pixels = MAX (directive_pixels, ((DenemoDirective *) h->data)->minpixels);
827             }
828         }
829       else                      /* a rest */
830         theobj->minpixelsalloted = restwidths[baseduration];
831 
832       // Allow extra space specified by attached LilyPond directives - example:
833       theobj->minpixelsalloted += directive_pixels;
834 
835 
836 
837       /* 12 pixels for the first dot, 6 for each dot thereafter */
838       if (chordval.numdots)
839         theobj->minpixelsalloted += 6;
840       for (i = 0; i < chordval.numdots; i++)
841         theobj->minpixelsalloted += 6;
842 
843       theobj->space_before = 0;
844       if (chordval.hasanacc)
845         for (tnode = chordval.notes; tnode; tnode = tnode->next)
846           {
847             thetone = (note *) tnode->data;
848             if (thetone->showaccidental)
849               theobj->space_before = MAX (theobj->space_before, thetone->position_of_accidental);
850           }
851       if (chordval.is_reversealigned){
852         if (chordval.is_stemup)
853           theobj->minpixelsalloted += headwidths[headtype];
854         else if (!chordval.hasanacc)
855           /* Accidental positioning already accounts for the extra leading
856              space that we need for reverse-aligned noteheads, provided
857              the chord has an accidental in it somewhere. We only have to
858              remark upon noteheads to the left of the stem if there weren't
859              any accidentals to position.  */
860           theobj->space_before += headwidths[headtype];
861       }
862       theobj->minpixelsalloted += EXTRAWIDTH;
863       break;
864     case TUPOPEN:
865     case TUPCLOSE:
866       /* The real way do this will be with a gdk_string_width. Until
867        * then, though: */
868       theobj->minpixelsalloted =
869 #if 0
870         40;
871 #else
872         16;
873 #endif
874       theobj->space_before = theobj->minpixelsalloted / 2;
875       break;
876     case LILYDIRECTIVE:
877       {
878         DenemoDirective *directive = (DenemoDirective *) theobj->object;
879         theobj->minpixelsalloted = directive->minpixels ? directive->minpixels : 16;
880         theobj->space_before = theobj->minpixelsalloted / 2;
881       }
882       break;
883     case CLEF:
884       theobj->minpixelsalloted = 35;
885       theobj->space_before = 0;
886       break;
887     case KEYSIG:
888       theobj->minpixelsalloted = 20; //needed so find_xes_in_measures assigns space to it without waiting for drawing to do so.
889       theobj->space_before = 0;
890       break;
891     case TIMESIG:
892       theobj->minpixelsalloted = 40;
893       theobj->space_before = 0;
894       break;
895     case STEMDIRECTIVE:
896       /* The real way do this will be with a gdk_string_width. Until
897        * then, though: */
898       theobj->minpixelsalloted = 40;
899       theobj->space_before = 0;
900       break;
901     case DYNAMIC:
902       theobj->minpixelsalloted = 40;
903       theobj->space_before = 0;
904       break;
905     case GRACE_START:
906     case GRACE_END:
907       theobj->minpixelsalloted = 16;
908       theobj->space_before = theobj->minpixelsalloted / 2;
909       break;
910     default:
911       theobj->minpixelsalloted = 0;
912       theobj->space_before = 0;
913       break;
914     }
915 }
916 
917 /**
918  *
919  * @param mid_c_offset the mid_c_offset of the the tone
920  * @param dclef the clef of the current tone
921  *
922  * @return the height of a tone based on its mid_c_offset and the clef that it's in
923  */
924 gint
calculateheight(gint mid_c_offset,gint dclef)925 calculateheight (gint mid_c_offset, gint dclef)
926 {
927   switch (dclef)
928     {
929     case DENEMO_TREBLE_CLEF:
930       return 5 * LINE_SPACE - HALF_LINE_SPACE * mid_c_offset;
931       break;                    /* Probably gratuitous */
932     case DENEMO_ALTO_CLEF:
933       return 2 * LINE_SPACE - HALF_LINE_SPACE * mid_c_offset;
934       break;
935     case DENEMO_G_8_CLEF:
936       return LINE_SPACE - HALF_LINE_SPACE * (mid_c_offset - 1);
937       break;
938     case DENEMO_BASS_CLEF:
939       return -LINE_SPACE - HALF_LINE_SPACE * mid_c_offset;
940       break;
941     case DENEMO_F_8_CLEF:
942       return -5 * LINE_SPACE - HALF_LINE_SPACE * (mid_c_offset - 1);
943       break;
944     case DENEMO_TENOR_CLEF:
945       return LINE_SPACE - HALF_LINE_SPACE * mid_c_offset;
946       break;
947     case DENEMO_SOPRANO_CLEF:
948       return LINE_SPACE - HALF_LINE_SPACE * (mid_c_offset - 6);
949       break;
950     case DENEMO_FRENCH_CLEF:
951       return 6 * LINE_SPACE - HALF_LINE_SPACE * (mid_c_offset);
952       break;
953     }
954 
955   return (0);
956 }
957 
958 /**
959  * Converts the given offset to a number
960  *
961  * @param n the offset to convert
962  * @return the result of the offset conversion
963  */
964 gint
offsettonumber(gint n)965 offsettonumber (gint n)
966 {
967   if (n >= 0)
968     return n % 7;
969   else
970     return (7 - (-n % 7)) % 7;
971   /* Not all C implementations conform to the more recent standard on how %
972      should operate on negative operands.  */
973 }
974 
975 /**
976  * converts the int mid_c_offset to the lilypond name
977  * returns a gchar * so it will have to be freed
978  * 0 returns "c", 1 returns "cis"
979  * The octave ",,, or '''" is also appended"
980  */
981 
982 gchar *
mid_c_offsettolily(int mid_c_offset,int enshift)983 mid_c_offsettolily (int mid_c_offset, int enshift)
984 {
985   gint octave, k;
986   GString *lilynote = g_string_new ("");
987 
988   g_string_append_printf (lilynote, "%c", mid_c_offsettoname (mid_c_offset));
989   if (enshift < 0)
990     for (k = enshift; k; k++)
991       g_string_append_printf (lilynote, "es");
992   else
993     for (k = enshift; k; k--)
994       g_string_append_printf (lilynote, "is");
995   octave = mid_c_offsettooctave (mid_c_offset);
996   if (octave < 0)
997     for (; octave; octave++)
998       g_string_append_printf (lilynote, ",");
999   else
1000     for (; octave; octave--)
1001       g_string_append_printf (lilynote, "\'");
1002 
1003   return g_string_free (lilynote, FALSE);
1004 }
1005 
1006 /**
1007  * converts the mid_c_offset to the correct letter name
1008  * @param mid_c_offset the mid_c_offset to convert
1009  * @return the character name of the mid_c_offset
1010  */
1011 gchar
mid_c_offsettoname(gint mid_c_offset)1012 mid_c_offsettoname (gint mid_c_offset)
1013 {
1014   gint otn = offsettonumber (mid_c_offset);
1015 
1016   return ((otn + 2) % 7) + 'a';
1017 }
1018 
1019 void
note2lilynotename(struct note * noteobject,GString * ret)1020 note2lilynotename (struct note *noteobject, GString * ret)
1021 {
1022   gint mid_c_offset = noteobject->mid_c_offset;
1023 
1024   g_string_append_printf (ret, "%c", mid_c_offsettoname (mid_c_offset));
1025 }
1026 
1027 void
note2lilyaccidental(struct note * noteobject,GString * ret)1028 note2lilyaccidental (struct note *noteobject, GString * ret)
1029 {
1030   gint enshift = noteobject->enshift;
1031   gint k;
1032   if (enshift < 0)
1033     for (k = enshift; k; k++)
1034       g_string_append_printf (ret, "es");
1035   else
1036     for (k = enshift; k; k--)
1037       g_string_append_printf (ret, "is");
1038 }
1039 
1040 void
note2lilyoctave(struct note * noteobject,GString * ret)1041 note2lilyoctave (struct note *noteobject, GString * ret)
1042 {
1043   gint mid_c_offset = noteobject->mid_c_offset;
1044   gint octave = mid_c_offsettooctave (mid_c_offset);
1045   if (octave < 0)
1046     for (; octave; octave++)
1047       g_string_append_printf (ret, ",");
1048   else
1049     for (; octave; octave--)
1050       g_string_append_printf (ret, "\'");
1051 }
1052 
1053 void
chord2lilyduration(struct chord * chordobject,GString * ret)1054 chord2lilyduration (struct chord *chordobject, GString * ret)
1055 {
1056   chord2lilybaseduration (chordobject, ret);
1057   chord2lilynumdots (chordobject, ret);
1058 }
1059 
1060 void
chord2lilybaseduration(struct chord * chordobject,GString * ret)1061 chord2lilybaseduration (struct chord *chordobject, GString * ret)
1062 {
1063   int baseduration = chordobject->baseduration;
1064   g_string_append_printf (ret, "%d", baseduration);
1065 }
1066 
1067 void
chord2lilynumdots(struct chord * chordobject,GString * ret)1068 chord2lilynumdots (struct chord *chordobject, GString * ret)
1069 {
1070   int numdots = chordobject->numdots;
1071   g_string_append_printf (ret, "%d", numdots);
1072 }
1073 
1074 /**
1075  * Calculate a pitches octave from the mid_c_offset
1076  * @param mid_c_offset the mid_c_offset to use
1077  * @return the octave of the given mid_c_offset
1078  */
1079 gint
mid_c_offsettooctave(gint mid_c_offset)1080 mid_c_offsettooctave (gint mid_c_offset)
1081 {
1082   if (mid_c_offset < 0)
1083     return -((-mid_c_offset + 6) / 7) + 1;
1084   else
1085     return (mid_c_offset / 7) + 1;
1086 }
1087 
1088 /**
1089  * g_list_foreach helper function to free the given data
1090  * @param data the list elements data
1091  * @param user_data any user supplied data (not used in this case)
1092  */
1093 void
freeit(gpointer data,gpointer user_data)1094 freeit (gpointer data, gpointer user_data)
1095 {
1096   g_free (data);
1097 }
1098 
1099 
1100 
1101 
1102 
1103 
1104 
1105 /************* routines for calling from debug code ***************/
1106 #include "command/staff.h"
1107 
1108 G_GNUC_UNUSED void
printobj(objnode * obj)1109 printobj (objnode * obj)
1110 {
1111   DenemoObject *curObj;
1112 
1113   curObj = (DenemoObject *) (obj->data);
1114   switch (curObj->type)
1115     {
1116     case CHORD:
1117       fprintf (stderr, "\t\t%s type\n", "CHORD");
1118       break;
1119     case TUPOPEN:
1120       fprintf (stderr, "\t\t%s type\n", "TUPOPEN");
1121       break;
1122     case TUPCLOSE:
1123       fprintf (stderr, "\t\t%s type\n", "TUPCLOSE");
1124       break;
1125     case CLEF:
1126       fprintf (stderr, "\t\t%s type\n", "CLEF");
1127       break;
1128     case TIMESIG:
1129       fprintf (stderr, "\t\t%s type\n", "TIMESIG");
1130       break;
1131     case KEYSIG:
1132       fprintf (stderr, "\t\t%s type\n", "KEYSIG");
1133       break;
1134     case BARLINE:
1135       fprintf (stderr, "\t\t%s type\n", "BARLINE");
1136       break;
1137     case STEMDIRECTIVE:
1138       fprintf (stderr, "\t\t%s type\n", "STEMDIRECTIVE");
1139       break;
1140     case MEASUREBREAK:
1141       fprintf (stderr, "\t\t%s type\n", "MEASUREBREAK");
1142       break;
1143     case DYNAMIC:
1144       fprintf (stderr, "\t\t%s type\n", "DYNAMIC");
1145       break;
1146     case GRACE_START:
1147       fprintf (stderr, "\t\t%s type\n", "GRACE_START");
1148       break;
1149     case GRACE_END:
1150       fprintf (stderr, "\t\t%s type\n", "GRACE_END");
1151       break;
1152     case LYRIC:
1153       fprintf (stderr, "\t\t%s type\n", "LYRIC");
1154       break;
1155     case FIGURE:
1156       fprintf (stderr, "\t\t%s type\n", "FIGURE");
1157       break;
1158     default:                   /* needs to be up to date with enum in include/denemo/denemo.h */
1159       fprintf (stderr, "!!!!!unknown object type %x - see enum in denemo.h\n", curObj->type);
1160       break;
1161     }
1162 }
1163 
1164 G_GNUC_UNUSED void
printobjs(objnode * obj)1165 printobjs (objnode * obj)
1166 {
1167   objnode *curobj;
1168   if (obj == NULL)
1169     {
1170       fprintf (stderr, "NULL object\n");
1171       return;
1172     }
1173   printobj (obj);
1174   fprintf (stderr, "previous objects\n");
1175   curobj = obj;
1176   while (curobj->prev)
1177     {
1178       printobj (curobj->prev);
1179       curobj = curobj->prev;
1180     }
1181   fprintf (stderr, "next objects\n");
1182   curobj = obj;
1183   while (curobj->next)
1184     {
1185       printobj (curobj->next);
1186       curobj = curobj->next;
1187     }
1188 }
1189 
1190 G_GNUC_UNUSED void
printmeasure(measurenode * mnode)1191 printmeasure (measurenode * mnode)
1192 {
1193   if (mnode == NULL)
1194     {
1195       fprintf (stderr, "Empty measure\n");
1196       return;
1197     }
1198   printobjs ((objnode*)measure_first_obj_node (mnode));
1199 }
1200 
1201 G_GNUC_UNUSED void
printmeasures(staffnode * thestaff)1202 printmeasures (staffnode * thestaff)
1203 {
1204   GList *measure = staff_first_measure_node (thestaff);
1205   gint measurenum = 1;
1206   for (measure = staff_first_measure_node (thestaff); measure; measure = measure->next)
1207     {
1208       fprintf (stderr, "*************Measure %d *************\n", measurenum++);
1209       printmeasure (measure);
1210     }
1211 }
1212 
1213 G_GNUC_UNUSED void
printscoreinfo(DenemoMovement * si)1214 printscoreinfo (DenemoMovement * si)
1215 {
1216   if (si->thescore == NULL)
1217     {
1218       fprintf (stderr, "Staff with NULL thescore field\n");
1219       return;
1220     }
1221   printmeasures (si->thescore);
1222 }
1223 
1224 /**
1225  * Function that initializes the code needed for the directory relocation.
1226  * @return none
1227  */
1228 void
initdir()1229 initdir ()
1230 {
1231 #ifndef G_OS_WIN32
1232   GError *error = NULL;
1233   if (!gbr_init (&error) && (error != (GError *) GBR_INIT_ERROR_DISABLED))
1234     {
1235       g_debug ("BinReloc failed to initialize:\n");
1236       g_debug ("Domain: %d (%s)\n", (int) error->domain, g_quark_to_string (error->domain));
1237       g_debug ("Code: %d\n", error->code);
1238       g_debug ("Message: %s\n", error->message);
1239       g_error_free (error);
1240       g_debug ("----------------\n");
1241     }
1242 #endif /* not G_OS_WIN32 */
1243 }
1244 
1245 extern gchar *gbr_find_pkg_data_dir (const gchar * default_pkg_data_dir, const gchar * pkg_name);
1246 
1247 static gchar *DENEMO_datadir = NULL;
1248 const gchar *
get_system_data_dir()1249 get_system_data_dir ()
1250 {
1251   //DENEMO_datadir?g_debug("datadir is %s at %p", DENEMO_datadir, DENEMO_datadir):g_debug("datadir not yet set");
1252   if (DENEMO_datadir == NULL)
1253     {
1254 #ifdef G_OS_WIN32
1255       gchar *rootdir = g_win32_get_package_installation_directory (NULL, NULL);
1256       DENEMO_datadir = g_build_filename (rootdir, "share", "denemo", NULL);
1257       g_message ("rootdir=%s", rootdir);
1258       g_message ("datadir=%s", DENEMO_datadir);
1259       g_free (rootdir);
1260 #else /* not G_OS_WIN32 */
1261 
1262 #ifdef _MACH_O_
1263 
1264       {
1265         char path[1024];
1266         guint size = sizeof (path);
1267         _NSGetExecutablePath (path, &size);
1268         gchar *bindir = (gchar *) g_malloc (size);
1269         if (_NSGetExecutablePath (bindir, &size) == 0)
1270           g_message ("Using bin path %s", bindir);
1271         else
1272           g_critical ("Cannot get bin dir");
1273         DENEMO_datadir = g_build_filename (g_path_get_dirname (bindir), "..", "share", "denemo", NULL);
1274         g_message ("OSX set data dir to %s", DENEMO_datadir);
1275       }
1276 #else
1277 #ifndef ENABLE_BINRELOC
1278       DENEMO_datadir = g_strdup (PKGDATADIR);
1279 #else
1280       DENEMO_datadir = gbr_find_pkg_data_dir (PKGDATADIR, PKGNAME);
1281 #endif //ENABLE_BINRELOC
1282 
1283 #endif //_MACH_O_
1284 #endif /* not G_OS_WIN32 */
1285     }
1286   return DENEMO_datadir;
1287 }
1288 
1289 const gchar *
get_prefix_dir(void)1290 get_prefix_dir (void)
1291 {
1292   gchar *prefix;
1293 #ifdef G_OS_WIN32
1294   prefix = g_win32_get_package_installation_directory (NULL, NULL);
1295 #else /* not G_OS_WIN32 */
1296 #ifdef _MACH_O_
1297   {
1298     char path[1024];
1299     guint size = sizeof (path);
1300     _NSGetExecutablePath (path, &size);
1301     gchar *bindir = (gchar *) g_malloc (size);
1302     if (_NSGetExecutablePath (bindir, &size) == 0)
1303       {
1304         prefix = g_build_filename (bindir, "..", "..", NULL);
1305         g_message ("OSX set data prefix to %s", prefix);
1306       }
1307     else
1308       g_critical ("Cannot get bin dir");
1309   }
1310 #else
1311 
1312 #ifndef ENABLE_BINRELOC
1313   prefix = g_strdup (PREFIX);
1314 #else
1315   prefix = gbr_find_prefix (PREFIX);
1316 #endif //ENABLE_BINRELOC
1317 
1318 #endif //_MACH_O_
1319 #endif //G_OS_WIN32
1320   return prefix;
1321 }
1322 static gchar *DENEMO_bindir = NULL;
1323 const gchar *
get_system_bin_dir(void)1324 get_system_bin_dir (void)
1325 {
1326 
1327   if (DENEMO_bindir == NULL)
1328     {
1329 #ifdef G_OS_WIN32
1330       gchar *rootdir = g_win32_get_package_installation_directory (NULL, NULL);
1331       DENEMO_bindir = g_build_filename (rootdir, "bin", NULL);
1332       g_message ("rootdir=%s", rootdir);
1333       g_message ("bindir=%s", DENEMO_bindir);
1334       g_free (rootdir);
1335 #else /* not G_OS_WIN32 */
1336 
1337 #ifdef _MACH_O_
1338 
1339       {
1340         char path[1024];
1341         guint size = sizeof (path);
1342         _NSGetExecutablePath (path, &size);
1343         gchar *bin = (gchar *) g_malloc (size);
1344         if (_NSGetExecutablePath (bin, &size) == 0)
1345           {
1346             DENEMO_bindir = g_build_filename (bin, "..", NULL);
1347             g_message ("Using bin path %s", DENEMO_bindir);
1348           }
1349         else
1350           g_critical ("Cannot get bin dir");
1351 
1352         g_message ("OSX set bin dir to %s", DENEMO_bindir);
1353       }
1354 #else
1355 
1356 #ifndef ENABLE_BINRELOC
1357       DENEMO_bindir = g_strdup (BINDIR);
1358 #else
1359       DENEMO_bindir = gbr_find_bin_dir (BINDIR);
1360 #endif //ENABLE_BINRELOC
1361 
1362 #endif //_MACH_O_
1363 #endif /* not G_OS_WIN32 */
1364     }
1365   return DENEMO_bindir;
1366 }
1367 
1368 /** UNUSED
1369 const gchar *
1370 get_system_conf_dir ()
1371 {
1372   static gchar *confdir = NULL;
1373   if (confdir == NULL)
1374     {
1375 #ifdef G_OS_WIN32
1376       gchar *rootdir = g_win32_get_package_installation_directory (NULL, NULL);
1377       confdir = g_build_filename (rootdir, "etc", "denemo", NULL);
1378       g_free (rootdir);
1379 #else // not G_OS_WIN32
1380 #ifdef _MACH_O_
1381 
1382       {
1383         char path[1024];
1384         guint size = sizeof (path);
1385         _NSGetExecutablePath (path, &size);
1386         gchar *bindir = (gchar *) g_malloc (size);
1387         if (_NSGetExecutablePath (bindir, &size) == 0)
1388           g_debug ("using bin path %s\n", bindir);
1389         else
1390           g_critical ("Cannot get bin dir\n");
1391         confdir = g_build_filename (g_path_get_dirname (bindir), "..", "etc", "denemo", NULL);
1392         g_debug ("OSX set conf dir to %s\n", confdir);
1393       }
1394 #else
1395 
1396 #ifndef ENABLE_BINRELOC
1397       confdir = g_build_filename (SYSCONFDIR, NULL);
1398 #else
1399       confdir = g_build_filename (gbr_find_etc_dir (SYSCONFDIR), "denemo", NULL);
1400 #endif //ENABLE_BINRELOC
1401 
1402 #endif //_MACH_O_
1403 #endif // not G_OS_WIN32
1404     }
1405   return confdir;
1406 }
1407 */
1408 
1409 const gchar *
get_system_locale_dir()1410 get_system_locale_dir ()
1411 {
1412   static gchar *localedir = NULL;
1413   if (localedir == NULL)
1414     {
1415 #ifdef G_OS_WIN32
1416       gchar *rootdir = g_win32_get_package_installation_directory (NULL, NULL);
1417       localedir = g_build_filename (rootdir, "share", "locale", NULL);
1418       g_free (rootdir);
1419 #else /* not G_OS_WIN32 */
1420 #ifdef _MACH_O_
1421 
1422       {
1423         char path[1024];
1424         guint size = sizeof (path);
1425         _NSGetExecutablePath (path, &size);
1426         gchar *bindir = (gchar *) g_malloc (size);
1427         if (_NSGetExecutablePath (bindir, &size) == 0)
1428           g_message ("Using bin path %s", bindir);
1429         else
1430           g_critical ("Cannot get bin dir");
1431         localedir = g_build_filename (g_path_get_dirname (bindir), "..", "share", "locale", NULL);
1432         g_message ("OSX set locale dir to %s", localedir);
1433       }
1434 #else
1435 #ifndef ENABLE_BINRELOC
1436       /* it seems to be the standard way (no binreloc)
1437        * to set the path of translations this way:
1438        * messages are in $LOCALEDIR/$LANG/denemo
1439        */
1440       localedir = g_strdup (LOCALEDIR);
1441 #else /* ENABLE_BINRELOC */
1442       /* binreloc says it is disabled even with built thanks to
1443        * --enable-binreloc... So, searhing falls back to
1444        *  $LOCALEDIR/denemo/$LANG which is not a valid path
1445        */
1446       localedir = gbr_find_locale_dir (LOCALEDIR);
1447 #endif /* ENABLE_BINRELOC */
1448 #endif
1449 #endif /* not G_OS_WIN32 */
1450     }
1451   return localedir;
1452 }
1453 
1454 const gchar*
get_system_font_dir()1455 get_system_font_dir(){
1456   static gchar* fontdir = NULL;
1457   if(fontdir == NULL)
1458   {
1459 #ifdef G_OS_WIN32
1460     gchar *prefix = g_win32_get_package_installation_directory (NULL, NULL);
1461 #else
1462     gchar *prefix = g_build_filename (get_prefix_dir (), NULL);
1463 #endif
1464     fontdir = g_build_filename (prefix, "share", "fonts", "truetype", "denemo", NULL);
1465   }
1466   return fontdir;
1467 }
1468 
1469 void
kill_process(GPid pid)1470 kill_process (GPid pid)
1471 {
1472 #ifdef G_OS_WIN32
1473   TerminateProcess (pid, 0);
1474 #else /* not G_OS_WIN32 */
1475   kill (pid, SIGTERM);
1476 #endif /* not G_OS_WIN32 */
1477   g_spawn_close_pid (pid);
1478 }
1479 
1480 
1481 void
init_denemo_notenames(void)1482 init_denemo_notenames (void)
1483 {
1484 
1485   define_scheme_literal_variable ("Denemo-Note0", NOTE0, NULL);
1486   define_scheme_literal_variable ("Denemo-Rest0", REST0, NULL);
1487   define_scheme_literal_variable ("Denemo-Note1", NOTE1, NULL);
1488   define_scheme_literal_variable ("Denemo-Rest1", REST1, NULL);
1489   define_scheme_literal_variable ("Denemo-Note2", NOTE2, NULL);
1490   define_scheme_literal_variable ("Denemo-Rest2", REST2, NULL);
1491   define_scheme_literal_variable ("Denemo-Note3", NOTE3, NULL);
1492   define_scheme_literal_variable ("Denemo-Rest3", REST3, NULL);
1493   define_scheme_literal_variable ("Denemo-Note4", NOTE4, NULL);
1494   define_scheme_literal_variable ("Denemo-Rest4", REST4, NULL);
1495   define_scheme_literal_variable ("Denemo-Note5", NOTE5, NULL);
1496   define_scheme_literal_variable ("Denemo-Rest5", REST5, NULL);
1497   define_scheme_literal_variable ("Denemo-Note6", NOTE6, NULL);
1498   define_scheme_literal_variable ("Denemo-Rest6", REST6, NULL);
1499   define_scheme_literal_variable ("Denemo-Note7", NOTE7, NULL);
1500   define_scheme_literal_variable ("Denemo-Rest7", REST7, NULL);
1501   define_scheme_literal_variable ("Denemo-Note8", NOTE8, NULL);
1502   define_scheme_literal_variable ("Denemo-Rest8", REST8, NULL);
1503 
1504 }
1505 
1506 #define HIGHLIGHT "<span background=\"lightblue\"> "
1507 
1508 /* markup the passed string to be in the denemo music font
1509 * caller must free the returned string
1510 */
1511 gchar *
music_font(gchar * str)1512 music_font (gchar * str)
1513 {
1514   GString *s = g_string_new ("");
1515   gint c = *str;
1516   for (c = *str; c; c = *++str)
1517     switch (c)
1518       {
1519       case '0':
1520         g_string_append (s, " " NOTE0 " ");
1521         break;
1522       case HIGHLIGHT_OFFSET + '0':
1523         g_string_append (s, HIGHLIGHT NOTE0 " </span>");
1524         break;
1525 
1526       case '1':
1527         g_string_append (s, " " NOTE1 " ");
1528         break;
1529       case HIGHLIGHT_OFFSET + '1':
1530         g_string_append (s, HIGHLIGHT NOTE1 " </span>");
1531         break;
1532       case '2':
1533         g_string_append (s, " " NOTE2 " ");
1534         break;
1535       case HIGHLIGHT_OFFSET + '2':
1536         g_string_append (s, HIGHLIGHT NOTE2 " </span>");
1537         break;
1538       case '3':
1539         g_string_append (s, " " NOTE3 " ");
1540         break;
1541       case HIGHLIGHT_OFFSET + '3':
1542         g_string_append (s, HIGHLIGHT NOTE3 " </span>");
1543         break;
1544       case '4':
1545         g_string_append (s, " " NOTE4 " ");
1546         break;
1547       case HIGHLIGHT_OFFSET + '4':
1548         g_string_append (s, HIGHLIGHT NOTE4 " </span>");
1549         break;
1550       case '5':
1551         g_string_append (s, " " NOTE5 " ");
1552         break;
1553       case HIGHLIGHT_OFFSET + '5':
1554         g_string_append (s, HIGHLIGHT NOTE5 " </span>");
1555         break;
1556       case '6':
1557         g_string_append (s, " " NOTE6 " ");
1558         break;
1559       case HIGHLIGHT_OFFSET + '6':
1560         g_string_append (s, HIGHLIGHT NOTE6 " </span>");
1561         break;
1562       case '7':
1563         g_string_append (s, " " NOTE7 " ");
1564         break;
1565       case HIGHLIGHT_OFFSET + '7':
1566         g_string_append (s, HIGHLIGHT NOTE7 " </span>");
1567         break;
1568       case '8':
1569         g_string_append (s, " " NOTE8 " ");
1570         break;
1571       case HIGHLIGHT_OFFSET + '8':
1572         g_string_append (s, HIGHLIGHT NOTE8 " </span>");
1573         break;
1574 
1575       case 'r':
1576         g_string_append (s, " " REST0 " ");
1577         break;
1578       case HIGHLIGHT_OFFSET + 'r':
1579         g_string_append (s, HIGHLIGHT REST0 " </span>");
1580         break;
1581 
1582       case 's':
1583         g_string_append (s, " " REST1 " ");
1584         break;
1585       case HIGHLIGHT_OFFSET + 's':
1586         g_string_append (s, HIGHLIGHT REST1 " </span>");
1587         break;
1588       case 't':
1589         g_string_append (s, " " REST2 " ");
1590         break;
1591       case HIGHLIGHT_OFFSET + 't':
1592         g_string_append (s, HIGHLIGHT REST2 " </span>");
1593         break;
1594       case 'u':
1595         g_string_append (s, " " REST3 " ");
1596         break;
1597       case HIGHLIGHT_OFFSET + 'u':
1598         g_string_append (s, HIGHLIGHT REST3 " </span>");
1599         break;
1600       case 'v':
1601         g_string_append (s, " " REST4 " ");
1602         break;
1603       case HIGHLIGHT_OFFSET + 'v':
1604         g_string_append (s, HIGHLIGHT REST4 " </span>");
1605         break;
1606       case 'w':
1607         g_string_append (s, " " REST5 " ");
1608         break;
1609       case HIGHLIGHT_OFFSET + 'w':
1610         g_string_append (s, HIGHLIGHT REST5 " </span>");
1611         break;
1612       case 'x':
1613         g_string_append (s, " " REST6 " ");
1614         break;
1615       case HIGHLIGHT_OFFSET + 'x':
1616         g_string_append (s, HIGHLIGHT REST6 " </span>");
1617         break;
1618       case 'y':
1619         g_string_append (s, " " REST7 " ");
1620         break;
1621       case HIGHLIGHT_OFFSET + 'y':
1622         g_string_append (s, HIGHLIGHT REST7 " </span>");
1623         break;
1624       case 'z':
1625         g_string_append (s, " " REST8 " ");
1626         break;
1627       case HIGHLIGHT_OFFSET + 'z':
1628         g_string_append (s, HIGHLIGHT REST8 " </span>");
1629         break;
1630       default:
1631         g_string_append_c (s, c);
1632       }
1633   return g_string_free (s, FALSE);
1634 
1635 }
1636 
1637 void
set_title_bar(DenemoProject * gui)1638 set_title_bar (DenemoProject * gui)
1639 {
1640   if(Denemo.non_interactive)
1641     return;
1642   gchar *title;
1643   if (gui->tabname && gui->tabname->len)
1644     title = gui->tabname->str;
1645   else
1646     title = _("(Untitled)");
1647   title = g_strdup_printf ("%s%c", title, gui->notsaved ? '*' : ' ');
1648   gtk_window_set_title (GTK_WINDOW (Denemo.window), title);
1649   gchar *base = g_path_get_basename (title);
1650   gint index = g_list_index (Denemo.projects, gui);
1651   if(index < 0)
1652     {
1653        g_critical ("project is %p is not in list of projects, first tab is  %p\n", gui, Denemo.projects->data);
1654        return;
1655 
1656     }
1657   GtkWidget *page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (Denemo.notebook), index);
1658   if (page==NULL)
1659     {
1660        g_critical ("Bad page, passed project is %p, first tab is  %p\n", gui, Denemo.projects->data);
1661        return;
1662 
1663     }
1664   gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (Denemo.notebook), page, base);
1665 
1666   gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (Denemo.notebook), page, base);
1667 
1668 
1669   g_free (title);
1670   g_free (base);
1671 }
1672 
1673 static const gchar *
enshift_string(gint enshift)1674 enshift_string (gint enshift)
1675 {
1676   switch (enshift)
1677     {
1678     case -2:
1679       return "��";
1680     case -1:
1681       return "♭";
1682     case 0:
1683       return " ";
1684     case 1:
1685       return "♯";
1686     case 2:
1687       return "��";
1688     default:
1689       return _("Error");
1690     }
1691 }
1692 
1693 gint64 thetime;
1694 
start_editing_timer(void)1695 static void start_editing_timer (void)
1696 {
1697 
1698     thetime = g_get_monotonic_time ();
1699 
1700 }
stop_editing_timer(void)1701 static void stop_editing_timer (void)
1702 {
1703     gint64 thistime = g_get_monotonic_time ();
1704     if ((thetime>0) && (thetime<thistime))
1705         Denemo.project->total_edit_time += (thistime - thetime)/1000000;
1706 }
1707 
reset_editing_timer(void)1708 void reset_editing_timer (void)
1709 {
1710     thetime = 0;
1711 }
1712 
time_spent_editing()1713 gchar *time_spent_editing()
1714 {
1715     gint seconds =  Denemo.project->total_edit_time;
1716     gint days = seconds/(24*60*60);
1717     gint hours;
1718     gint minutes;
1719 
1720     seconds -= days*(24*60*60);
1721     hours = (seconds/(60*60));
1722     seconds -= hours*(60*60);
1723     minutes = seconds/60;
1724     seconds -= minutes*60;
1725     return g_strdup_printf("%d days %d hours %d minutes %d seconds\n", days, hours, minutes, seconds);
1726 }
1727 
1728 /* set the status of the current musical score - its change count and
1729    title bar and status bars.
1730    DenemoProject *gui the musical score.
1731    gboolean change TRUE = a change has just been made
1732                    FALSE = the score is to be assumed saved
1733 */
1734 void
score_status(DenemoProject * gui,gboolean change)1735 score_status (DenemoProject * gui, gboolean change)
1736 {
1737   if (change)
1738     {
1739       gboolean just_changed = !gui->notsaved;
1740       gui->notsaved = TRUE;
1741       gui->changecount++;
1742       gui->movement->changecount++;
1743       if (just_changed)
1744         if(!Denemo.non_interactive)
1745             start_editing_timer();
1746 
1747     }
1748   else
1749     {
1750       gui->notsaved = FALSE;
1751       if(!Denemo.non_interactive)
1752        stop_editing_timer();
1753     }
1754   if(!Denemo.non_interactive)
1755      {
1756             set_title_bar (gui);
1757             write_status (gui);
1758     }
1759 }
1760 
1761 /**
1762  * If the curObj is a chord with a note(s)
1763  * return the first note at or below cursory, or the last note
1764  * else return NULL
1765  */
1766 note *
findnote(DenemoObject * curObj,gint cursory)1767 findnote (DenemoObject * curObj, gint cursory)
1768 {
1769   note *curnote = NULL;
1770   if (curObj && curObj->type == CHORD && ((chord *) curObj->object)->notes)
1771     {
1772       GList *notes = ((chord *) curObj->object)->notes;
1773       for (; notes; notes = notes->next)
1774         {
1775           curnote = (note *) notes->data;
1776           //g_debug("comparing %d and %d\n", cursory, curnote->y);
1777           if (cursory <= curnote->mid_c_offset)
1778             break;
1779         }
1780 
1781     }
1782   return curnote;
1783 }
1784 /**
1785  * If the curObj is a chord with a note(s)
1786  * return the note at cursory else return NULL
1787  */
1788 note *
findnote_strict(DenemoObject * curObj,gint cursory)1789 findnote_strict (DenemoObject * curObj, gint cursory)
1790 {
1791   note *curnote = NULL;
1792   if (curObj && curObj->type == CHORD && ((chord *) curObj->object)->notes)
1793     {
1794       GList *notes = ((chord *) curObj->object)->notes;
1795       for (; notes; notes = notes->next)
1796         {
1797           curnote = (note *) notes->data;
1798           //g_debug("comparing %d and %d\n", cursory, curnote->y);
1799           if (cursory == curnote->mid_c_offset)
1800             return curnote;
1801         }
1802 
1803     }
1804   return NULL;
1805 }
1806 
1807 /* get a fret diagram for the chord at the cursor or before the cursor if not on the chord  */
get_fretdiagram_as_markup(void)1808 gchar *get_fretdiagram_as_markup (void)
1809 {
1810 DenemoProject *gui = Denemo.project;
1811    DenemoObject *curObj;
1812       if (!Denemo.project || !(Denemo.project->movement) || !(Denemo.project->movement->currentobject) || !(curObj = Denemo.project->movement->currentobject->data) || !(DENEMO_OBJECT_TYPE_NAME (curObj)))
1813         return NULL;
1814       if(curObj->type != CHORD && Denemo.project->movement->currentobject->next)
1815         curObj = Denemo.project->movement->currentobject->next->data;
1816       if (gui->lilysync != gui->changecount)
1817         refresh_lily_cb (NULL, Denemo.project);
1818       if (curObj->lilypond)
1819         {
1820               gchar *text = g_strdup_printf ("\\score{\n\\DenemoGlobalTranspose\n\\new FretBoards {%s}\n\\layout{indent=0.0}\n}",  curObj->lilypond);
1821               return text;
1822         }
1823     return NULL;
1824 }
1825 
1826 /* get a chord symbol for the chord at the cursor or before the cursor if not on the chord */
get_fakechord_as_markup(gchar * size,gchar * font)1827 gchar *get_fakechord_as_markup (gchar *size, gchar *font)
1828 {
1829 DenemoProject *gui = Denemo.project;
1830    DenemoObject *curObj;
1831       if (!Denemo.project || !(Denemo.project->movement) || !(Denemo.project->movement->currentobject) || !(curObj = Denemo.project->movement->currentobject->data) || !(DENEMO_OBJECT_TYPE_NAME (curObj)))
1832         return NULL;
1833       if((curObj->type != CHORD) && Denemo.project->movement->currentobject->next)
1834         curObj = Denemo.project->movement->currentobject->next->data;
1835       if (gui->lilysync != gui->changecount)
1836         refresh_lily_cb (NULL, Denemo.project);
1837       if (curObj->lilypond)
1838         {
1839             gchar *text = g_strdup_printf ("\\score{\n\\DenemoGlobalTranspose\n\\new ChordNames {\n\\override ChordName.font-name = #'\"%s\"\n\\override ChordName.font-size = #%s %s}\n\\layout{indent=0.0}\n}\n", font, size, curObj->lilypond);
1840             return text;
1841         }
1842     return NULL;
1843 }
1844 
1845 /****************
1846  * write the status bar
1847 
1848 ********************/
1849 
1850 void
write_status(DenemoProject * gui)1851 write_status (DenemoProject * gui)
1852 {
1853   if(Denemo.non_interactive)
1854     return;
1855 
1856   gint minutes = 0;
1857   gdouble seconds = 0.0;
1858   gdouble early = 0.0, late = 0.0;
1859   gchar *selection;
1860   if (gui->movement == NULL)
1861     return;
1862 
1863   static GList *last_object;
1864 
1865   if (gui->movement->currentobject)
1866        {
1867            if (last_object != gui->movement->currentobject)
1868                 {
1869                     if(get_wysiwyg_info()->stage != TypesetForPlaybackView)
1870                         get_wysiwyg_info()->stage = STAGE_NONE;//remove the mark in the printview window as the cursor has moved
1871                     get_wysiwyg_info()->Mark.width = 0;
1872                     gtk_widget_queue_draw (Denemo.printarea);
1873                 }
1874         last_object = gui->movement->currentobject;
1875         }
1876 
1877   if (gui->movement->currentobject && gui->movement->currentobject->data)
1878     {
1879       DenemoObject *curObj = gui->movement->currentobject->data;
1880       if ((gui->movement->smfsync == gui->movement->changecount))
1881         {
1882           early = curObj->earliest_time, late = curObj->latest_time;
1883         }
1884 
1885       switch (curObj->type)
1886         {
1887         case CHORD:
1888           {
1889             chord *thechord = ((chord *) curObj->object);
1890             selection = g_strdup_printf ("%s%s%s%s%s%s%s%s%s",
1891                                          thechord->notes ? (g_list_length (thechord->notes) > 1 ? _("Chord ") : _("Note ")) : _("Rest "), thechord->slur_begin_p ? _(", begin slur") : "", thechord->slur_end_p ? _(", end slur") : "", thechord->is_tied ? _(", tied") : "", thechord->crescendo_begin_p ? _(", begin cresc.") : "", thechord->crescendo_end_p ? _(", end cresc.") : "", thechord->diminuendo_begin_p ? _(", begin dim.") : "", thechord->diminuendo_end_p ? _(", end dim.") : "", thechord->is_grace ? _(", grace note") : "");
1892             if (thechord->notes)
1893               {
1894                 GList *g;
1895                 for (g = thechord->notes; g; g = g->next)
1896                   {
1897                     note *thenote = (note *) g->data;
1898                     GList *h;
1899                     for (h = thenote->directives; h; h = h->next)
1900                       {
1901                         DenemoDirective *directive = (DenemoDirective *) h->data;
1902                         if (directive->postfix || directive->prefix)
1903                           {
1904                             gchar *old = selection;
1905                             selection = g_strdup_printf ("%.50s (%s) %.50s", directive->prefix ? directive->prefix->str : "", selection, directive->postfix ? directive->postfix->str : "");
1906                             g_free (old);
1907                           }
1908                       }
1909                   }
1910               }
1911           }
1912           break;
1913 
1914         case TUPOPEN:
1915           selection = g_strdup_printf (_("Tuplet %d/%d"), ((tupopen *) curObj->object)->numerator, ((tupopen *) curObj->object)->denominator);
1916           break;
1917         case TUPCLOSE:
1918           selection = g_strdup_printf (_("End tuplet"));
1919           break;
1920         case CLEF:
1921           selection = g_strdup_printf (_("Clef change"));
1922           break;
1923         case TIMESIG:
1924           selection = g_strdup_printf (_("Time signature change"));
1925           break;
1926         case KEYSIG:
1927           selection = g_strdup_printf (_("Key signature change"));
1928           break;
1929         case STEMDIRECTIVE:
1930           selection = g_strdup_printf (_("Stem directive: %s"), ((stemdirective *) curObj->object)->type == DENEMO_STEMDOWN ? _("stem down") : ((stemdirective *) curObj->object)->type == DENEMO_STEMUP ? _("stem up") : _("normal stemming"));
1931           break;
1932         case DYNAMIC:
1933           selection = g_strdup_printf (_("Dynamic: %s"), ((dynamic *) curObj->object)->type->str);
1934           break;
1935 
1936         case LILYDIRECTIVE:
1937           {
1938             DenemoDirective *directive = (DenemoDirective *) curObj->object;
1939             selection = g_strdup_printf (_("Directive:(%.20s) %.20s%.50s"), directive->tag ? directive->tag->str : _("Unknown Tag"), directive->x ? _("Not all layouts") : directive->y ? _("Only for one Layout") : "", directive->postfix ? directive->postfix->str : directive->prefix ? directive->prefix->str : directive->graphic_name ? directive->graphic_name->str : directive->display ? directive->display->str : "empty");
1940           }
1941           break;
1942         default:
1943           selection = g_strdup_printf (_("Cursor on an unknown object"));
1944         }
1945 
1946         //DenemoMeasure *measure = gui->movement->currentmeasure->data;
1947         //selection = g_strdup_printf ("%s %s %d/%d %d", selection, curObj->clef?get_clef_name (curObj->clef->type):"NULL", measure->timesig?measure->timesig->time1:0, measure->timesig?measure->timesig->time2:0, curObj->keysig?curObj->keysig->number:0xFFFF);
1948 
1949 
1950     }
1951   else
1952     selection = g_strdup_printf (_("Cursor not on any object"));
1953 
1954   GString *status = g_string_new (_("Movement"));
1955   gint index = g_list_index (gui->movements, gui->movement);
1956   const gchar *dur ="";
1957   switch (get_prevailing_duration())
1958   {
1959       case 0: dur = NOTE0;
1960       break;
1961       case 1: dur = NOTE1;
1962       break;
1963       case 2: dur = NOTE2;
1964       break;
1965       case 3: dur = NOTE3;
1966       break;
1967       case 4: dur = NOTE4;
1968       break;
1969       case 5: dur = NOTE5;
1970       break;
1971       case 6: dur = NOTE6;
1972       break;
1973       case 7: dur = NOTE7;
1974       break;
1975       case 8: dur = NOTE8;
1976       break;
1977 
1978 
1979   }
1980   g_string_printf (status, "%s%s %d: %s: ", enshift_string (gui->movement->pending_enshift), dur, index + 1, selection);
1981 
1982 
1983 
1984   if (gui->movement->smf && (gui->movement->smfsync == gui->movement->changecount) && Denemo.prefs.playback_controls)
1985     g_string_append_printf (status, _("%d min %.2f sec %.2f %.2f"), minutes, seconds, early, late);
1986   else
1987     g_string_append_printf (status, _(" Staff %d Measure %d Position %d %s"), gui->movement->currentstaffnum, gui->movement->currentmeasurenum, gui->movement->cursor_x + 1, gui->movement->cursor_appending ? _("Appending") : _("Not Appending") /*not understood this one... , gui->movement->cursoroffend?"Off End":"Not Off End" */ );
1988 
1989   if (Denemo.prefs.midi_in_controls)
1990     {
1991       gchar *thesharp = sharpest ();
1992       gchar *theflat = flattest ();
1993       g_string_append_printf (status, " |%s - %s|", theflat, thesharp);
1994       g_free (theflat);
1995       g_free (thesharp);
1996     }
1997 
1998   g_free (selection);
1999   gchar *end_valid;
2000   if (!g_utf8_validate (status->str, -1, (const gchar **)&end_valid))
2001     *end_valid = '\0';
2002   gtk_label_set_text (GTK_LABEL (Denemo.statuslabel), status->str);
2003 
2004   g_string_free (status, TRUE);
2005   update_object_info ();
2006 }
2007 
2008 void
write_input_status(void)2009 write_input_status (void)
2010 {
2011   if(Denemo.non_interactive)
2012     return;
2013   gtk_label_set_markup (GTK_LABEL (Denemo.input_label), Denemo.input_filters->str);
2014 }
2015 
2016 /**
2017  * Display a message box asking primary & secondary messages
2018  * @return TRUE if the OK button was clicked or Enter pressed
2019  */
2020 gboolean
confirm(gchar * primary,gchar * secondary)2021 confirm (gchar * primary, gchar * secondary)
2022 {
2023   GtkWidget *dialog;
2024   gboolean r = 0;
2025 
2026   dialog = gtk_message_dialog_new (GTK_WINDOW (Denemo.window), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s", primary);
2027 
2028   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary);
2029   gtk_widget_show_all (dialog);
2030   r = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES);
2031   gtk_widget_destroy (dialog);
2032   return r;
2033 }
2034 
2035 gboolean
choose_option(gchar * title,gchar * primary,gchar * secondary)2036 choose_option (gchar *title, gchar * primary, gchar * secondary)
2037 {
2038   GtkWidget *dialog;
2039   gboolean r;
2040   dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (Denemo.window), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
2041                                                       primary, GTK_RESPONSE_ACCEPT, secondary, GTK_RESPONSE_REJECT, NULL);
2042   //g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
2043   gtk_window_set_urgency_hint (GTK_WINDOW (dialog), TRUE);
2044   gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(Denemo.window));
2045   gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
2046   r = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT);
2047   gtk_widget_destroy (dialog);
2048   return r;
2049 }
2050 
2051 
2052 /* free a GString and the string it holds, and set the pointer to it to NULL */
2053 void
nullify_gstring(GString ** s)2054 nullify_gstring (GString ** s)
2055 {
2056   if (*s)
2057     g_string_free (*s, TRUE);
2058   *s = NULL;
2059 }
2060 
2061 /* dialog to get a filename from the user
2062  */
choose_file(gchar * title,gchar * startdir,GList * extensions)2063 gchar *choose_file (gchar *title, gchar *startdir, GList *extensions)
2064 {
2065   GtkWidget *dialog;
2066   gchar *filename = NULL;
2067   dialog = gtk_file_chooser_dialog_new (title,
2068                                       NULL,
2069                                       GTK_FILE_CHOOSER_ACTION_OPEN,
2070                                       _("_Cancel"), GTK_RESPONSE_CANCEL,
2071                                       _("_Open"), GTK_RESPONSE_ACCEPT,
2072                                       NULL);
2073   GtkFileFilter *filter = gtk_file_filter_new();
2074   GString *filter_description = g_string_new ("");
2075   for(extensions;extensions;extensions=extensions->next)
2076     {
2077     gtk_file_filter_add_pattern (filter,(gchar*)extensions->data);
2078     g_string_append_printf (filter_description, "%s ", (gchar*)extensions->data);
2079     }
2080   gtk_file_filter_set_name (filter, filter_description->str);
2081   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
2082   gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), startdir);
2083 
2084   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
2085       {
2086         filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
2087       }
2088 
2089   gtk_widget_destroy (dialog);
2090   return filename;
2091 }
2092 
2093 
2094 static void
hide_windows(void)2095 hide_windows (void)
2096 {
2097     if (Denemo.prefs.hide_windows)
2098         {
2099             if(Denemo.window)
2100                 gtk_widget_hide (Denemo.window);
2101             if(Denemo.printarea)
2102                 gtk_widget_hide (gtk_widget_get_toplevel(Denemo.printarea));
2103         }
2104 }
2105 static void
show_windows(void)2106 show_windows (void)
2107 {
2108    if (Denemo.prefs.hide_windows)
2109         {
2110             if(Denemo.window)
2111                 gtk_widget_show (Denemo.window);
2112              if(Denemo.printarea)
2113                 gtk_widget_show (gtk_widget_get_toplevel(Denemo.printarea));
2114         }
2115 }
2116 
2117 /**
2118  * Pops up a dialog box that has a text entry box and ok/cancel buttons
2119  * title is a title for the box.
2120  * initial_value is for the text entry box, or NULL if none.
2121  * instruction is a prompt for the user.
2122  * Returns a new value on Ok and NULL if cancelled.
2123  * The returned value should be freed by the caller.
2124  *
2125  */
2126 
2127 gchar *
string_dialog_entry(DenemoProject * gui,gchar * title,gchar * instruction,gchar * initial_value)2128 string_dialog_entry (DenemoProject * gui, gchar * title, gchar * instruction, gchar * initial_value)
2129 {
2130   return string_dialog_entry_with_widget (gui, title, instruction, initial_value, NULL);
2131 }
2132 
2133 /* as string_dialog_entry() but with extra widget */
2134 gchar *
string_dialog_entry_with_widget_opt(DenemoProject * gui,gchar * wlabel,gchar * direction,gchar * PreValue,GtkWidget * widget,gboolean modal)2135 string_dialog_entry_with_widget_opt (DenemoProject * gui, gchar * wlabel, gchar * direction, gchar * PreValue, GtkWidget * widget, gboolean modal)
2136 {
2137 
2138   GtkWidget *dialog;
2139   GtkWidget *entry;
2140   GtkWidget *label;
2141   gchar *entry_string = NULL;
2142   //GString *string;
2143   entry = gtk_entry_new ();
2144 
2145   dialog = modal ? gtk_dialog_new_with_buttons (wlabel, GTK_WINDOW (Denemo.window), (GtkDialogFlags) (GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_ACCEPT, _("_Cancel"), GTK_RESPONSE_REJECT, NULL) : gtk_dialog_new_with_buttons (wlabel, GTK_WINDOW (Denemo.window), (GtkDialogFlags) (GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_ACCEPT, NULL);
2146 
2147   g_signal_connect (dialog, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), NULL); //if the user tries to dismiss the window, hide it, will that then hang??? It doesn't on GNOME using the right-click menu to close the window
2148 
2149   label = gtk_label_new (direction);
2150   GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
2151   gtk_container_add (GTK_CONTAINER (content_area), label);
2152 
2153   if (widget)
2154     gtk_container_add (GTK_CONTAINER (content_area), widget);
2155 
2156   if (PreValue != NULL)
2157     {
2158       gtk_entry_set_text (GTK_ENTRY (entry), (gchar *) PreValue);
2159     }
2160   gtk_container_add (GTK_CONTAINER (content_area), entry);
2161 
2162   gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
2163   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
2164   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
2165   gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(Denemo.window));
2166   gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
2167   gtk_widget_show_all (dialog);
2168 
2169   if (modal)
2170     {
2171       gtk_widget_grab_focus (entry);
2172       hide_windows();
2173 
2174       if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
2175         {
2176             gchar *string = NULL;
2177             if (GTK_DIALOG (dialog))
2178                 {
2179                 entry_string = (gchar *) gtk_entry_get_text (GTK_ENTRY (entry));
2180                 string = g_strdup (entry_string);
2181                 gtk_widget_destroy (dialog);
2182                 }
2183                show_windows();
2184               return string;
2185         }
2186       else
2187         {
2188           if (GTK_DIALOG (dialog))
2189             gtk_widget_destroy (dialog);
2190 
2191         }
2192      show_windows();
2193      return NULL;
2194     }
2195   else
2196     {
2197       g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_main_quit), entry);
2198       gtk_main ();
2199       if (GTK_IS_WIDGET (entry))
2200         {
2201           entry_string = GTK_IS_WIDGET (entry) ? g_strdup ((gchar *) gtk_entry_get_text (GTK_ENTRY (entry))) : NULL;
2202           gtk_widget_destroy (dialog);
2203           return entry_string;
2204         }
2205       return NULL;
2206     }
2207 }
2208 
2209 gchar *
string_dialog_entry_with_widget(DenemoProject * gui,gchar * wlabel,gchar * direction,gchar * PreValue,GtkWidget * widget)2210 string_dialog_entry_with_widget (DenemoProject * gui, gchar * wlabel, gchar * direction, gchar * PreValue, GtkWidget * widget)
2211 {
2212   return string_dialog_entry_with_widget_opt (gui, wlabel, direction, PreValue, widget, TRUE);
2213 }
2214 
2215 /* as string_dialog_entry_with_widget() but gives a text editor instead of a single line editor */
2216 gchar *
string_dialog_editor_with_widget_opt(DenemoProject * gui,gchar * wlabel,gchar * direction,gchar * PreValue,GtkWidget * widget,gboolean modal,gpointer keypress_callback)2217 string_dialog_editor_with_widget_opt (DenemoProject * gui, gchar * wlabel, gchar * direction, gchar * PreValue, GtkWidget * widget, gboolean modal, gpointer keypress_callback)
2218 {
2219   GtkWidget *dialog;
2220   GtkWidget *textview;
2221   GtkWidget *label;
2222   textview = gtk_text_view_new ();
2223   GtkTextBuffer *textbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
2224   gtk_text_buffer_set_text (textbuffer, PreValue ? PreValue : "", -1);
2225   GtkWidget *sw = gtk_scrolled_window_new (gtk_adjustment_new (1.0, 1.0, 2.0, 1.0, 4.0, 1.0), gtk_adjustment_new (1.0, 1.0, 2.0, 1.0, 4.0, 1.0));
2226 
2227   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2228 
2229   dialog = modal ? gtk_dialog_new_with_buttons (wlabel, GTK_WINDOW (Denemo.window), (GtkDialogFlags) (GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_ACCEPT, _("_Cancel"), GTK_RESPONSE_REJECT, NULL) : gtk_dialog_new_with_buttons (wlabel, GTK_WINDOW (Denemo.window), (GtkDialogFlags) (GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_ACCEPT, NULL);
2230   if(keypress_callback)
2231     g_signal_connect (G_OBJECT (textview), "key-press-event", G_CALLBACK (keypress_callback), textbuffer);
2232 
2233   label = gtk_label_new (direction);
2234   GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
2235   gtk_box_pack_start (GTK_BOX (content_area), label, FALSE, TRUE, 0);
2236   if (widget)
2237     {
2238       gtk_box_pack_start (GTK_BOX (content_area), widget, FALSE, TRUE, 0);
2239       g_object_set_data (G_OBJECT (widget), "textbuffer", textbuffer);
2240       g_object_set_data (G_OBJECT (widget), "textview", textview);
2241     }
2242   gtk_container_add (GTK_CONTAINER (sw), textview);
2243   gtk_box_pack_start (GTK_BOX (content_area), sw, TRUE, TRUE, 0);
2244 
2245   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
2246 
2247 
2248   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
2249   gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(Denemo.window));
2250   gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
2251   gtk_widget_show_all (dialog);
2252   gtk_widget_grab_focus (textview);
2253   if (modal)
2254     {
2255       if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
2256         {
2257           GtkTextIter startiter, enditer;
2258           gtk_text_buffer_get_start_iter (textbuffer, &startiter);
2259           gtk_text_buffer_get_end_iter (textbuffer, &enditer);
2260           gchar *text = gtk_text_buffer_get_text (textbuffer, &startiter, &enditer, FALSE);
2261           gtk_widget_destroy (dialog);
2262           return text;
2263         }
2264       else
2265         {
2266           gtk_widget_destroy (dialog);
2267           return NULL;
2268         }
2269       return NULL;
2270     }
2271   else
2272     {
2273       g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_main_quit), NULL);
2274       gtk_main ();
2275       if (GTK_IS_TEXT_BUFFER (textbuffer))
2276         {
2277           GtkTextIter startiter, enditer;
2278           gtk_text_buffer_get_start_iter (textbuffer, &startiter);
2279           gtk_text_buffer_get_end_iter (textbuffer, &enditer);
2280           gchar *text = gtk_text_buffer_get_text (textbuffer, &startiter, &enditer, FALSE);
2281           gtk_widget_destroy (dialog);
2282           return text;
2283         }
2284       else
2285         {
2286           return NULL;
2287         }
2288     }
2289 }
2290 
2291 gchar *
string_dialog_editor_with_widget(DenemoProject * gui,gchar * wlabel,gchar * direction,gchar * PreValue,GtkWidget * widget,gpointer keypress_callback)2292 string_dialog_editor_with_widget (DenemoProject * gui, gchar * wlabel, gchar * direction, gchar * PreValue, GtkWidget * widget, gpointer keypress_callback)
2293 {
2294   return string_dialog_editor_with_widget_opt (gui, wlabel, direction, PreValue, widget, TRUE, keypress_callback);
2295 }
2296 
2297 static gboolean
option_choice(GtkWidget * widget,gchar ** response)2298 option_choice (GtkWidget * widget, gchar ** response)
2299 {
2300   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
2301     *response = g_object_get_data (G_OBJECT (widget), "choice");
2302   //do not respond to the toggling off of other radio buttons
2303   return TRUE;
2304 }
2305 
2306 static gint root_x;
2307 static gint root_y;
dialog_realize(GtkWidget * dialog)2308 static gboolean dialog_realize (GtkWidget *dialog) {
2309   if(root_x)
2310    gtk_window_move (GTK_WINDOW(dialog), root_x, root_y);
2311     return FALSE;
2312 }
2313 
2314 /* run a dialog for the user to select a string from the NULL separated strings, str
2315  return NULL if user cancels.*/
2316 static gchar *
get_option_recursive(gchar * title,gchar * str,gint length,gboolean more)2317 get_option_recursive (gchar *title, gchar * str, gint length, gboolean more)
2318 {
2319   gchar *response = NULL;
2320   if (title==NULL)
2321     title = _("Select from List (or Cancel)");
2322   GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
2323                                                    GTK_WINDOW (Denemo.window),
2324                                                    (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
2325                                                    _("_OK"), GTK_RESPONSE_ACCEPT,
2326                                                    _("_Cancel"), GTK_RESPONSE_REJECT,
2327                                                    NULL);
2328   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
2329   g_signal_connect_after (G_OBJECT(dialog), "realize", G_CALLBACK(dialog_realize), NULL);
2330   GtkWidget *vbox = gtk_vbox_new (FALSE, 1);
2331   GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
2332   gtk_container_add (GTK_CONTAINER (content_area), vbox);
2333 
2334   gchar *opt;
2335   GtkWidget *widget1, *widget;
2336   for (opt = str; (opt - str) < length; opt += strlen (opt) + 1)
2337     {
2338       if (opt == str)
2339         {
2340           widget = widget1 = gtk_radio_button_new_with_label (NULL, opt);
2341           response = str;       //this is the first radio button, we set response to be the input string ie first option, in case the user makes no choice, in which case the callback option_choice is not called.
2342         }
2343       else
2344         {
2345           widget = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (widget1), opt);
2346         }
2347       g_object_set_data (G_OBJECT (widget), "choice", (gpointer) opt);
2348       g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (option_choice), &response);
2349       gtk_container_add (GTK_CONTAINER (vbox), widget);
2350     }
2351 
2352    if(more)
2353         {
2354             opt = _("More...");
2355             widget = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (widget1), opt);
2356             g_object_set_data (G_OBJECT (widget), "choice", (gpointer) opt);
2357             g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (option_choice), &response);
2358             gtk_container_add (GTK_CONTAINER (vbox), widget);
2359         }
2360   gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(Denemo.window));
2361   gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
2362   gtk_widget_show_all (dialog);
2363   hide_windows ();
2364   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_REJECT)
2365     {
2366       response = NULL;
2367     }
2368   g_debug ("Returning contents of response is %s\n", response);
2369   gtk_window_get_position (GTK_WINDOW(dialog), &root_x, &root_y);
2370   gtk_widget_destroy (dialog);
2371   show_windows ();
2372   return response;
2373 }
2374 #define MAX_ITEMS (Denemo.prefs.max_menu_size)
get_option(gchar * title,gchar * str,gint length)2375 gchar *get_option (gchar *title, gchar * str, gint length)
2376 {
2377   gchar *opt;
2378   gint i;
2379   for (opt = str, i = 0; (opt - str) < length; i++, opt += strlen (opt) + 1)
2380         {
2381         if (i < MAX_ITEMS)
2382             continue;
2383         else
2384             {
2385                 gchar *response = get_option_recursive (title, str, opt-str, TRUE);
2386                 if(response && (!strcmp (response, _("More..."))))
2387                     {
2388                         length -= (opt - str);
2389                         str = opt;
2390                         i = 0;
2391                         continue;
2392                     }
2393                 else return response;
2394             }
2395         }
2396  if ((opt - str) >= length)
2397     return get_option_recursive (title, str, length, FALSE);
2398  return NULL;
2399 }
2400 
2401 
2402 
2403 
2404 /* output text to the console (lilypond errors) window. If text==NULL clear window*/
2405 void
console_output(gchar * text)2406 console_output (gchar * text)
2407 {
2408   GtkTextIter enditer;
2409   GtkTextBuffer *buffer = gtk_text_view_get_buffer ((GtkTextView *) (Denemo.console));
2410   gtk_text_buffer_get_end_iter (buffer, &enditer);
2411   if (text)
2412     gtk_text_buffer_insert (buffer, &enditer, text, -1);
2413   else
2414     gtk_text_buffer_set_text (buffer, "", -1);
2415 }
2416 
2417 /* returns an override flag ORd from all those in the list of directives,
2418    excluding ones with DENEMO_OVERRIDE_HIDDEN set */
2419 gint
get_override(GList * g)2420 get_override (GList * g)
2421 {
2422   gint ret = 0;
2423   for (; g; g = g->next)
2424     {
2425       DenemoDirective *d = g->data;
2426       if (!(d->override & DENEMO_OVERRIDE_HIDDEN))
2427         ret |= d->override;
2428     }
2429   return ret;
2430 }
2431 
2432 //modfies name to truncate at the extension (a dot at end before any directory separators), returning a pointer to the extension chopped off
2433 // returns NULL if no extension, with name unchanged
2434 
2435 gchar *
remove_extension(gchar * name)2436 remove_extension (gchar * name)
2437 {
2438   gchar *c;
2439   if (name)
2440     for (c = name + strlen (name); c != name; c--)
2441       {
2442         if (*c == '.')
2443           {
2444             *c = '\0';
2445             return c + 1;
2446           }
2447         if (*c == G_DIR_SEPARATOR)
2448           break;
2449       }
2450   return NULL;
2451 }
2452 
2453 //modifies name, removing the extension and returns a newly allocated string
2454 //with the passed extension
2455 gchar *
substitute_extension(gchar * name,gchar * extension)2456 substitute_extension (gchar * name, gchar * extension)
2457 {
2458   (void) remove_extension (name);
2459   return g_strdup_printf ("%s.%s", name, extension);
2460 }
2461 
2462 enum clefs
cleftypefromname(gchar * str)2463 cleftypefromname (gchar * str)
2464 {
2465   enum clefs ret = DENEMO_TREBLE_CLEF;
2466 
2467   if (g_strcasecmp (str, "treble") == 0)
2468     ret = DENEMO_TREBLE_CLEF;
2469   else if (g_strcasecmp (str, "bass") == 0)
2470     ret = DENEMO_BASS_CLEF;
2471   else if (g_strcasecmp (str, "alto") == 0)
2472     ret = DENEMO_ALTO_CLEF;
2473   else if (g_strcasecmp (str, "\"g_8\"") == 0)
2474     ret = DENEMO_G_8_CLEF;
2475   else if (g_strcasecmp (str, "tenor") == 0)
2476     ret = DENEMO_TENOR_CLEF;
2477   else if (g_strcasecmp (str, "soprano") == 0)
2478     ret = DENEMO_SOPRANO_CLEF;
2479   g_free (str);
2480   return ret;
2481 }
2482 
2483 gint
get_widget_height(GtkWidget * w)2484 get_widget_height (GtkWidget * w)
2485 {
2486   GtkAllocation allocation;
2487   gtk_widget_get_allocation (w, &allocation);
2488   return allocation.height;
2489 }
2490 
2491 gint
get_widget_width(GtkWidget * w)2492 get_widget_width (GtkWidget * w)
2493 {
2494   GtkAllocation allocation;
2495   gtk_widget_get_allocation (w, &allocation);
2496   return allocation.width;
2497 }
2498 
2499 void
switch_back_to_main_window(void)2500 switch_back_to_main_window (void)
2501 {
2502   if (Denemo.non_interactive)
2503     return;
2504   gtk_window_present (GTK_WINDOW (Denemo.window));
2505   gtk_widget_grab_focus (Denemo.scorearea);
2506 }
2507 
2508 /* set all labels in the hierarchy below widget to use markup */
2509 void
use_markup(GtkWidget * widget)2510 use_markup (GtkWidget * widget)
2511 {
2512   if (!widget)
2513     return;
2514   if (GTK_IS_LABEL (widget))
2515     {
2516       gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
2517     }
2518   else if (GTK_IS_CONTAINER (widget))
2519     {
2520       GList *g = gtk_container_get_children (GTK_CONTAINER (widget));
2521       for (; g; g = g->next)
2522         use_markup (g->data);
2523       if (GTK_IS_MENU_ITEM (widget))
2524         {
2525           use_markup (gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)));
2526         }
2527     }
2528 }
2529 
2530 #ifdef FAKE_TOOLTIPS
2531  static GtkWidget *TooltipDialog = NULL;
2532 static gboolean not_wanted = TRUE;
2533 static gboolean not_wanted_in_this_session = FALSE;
2534 
no_longer_wanted(GtkWidget * w)2535 static gboolean no_longer_wanted (GtkWidget *w)
2536 {
2537    not_wanted = TRUE;
2538    if(Denemo.prefs.newbie)
2539     not_wanted_in_this_session = FALSE;
2540    TooltipDialog = NULL;
2541    return FALSE;
2542 }
show_tooltip(GtkWidget * w,GdkEvent * ev,gchar * text)2543 gboolean show_tooltip (GtkWidget *w, GdkEvent *ev, gchar *text)
2544 {
2545   static gchar *last_tooltip;
2546   if (Denemo.prefs.newbie)
2547     not_wanted_in_this_session = not_wanted = FALSE;
2548   if (not_wanted)
2549     return FALSE;
2550   if (not_wanted_in_this_session)
2551     return FALSE;
2552 
2553   if (text && (*text) && (last_tooltip != text))
2554        {
2555            if (TooltipDialog)
2556                 {
2557                     gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (TooltipDialog), text);
2558                     gtk_widget_show (TooltipDialog);
2559                 }
2560                 else
2561                 {
2562                     TooltipDialog = infodialog (text);
2563                     g_signal_connect (G_OBJECT (TooltipDialog), "delete-event", G_CALLBACK (no_longer_wanted), NULL);
2564                 }
2565         }
2566     last_tooltip = text;
2567 
2568     return FALSE;//allow normal response
2569 }
free_tooltip(GtkWidget * w,gchar * tooltip)2570 void free_tooltip (GtkWidget *w, gchar *tooltip)
2571 {
2572   //g_print ("Freeing tooltip\n");
2573    g_free (tooltip);
2574 }
2575 #endif
2576 // Help for beginners using keyboard shortcuts
2577 static GtkWidget *KeyStrokes;
2578 static GtkWidget *KeyStrokeLabel;
2579 static GtkWidget *KeyStrokeHelp;
2580 
2581 
2582 void
KeyStrokeAwait(gchar * first_keypress)2583 KeyStrokeAwait (gchar * first_keypress)
2584 {
2585   KeyStrokeShow (first_keypress, DENEMO_NO_COMMAND, TwoKey);
2586 }
2587 
2588 void
KeyStrokeDecline(gchar * first_keypress)2589 KeyStrokeDecline (gchar * first_keypress)
2590 {
2591   KeyStrokeShow (first_keypress, DENEMO_NO_COMMAND, SingleKey);
2592 }
2593 
MouseGestureShow(gchar * str,gchar * help,DenemoShortcutType type)2594 void MouseGestureShow (gchar *str, gchar *help, DenemoShortcutType type)
2595 {
2596   gtk_label_set_text (GTK_LABEL (KeyStrokeHelp), help);
2597   KeyStrokeShow (str, DENEMO_NO_COMMAND, type);
2598 }
KeyPlusMouseGestureShow(gchar * str,gint command_idx)2599 void KeyPlusMouseGestureShow(gchar *str, gint command_idx)
2600 {
2601   const gchar *label = lookup_label_from_idx (Denemo.map, command_idx);
2602   const gchar *tooltip = lookup_tooltip_from_idx (Denemo.map, command_idx);
2603   gchar *text = g_strdup_printf (_("Mouse shortcut <span font_desc=\"24\" foreground=\"blue\">%s</span>" " invokes command <span font_desc=\"24\" foreground=\"dark red\">%s</span>"), str, label);
2604 
2605   gtk_window_set_title (GTK_WINDOW (KeyStrokes),  _("Mouse Shortcut"));
2606   gtk_label_set_markup (GTK_LABEL (KeyStrokeLabel), text);
2607   gtk_label_set_text (GTK_LABEL (KeyStrokeHelp), tooltip);
2608   g_free (text);
2609   gtk_widget_show (KeyStrokes);
2610 }
2611 
2612 void
KeyStrokeShow(gchar * str,gint command_idx,DenemoShortcutType type)2613 KeyStrokeShow (gchar * str, gint command_idx, DenemoShortcutType type)
2614 {
2615   if (str != NULL)
2616     {
2617       gchar *text;
2618       if (command_idx != DENEMO_NO_COMMAND)
2619         {
2620           const gchar *label = lookup_label_from_idx (Denemo.map, command_idx);
2621           const gchar *tooltip = lookup_tooltip_from_idx (Denemo.map, command_idx);
2622           if (type)
2623             {
2624               text = g_strdup_printf (_("Key Press <span font_desc=\"24\" foreground=\"blue\">%s</span>" " invokes command <span font_desc=\"24\" foreground=\"dark red\">%s</span>"), str, label);
2625 
2626             }
2627           else
2628             {
2629               text = g_strdup_printf (_("Key Presses <span font_desc=\"24\" foreground=\"blue\">%s</span>" " invoke command <span font_desc=\"24\" foreground=\"dark red\">%s</span>"), str, label);
2630             }
2631           gtk_window_set_title (GTK_WINDOW (KeyStrokes), type==SingleKey ? _("Single Key Press") : _("Two Key Presses"));
2632           gtk_label_set_markup (GTK_LABEL (KeyStrokeLabel), text);
2633           gtk_label_set_text (GTK_LABEL (KeyStrokeHelp), tooltip);
2634           g_free (text);
2635         }
2636       else // no command
2637         {
2638           switch (type) {
2639             case SingleKey:
2640               gtk_window_set_title (GTK_WINDOW (KeyStrokes), _("Key Press"));
2641               gtk_label_set_text (GTK_LABEL (KeyStrokeHelp), "");
2642               text = g_strdup_printf (_("Key Press <span font_desc=\"24\" foreground=\"blue\">%s</span>" " Is not a shortcut.\n%s"), str,
2643               (Denemo.project->view != DENEMO_MENU_VIEW)?
2644               _("(The menus are now restored in case you are lost.)"):"");
2645               break;
2646             case TwoKey:
2647               gtk_window_set_title (GTK_WINDOW (KeyStrokes), _("First Key Press"));
2648               gtk_label_set_text (GTK_LABEL (KeyStrokeHelp), "");
2649               text = g_strdup_printf (_("Key Press <span font_desc=\"24\" foreground=\"blue\">%s</span>" " Awaiting continuation"), str);
2650               break;
2651             case MouseGesture:
2652               gtk_window_set_title (GTK_WINDOW (KeyStrokes), _("Mouse"));
2653               text = g_strdup_printf (_("Mouse <span font_desc=\"24\" foreground=\"blue\">%s</span>"), str);
2654               break;
2655             case KeyPlusMouse:
2656               gtk_window_set_title (GTK_WINDOW (KeyStrokes), _("Key + Mouse"));
2657               text = g_strdup_printf (_("Key Press <span font_desc=\"24\" foreground=\"blue\">%s</span>"), str);
2658               break;
2659             default:
2660               g_warning("bad call");
2661               return;
2662           }
2663           gtk_label_set_markup (GTK_LABEL (KeyStrokeLabel), text);
2664           g_free (text);
2665         }
2666     }
2667   gtk_widget_show (KeyStrokes);
2668 }
2669 
2670 static gboolean
toggle_show_keystroke_preference(void)2671 toggle_show_keystroke_preference (void)
2672 {
2673   Denemo.prefs.learning = FALSE;
2674   gtk_widget_hide (KeyStrokes);
2675   return TRUE;
2676 }
2677 
2678 void
initialize_keystroke_help(void)2679 initialize_keystroke_help (void)
2680 {
2681   if (KeyStrokes == NULL)
2682     {
2683       KeyStrokes = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2684       g_signal_connect (G_OBJECT (KeyStrokes), "delete-event", G_CALLBACK (toggle_show_keystroke_preference), NULL);
2685       gtk_window_set_transient_for (GTK_WINDOW(KeyStrokes), GTK_WINDOW(Denemo.window));
2686       gtk_window_set_keep_above (GTK_WINDOW (KeyStrokes), TRUE);
2687       gtk_window_set_accept_focus (GTK_WINDOW (KeyStrokes), FALSE);
2688       KeyStrokeLabel = gtk_label_new ("");
2689       //gtk_label_set_line_wrap (KeyStrokeLabel, TRUE);
2690       KeyStrokeHelp = gtk_label_new ("");
2691       gtk_label_set_line_wrap (GTK_LABEL(KeyStrokeHelp), TRUE);
2692       GtkWidget *vbox = gtk_vbox_new (FALSE, 8);
2693       gtk_container_add (GTK_CONTAINER (KeyStrokes), vbox);
2694       gtk_box_pack_start (GTK_BOX (vbox), KeyStrokeLabel, FALSE, TRUE, 0);
2695       gtk_box_pack_start (GTK_BOX (vbox), KeyStrokeHelp, FALSE, TRUE, 0);
2696       gtk_label_set_use_markup (GTK_LABEL (KeyStrokeLabel), TRUE);
2697       gtk_widget_show_all (KeyStrokes);
2698     }
2699   gtk_widget_hide (KeyStrokes);
2700 }
2701 
2702 /**
2703  * find_dir_for_file:
2704  * @filename: The file to search
2705  * @dirs: A dir paths array, ending by NULL, where to search.
2706  *
2707  * Finds the first dir in the list that contains 'filename', and free the array.
2708  *
2709  * Returns: The dir path if found, NULL either
2710  **/
2711 gchar*
find_dir_for_file(gchar * filename,GList * dirs)2712 find_dir_for_file(gchar* filename, GList* dirs)
2713 {
2714   gchar *dir = NULL;
2715   gchar *path = NULL;
2716   GList* curdir = NULL;
2717 
2718   for(curdir = dirs ; curdir ; curdir = g_list_next(curdir))
2719   {
2720     if(!dir)
2721     {
2722       path = g_build_filename (curdir->data, filename, NULL);
2723       if(g_file_test (path, G_FILE_TEST_EXISTS))
2724           dir = g_strdup(curdir->data); //even though found, the loop is continued to clear the list of dirs
2725      // else here causes a memory leak as path is not used hereafter
2726       g_free(path);
2727     }
2728     g_free(curdir->data);
2729   }
2730   return dir;
2731 }
2732 
2733 /**
2734  * find_dir_for_files:
2735  * @files: The files to search
2736  * @dirs: A dir paths list, where to search.
2737  *
2738  * Finds the first dir in the list that contains 'filename', and free the array.
2739  *
2740  * Returns: The dir path if found, NULL either
2741  **/
2742 gchar*
find_dir_for_files(GList * files,GList * dirs)2743 find_dir_for_files(GList* files, GList* dirs)
2744 {
2745   gchar *dir = NULL;
2746   gchar *path = NULL;
2747   GList* curdir = NULL;
2748   GList* curfile = NULL;
2749 
2750   for(curdir = dirs; curdir; curdir = g_list_next(curdir))
2751   {
2752     for(curfile = files; curfile; curfile = g_list_next(curfile))
2753     {
2754       if(!dir)
2755       {
2756         path = g_build_filename (curdir->data, curfile->data, NULL);
2757         if(g_file_test (path, G_FILE_TEST_EXISTS))
2758           dir = g_strdup(curdir->data);
2759         g_free(path);
2760       }
2761     }
2762     g_free(curdir->data);
2763   }
2764   return dir;
2765 }
2766 
2767 /**
2768  * find_path_for_file:
2769  * @filename: The file to search
2770  * @dirs: A dir paths list, where to search.
2771  *
2772  * Finds the first dir in the list that contains 'filename', and free the array.
2773  *
2774  * Returns: The file path if found, NULL either
2775  **/
2776 gchar*
find_path_for_file(gchar * filename,GList * dirs)2777 find_path_for_file(gchar* filename, GList* dirs)
2778 {
2779   gchar* dir = find_dir_for_file (filename, dirs);
2780   if(dir){
2781     gchar* path = g_build_filename(dir, filename, NULL);
2782     g_free(dir);
2783     return path;
2784   }
2785   return NULL;
2786 }
2787 gchar *
get_project_dir(void)2788 get_project_dir (void) {
2789     if(Denemo.project && Denemo.project->filename->len)
2790         {
2791             return g_path_get_dirname (Denemo.project->filename->str);
2792         }
2793     return g_strdup(g_get_home_dir ());
2794 }
2795 const gchar*
get_local_dir(DenemoDirectory dir)2796 get_local_dir(DenemoDirectory dir)
2797 {
2798   switch(dir)
2799   {
2800     case DENEMO_DIR_COMMANDS:   return COMMANDS_DIR;
2801     case DENEMO_DIR_UI:         return UI_DIR;
2802     case DENEMO_DIR_SOUNDFONTS: return SOUNDFONTS_DIR;
2803     case DENEMO_DIR_PIXMAPS:    return PIXMAPS_DIR;
2804     case DENEMO_DIR_FONTS:      return FONTS_DIR;
2805     case DENEMO_DIR_LOCALE:     return LOCALE_DIR;
2806     case DENEMO_DIR_LILYPOND_INCLUDE:     return LILYPOND_INCLUDE_DIR;
2807     default:         return NULL;
2808   }
2809 }
2810 
2811 gchar*
get_system_dir(DenemoDirectory dir)2812 get_system_dir(DenemoDirectory dir)
2813 {
2814   switch(dir)
2815   {
2816     case DENEMO_DIR_COMMANDS:
2817     case DENEMO_DIR_UI:
2818     case DENEMO_DIR_SOUNDFONTS:
2819     case DENEMO_DIR_FONTS:
2820     case DENEMO_DIR_LILYPOND_INCLUDE:
2821       return g_build_filename(get_system_data_dir (), get_local_dir(dir), NULL);
2822     case DENEMO_DIR_PIXMAPS:
2823       return g_build_filename(get_system_data_dir (), PIXMAPS_DIR, NULL);
2824       break;
2825     case DENEMO_DIR_LOCALE:
2826       return g_strdup(get_system_locale_dir ());
2827       break;
2828     case DENEMO_DIR_BIN:
2829       return g_strdup(get_system_bin_dir ());
2830       break;
2831     default:
2832       return NULL;
2833   }
2834 }
2835 
2836 const gchar*
get_executable_dir()2837 get_executable_dir ()
2838 {
2839   static const gchar* dir = NULL;
2840   if(dir == NULL)
2841   {
2842     char path[1024];
2843     gint n;
2844 #ifdef G_OS_WIN32
2845     GetModuleFileNameW(NULL, path, MAX_PATH);
2846 
2847 #elif defined _MACH_O_
2848     guint size = sizeof (path);
2849     _NSGetExecutablePath (path, &size);
2850 
2851 #else
2852    if ((n=readlink("/proc/self/exe", path, sizeof(path))) < 0)
2853    {
2854     perror("/proc/self/exe");
2855     return NULL;
2856    }
2857    path[n] = 0;
2858 #endif
2859     dir = g_path_get_dirname(path);
2860   }
2861   return dir;
2862 }
2863 
2864 /**
2865  * find:
2866  * @dir: The denemo directory where to search
2867  * @filename: The file to search
2868  *
2869  * Finds a file by searching:
2870  *  - in the local directory
2871  *  - in the executable parent directory
2872  *  - in the user directory
2873  *  - in the system directory
2874  *  - in the system fonts directory
2875  **/
2876 gchar*
find_denemo_file(DenemoDirectory dir,gchar * filename)2877 find_denemo_file (DenemoDirectory dir, gchar* filename)
2878 {
2879   //g_debug("find_denemo_file called with %d and %s\n", dir, filename);
2880   GList* dirs = NULL;
2881   dirs = g_list_append(dirs, g_build_filename(PACKAGE_SOURCE_DIR, get_local_dir (dir), NULL));
2882   dirs = g_list_append(dirs, g_build_filename(get_executable_dir (), "..", get_local_dir (dir), NULL));
2883   dirs = g_list_append(dirs, g_build_filename(get_user_data_dir (TRUE), get_local_dir (dir), NULL));
2884   dirs = g_list_append(dirs, g_strdup(get_system_dir(dir)));
2885   dirs = g_list_append(dirs, g_build_filename(get_executable_dir (), "..", "share","fonts","truetype","denemo", NULL));
2886   return find_path_for_file (filename, dirs);
2887 }
2888 
escape_scheme(gchar * input)2889 gchar *escape_scheme (gchar *input)
2890 {
2891     gchar *c = input -1;
2892     GString *out = g_string_new("");
2893        for(c=input; c && *c; c++)
2894         {
2895             if(*c=='"')
2896                 g_string_append (out, "\\\\\\\"");
2897             else
2898                 if(*c=='\\')
2899                     g_string_append(out, "\\\\");
2900                 else
2901                 {
2902                     g_string_append_printf (out, "%c", *c);
2903                 }
2904         }
2905     return g_string_free(out, FALSE);
2906 }
2907 
shift_held_down(void)2908 gboolean shift_held_down(void)
2909     {
2910         GdkModifierType mask;
2911         GdkWindow *win = gtk_widget_get_window (Denemo.window);
2912 #if GTK_MAJOR_VERSION == 2
2913         gdk_window_get_pointer (win, NULL, NULL, &mask);
2914 #else
2915         gdk_window_get_device_position (win, gdk_device_manager_get_client_pointer (gdk_display_get_device_manager(gdk_display_get_default())) ,NULL, NULL, &mask);
2916 #endif
2917         return (mask & GDK_SHIFT_MASK);
2918     }
2919