Put some OSX code into gtk version
authorH.G. Muller <h.g.muller@hccnet.nl>
Sun, 29 Dec 2013 21:09:10 +0000 (22:09 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Sat, 4 Jan 2014 11:49:09 +0000 (12:49 +0100)
Under control of #ifdef OSX code is added to integrate the GTK front-end
into OS X. This involves moving the menu bar to outside the window, and
catching the signal that OS X sends to running applications when opening
another instance was requested. Som files are renamed to conform to the
file tree of the OS X App package.

args.h
gtk/xboard.c
gtk/xoptions.c
winboard/winboard.c
xaw/xboard.c

diff --git a/args.h b/args.h
index 0c403de..362b2eb 100644 (file)
--- a/args.h
+++ b/args.h
@@ -947,7 +947,7 @@ ParseArgs(GetFunc get, void *cl)
       ch = get(cl);
       while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
       continue;
-    } else if (ch == '/' || ch == '-') {
+    } else if (ch == SLASH || ch == '-') {
       /* Switch */
       q = argName;
       while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
index 7711047..60b50d1 100644 (file)
@@ -167,6 +167,19 @@ extern char *getenv();
 #include "gettext.h"
 #include "draw.h"
 
+#ifdef OSX
+#  include "gtkmacintegration/gtkosxapplication.h"
+   // prevent pathname of positional file argument provided by OSx being be mistaken for option name
+   // (price is that we won't recognize Windows option format anymore).
+#  define SLASH '-'
+   // redefine some defaults
+#  undef ICS_LOGON
+#  undef SYSCONFDIR
+#  define ICS_LOGON "Library/Preferences/XboardICS.conf"
+#  define SYSCONFDIR "../etc"
+#else
+#  define SLASH '/'
+#endif
 
 #ifdef __EMX__
 #ifndef HAVE_USLEEP
@@ -713,6 +726,24 @@ SlaveResize (Option *opt)
   gtk_window_resize(GTK_WINDOW(shells[DummyDlg]), slaveW + opt->max, slaveH + opt->value);
 }
 
+#ifdef OSX
+static char clickedFile[MSG_SIZ];
+static int suppress;
+
+static gboolean
+StartNewXBoard(GtkosxApplication *app, gchar *path, gpointer user_data)
+{ // handler of OSX OpenFile signal, which sends us the filename of clicked file or first argument
+  if(suppress) { // we just started XBoard without arguments
+    strncpy(clickedFile, path, MSG_SIZ); // remember file name, but otherwise ignore
+  } else {       // we are running something presumably useful
+    char buf[MSG_SIZ];
+    snprintf(buf, MSG_SIZ, "open -n -a \"xboard\" --args \"%s\"", path);
+    system(buf); // start new instance on this file
+  }
+  return TRUE;
+}
+#endif
+
 int
 main (int argc, char **argv)
 {
@@ -739,6 +770,28 @@ main (int argc, char **argv)
 
     /* set up GTK */
     gtk_init (&argc, &argv);
+#ifdef OSX
+    {   // prepare to catch OX OpenFile signal, which will tell us the clicked file
+       GtkosxApplication *theApp = g_object_new(GTKOSX_TYPE_APPLICATION, NULL);
+       g_signal_connect(theApp, "NSApplicationOpenFile", G_CALLBACK(StartNewXBoard), NULL);
+       // we must call application ready before we can get the signal,
+       // and supply a (dummy) menu bar before that, to avoid problems with dual apples in it
+       gtkosx_application_set_menu_bar(theApp, GTK_MENU_SHELL(gtk_menu_bar_new()));
+       gtkosx_application_ready(theApp);
+       suppress = (argc == 1 || argc > 1 && argv[1][00] != '-'); // OSX sends signal even if name was already argv[1]!
+       if(argc == 1) {                  // called without args: OSX open-file signal might follow
+           static char *fakeArgv[3] = {NULL, clickedFile, NULL};
+           usleep(10000);               // wait 10 msec (and hope this is long enough).
+           while(gtk_events_pending())
+               gtk_main_iteration();    // process all events that came in upto now
+           suppress = 0;                // future open-file signals should start new instance
+           if(clickedFile[0]) {         // we were sent an open-file signal with filename!
+             fakeArgv[0] = argv[0];
+             argc = 2; argv = fakeArgv; // fake that we were called as "xboard filename"
+           }
+       }
+    }
+#endif
 
     /* set up keyboard accelerators group */
     GtkAccelerators = gtk_accel_group_new();
@@ -1688,8 +1741,8 @@ void MoveTypeInProc(eventkey)
 {
     char buf[10];
 
-    // ingnore if ctrl or alt is pressed
-    if (eventkey->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) {
+    // ingnore if ctrl, alt, or meta is pressed
+    if (eventkey->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_META_MASK)) {
         return;
     }
 
index fb872ce..0eb64ff 100644 (file)
@@ -51,6 +51,9 @@ extern char *getenv();
 #include <cairo/cairo-xlib.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
+#ifdef OSX
+#  include "gtkmacintegration/gtkosxapplication.h"
+#endif
 
 #include "common.h"
 #include "backend.h"
@@ -425,6 +428,10 @@ CreateMenuPopup (Option *opt, int n, int def)
       {
        char *msg = mb[i].string;
        if(!msg) break;
+#ifdef OSX
+       if(!strcmp(msg, "Quit ")) continue;             // Quit item will appear automatically in App menu
+       if(!strcmp(msg, "About XBoard")) msg = "About"; // 'XBoard' will be appended automatically when moved to App menu 1st item
+#endif
        if(strcmp(msg, "----")) { //
          if(!(opt->min & NO_GETTEXT)) msg = _(msg);
          if(mb[i].handle) {
@@ -438,11 +445,17 @@ CreateMenuPopup (Option *opt, int n, int def)
            GdkModifierType accelerator_mods;
 
            gtk_accelerator_parse(mb[i].accel, &accelerator_key, &accelerator_mods);
+#ifdef OSX
+           if(accelerator_mods & GDK_CONTROL_MASK) {  // in OSX use Meta where Linux uses Ctrl
+               accelerator_mods &= ~GDK_CONTROL_MASK; // clear Ctrl flag
+               accelerator_mods |= GDK_META_MASK;     // set Meta flag
+           } 
+#endif
            gtk_widget_add_accelerator (GTK_WIDGET(entry), "activate",GtkAccelerators,
                                        accelerator_key, accelerator_mods, GTK_ACCEL_VISIBLE);
-         };
-         gtk_widget_show(entry);
+         }
        } else entry = gtk_separator_menu_item_new();
+       gtk_widget_show(entry);
        gtk_menu_append(GTK_MENU (menu), entry);
 //CreateMenuItem(menu, opt->min & NO_GETTEXT ? msg : _(msg), (XtCallbackProc) ComboSelect, (n<<16)+i);
        mb[i].handle = (void*) entry; // save item ID, for enabling / checkmarking
@@ -1480,9 +1493,21 @@ if(appData.debugMode) printf("n=%d, h=%d, w=%d\n",n,height,width);
            break;
          case BarEnd:
            top--;
+#ifndef OSX
             gtk_table_attach(GTK_TABLE(table), menuBar, left, left+r, top, top+1, GTK_FILL | GTK_EXPAND, GTK_FILL, 2, 1);
 
            if(option[i].target) ((ButtonCallback*)option[i].target)(boxStart); // callback that can make sizing decisions
+#else
+           top--; // in OSX menu bar is not put in window, so also don't count it
+           {   // in stead, offer it to OSX, and move About item to top of App menu
+               GtkosxApplication *theApp = g_object_new(GTKOSX_TYPE_APPLICATION, NULL);
+               extern MenuItem helpMenu[]; // oh, well... Adding items in help menu breaks this anyway
+               gtk_widget_hide (menuBar);
+               gtkosx_application_set_menu_bar(theApp, GTK_MENU_SHELL(menuBar));
+               gtkosx_application_insert_app_menu_item(theApp, GTK_MENU_ITEM(helpMenu[8].handle), 0); // hack
+               gtkosx_application_sync_menubar(theApp);
+           } 
+#endif
            break;
          case BoxEnd:
 //         XtManageChildren(&form, 1);
index ed71d93..60d92db 100644 (file)
@@ -92,6 +92,8 @@
 #include "help.h"\r
 #include "wsnap.h"\r
 \r
+#define SLASH '/'\r
+\r
 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );\r
 \r
   int myrandom(void);\r
index 1b13b7c..d93743f 100644 (file)
@@ -203,6 +203,7 @@ extern char *getenv();
 #include "gettext.h"
 #include "draw.h"
 
+#define SLASH '/'
 
 #ifdef __EMX__
 #ifndef HAVE_USLEEP