// gimp-win-remote.c
// Copyright (C) 2002, 2004 Edward G. Bruck <gmb@canada.com>
//
// gimp-win-remote is a program that allows the user running 9x/2000/XP 
// to open a graphic file in an already running GIMP process. If GIMP 
// isn't running, gimp-win-remote will launch it and open the requested 
// file(s).
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


//
// INCLUDES:
//
#include <windows.h>
#include <shlobj.h>
#include <shellapi.h>

//
// PROTOTYPES:
//
int LaunchGIMP(char* pszCmdLine);
int DragAndDropGIMP(HWND hWnd);
BOOL CALLBACK FindGIMPWindow(HWND hWnd, LPARAM lParam);


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                      LPSTR lpCmdLine, int nCmdShow)
{
    HWND hWnd = NULL; // GIMP's window

    // Can't just look for "The GIMP" as other languages use
    // different title text. Lets do this the hard way
    // and examine all the windows. 
    EnumWindows(FindGIMPWindow, (LPARAM)&hWnd);

    // Is GIMP running?
    if (hWnd != NULL)
    {
        return DragAndDropGIMP(hWnd);
    }
    else
    {
        return LaunchGIMP(lpCmdLine);
    }
}


// Find path to GIMP in the registry and then launch it with the
// passed command line.
int LaunchGIMP(char* pszCmdLine)
{
    HKEY hRegData;
    char szAppPath[_MAX_PATH]={0};   // path to exe
    DWORD dwSize;
    DWORD dwType = 0;
    DWORD dwDisp;
    int iRetCode=-1;
    int iShowParam = SW_SHOW;

    // any files?
    if (strlen(pszCmdLine)==0 || pszCmdLine==NULL)
        return iRetCode;

    // Read path to GIMP
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
		             "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\gimp-2.0.exe",
		             0, KEY_READ, &hRegData) == ERROR_SUCCESS)
    {
        dwSize = sizeof(szAppPath);
        if (RegQueryValueEx(hRegData, "", 0, &dwType,
			(PBYTE)szAppPath, (LPDWORD)&dwSize) == ERROR_SUCCESS)
        {
			char szExt[_MAX_EXT]={0};

			// Extract the path from where gimp-2.0.exe was launched. Could
            // use the path in registry, but you never know where in the
            // string it will be.
            char szPath[_MAX_PATH]={0};
            char *pEnd = strrchr(szAppPath, '\\');

            // Could we find last slash?
            if (pEnd != NULL)
            {
                int len = pEnd-szAppPath;
                
                // just incase
                if (len > 0 && len < _MAX_PATH)
                {
                    strncpy(szPath, szAppPath, len);
                }
            }

			// look for extension
			pEnd = strrchr(szAppPath, '.');
			if (pEnd != NULL)
			{
				// copy to szExt and trim trailing spaces 
				// (which RegQueryValueEx seems wont to append)
				int len = strlen(pEnd);
				int k = 0;
				while (k < len && *pEnd != '\0' && *pEnd != ' ') 
				{
					szExt[k] = *pEnd;
					k++;
					pEnd++;
				}
			}

			// determine if app being launched is .exe or (.cmd|.bat)
			// If a script, launch with special handling to not show the console window
            if (stricmp(szExt,".cmd") == 0 || 
				stricmp(szExt,".bat") == 0)
            {
				iShowParam = SW_HIDE; 
				// we're going to launch a script file that will launch the Gimp,
				// and we don't want the console window for the command processor
				// that will handle the script to flash up, so we launch it with SW_HIDE
				// (of course we want SH_SHOW when directly launching the Gimp.)
            }
			
			// Try launching GIMP with the passed params.
			if (ShellExecute(NULL, "open", szAppPath,
				pszCmdLine, szPath, iShowParam) <= (HINSTANCE)32)
			{
				MessageBox(NULL, "Failed to launch GIMP!", "gimp-win-remote 2.0.2",
					MB_ICONEXCLAMATION);
			}
			else
			{
				iRetCode = 0;
            }
        }
    }

    // close the key
    RegCloseKey(hRegData);

    return iRetCode;
}


// GIMP is running, so we simulate a drag & drop event.
// Uses __argv & __argc for list of files to drop.
int DragAndDropGIMP(HWND hWnd)
{
    int iNumFiles   = __argc-1;
    int iCurBytePos = sizeof(DROPFILES);
    LPDROPFILES pDropFiles;
    HGLOBAL hGlobal;
    int i;

    // any files?
    if (iNumFiles == 0)
        return -1;

    // May use more memory than is needed... oh well.
    hGlobal = GlobalAlloc(GHND | GMEM_SHARE,
                          sizeof(DROPFILES) +
                          (_MAX_PATH * iNumFiles) + 1);

    // memory failure?
    if (hGlobal == NULL)
        return -1;

    // lock the memory
    pDropFiles = (LPDROPFILES)GlobalLock(hGlobal);

    // set offset where the file list begins 
    pDropFiles->pFiles = sizeof(DROPFILES);

    // no wide chars and drop point is in client coordinates
    pDropFiles->fWide = FALSE;
    pDropFiles->pt.x = pDropFiles->pt.y = 0;
    pDropFiles->fNC = FALSE;

    for(i=0; i < iNumFiles; ++i)
    {
        strcpy(((LPSTR)(pDropFiles) + iCurBytePos), __argv[i+1]);

        // Move the current position beyond the file name copied.
        // +1 for NULL terminator
        iCurBytePos += strlen(__argv[i+1]) + 1;
    }

    ((LPSTR)(pDropFiles))[iCurBytePos] = 0;
    GlobalUnlock(hGlobal);

    // Force gimp to the foreground
    SetForegroundWindow(hWnd);
    ShowWindow(hWnd, SW_RESTORE);

    // send the file list
    PostMessage(hWnd, WM_DROPFILES, (WPARAM)hGlobal, 0);

    return 0;
}

// Callback to enumerate all windows searching for
// GIMP as the user could be running under a different language.
// The word GIMP is in all languages supported in my 1.2.0 build.
BOOL CALLBACK FindGIMPWindow(HWND hWnd, LPARAM lParam)
{
    char szTitle[40]; // should be enough to find GIMP

    if (GetWindowText(hWnd, szTitle, sizeof(szTitle)) != 0)
    {
        // look for GIMP
        char* pszToken = strtok(szTitle, " ");
        while(pszToken != NULL)
        {
            if (stricmp(pszToken,"GIMP") == 0)
            {
                // sanity check class name         
                char szClass[20]; // should be enough

                if (GetClassName(hWnd, szClass, sizeof(szClass)) != 0)
                {
                    // if ok, then stop enumerating
                    if (stricmp(szClass, "gdkWindowTopLevel") == 0)
                    {
                        *((HWND*)lParam) = hWnd;
                        return FALSE;
                    }
                }
            }
            // get next token
            pszToken = strtok(NULL, " ");
        }
    }
     
    return TRUE;
}
