Add --parent-id argument to emacsclient.
[bpt/emacs.git] / lib-src / emacsclient.c
index f66d6b4..3172ebb 100644 (file)
@@ -1,6 +1,6 @@
 /* Client process that communicates with GNU Emacs acting as server.
    Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+                 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -138,6 +138,9 @@ int current_frame = 1;
 /* The display on which Emacs should work.  --display.  */
 char *display = NULL;
 
+/* The parent window ID, if we are opening a frame via XEmbed.  */
+char *parent_id = NULL;
+
 /* Nonzero means open a new Emacs frame on the current terminal. */
 int tty = 0;
 
@@ -173,6 +176,7 @@ struct option longopts[] =
 #ifndef WINDOWSNT
   { "display", required_argument, NULL, 'd' },
 #endif
+  { "parent-id", required_argument, NULL, 'p' },
   { 0, 0, 0, 0 }
 };
 
@@ -340,7 +344,7 @@ w32_get_resource (predefined, key, type)
 /*
   getenv wrapper for Windows
 
-  This is needed to duplicate Emacs's behavior, which is to look for enviroment
+  This is needed to duplicate Emacs's behavior, which is to look for environment
   variables in the registry if they don't appear in the environment.
 */
 char *
@@ -392,6 +396,33 @@ w32_getenv (envvar)
   return NULL;
 }
 
+void
+w32_set_user_model_id ()
+{
+  HMODULE shell;
+  HRESULT (WINAPI * set_user_model) (wchar_t * id);
+
+  /* On Windows 7 and later, we need to set the user model ID
+     to associate emacsclient launched files with Emacs frames
+     in the UI.  */
+  shell = LoadLibrary("shell32.dll");
+  if (shell)
+    {
+      set_user_model
+       = (void *) GetProcAddress (shell,
+                                  "SetCurrentProcessExplicitAppUserModelID");
+      /* If the function is defined, then we are running on Windows 7
+        or newer, and the UI uses this to group related windows
+        together.  Since emacs, runemacs, emacsclient are related, we
+        want them grouped even though the executables are different,
+        so we need to set a consistent ID between them.  */
+      if (set_user_model)
+       set_user_model (L"GNU.Emacs");
+
+      FreeLibrary (shell);
+    }
+}
+
 int
 w32_window_app ()
 {
@@ -556,6 +587,11 @@ decode_options (argc, argv)
           current_frame = 0;
           break;
 
+       case 'p':
+         parent_id = optarg;
+          current_frame = 0;
+         break;
+
        case 'H':
          print_help_and_exit ();
          break;
@@ -628,21 +664,23 @@ The following OPTIONS are accepted:\n\
                        use the current Emacs frame\n\
 -e, --eval             Evaluate the FILE arguments as ELisp expressions\n\
 -n, --no-wait          Don't wait for the server to return\n\
--d, --display=DISPLAY  Visit the file in the given display\n"
+-d DISPLAY, --display=DISPLAY\n\
+                       Visit the file in the given display\n\
+--parent-id=ID          Open in parent window ID, via XEmbed\n"
 #ifndef NO_SOCKETS_IN_FILE_SYSTEM
-"-s, --socket-name=FILENAME\n\
+"-s SOCKET, --socket-name=SOCKET\n\
                        Set filename of the UNIX socket for communication\n"
 #endif
-"-f, --server-file=FILENAME\n\
+"-f SERVER, --server-file=SERVER\n\
                        Set filename of the TCP authentication file\n\
--a, --alternate-editor=EDITOR\n\
+-a EDITOR, --alternate-editor=EDITOR\n\
                        Editor to fallback to if the server is not running\n"
-#ifdef WINDOWSNT
+#ifndef WINDOWSNT
 "                      If EDITOR is the empty string, start Emacs in daemon\n\
                        mode and try connecting again\n"
-#endif /* WINDOWSNT */
+#endif /* not WINDOWSNT */
 "\n\
-Report bugs to bug-gnu-emacs@gnu.org.\n", progname);
+Report bugs with M-x report-emacs-bug.\n", progname);
   exit (EXIT_SUCCESS);
 }
 
@@ -695,7 +733,6 @@ main (argc, argv)
 #define SEND_BUFFER_SIZE   4096
 
 extern char *strerror ();
-extern int errno;
 
 /* Buffer to accumulate data to send in TCP connections.  */
 char send_buffer[SEND_BUFFER_SIZE + 1];
@@ -1414,22 +1451,23 @@ w32_find_emacs_process (hWnd, lParam)
 void
 w32_give_focus ()
 {
-  HMODULE hUser32;
+  HANDLE user32;
 
   /* It shouldn't happen when dealing with TCP sockets.  */
   if (!emacs_pid) return;
 
-  if (!(hUser32 = LoadLibrary ("user32.dll"))) return;
+  user32 = GetModuleHandle ("user32.dll");
+
+  if (!user32)
+    return;
 
   /* Modern Windows restrict which processes can set the foreground window.
      emacsclient can allow Emacs to grab the focus by calling the function
      AllowSetForegroundWindow.  Unfortunately, older Windows (W95, W98 and
      NT) lack this function, so we have to check its availability.  */
-  if ((set_fg = GetProcAddress (hUser32, "AllowSetForegroundWindow"))
-      && (get_wc = GetProcAddress (hUser32, "RealGetWindowClassA")))
+  if ((set_fg = GetProcAddress (user32, "AllowSetForegroundWindow"))
+      && (get_wc = GetProcAddress (user32, "RealGetWindowClassA")))
     EnumWindows (w32_find_emacs_process, (LPARAM) 0);
-
-  FreeLibrary (hUser32);
 }
 #endif
 
@@ -1500,6 +1538,12 @@ main (argc, argv)
   main_argv = argv;
   progname = argv[0];
 
+#ifdef WINDOWSNT
+  /* On Windows 7 and later, we need to explicitly associate emacsclient
+     with emacs so the UI behaves sensibly.  */
+  w32_set_user_model_id ();
+#endif
+
   /* Process options.  */
   decode_options (argc, argv);
 
@@ -1586,6 +1630,13 @@ main (argc, argv)
       send_to_emacs (emacs_socket, " ");
     }
 
+  if (parent_id)
+    {
+      send_to_emacs (emacs_socket, "-parent-id ");
+      quote_argument (emacs_socket, parent_id);
+      send_to_emacs (emacs_socket, " ");
+    }
+
   /* If using the current frame, send tty information to Emacs anyway.
      In daemon mode, Emacs may need to occupy this tty if no other
      frame is available.  */