Moved clipboard event handling functions and some private data
structures to clipboard.c.

diff --git a/dlls/x11drv/clipboard.c b/dlls/x11drv/clipboard.c
index ae3bc85..7797c9b 100644
--- a/dlls/x11drv/clipboard.c
+++ b/dlls/x11drv/clipboard.c
@@ -107,6 +107,35 @@
     UINT flags;
 } CLIPBOARDINFO, *LPCLIPBOARDINFO;
 
+typedef struct tagWINE_CLIPDATA {
+    UINT        wFormatID;
+    HANDLE16    hData16;
+    HANDLE      hData32;
+    UINT        drvData;
+    UINT        wFlags;
+    struct tagWINE_CLIPDATA *PrevData;
+    struct tagWINE_CLIPDATA *NextData;
+} WINE_CLIPDATA, *LPWINE_CLIPDATA;
+
+typedef HANDLE (*DRVEXPORTFUNC)(Window requestor, Atom aTarget, Atom rprop,
+    LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
+typedef HANDLE (*DRVIMPORTFUNC)(LPBYTE hData, UINT cBytes);
+
+typedef struct tagWINE_CLIPFORMAT {
+    UINT        wFormatID;
+    LPCWSTR     Name;
+    UINT        drvData;
+    UINT        wFlags;
+    DRVIMPORTFUNC  lpDrvImportFunc;
+    DRVEXPORTFUNC  lpDrvExportFunc;
+    struct tagWINE_CLIPFORMAT *PrevFormat;
+    struct tagWINE_CLIPFORMAT *NextFormat;
+} WINE_CLIPFORMAT, *LPWINE_CLIPFORMAT;
+
+#define CF_FLAG_BUILTINFMT   1 /* Built-in windows format */
+#define CF_FLAG_UNOWNED      2 /* cached data is not owned */
+#define CF_FLAG_SYNTHESIZED  8 /* Implicitly converted data */
+
 static int selectionAcquired = 0;              /* Contains the current selection masks */
 static Window selectionWindow = None;          /* The top level X window which owns the selection */
 static BOOL usePrimary = FALSE;                /* Use primary selection in additon to the clipboard selection */
@@ -115,20 +144,20 @@
 INT X11DRV_RegisterClipboardFormat(LPCWSTR FormatName);
 void X11DRV_EmptyClipboard(BOOL keepunowned);
 void X11DRV_EndClipboardUpdate(void);
-HANDLE X11DRV_CLIPBOARD_ImportClipboardData(LPBYTE lpdata, UINT cBytes);
-HANDLE X11DRV_CLIPBOARD_ImportEnhMetaFile(LPBYTE lpdata, UINT cBytes);
-HANDLE X11DRV_CLIPBOARD_ImportMetaFilePict(LPBYTE lpdata, UINT cBytes);
-HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(LPBYTE lpdata, UINT cBytes);
-HANDLE X11DRV_CLIPBOARD_ImportXAString(LPBYTE lpdata, UINT cBytes);
-HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Window requestor, Atom aTarget,
+static HANDLE X11DRV_CLIPBOARD_ImportClipboardData(LPBYTE lpdata, UINT cBytes);
+static HANDLE X11DRV_CLIPBOARD_ImportEnhMetaFile(LPBYTE lpdata, UINT cBytes);
+static HANDLE X11DRV_CLIPBOARD_ImportMetaFilePict(LPBYTE lpdata, UINT cBytes);
+static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(LPBYTE lpdata, UINT cBytes);
+static HANDLE X11DRV_CLIPBOARD_ImportXAString(LPBYTE lpdata, UINT cBytes);
+static HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Window requestor, Atom aTarget,
     Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
-HANDLE X11DRV_CLIPBOARD_ExportString(Window requestor, Atom aTarget,
+static HANDLE X11DRV_CLIPBOARD_ExportString(Window requestor, Atom aTarget,
     Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
-HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Window requestor, Atom aTarget,
+static HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Window requestor, Atom aTarget,
     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
-HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Window requestor, Atom aTarget,
+static HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Window requestor, Atom aTarget,
     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
-HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Window requestor, Atom aTarget,
+static HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Window requestor, Atom aTarget,
     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
 static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat(LPCWSTR FormatName, Atom prop);
 static BOOL X11DRV_CLIPBOARD_ReadSelection(LPWINE_CLIPFORMAT lpData, Window w, Atom prop);
@@ -143,6 +172,7 @@
 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(LPWINE_CLIPDATA lpData);
 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(void);
 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(void);
+static void X11DRV_HandleSelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
 
 /* Clipboard formats
  * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure
@@ -2574,3 +2604,355 @@
 
     TRACE("%d formats added to cached data\n", ClipDataCount - count);
 }
+
+
+/***********************************************************************
+ *           add_targets
+ *
+ * Utility function for X11DRV_SelectionRequest_TARGETS.
+ */
+static BOOL add_targets(Atom* targets, unsigned long cTargets, Atom prop)
+{
+    unsigned int i;
+    BOOL bExists;
+
+    /* Scan through what we have so far to avoid duplicates */
+    for (i = 0, bExists = FALSE; i < cTargets; i++)
+    {
+        if (targets[i] == prop)
+        {
+            bExists = TRUE;
+            break;
+        }
+    }
+
+    if (!bExists)
+        targets[cTargets] = prop;
+
+    return !bExists;
+}
+
+
+/***********************************************************************
+ *           X11DRV_SelectionRequest_TARGETS
+ *  Service a TARGETS selection request event
+ */
+static Atom X11DRV_SelectionRequest_TARGETS( Display *display, Window requestor,
+                                             Atom target, Atom rprop )
+{
+    Atom* targets;
+    UINT wFormat;
+    UINT alias;
+    ULONG cTargets;
+    LPWINE_CLIPFORMAT lpFormat;
+
+    /*
+     * Count the number of items we wish to expose as selection targets.
+     * We include the TARGETS item, and property aliases
+     */
+    cTargets = X11DRV_CountClipboardFormats() + 1;
+
+    for (wFormat = 0; (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
+    {
+        lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
+
+        if (lpFormat)
+        {
+            if (!lpFormat->lpDrvExportFunc)
+                cTargets--;
+
+            if (X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData))
+                cTargets++;
+        }
+        /* else most likely unregistered format such as CF_PRIVATE or CF_GDIOBJ */
+    }
+
+    TRACE(" found %ld formats\n", cTargets);
+
+    /* Allocate temp buffer */
+    targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
+    if(targets == NULL)
+        return None;
+
+    /* Create TARGETS property list (First item in list is TARGETS itself) */
+    for (targets[0] = x11drv_atom(TARGETS), cTargets = 1, wFormat = 0;
+         (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
+    {
+        lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
+
+        if (lpFormat)
+        {
+            if (lpFormat->lpDrvExportFunc)
+            {
+                if (add_targets(targets, cTargets, lpFormat->drvData))
+                    cTargets++;
+            }
+
+            /* Check if any alias should be listed */
+            alias = X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData);
+            if (alias)
+            {
+                if (add_targets(targets, cTargets, alias))
+                    cTargets++;
+            }
+        }
+    }
+
+    wine_tsx11_lock();
+
+    if (TRACE_ON(clipboard))
+    {
+        unsigned int i;
+        for ( i = 0; i < cTargets; i++)
+        {
+            if (targets[i])
+            {
+                char *itemFmtName = XGetAtomName(display, targets[i]);
+                TRACE("\tAtom# %d:  Property %ld Type %s\n", i, targets[i], itemFmtName);
+                XFree(itemFmtName);
+            }
+        }
+    }
+
+    /* We may want to consider setting the type to xaTargets instead,
+     * in case some apps expect this instead of XA_ATOM */
+    XChangeProperty(display, requestor, rprop, XA_ATOM, 32,
+                    PropModeReplace, (unsigned char *)targets, cTargets);
+    wine_tsx11_unlock();
+
+    HeapFree(GetProcessHeap(), 0, targets);
+
+    return rprop;
+}
+
+
+/***********************************************************************
+ *           X11DRV_SelectionRequest_MULTIPLE
+ *  Service a MULTIPLE selection request event
+ *  rprop contains a list of (target,property) atom pairs.
+ *  The first atom names a target and the second names a property.
+ *  The effect is as if we have received a sequence of SelectionRequest events
+ *  (one for each atom pair) except that:
+ *  1. We reply with a SelectionNotify only when all the requested conversions
+ *  have been performed.
+ *  2. If we fail to convert the target named by an atom in the MULTIPLE property,
+ *  we replace the atom in the property by None.
+ */
+static Atom X11DRV_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
+{
+    Display *display = pevent->display;
+    Atom           rprop;
+    Atom           atype=AnyPropertyType;
+    int            aformat;
+    unsigned long  remain;
+    Atom*          targetPropList=NULL;
+    unsigned long  cTargetPropList = 0;
+
+    /* If the specified property is None the requestor is an obsolete client.
+     * We support these by using the specified target atom as the reply property.
+     */
+    rprop = pevent->property;
+    if( rprop == None )
+        rprop = pevent->target;
+    if (!rprop)
+        return 0;
+
+    /* Read the MULTIPLE property contents. This should contain a list of
+     * (target,property) atom pairs.
+     */
+    wine_tsx11_lock();
+    if(XGetWindowProperty(display, pevent->requestor, rprop,
+                          0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
+                          &cTargetPropList, &remain,
+                          (unsigned char**)&targetPropList) != Success)
+    {
+        wine_tsx11_unlock();
+        TRACE("\tCouldn't read MULTIPLE property\n");
+    }
+    else
+    {
+        TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
+              XGetAtomName(display, atype), aformat, cTargetPropList, remain);
+        wine_tsx11_unlock();
+
+        /*
+         * Make sure we got what we expect.
+         * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
+         * in a MULTIPLE selection request should be of type ATOM_PAIR.
+         * However some X apps(such as XPaint) are not compliant with this and return
+         * a user defined atom in atype when XGetWindowProperty is called.
+         * The data *is* an atom pair but is not denoted as such.
+         */
+        if(aformat == 32 /* atype == xAtomPair */ )
+        {
+            unsigned int i;
+
+            /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
+             * for each (target,property) pair */
+
+            for (i = 0; i < cTargetPropList; i+=2)
+            {
+                XSelectionRequestEvent event;
+
+                if (TRACE_ON(clipboard))
+                {
+                    char *targetName, *propName;
+                    wine_tsx11_lock();
+                    targetName = XGetAtomName(display, targetPropList[i]);
+                    propName = XGetAtomName(display, targetPropList[i+1]);
+                    TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
+                          i/2, targetName, propName);
+                    XFree(targetName);
+                    XFree(propName);
+                    wine_tsx11_unlock();
+                }
+
+                /* We must have a non "None" property to service a MULTIPLE target atom */
+                if ( !targetPropList[i+1] )
+                {
+                    TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
+                    continue;
+                }
+
+                /* Set up an XSelectionRequestEvent for this (target,property) pair */
+                memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
+                event.target = targetPropList[i];
+                event.property = targetPropList[i+1];
+
+                /* Fire a SelectionRequest, informing the handler that we are processing
+                 * a MULTIPLE selection request event.
+                 */
+                X11DRV_HandleSelectionRequest( hWnd, &event, TRUE );
+            }
+        }
+
+        /* Free the list of targets/properties */
+        wine_tsx11_lock();
+        XFree(targetPropList);
+        wine_tsx11_unlock();
+    }
+
+    return rprop;
+}
+
+
+/***********************************************************************
+ *           X11DRV_HandleSelectionRequest
+ *  Process an event selection request event.
+ *  The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
+ *  recursively while servicing a "MULTIPLE" selection target.
+ *
+ *  Note: We only receive this event when WINE owns the X selection
+ */
+static void X11DRV_HandleSelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
+{
+    Display *display = event->display;
+    XSelectionEvent result;
+    Atom rprop = None;
+    Window request = event->requestor;
+
+    TRACE("\n");
+
+    /*
+     * We can only handle the selection request if :
+     * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
+     * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
+     * since this has been already done.
+     */
+    if ( !bIsMultiple )
+    {
+        if (((event->selection != XA_PRIMARY) && (event->selection != x11drv_atom(CLIPBOARD))))
+            goto END;
+    }
+
+    /* If the specified property is None the requestor is an obsolete client.
+     * We support these by using the specified target atom as the reply property.
+     */
+    rprop = event->property;
+    if( rprop == None )
+        rprop = event->target;
+
+    if(event->target == x11drv_atom(TARGETS))  /*  Return a list of all supported targets */
+    {
+        /* TARGETS selection request */
+        rprop = X11DRV_SelectionRequest_TARGETS( display, request, event->target, rprop );
+    }
+    else if(event->target == x11drv_atom(MULTIPLE))  /*  rprop contains a list of (target, property) atom pairs */
+    {
+        /* MULTIPLE selection request */
+        rprop = X11DRV_SelectionRequest_MULTIPLE( hWnd, event );
+    }
+    else
+    {
+        LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(event->target);
+
+        if (!lpFormat)
+            lpFormat = X11DRV_CLIPBOARD_LookupAliasProperty(event->target);
+
+        if (lpFormat && lpFormat->lpDrvExportFunc)
+        {
+            LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(lpFormat->wFormatID);
+
+            if (lpData)
+            {
+                unsigned char* lpClipData;
+                DWORD cBytes;
+                HANDLE hClipData = lpFormat->lpDrvExportFunc(request, event->target,
+                                                             rprop, lpData, &cBytes);
+
+                if (hClipData && (lpClipData = GlobalLock(hClipData)))
+                {
+                    TRACE("\tUpdating property %s, %ld bytes\n", debugstr_w(lpFormat->Name), cBytes);
+
+                    wine_tsx11_lock();
+                    XChangeProperty(display, request, rprop, event->target,
+                                    8, PropModeReplace, (unsigned char *)lpClipData, cBytes);
+                    wine_tsx11_unlock();
+
+                    GlobalUnlock(hClipData);
+                    GlobalFree(hClipData);
+                }
+            }
+        }
+    }
+
+END:
+    /* reply to sender
+     * SelectionNotify should be sent only at the end of a MULTIPLE request
+     */
+    if ( !bIsMultiple )
+    {
+        result.type = SelectionNotify;
+        result.display = display;
+        result.requestor = request;
+        result.selection = event->selection;
+        result.property = rprop;
+        result.target = event->target;
+        result.time = event->time;
+        TRACE("Sending SelectionNotify event...\n");
+        wine_tsx11_lock();
+        XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
+        wine_tsx11_unlock();
+    }
+}
+
+
+/***********************************************************************
+ *           X11DRV_SelectionRequest
+ */
+void X11DRV_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event )
+{
+    if (!hWnd) return;
+    X11DRV_HandleSelectionRequest( hWnd, event, FALSE );
+}
+
+
+/***********************************************************************
+ *           X11DRV_SelectionClear
+ */
+void X11DRV_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
+{
+    if (!hWnd) return;
+    if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
+        X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd, event->time );
+}