/* $Id: xfce-gdk-extensions.c 21491 2006-05-04 21:23:29Z benny $ */
/*-
 * Copyright (c) 2003      Mark McLoughlin <mark@skynet.ie>
 * Copyright (c) 2004-2006 Benedikt Meurer <benny@xfce.org>
 * All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif

#include <X11/Xlib.h>

#include <gdk/gdkx.h>

#include <libxfcegui4/libxfcegui4.h>



/**
 * xfce_gdk_display_get_fullname:
 * @display : A valid Gdk display.
 *
 * Determines the full qualified name of @display. The full name includes
 * both the hostname of the Xserver node and the display number
 * of the Xserver.
 *
 * Return value: The full qualified name of @display.
 *
 * Since: 4.2
 */
gchar*
xfce_gdk_display_get_fullname (GdkDisplay *display)
{
  const gchar *name;
  const gchar *np;
  gchar       *hostname;
  gchar        buffer[256];
  gchar       *bp;
                                                                                
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  name = gdk_display_get_name (display);
  if (*name == ':')
    {
      hostname = xfce_gethostname ();
      g_strlcpy (buffer, hostname, 256);
      g_free (hostname);
                                                                                
      bp = buffer + strlen (buffer);
                                                                                
      for (np = name; *np != '\0' && *np != '.' && bp < buffer + 255; )
        *bp++ = *np++;
      *bp = '\0';
    }
  else
    {
      g_strlcpy (buffer, name, 256);
                                                                                
      for (bp = buffer + strlen (buffer) - 1; *bp != ':'; --bp)
        if (*bp == '.')
          {
            *bp = '\0';
            break;
          }
    }
                                                                                
  return g_strdup (buffer);
}



static gboolean
screen_contains_pointer (GdkScreen *screen,
                         int       *x,
			                   int       *y)
{
	GdkWindow    *root_window;
	Window        root, child;
	Bool          retval;
	int           rootx, rooty;
	int           winx, winy;
	unsigned int  xmask;

	root_window = gdk_screen_get_root_window (screen);

	retval = XQueryPointer (GDK_SCREEN_XDISPLAY (screen),
                          GDK_DRAWABLE_XID (root_window),
                          &root, &child, &rootx, &rooty,
                          &winx, &winy, &xmask);

	if (x)
		*x = retval ? rootx : -1;
	if (y)
		*y = retval ? rooty : -1;

	return retval;
}



/**
 * xfce_gdk_display_locate_monitor_with_pointer:
 * @display        : A Gdk display or %NULL to choose the default display.
 * @monitor_return : Address to store the monitor number to or %NULL.
 *
 * Locates the monitor and the screen which contains the pointer. If
 * it is not possible to determine the current pointer position, %NULL
 * is returned.
 *
 * Return value: The screen that contains the pointer.
 *
 * Since: 4.2
 **/
GdkScreen*
xfce_gdk_display_locate_monitor_with_pointer (GdkDisplay *display,
                                              gint       *monitor_return)
{
	int n_screens, i;

  if (display == NULL)
    display = gdk_display_get_default ();

	n_screens = gdk_display_get_n_screens (display);
	for (i = 0; i < n_screens; i++)
    {
      GdkScreen  *screen;
      int         x, y;

      screen = gdk_display_get_screen (display, i);

      if (screen_contains_pointer (screen, &x, &y))
        {
          if (monitor_return)
            *monitor_return = gdk_screen_get_monitor_at_point (screen, x, y);

          return screen;
	    	}
  	}

	if (monitor_return)
		*monitor_return = 0;

	return NULL;
}



/**
 * xfce_gdk_screen_get_fullname:
 * @screen : A Gdk screen.
 *
 * Like xfce_gdk_display_get_fullname(), but also includes the screen
 * number.
 *
 * Return value: The full qualified name of @screen.
 *
 * Since: 4.2
 **/
gchar*
xfce_gdk_screen_get_fullname (GdkScreen *screen)
{
  GdkDisplay *display;
  gchar      *display_name;
  gchar      *screen_name;

  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);

  display = gdk_screen_get_display (screen);
  display_name = xfce_gdk_display_get_fullname (display);
  screen_name = g_strdup_printf ("%s.%d", display_name,
                                 gdk_screen_get_number (screen));
  g_free (display_name);
  
  return screen_name;
}



/**
 * xfce_gdk_spawn_on_screen:
 * @screen            : a #GdkScreen
 * @working_directory : child's current working directory, or %NULL to 
 *                      inherit parent's
 * @argv              : child's argument vector
 * @envp              : child's environment, or %NULL to inherit parent's
 * @flags             : flags from #GSpawnFlags
 * @child_setup       : function to run in the child just before exec()
 * @user_data         : user data for @child_setup
 * @child_pid         : return location for child process ID, or %NULL
 * @error             : return location for error
 *
 * Like g_spawn_async(), except the child process is spawned in such
 * an environment that on calling gdk_display_open() it would be
 * returned a #GdkDisplay with @screen as the default screen.
 *
 * This is useful for applications which wish to launch an application
 * on a specific screen.
 *
 * Return value: %TRUE on success, %FALSE if error is set
 *
 * Since: 4.2
 **/
gboolean
xfce_gdk_spawn_on_screen (GdkScreen           *screen,
                          const gchar         *working_directory,
                          gchar              **argv,
                          gchar              **envp,
                          GSpawnFlags          flags,
                          GSpawnChildSetupFunc child_setup,
                          gpointer             user_data,
                          gint                *child_pid,
                          GError             **error)
{
  return gdk_spawn_on_screen (screen, working_directory, argv, envp,
                              flags, child_setup, user_data, child_pid,
                              error);
}



/**
 * xfce_gdk_spawn_on_screen_with_pipes:
 * @screen            : a #GdkScreen
 * @working_directory : child's current working directory, or %NULL to 
 *                      inherit parent's
 * @argv              : child's argument vector
 * @envp              : child's environment, or %NULL to inherit parent's
 * @flags             : flags from #GSpawnFlags
 * @child_setup       : function to run in the child just before exec()
 * @user_data         : user data for @child_setup
 * @child_pid         : return location for child process ID, or %NULL
 * @standard_input    : return location for file descriptor to write to 
 *                      child's stdin, or %NULL
 * @standard_output   : return location for file descriptor to read child's 
 *                      stdout, or %NULL
 * @standard_error    : return location for file descriptor to read child's 
 *                      stderr, or %NULL
 * @error             : return location for error
 *
 * Like g_spawn_async_with_pipes(), except the child process is
 * spawned in such an environment that on calling gdk_display_open()
 * it would be returned a #GdkDisplay with @screen as the default
 * screen.
 *
 * This is useful for applications which wish to launch an application
 * on a specific screen.
 *
 * Return value: %TRUE on success, %FALSE if an error was set
 *
 * Since: 4.2
 **/
gboolean
xfce_gdk_spawn_on_screen_with_pipes (GdkScreen            *screen,
				                             const gchar          *working_directory,
                              			 gchar               **argv,
			                               gchar               **envp,
                                     GSpawnFlags           flags,
                                     GSpawnChildSetupFunc  child_setup,
                                     gpointer              user_data,
                                     gint                 *child_pid,
                                     gint                 *standard_input,
                                     gint                 *standard_output,
                                     gint                 *standard_error,
                                     GError              **error)
{
  return gdk_spawn_on_screen_with_pipes (screen, working_directory,
                                         argv, envp, flags, child_setup,
                                         user_data, child_pid, standard_input,
                                         standard_output, standard_error,
                                         error);
}



/**
 * xfce_gdk_spawn_command_line_on_screen:
 * @screen       : a #GdkScreen
 * @command_line : a command line
 * @error        : return location for errors
 *
 * Like g_spawn_command_line_async(), except the child process is
 * spawned in such an environment that on calling gdk_display_open()
 * it would be returned a #GdkDisplay with @screen as the default
 * screen.
 *
 * This is useful for applications which wish to launch an application
 * on a specific screen.
 *
 * Return value: %TRUE on success, %FALSE if error is set.
 *
 * Since: 4.2
 **/
gboolean
xfce_gdk_spawn_command_line_on_screen (GdkScreen    *screen,
				                               const gchar  *command_line,
                              				 GError      **error)
{
  return gdk_spawn_command_line_on_screen (screen, command_line, error);
}
