ardour
gtkapplication_quartz.mm
Go to the documentation of this file.
1 /* GTK+ application-level integration for the Mac OS X/Cocoa
2  *
3  * Copyright (C) 2007 Pioneer Research Center USA, Inc.
4  * Copyright (C) 2007 Imendio AB
5  * Copyright (C) 2009 Paul Davis
6  *
7  * This is a reimplementation in Cocoa of the sync-menu.c concept
8  * from Imendio, although without the "set quit menu" API since
9  * a Cocoa app needs to handle termination anyway.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; version 2.1
14  * of the License.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the
23  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24  * Boston, MA 02111-1307, USA.
25  */
26 
27 #include <sigc++/signal.h>
28 #include <sigc++/slot.h>
29 
30 #include <string.h>
31 #include <gtk/gtk.h>
32 #include <gdk/gdkkeysyms.h>
35 
36 #import <AppKit/NSMenu.h>
37 #import <AppKit/NSMenuItem.h>
38 #import <AppKit/NSCell.h>
39 #import <AppKit/NSEvent.h>
40 #import <AppKit/NSApplication.h>
41 #import <Foundation/NSString.h>
42 #import <Foundation/NSNotification.h>
43 
44 #define UNUSED_PARAMETER(a) (void) (a)
45 
46 // #define DEBUG(format, ...) g_printerr ("%s: " format, G_STRFUNC, ## __VA_ARGS__)
47 #define DEBUG(format, ...)
48 
49 /* TODO
50  *
51  * - Sync adding/removing/reordering items
52  * - Create on demand? (can this be done with gtk+? ie fill in menu
53  items when the menu is opened)
54  * - Figure out what to do per app/window...
55  *
56  */
57 
58 static gint _exiting = 0;
59 
60 static guint
62 {
63  switch (keyval) {
64  case GDK_BackSpace:
65  return NSBackspaceCharacter;
66  case GDK_Delete:
67  return NSDeleteFunctionKey;
68  case GDK_Pause:
69  return NSPauseFunctionKey;
70  case GDK_Scroll_Lock:
71  return NSScrollLockFunctionKey;
72  case GDK_Sys_Req:
73  return NSSysReqFunctionKey;
74  case GDK_Home:
75  return NSHomeFunctionKey;
76  case GDK_Left:
77  case GDK_leftarrow:
78  return NSLeftArrowFunctionKey;
79  case GDK_Up:
80  case GDK_uparrow:
81  return NSUpArrowFunctionKey;
82  case GDK_Right:
83  case GDK_rightarrow:
84  return NSRightArrowFunctionKey;
85  case GDK_Down:
86  case GDK_downarrow:
87  return NSDownArrowFunctionKey;
88  case GDK_Page_Up:
89  return NSPageUpFunctionKey;
90  case GDK_Page_Down:
91  return NSPageDownFunctionKey;
92  case GDK_End:
93  return NSEndFunctionKey;
94  case GDK_Begin:
95  return NSBeginFunctionKey;
96  case GDK_Select:
97  return NSSelectFunctionKey;
98  case GDK_Print:
99  return NSPrintFunctionKey;
100  case GDK_Execute:
101  return NSExecuteFunctionKey;
102  case GDK_Insert:
103  return NSInsertFunctionKey;
104  case GDK_Undo:
105  return NSUndoFunctionKey;
106  case GDK_Redo:
107  return NSRedoFunctionKey;
108  case GDK_Menu:
109  return NSMenuFunctionKey;
110  case GDK_Find:
111  return NSFindFunctionKey;
112  case GDK_Help:
113  return NSHelpFunctionKey;
114  case GDK_Break:
115  return NSBreakFunctionKey;
116  case GDK_Mode_switch:
117  return NSModeSwitchFunctionKey;
118  case GDK_F1:
119  return NSF1FunctionKey;
120  case GDK_F2:
121  return NSF2FunctionKey;
122  case GDK_F3:
123  return NSF3FunctionKey;
124  case GDK_F4:
125  return NSF4FunctionKey;
126  case GDK_F5:
127  return NSF5FunctionKey;
128  case GDK_F6:
129  return NSF6FunctionKey;
130  case GDK_F7:
131  return NSF7FunctionKey;
132  case GDK_F8:
133  return NSF8FunctionKey;
134  case GDK_F9:
135  return NSF9FunctionKey;
136  case GDK_F10:
137  return NSF10FunctionKey;
138  case GDK_F11:
139  return NSF11FunctionKey;
140  case GDK_F12:
141  return NSF12FunctionKey;
142  case GDK_F13:
143  return NSF13FunctionKey;
144  case GDK_F14:
145  return NSF14FunctionKey;
146  case GDK_F15:
147  return NSF15FunctionKey;
148  case GDK_F16:
149  return NSF16FunctionKey;
150  case GDK_F17:
151  return NSF17FunctionKey;
152  case GDK_F18:
153  return NSF18FunctionKey;
154  case GDK_F19:
155  return NSF19FunctionKey;
156  case GDK_F20:
157  return NSF20FunctionKey;
158  case GDK_F21:
159  return NSF21FunctionKey;
160  case GDK_F22:
161  return NSF22FunctionKey;
162  case GDK_F23:
163  return NSF23FunctionKey;
164  case GDK_F24:
165  return NSF24FunctionKey;
166  case GDK_F25:
167  return NSF25FunctionKey;
168  case GDK_F26:
169  return NSF26FunctionKey;
170  case GDK_F27:
171  return NSF27FunctionKey;
172  case GDK_F28:
173  return NSF28FunctionKey;
174  case GDK_F29:
175  return NSF29FunctionKey;
176  case GDK_F30:
177  return NSF30FunctionKey;
178  case GDK_F31:
179  return NSF31FunctionKey;
180  case GDK_F32:
181  return NSF32FunctionKey;
182  case GDK_F33:
183  return NSF33FunctionKey;
184  case GDK_F34:
185  return NSF34FunctionKey;
186  case GDK_F35:
187  return NSF35FunctionKey;
188  default:
189  break;
190  }
191 
192  return 0;
193 }
194 
195 static gboolean
196 keyval_is_keypad (guint keyval)
197 {
198  switch (keyval) {
199  case GDK_KP_F1:
200  case GDK_KP_F2:
201  case GDK_KP_F3:
202  case GDK_KP_F4:
203  case GDK_KP_Home:
204  case GDK_KP_Left:
205  case GDK_KP_Up:
206  case GDK_KP_Right:
207  case GDK_KP_Down:
208  case GDK_KP_Page_Up:
209  case GDK_KP_Page_Down:
210  case GDK_KP_End:
211  case GDK_KP_Begin:
212  case GDK_KP_Insert:
213  case GDK_KP_Delete:
214  case GDK_KP_Equal:
215  case GDK_KP_Multiply:
216  case GDK_KP_Add:
217  case GDK_KP_Separator:
218  case GDK_KP_Subtract:
219  case GDK_KP_Decimal:
220  case GDK_KP_Divide:
221  case GDK_KP_0:
222  case GDK_KP_1:
223  case GDK_KP_2:
224  case GDK_KP_3:
225  case GDK_KP_4:
226  case GDK_KP_5:
227  case GDK_KP_6:
228  case GDK_KP_7:
229  case GDK_KP_8:
230  case GDK_KP_9:
231  return TRUE;
232  break;
233  default:
234  break;
235  }
236  return FALSE;
237 }
238 
239 static guint
241 {
242  switch (keyval) {
243  case GDK_KP_F1:
244  return GDK_F1;
245  case GDK_KP_F2:
246  return GDK_F2;
247  case GDK_KP_F3:
248  return GDK_F3;
249  case GDK_KP_F4:
250  return GDK_F4;
251  case GDK_KP_Home:
252  return GDK_Home;
253  case GDK_KP_Left:
254  return GDK_Left;
255  case GDK_KP_Up:
256  return GDK_Up;
257  case GDK_KP_Right:
258  return GDK_Right;
259  case GDK_KP_Down:
260  return GDK_Down;
261  case GDK_KP_Page_Up:
262  return GDK_Page_Up;
263  case GDK_KP_Page_Down:
264  return GDK_Page_Down;
265  case GDK_KP_End:
266  return GDK_End;
267  case GDK_KP_Begin:
268  return GDK_Begin;
269  case GDK_KP_Insert:
270  return GDK_Insert;
271  case GDK_KP_Delete:
272  return GDK_Delete;
273  case GDK_KP_Equal:
274  return GDK_equal;
275  case GDK_KP_Multiply:
276  return GDK_asterisk;
277  case GDK_KP_Add:
278  return GDK_plus;
279  case GDK_KP_Subtract:
280  return GDK_minus;
281  case GDK_KP_Decimal:
282  return GDK_period;
283  case GDK_KP_Divide:
284  return GDK_slash;
285  case GDK_KP_0:
286  return GDK_0;
287  case GDK_KP_1:
288  return GDK_1;
289  case GDK_KP_2:
290  return GDK_2;
291  case GDK_KP_3:
292  return GDK_3;
293  case GDK_KP_4:
294  return GDK_4;
295  case GDK_KP_5:
296  return GDK_5;
297  case GDK_KP_6:
298  return GDK_6;
299  case GDK_KP_7:
300  return GDK_7;
301  case GDK_KP_8:
302  return GDK_8;
303  case GDK_KP_9:
304  return GDK_9;
305  default:
306  break;
307  }
308 
309  return GDK_VoidSymbol;
310 }
311 
312 static const gchar*
314 {
315  switch (keyval) {
316  case GDK_space:
317  return " ";
318  case GDK_exclam:
319  return "!";
320  case GDK_quotedbl:
321  return "\"";
322  case GDK_numbersign:
323  return "#";
324  case GDK_dollar:
325  return "$";
326  case GDK_percent:
327  return "%";
328  case GDK_ampersand:
329  return "&";
330  case GDK_apostrophe:
331  return "'";
332  case GDK_parenleft:
333  return "(";
334  case GDK_parenright:
335  return ")";
336  case GDK_asterisk:
337  return "*";
338  case GDK_plus:
339  return "+";
340  case GDK_comma:
341  return ",";
342  case GDK_minus:
343  return "-";
344  case GDK_period:
345  return ".";
346  case GDK_slash:
347  return "/";
348  case GDK_0:
349  return "0";
350  case GDK_1:
351  return "1";
352  case GDK_2:
353  return "2";
354  case GDK_3:
355  return "3";
356  case GDK_4:
357  return "4";
358  case GDK_5:
359  return "5";
360  case GDK_6:
361  return "6";
362  case GDK_7:
363  return "7";
364  case GDK_8:
365  return "8";
366  case GDK_9:
367  return "9";
368  case GDK_colon:
369  return ":";
370  case GDK_semicolon:
371  return ";";
372  case GDK_less:
373  return "<";
374  case GDK_equal:
375  return "=";
376  case GDK_greater:
377  return ">";
378  case GDK_question:
379  return "?";
380  case GDK_at:
381  return "@";
382  case GDK_A:
383  case GDK_a:
384  return "a";
385  case GDK_B:
386  case GDK_b:
387  return "b";
388  case GDK_C:
389  case GDK_c:
390  return "c";
391  case GDK_D:
392  case GDK_d:
393  return "d";
394  case GDK_E:
395  case GDK_e:
396  return "e";
397  case GDK_F:
398  case GDK_f:
399  return "f";
400  case GDK_G:
401  case GDK_g:
402  return "g";
403  case GDK_H:
404  case GDK_h:
405  return "h";
406  case GDK_I:
407  case GDK_i:
408  return "i";
409  case GDK_J:
410  case GDK_j:
411  return "j";
412  case GDK_K:
413  case GDK_k:
414  return "k";
415  case GDK_L:
416  case GDK_l:
417  return "l";
418  case GDK_M:
419  case GDK_m:
420  return "m";
421  case GDK_N:
422  case GDK_n:
423  return "n";
424  case GDK_O:
425  case GDK_o:
426  return "o";
427  case GDK_P:
428  case GDK_p:
429  return "p";
430  case GDK_Q:
431  case GDK_q:
432  return "q";
433  case GDK_R:
434  case GDK_r:
435  return "r";
436  case GDK_S:
437  case GDK_s:
438  return "s";
439  case GDK_T:
440  case GDK_t:
441  return "t";
442  case GDK_U:
443  case GDK_u:
444  return "u";
445  case GDK_V:
446  case GDK_v:
447  return "v";
448  case GDK_W:
449  case GDK_w:
450  return "w";
451  case GDK_X:
452  case GDK_x:
453  return "x";
454  case GDK_Y:
455  case GDK_y:
456  return "y";
457  case GDK_Z:
458  case GDK_z:
459  return "z";
460  case GDK_bracketleft:
461  return "[";
462  case GDK_backslash:
463  return "\\";
464  case GDK_bracketright:
465  return "]";
466  case GDK_asciicircum:
467  return "^";
468  case GDK_underscore:
469  return "_";
470  case GDK_grave:
471  return "`";
472  case GDK_braceleft:
473  return "{";
474  case GDK_bar:
475  return "|";
476  case GDK_braceright:
477  return "}";
478  case GDK_asciitilde:
479  return "~";
480  default:
481  break;
482  }
483  return NULL;
484 };
485 
486 static gboolean
487 keyval_is_uppercase (guint keyval)
488 {
489  switch (keyval) {
490  case GDK_A:
491  case GDK_B:
492  case GDK_C:
493  case GDK_D:
494  case GDK_E:
495  case GDK_F:
496  case GDK_G:
497  case GDK_H:
498  case GDK_I:
499  case GDK_J:
500  case GDK_K:
501  case GDK_L:
502  case GDK_M:
503  case GDK_N:
504  case GDK_O:
505  case GDK_P:
506  case GDK_Q:
507  case GDK_R:
508  case GDK_S:
509  case GDK_T:
510  case GDK_U:
511  case GDK_V:
512  case GDK_W:
513  case GDK_X:
514  case GDK_Y:
515  case GDK_Z:
516  return TRUE;
517  default:
518  return FALSE;
519  }
520  return FALSE;
521 }
522 
523 /* gtk/osx has a problem in that mac main menu events
524  are handled using an "internal" event handling system that
525  doesn't pass things back to the glib/gtk main loop. if we call
526  gtk_main_iteration() block while in a menu event handler, then
527  glib gets confused and thinks there are two threads running
528  g_main_poll_func(). apps call call gdk_quartz_in_menu_event_handler()
529  if they need to check this.
530  */
531 
532 static int _in_menu_event_handler = 0;
533 
534 int
536 {
537  return _in_menu_event_handler;
538 }
539 
540 static gboolean
541 idle_call_activate (gpointer data)
542 {
543  gtk_menu_item_activate ((GtkMenuItem*) data);
544  return FALSE;
545 }
546 
547 @interface GNSMenuItem : NSMenuItem
548 {
549  @public
550  GtkMenuItem* gtk_menu_item;
551  GClosure *accel_closure;
552 }
553 - (id) initWithTitle:(NSString*) title andGtkWidget:(GtkMenuItem*) w;
554 - (void) activate:(id) sender;
555 @end
556 
557 @implementation GNSMenuItem
558 - (id) initWithTitle:(NSString*) title andGtkWidget:(GtkMenuItem*) w
559 {
560  /* All menu items have the action "activate", which will be handled by this child class
561  */
562 
563  self = [ super initWithTitle:title action:@selector(activate:) keyEquivalent:@"" ];
564 
565  if (self) {
566  /* make this handle its own action */
567  [ self setTarget:self ];
568  gtk_menu_item = w;
569  accel_closure = 0;
570  }
571  return self;
572 }
573 - (void) activate:(id) sender
574 {
575  UNUSED_PARAMETER(sender);
576  g_idle_add (idle_call_activate, gtk_menu_item);
577 }
578 @end
579 
580 static void push_menu_shell_to_nsmenu (GtkMenuShell *menu_shell,
581  NSMenu *menu,
582  gboolean toplevel,
583  gboolean debug);
584 
585 /*
586  * utility functions
587  */
588 
589 static GtkWidget *
590 find_menu_label (GtkWidget *widget)
591 {
592  GtkWidget *label = NULL;
593 
594  if (GTK_IS_LABEL (widget))
595  return widget;
596 
597  if (GTK_IS_CONTAINER (widget))
598  {
599  GList *children;
600  GList *l;
601 
602  children = gtk_container_get_children (GTK_CONTAINER (widget));
603 
604  for (l = children; l; l = l->next)
605  {
606  label = find_menu_label ((GtkWidget*) l->data);
607  if (label)
608  break;
609  }
610 
611  g_list_free (children);
612  }
613 
614  return label;
615 }
616 
617 static const gchar *
618 get_menu_label_text (GtkWidget *menu_item,
619  GtkWidget **label)
620 {
621  GtkWidget *my_label;
622 
623  my_label = find_menu_label (menu_item);
624  if (label)
625  *label = my_label;
626 
627  if (my_label)
628  return gtk_label_get_text (GTK_LABEL (my_label));
629 
630  return NULL;
631 }
632 
633 static gboolean
634 accel_find_func (GtkAccelKey * /*key*/,
635  GClosure *closure,
636  gpointer data)
637 {
638  return (GClosure *) data == closure;
639 }
640 
641 
642 /*
643  * CocoaMenu functions
644  */
645 
646 static GQuark cocoa_menu_quark = 0;
647 
648 static NSMenu *
649 cocoa_menu_get (GtkWidget *widget)
650 {
651  return (NSMenu*) g_object_get_qdata (G_OBJECT (widget), cocoa_menu_quark);
652 }
653 
654 static void
655 cocoa_menu_free (gpointer *ptr)
656 {
657  NSMenu* menu = (NSMenu*) ptr;
658  [menu release];
659 }
660 
661 static void
662 cocoa_menu_connect (GtkWidget *menu,
663  NSMenu* cocoa_menu)
664 {
665  [cocoa_menu retain];
666 
667  if (cocoa_menu_quark == 0)
668  cocoa_menu_quark = g_quark_from_static_string ("NSMenu");
669 
670  g_object_set_qdata_full (G_OBJECT (menu), cocoa_menu_quark,
671  cocoa_menu,
672  (GDestroyNotify) cocoa_menu_free);
673 }
674 
675 /*
676  * NSMenuItem functions
677  */
678 
679 static GQuark cocoa_menu_item_quark = 0;
680 static void cocoa_menu_item_connect (GtkWidget* menu_item,
681  GNSMenuItem* cocoa_menu_item,
682  GtkWidget *label);
683 
684 static void
685 cocoa_menu_item_free (gpointer *ptr)
686 {
687  GNSMenuItem* item = (GNSMenuItem*) ptr;
688  [item release];
689 }
690 
691 static GNSMenuItem *
692 cocoa_menu_item_get (GtkWidget *widget)
693 {
694  return (GNSMenuItem*) g_object_get_qdata (G_OBJECT (widget), cocoa_menu_item_quark);
695 }
696 
697 static void
698 cocoa_menu_item_update_state (NSMenuItem* cocoa_item,
699  GtkWidget *widget)
700 {
701  gboolean sensitive;
702  gboolean visible;
703 
704  g_object_get (widget,
705  "sensitive", &sensitive,
706  "visible", &visible,
707  NULL);
708 
709  if (!sensitive)
710  [cocoa_item setEnabled:NO];
711  else
712  [cocoa_item setEnabled:YES];
713 
714 #if 0
715  // requires OS X 10.5 or later
716  if (!visible)
717  [cocoa_item setHidden:YES];
718  else
719  [cocoa_item setHidden:NO];
720 #endif
721 }
722 
723 static void
724 cocoa_menu_item_update_active (NSMenuItem *cocoa_item,
725  GtkWidget *widget)
726 {
727  gboolean active;
728 
729  g_object_get (widget, "active", &active, NULL);
730 
731  if (active)
732  [cocoa_item setState:NSOnState];
733  else
734  [cocoa_item setState:NSOffState];
735 }
736 
737 static void
738 cocoa_menu_item_update_submenu (NSMenuItem *cocoa_item,
739  GtkWidget *widget)
740 {
741  GtkWidget *submenu;
742 
743  g_return_if_fail (cocoa_item != NULL);
744  g_return_if_fail (widget != NULL);
745 
746  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
747 
748  if (submenu)
749  {
750  GtkWidget* label = NULL;
751  const gchar *label_text;
752  NSMenu* cocoa_submenu;
753 
754  label_text = get_menu_label_text (widget, &label);
755 
756  /* create a new nsmenu to hold the GTK menu */
757 
758  if (label_text)
759  cocoa_submenu = [ [ NSMenu alloc ] initWithTitle:[ [ NSString alloc] initWithCString:label_text encoding:NSUTF8StringEncoding]];
760  else
761  cocoa_submenu = [ [ NSMenu alloc ] initWithTitle:@""];
762 
763  [cocoa_submenu setAutoenablesItems:NO];
764  cocoa_menu_connect (submenu, cocoa_submenu);
765 
766  /* connect the new nsmenu to the passed-in item (which lives in
767  the parent nsmenu)
768  (Note: this will release any pre-existing version of this submenu)
769  */
770  [ cocoa_item setSubmenu:cocoa_submenu];
771 
772  /* and push the GTK menu into the submenu */
773  push_menu_shell_to_nsmenu (GTK_MENU_SHELL (submenu), cocoa_submenu, FALSE, FALSE);
774 
775  [ cocoa_submenu release ];
776  }
777 }
778 
779 static void
780 cocoa_menu_item_update_label (NSMenuItem *cocoa_item,
781  GtkWidget *widget)
782 {
783  const gchar *label_text;
784 
785  g_return_if_fail (cocoa_item != NULL);
786  g_return_if_fail (widget != NULL);
787 
788  label_text = get_menu_label_text (widget, NULL);
789  if (label_text)
790  [cocoa_item setTitle:[ [ NSString alloc] initWithCString:label_text encoding:NSUTF8StringEncoding]];
791  else
792  [cocoa_item setTitle:@""];
793 }
794 
795 static void
796 cocoa_menu_item_update_accelerator (NSMenuItem *cocoa_item,
797  GtkWidget *widget)
798 {
799  GtkWidget *label;
800 
801  g_return_if_fail (cocoa_item != NULL);
802  g_return_if_fail (widget != NULL);
803 
804  /* important note: this function doesn't do anything to actually change
805  key handling. Its goal is to get Cocoa to display the correct
806  accelerator as part of a menu item. Actual accelerator handling
807  is still done by GTK, so this is more cosmetic than it may
808  appear.
809  */
810 
811  get_menu_label_text (widget, &label);
812 
813  if (GTK_IS_ACCEL_LABEL (label) &&
814  GTK_ACCEL_LABEL (label)->accel_closure)
815  {
816  GtkAccelKey *key;
817 
818  key = gtk_accel_group_find (GTK_ACCEL_LABEL (label)->accel_group,
820  GTK_ACCEL_LABEL (label)->accel_closure);
821 
822  if (key &&
823  key->accel_key &&
824  key->accel_flags & GTK_ACCEL_VISIBLE)
825  {
826  guint modifiers = 0;
827  const gchar* str = NULL;
828  guint actual_key = key->accel_key;
829 
830  if (keyval_is_keypad (actual_key)) {
831  if ((actual_key = keyval_keypad_nonkeypad_equivalent (actual_key)) == GDK_VoidSymbol) {
832  /* GDK_KP_Separator */
833  [cocoa_item setKeyEquivalent:@""];
834  return;
835  }
836  modifiers |= NSNumericPadKeyMask;
837  }
838 
839  /* if we somehow got here with GDK_A ... GDK_Z rather than GDK_a ... GDK_z, then take note
840  of that and make sure we use a shift modifier.
841  */
842 
843  if (keyval_is_uppercase (actual_key)) {
844  modifiers |= NSShiftKeyMask;
845  }
846 
847  str = gdk_quartz_keyval_to_string (actual_key);
848 
849  if (str) {
850  unichar ukey = str[0];
851  [cocoa_item setKeyEquivalent:[NSString stringWithCharacters:&ukey length:1]];
852  } else {
853  unichar ukey = gdk_quartz_keyval_to_ns_keyval (actual_key);
854  if (ukey != 0) {
855  [cocoa_item setKeyEquivalent:[NSString stringWithCharacters:&ukey length:1]];
856  } else {
857  /* cannot map this key to Cocoa key equivalent */
858  [cocoa_item setKeyEquivalent:@""];
859  return;
860  }
861  }
862 
863  if (key->accel_mods || modifiers)
864  {
865  if (key->accel_mods & GDK_SHIFT_MASK) {
866  modifiers |= NSShiftKeyMask;
867  }
868 
869  /* gdk/quartz maps Alt/Option to Mod1 */
870 
871  if (key->accel_mods & (GDK_MOD1_MASK)) {
872  modifiers |= NSAlternateKeyMask;
873  }
874 
875  if (key->accel_mods & GDK_CONTROL_MASK) {
876  modifiers |= NSControlKeyMask;
877  }
878 
879  /* gdk/quartz maps Command to Meta (XXX check this - it may move to SUPER at some point) */
880 
881  if (key->accel_mods & GDK_META_MASK) {
882  modifiers |= NSCommandKeyMask;
883  }
884  }
885 
886  [cocoa_item setKeyEquivalentModifierMask:modifiers];
887  return;
888  }
889  }
890 
891  /* otherwise, clear the menu shortcut */
892  [cocoa_item setKeyEquivalent:@""];
893 }
894 
895 static void
896 cocoa_menu_item_accel_changed (GtkAccelGroup* /*accel_group*/,
897  guint /*keyval*/,
898  GdkModifierType /*modifier*/,
899  GClosure *accel_closure,
900  GtkWidget *widget)
901 {
902  GNSMenuItem *cocoa_item;
903  GtkWidget *label;
904 
905  if (_exiting)
906  return;
907 
908  cocoa_item = cocoa_menu_item_get (widget);
909  get_menu_label_text (widget, &label);
910 
911  if (GTK_IS_ACCEL_LABEL (label) &&
912  GTK_ACCEL_LABEL (label)->accel_closure == accel_closure)
913  cocoa_menu_item_update_accelerator (cocoa_item, widget);
914 }
915 
916 static void
918  GtkWidget *widget)
919 {
920  GtkAccelGroup *group;
921  GtkWidget *label;
922 
923  get_menu_label_text (widget, &label);
924 
925  if (cocoa_item->accel_closure)
926  {
927  group = gtk_accel_group_from_accel_closure (cocoa_item->accel_closure);
928 
929  g_signal_handlers_disconnect_by_func (group,
931  widget);
932 
933  g_closure_unref (cocoa_item->accel_closure);
934  cocoa_item->accel_closure = NULL;
935  }
936 
937  if (GTK_IS_ACCEL_LABEL (label)) {
938  cocoa_item->accel_closure = GTK_ACCEL_LABEL (label)->accel_closure;
939  }
940 
941  if (cocoa_item->accel_closure)
942  {
943  g_closure_ref (cocoa_item->accel_closure);
944 
945  group = gtk_accel_group_from_accel_closure (cocoa_item->accel_closure);
946 
947  g_signal_connect_object (group, "accel-changed",
948  G_CALLBACK (cocoa_menu_item_accel_changed),
949  widget, (GConnectFlags) 0);
950  }
951 
952  cocoa_menu_item_update_accelerator (cocoa_item, widget);
953 }
954 
955 static void
957  GParamSpec *pspec,
958  gpointer)
959 {
960  GNSMenuItem *cocoa_item;
961 
962  if (_exiting)
963  return;
964 
965  cocoa_item = cocoa_menu_item_get (GTK_WIDGET (object));
966 
967  if (!strcmp (pspec->name, "label"))
968  {
969  cocoa_menu_item_update_label (cocoa_item,
970  GTK_WIDGET (object));
971  }
972  else if (!strcmp (pspec->name, "accel-closure"))
973  {
975  GTK_WIDGET (object));
976  }
977 }
978 
979 static void
980 cocoa_menu_item_notify (GObject *object,
981  GParamSpec *pspec,
982  NSMenuItem *cocoa_item)
983 {
984  if (_exiting)
985  return;
986 
987  if (!strcmp (pspec->name, "sensitive") ||
988  !strcmp (pspec->name, "visible"))
989  {
990  cocoa_menu_item_update_state (cocoa_item, GTK_WIDGET (object));
991  }
992  else if (!strcmp (pspec->name, "active"))
993  {
994  cocoa_menu_item_update_active (cocoa_item, GTK_WIDGET (object));
995  }
996  else if (!strcmp (pspec->name, "submenu"))
997  {
998  cocoa_menu_item_update_submenu (cocoa_item, GTK_WIDGET (object));
999  }
1000 }
1001 
1002 static void
1003 cocoa_menu_item_connect (GtkWidget* menu_item,
1004  GNSMenuItem* cocoa_item,
1005  GtkWidget *label)
1006 {
1007  GNSMenuItem* old_item = cocoa_menu_item_get (menu_item);
1008 
1009  [cocoa_item retain];
1010 
1011  if (cocoa_menu_item_quark == 0)
1012  cocoa_menu_item_quark = g_quark_from_static_string ("NSMenuItem");
1013 
1014  g_object_set_qdata_full (G_OBJECT (menu_item), cocoa_menu_item_quark,
1015  cocoa_item,
1016  (GDestroyNotify) cocoa_menu_item_free);
1017 
1018  if (!old_item) {
1019 
1020  g_signal_connect (menu_item, "notify",
1021  G_CALLBACK (cocoa_menu_item_notify),
1022  cocoa_item);
1023 
1024  if (label)
1025  g_signal_connect_swapped (label, "notify::label",
1026  G_CALLBACK (cocoa_menu_item_notify_label),
1027  menu_item);
1028  }
1029 }
1030 
1031 static void
1032 add_menu_item (NSMenu* cocoa_menu, GtkWidget* menu_item, int index)
1033 {
1034  GtkWidget* label = NULL;
1035  GNSMenuItem *cocoa_item;
1036 
1037  DEBUG ("add %s to menu %s separator ? %d\n", get_menu_label_text (menu_item, NULL),
1038  [[cocoa_menu title] cStringUsingEncoding:NSUTF8StringEncoding],
1039  GTK_IS_SEPARATOR_MENU_ITEM(menu_item));
1040 
1041  cocoa_item = cocoa_menu_item_get (menu_item);
1042 
1043  if (cocoa_item)
1044  return;
1045 
1046  if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item)) {
1047  cocoa_item = [NSMenuItem separatorItem];
1048  DEBUG ("\ta separator\n");
1049  } else {
1050 
1051  if (!GTK_WIDGET_VISIBLE (menu_item)) {
1052  DEBUG ("\tnot visible\n");
1053  return;
1054  }
1055 
1056  const gchar* label_text = get_menu_label_text (menu_item, &label);
1057 
1058  if (label_text)
1059  cocoa_item = [ [ GNSMenuItem alloc] initWithTitle:[ [ NSString alloc] initWithCString:label_text encoding:NSUTF8StringEncoding]
1060  andGtkWidget:(GtkMenuItem*)menu_item];
1061  else
1062  cocoa_item = [ [ GNSMenuItem alloc] initWithTitle:@"" andGtkWidget:(GtkMenuItem*)menu_item];
1063  DEBUG ("\tan item\n");
1064  }
1065 
1066  /* connect GtkMenuItem and NSMenuItem so that we can notice changes to accel/label/submenu etc. */
1067  cocoa_menu_item_connect (menu_item, (GNSMenuItem*) cocoa_item, label);
1068 
1069  [ cocoa_item setEnabled:YES];
1070  if (index >= 0)
1071  [ cocoa_menu insertItem:cocoa_item atIndex:index];
1072  else
1073  [ cocoa_menu addItem:cocoa_item];
1074 
1075  if (!GTK_WIDGET_IS_SENSITIVE (menu_item))
1076  [cocoa_item setState:NSOffState];
1077 
1078 #if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
1079  if (!GTK_WIDGET_VISIBLE (menu_item))
1080  [cocoa_item setHidden:YES];
1081 #endif
1082 
1083  if (GTK_IS_CHECK_MENU_ITEM (menu_item))
1084  cocoa_menu_item_update_active (cocoa_item, menu_item);
1085 
1086  if (!GTK_IS_SEPARATOR_MENU_ITEM (menu_item))
1087  cocoa_menu_item_update_accel_closure (cocoa_item, menu_item);
1088 
1089  if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item)))
1090  cocoa_menu_item_update_submenu (cocoa_item, menu_item);
1091 
1092  [ cocoa_item release];
1093 }
1094 
1095 static void
1096 push_menu_shell_to_nsmenu (GtkMenuShell *menu_shell,
1097  NSMenu* cocoa_menu,
1098  gboolean /*toplevel*/,
1099  gboolean /*debug*/)
1100 {
1101  GList *children;
1102  GList *l;
1103 
1104  children = gtk_container_get_children (GTK_CONTAINER (menu_shell));
1105 
1106  for (l = children; l; l = l->next)
1107  {
1108  GtkWidget *menu_item = (GtkWidget*) l->data;
1109 
1110  if (GTK_IS_TEAROFF_MENU_ITEM (menu_item))
1111  continue;
1112 
1113  if (g_object_get_data (G_OBJECT (menu_item), "gtk-empty-menu-item"))
1114  continue;
1115 
1116  add_menu_item (cocoa_menu, menu_item, -1);
1117  }
1118 
1119  g_list_free (children);
1120 }
1121 
1122 
1123 static gulong emission_hook_id = 0;
1124 
1125 static gboolean
1126 parent_set_emission_hook (GSignalInvocationHint* /*ihint*/,
1127  guint /*n_param_values*/,
1128  const GValue* param_values,
1129  gpointer data)
1130 {
1131  GtkWidget *instance = (GtkWidget*) g_value_get_object (param_values);
1132 
1133  if (GTK_IS_MENU_ITEM (instance))
1134  {
1135  GtkWidget *previous_parent = (GtkWidget*) g_value_get_object (param_values + 1);
1136  GtkWidget *menu_shell = NULL;
1137 
1138  if (GTK_IS_MENU_SHELL (previous_parent))
1139  {
1140  menu_shell = previous_parent;
1141  }
1142  else if (GTK_IS_MENU_SHELL (instance->parent))
1143  {
1144  menu_shell = instance->parent;
1145  }
1146 
1147  if (menu_shell)
1148  {
1149  NSMenu *cocoa_menu = cocoa_menu_get (menu_shell);
1150 
1151  if (cocoa_menu)
1152  {
1153  push_menu_shell_to_nsmenu (GTK_MENU_SHELL (menu_shell),
1154  cocoa_menu,
1155  cocoa_menu == (NSMenu*) data,
1156  FALSE);
1157  }
1158  }
1159  }
1160 
1161  return TRUE;
1162 }
1163 
1164 static void
1165 parent_set_emission_hook_remove (GtkWidget*, gpointer)
1166 {
1167  g_signal_remove_emission_hook (g_signal_lookup ("parent-set", GTK_TYPE_WIDGET),
1169 }
1170 
1171 /* Building "standard" Cocoa/OS X menus */
1172 
1173 #warning You can safely ignore the next warning about a duplicate interface definition
1175  - (void)setAppleMenu:(NSMenu *)aMenu;
1176 @end
1177 
1178 static NSMenu* _main_menubar = 0;
1179 static NSMenu* _window_menu = 0;
1180 static NSMenu* _app_menu = 0;
1181 
1182 static int
1183 add_to_menubar (NSMenu *menu)
1184 {
1185  NSMenuItem *dummyItem = [[NSMenuItem alloc] initWithTitle:@""
1186  action:nil keyEquivalent:@""];
1187  [dummyItem setSubmenu:menu];
1188  [_main_menubar addItem:dummyItem];
1189  [dummyItem release];
1190  return 0;
1191 }
1192 
1193 #if 0
1194 static int
1195 add_to_app_menu (NSMenu *menu)
1196 {
1197  NSMenuItem *dummyItem = [[NSMenuItem alloc] initWithTitle:@""
1198  action:nil keyEquivalent:@""];
1199  [dummyItem setSubmenu:menu];
1200  [_app_menu addItem:dummyItem];
1201  [dummyItem release];
1202  return 0;
1203 }
1204 #endif
1205 
1206 static int
1208 {
1209  NSMenuItem *menuitem;
1210  // Create the application (Apple) menu.
1211  _app_menu = [[NSMenu alloc] initWithTitle: @"Apple Menu"];
1212 
1213  NSMenu *menuServices = [[NSMenu alloc] initWithTitle: @"Services"];
1214  [NSApp setServicesMenu:menuServices];
1215 
1216  [_app_menu addItem: [NSMenuItem separatorItem]];
1217  menuitem = [[NSMenuItem alloc] initWithTitle: @"Services"
1218  action:nil keyEquivalent:@""];
1219  [menuitem setSubmenu:menuServices];
1220  [_app_menu addItem: menuitem];
1221  [menuitem release];
1222  [_app_menu addItem: [NSMenuItem separatorItem]];
1223  menuitem = [[NSMenuItem alloc] initWithTitle:@"Hide"
1224  action:@selector(hide:) keyEquivalent:@""];
1225  [menuitem setTarget: NSApp];
1226  [_app_menu addItem: menuitem];
1227  [menuitem release];
1228  menuitem = [[NSMenuItem alloc] initWithTitle:@"Hide Others"
1229  action:@selector(hideOtherApplications:) keyEquivalent:@""];
1230  [menuitem setTarget: NSApp];
1231  [_app_menu addItem: menuitem];
1232  [menuitem release];
1233  menuitem = [[NSMenuItem alloc] initWithTitle:@"Show All"
1234  action:@selector(unhideAllApplications:) keyEquivalent:@""];
1235  [menuitem setTarget: NSApp];
1236  [_app_menu addItem: menuitem];
1237  [menuitem release];
1238  [_app_menu addItem: [NSMenuItem separatorItem]];
1239  menuitem = [[NSMenuItem alloc] initWithTitle:@"Quit"
1240  action:@selector(terminate:) keyEquivalent:@"q"];
1241  [menuitem setTarget: NSApp];
1242  [_app_menu addItem: menuitem];
1243  [menuitem release];
1244 
1245  [NSApp setAppleMenu:_app_menu];
1247 
1248  return 0;
1249 }
1250 
1251 #if 0
1252 static int
1253 add_to_window_menu (NSMenu *menu)
1254 {
1255  NSMenuItem *dummyItem = [[NSMenuItem alloc] initWithTitle:@""
1256  action:nil keyEquivalent:@""];
1257  [dummyItem setSubmenu:menu];
1258  [_window_menu addItem:dummyItem];
1259  [dummyItem release];
1260  return 0;
1261 }
1262 
1263 static int
1264 create_window_menu ()
1265 {
1266  _window_menu = [[NSMenu alloc] initWithTitle: @"Window"];
1267 
1268  [_window_menu addItemWithTitle:@"Minimize"
1269  action:@selector(performMiniaturize:) keyEquivalent:@""];
1270  [_window_menu addItem: [NSMenuItem separatorItem]];
1271  [_window_menu addItemWithTitle:@"Bring All to Front"
1272  action:@selector(arrangeInFront:) keyEquivalent:@""];
1273 
1274  [NSApp setWindowsMenu:_window_menu];
1276 
1277  return 0;
1278 }
1279 #endif
1280 
1281 /*
1282  * public functions
1283  */
1284 
1285 extern "C" void
1286 gtk_application_set_menu_bar (GtkMenuShell *menu_shell)
1287 {
1288  NSMenu* cocoa_menubar;
1289 
1290  g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1291 
1292  if (cocoa_menu_quark == 0)
1293  cocoa_menu_quark = g_quark_from_static_string ("NSMenu");
1294 
1295  if (cocoa_menu_item_quark == 0)
1296  cocoa_menu_item_quark = g_quark_from_static_string ("NSMenuItem");
1297 
1298  cocoa_menubar = [ [ NSApplication sharedApplication] mainMenu];
1299 
1300  /* turn off auto-enabling for the menu - its silly and slow and
1301  doesn't really make sense for a Gtk/Cocoa hybrid menu.
1302  */
1303 
1304  [cocoa_menubar setAutoenablesItems:NO];
1305 
1307  g_signal_add_emission_hook (g_signal_lookup ("parent-set",
1308  GTK_TYPE_WIDGET),
1309  0,
1311  cocoa_menubar, NULL);
1312 
1313 
1314  g_signal_connect (menu_shell, "destroy",
1315  G_CALLBACK (parent_set_emission_hook_remove),
1316  NULL);
1317 
1318  push_menu_shell_to_nsmenu (menu_shell, cocoa_menubar, TRUE, FALSE);
1319 }
1320 
1321 extern "C" void
1323  GtkMenuItem *menu_item)
1324 {
1325  // we know that the application menu is always the submenu of the first item in the main menu
1326  NSMenu* mainMenu;
1327  NSMenu *appMenu;
1328  NSMenuItem *firstItem;
1329  GList *list;
1330  gint index = 0;
1331 
1332  mainMenu = [NSApp mainMenu];
1333  firstItem = [ mainMenu itemAtIndex:0];
1334  appMenu = [ firstItem submenu ];
1335 
1336  g_return_if_fail (group != NULL);
1337  g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1338 
1339  for (list = _gtk_application_menu_groups; list; list = g_list_next (list))
1340  {
1341  GtkApplicationMenuGroup *list_group = (GtkApplicationMenuGroup*) list->data;
1342 
1343  index += g_list_length (list_group->items);
1344 
1345  /* adjust index for the separator between groups, but not
1346  * before the first group
1347  */
1348  if (list_group->items && list->prev)
1349  index++;
1350 
1351  if (group == list_group)
1352  {
1353  /* add a separator before adding the first item, but not
1354  * for the first group
1355  */
1356 
1357  if (!group->items && list->prev)
1358  {
1359  [appMenu insertItem:[NSMenuItem separatorItem] atIndex:index+1];
1360  index++;
1361  }
1362  DEBUG ("Add to APP menu bar %s\n", get_menu_label_text (GTK_WIDGET(menu_item), NULL));
1363  add_menu_item (appMenu, GTK_WIDGET(menu_item), index+1);
1364 
1365  group->items = g_list_append (group->items, menu_item);
1366  gtk_widget_hide (GTK_WIDGET (menu_item));
1367  return;
1368  }
1369  }
1370 
1371  if (!list)
1372  g_warning ("%s: app menu group %p does not exist",
1373  G_STRFUNC, group);
1374 }
1375 
1376 /* application delegate, currently in C++ */
1377 
1378 #include <gtkmm2ext/application.h>
1379 #include <glibmm/ustring.h>
1380 
1381 namespace Gtk {
1382  namespace Application {
1383  sigc::signal<void,bool> ActivationChanged;
1384  sigc::signal<void,const Glib::ustring&> ShouldLoad;
1385  sigc::signal<void> ShouldQuit;
1386  }
1387 }
1388 
1389 @interface GtkApplicationNotificationObject : NSObject {}
1391 @end
1392 
1393 @implementation GtkApplicationNotificationObject
1395 {
1396  self = [ super init ];
1397 
1398  if (self) {
1399  [[NSNotificationCenter defaultCenter] addObserver:self
1400  selector:@selector(appDidBecomeActive:)
1401  name:NSApplicationDidBecomeActiveNotification
1402  object:[NSApplication sharedApplication]];
1403 
1404  [[NSNotificationCenter defaultCenter] addObserver:self
1405  selector:@selector(appDidBecomeInactive:)
1406  name:NSApplicationWillResignActiveNotification
1407  object:[NSApplication sharedApplication]];
1408  }
1409 
1410  return self;
1411 }
1412 
1413 - (void)appDidBecomeActive:(NSNotification *) notification
1414 {
1415  UNUSED_PARAMETER(notification);
1417 }
1418 
1419 - (void)appDidBecomeInactive:(NSNotification *) notification
1420 {
1421  UNUSED_PARAMETER(notification);
1423 }
1424 
1425 @end
1426 
1427 @interface GtkApplicationDelegate : NSObject
1428 -(BOOL) application:(NSApplication*) app openFile:(NSString*) file;
1429 - (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication *) app;
1430 @end
1431 
1432 @implementation GtkApplicationDelegate
1433 -(BOOL) application:(NSApplication*) app openFile:(NSString*) file
1434 {
1435  UNUSED_PARAMETER(app);
1436  Glib::ustring utf8_path ([file UTF8String]);
1438  return 1;
1439 }
1440 - (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication *) app
1441 {
1442  UNUSED_PARAMETER(app);
1444  return NSTerminateCancel;
1445 }
1446 @end
1447 
1448 
1449 /* Basic setup */
1450 
1451 extern "C" int
1453 {
1454  _main_menubar = [[NSMenu alloc] initWithTitle: @""];
1455 
1456  if (!_main_menubar)
1457  return -1;
1458 
1459  [NSApp setMainMenu: _main_menubar];
1460  create_apple_menu ();
1461  // create_window_menu ();
1462 
1463  /* this will stick around for ever ... is that OK ? */
1464 
1465  [ [GtkApplicationNotificationObject alloc] init];
1466  [ NSApp setDelegate: [GtkApplicationDelegate new]];
1467 
1468  return 0;
1469 }
1470 
1471 extern "C" void
1473 {
1474  [ NSApp finishLaunching ];
1475  [[NSApplication sharedApplication] activateIgnoringOtherApps : YES];
1476 }
1477 
1478 extern "C" void
1480 {
1481  _exiting = 1;
1482 
1483  if (_window_menu) {
1484  [ _window_menu release ];
1485  _window_menu = 0;
1486  }
1487  if (_app_menu) {
1488  [ _app_menu release ];
1489  _app_menu = 0;
1490  }
1491  if (_main_menubar) {
1492  [ _main_menubar release ];
1493  _main_menubar = 0;
1494  }
1495 }
static void push_menu_shell_to_nsmenu(GtkMenuShell *menu_shell, NSMenu *menu, gboolean toplevel, gboolean debug)
static void cocoa_menu_free(gpointer *ptr)
static void cocoa_menu_item_update_submenu(NSMenuItem *cocoa_item, GtkWidget *widget)
void gtk_application_ready()
static Application * instance()
#define DEBUG(format,...)
Definition: ardour_ui.h:130
static GtkWidget * find_menu_label(GtkWidget *widget)
void gtk_application_cleanup()
static void add_menu_item(NSMenu *cocoa_menu, GtkWidget *menu_item, int index)
static gboolean accel_find_func(GtkAccelKey *, GClosure *closure, gpointer data)
static void cocoa_menu_item_update_accel_closure(GNSMenuItem *cocoa_item, GtkWidget *widget)
static void cocoa_menu_item_free(gpointer *ptr)
static void cocoa_menu_item_connect(GtkWidget *menu_item, GNSMenuItem *cocoa_menu_item, GtkWidget *label)
static gulong emission_hook_id
GList * _gtk_application_menu_groups
static GQuark cocoa_menu_item_quark
GClosure * accel_closure
void gtk_application_set_menu_bar(GtkMenuShell *menu_shell)
int gtk_application_init()
typedefG_BEGIN_DECLS struct _GtkApplicationMenuGroup GtkApplicationMenuGroup
static NSMenu * _main_menubar
static void cocoa_menu_connect(GtkWidget *menu, NSMenu *cocoa_menu)
sigc::signal< void > ShouldQuit
Definition: application.h:55
static gboolean keyval_is_keypad(guint keyval)
static gboolean idle_call_activate(gpointer data)
static const gchar * get_menu_label_text(GtkWidget *menu_item, GtkWidget **label)
sigc::signal< void, bool > ActivationChanged
Definition: application.h:53
static void cocoa_menu_item_update_state(NSMenuItem *cocoa_item, GtkWidget *widget)
static NSMenu * cocoa_menu_get(GtkWidget *widget)
static void cocoa_menu_item_notify(GObject *object, GParamSpec *pspec, NSMenuItem *cocoa_item)
sigc::signal< void, const Glib::ustring & > ShouldLoad
static const struct @24 modifiers[]
static const gchar * gdk_quartz_keyval_to_string(guint keyval)
static int add_to_menubar(NSMenu *menu)
static GQuark cocoa_menu_quark
static gboolean keyval_is_uppercase(guint keyval)
static GNSMenuItem * cocoa_menu_item_get(GtkWidget *widget)
LIBARDOUR_API PBD::PropertyDescriptor< bool > active
Definition: route_group.cc:43
static NSMenu * _app_menu
sigc::signal< void, const Glib::ustring & > ShouldLoad
Definition: application.h:54
static gboolean parent_set_emission_hook(GSignalInvocationHint *, guint, const GValue *param_values, gpointer data)
static int _in_menu_event_handler
static void cocoa_menu_item_update_accelerator(NSMenuItem *cocoa_item, GtkWidget *widget)
void gtk_application_add_app_menu_item(GtkApplicationMenuGroup *group, GtkMenuItem *menu_item)
static void cocoa_menu_item_notify_label(GObject *object, GParamSpec *pspec, gpointer)
static NSMenu * _window_menu
#define UNUSED_PARAMETER(a)
sigc::signal< void > ShouldQuit
static gint _exiting
static void parent_set_emission_hook_remove(GtkWidget *, gpointer)
GtkMenuItem * gtk_menu_item
static void cocoa_menu_item_accel_changed(GtkAccelGroup *, guint, GdkModifierType, GClosure *accel_closure, GtkWidget *widget)
static void cocoa_menu_item_update_label(NSMenuItem *cocoa_item, GtkWidget *widget)
static guint gdk_quartz_keyval_to_ns_keyval(guint keyval)
static void cocoa_menu_item_update_active(NSMenuItem *cocoa_item, GtkWidget *widget)
sigc::signal< void, bool > ActivationChanged
LIBARDOUR_API bool init(bool with_vst, bool try_optimization, const char *localedir)
Definition: globals.cc:376
static int create_apple_menu()
static guint keyval_keypad_nonkeypad_equivalent(guint keyval)
int gdk_quartz_in_menu_event_handler()