Atrinik Client 2.5
toolkit/clipboard.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00034 #include <global.h>
00035 #include <SDL_syswm.h>
00036 
00037 #if defined(HAVE_X11)
00038 #include <X11/Xlib.h>
00039 #include <X11/Xatom.h>
00040 
00041 #ifdef HAVE_X11_XMU
00042 #   include <X11/Xmu/Atoms.h>
00043 #endif
00044 
00045 static Display *SDL_Display = NULL;
00046 static Window SDL_Window;
00047 #elif defined(WIN32)
00048 static HWND SDL_Window = NULL;
00049 #endif
00050 
00051 #if defined(HAVE_X11)
00052 static int clipboard_filter(const SDL_Event *event)
00053 {
00054     /* Post all non-window manager specific events */
00055     if (event->type != SDL_SYSWMEVENT)
00056     {
00057         return 1;
00058     }
00059 
00060     /* Handle window-manager specific clipboard events. */
00061     switch (event->syswm.msg->event.xevent.type)
00062     {
00063         /* Copy the selection from XA_CUT_BUFFER0 to the requested property. */
00064         case SelectionRequest:
00065         {
00066             XSelectionRequestEvent *req;
00067             XEvent sevent;
00068             int seln_format;
00069             unsigned long nbytes, overflow;
00070             unsigned char *seln_data;
00071 
00072             req = &event->syswm.msg->event.xevent.xselectionrequest;
00073             sevent.xselection.type = SelectionNotify;
00074             sevent.xselection.display = req->display;
00075             sevent.xselection.selection = req->selection;
00076             sevent.xselection.target = None;
00077             sevent.xselection.property = None;
00078             sevent.xselection.requestor = req->requestor;
00079             sevent.xselection.time = req->time;
00080 
00081             if (XGetWindowProperty(SDL_Display, DefaultRootWindow(SDL_Display), XA_CUT_BUFFER0, 0, INT_MAX / 4, False, req->target, &sevent.xselection.target, &seln_format, &nbytes, &overflow, &seln_data) == Success)
00082             {
00083                 if (sevent.xselection.target == req->target)
00084                 {
00085                     if (sevent.xselection.target == XA_STRING)
00086                     {
00087                         if (seln_data[nbytes - 1] == '\0')
00088                         {
00089                             nbytes--;
00090                         }
00091                     }
00092 
00093                     XChangeProperty(SDL_Display, req->requestor, req->property, sevent.xselection.target, seln_format, PropModeReplace, seln_data, nbytes);
00094                     sevent.xselection.property = req->property;
00095                 }
00096 
00097                 XFree(seln_data);
00098             }
00099 
00100             XSendEvent(SDL_Display, req->requestor, False, 0, &sevent);
00101             XSync(SDL_Display, False);
00102         }
00103 
00104         break;
00105     }
00106 
00107     /* Post the event for X11 clipboard reading above. */
00108     return 1;
00109 }
00110 #endif
00111 
00115 int clipboard_init()
00116 {
00117     SDL_SysWMinfo info;
00118 
00119     /* Grab the window manager specific information. */
00120     SDL_VERSION(&info.version);
00121 
00122     if (SDL_GetWMInfo(&info))
00123     {
00124         /* Save the information for later use. */
00125 #if defined(HAVE_X11)
00126         if (info.subsystem == SDL_SYSWM_X11)
00127         {
00128             SDL_Display = info.info.x11.display;
00129             SDL_Window = info.info.x11.window;
00130 
00131             /* Enable the special window hook events. */
00132             SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
00133             SDL_SetEventFilter(clipboard_filter);
00134 
00135             return 1;
00136         }
00137         else
00138         {
00139             LOG(llevBug, "SDL is not running on X11 display.\n");
00140             return 0;
00141         }
00142 
00143 #elif defined(WIN32)
00144         SDL_Window = info.window;
00145         return 1;
00146 
00147 #else
00148         return 0;
00149 
00150 #endif
00151     }
00152 
00153     return 0;
00154 }
00155 
00160 int clipboard_set(const char *str)
00161 {
00162 #if defined(HAVE_X11)
00163     if (!SDL_Display)
00164     {
00165         return 0;
00166     }
00167 
00168     XChangeProperty(SDL_Display, DefaultRootWindow(SDL_Display), XA_CUT_BUFFER0, XA_STRING, 8, PropModeReplace, (unsigned const char *) str, strlen(str));
00169 
00170     if (XGetSelectionOwner(SDL_Display, XA_PRIMARY) != SDL_Window)
00171     {
00172         XSetSelectionOwner(SDL_Display, XA_PRIMARY, SDL_Window, CurrentTime);
00173     }
00174 
00175 #ifdef HAVE_X11_XMU
00176     if (XGetSelectionOwner(SDL_Display, XA_CLIPBOARD(SDL_Display)) != SDL_Window)
00177     {
00178         XSetSelectionOwner(SDL_Display, XA_CLIPBOARD(SDL_Display), SDL_Window, CurrentTime);
00179     }
00180 #endif
00181 
00182     if (getenv("KDE_FULL_SESSION"))
00183     {
00184         char buf[4096 * 4];
00185 
00186         snprintf(buf, sizeof(buf), "dbus-send --type=method_call --dest=org.kde.klipper /klipper org.kde.klipper.klipper.setClipboardContents string:\"%s\"", str);
00187 
00188         if (system(buf) != 0)
00189         {
00190             return 0;
00191         }
00192     }
00193 
00194     return 1;
00195 #elif defined(WIN32)
00196     if (!SDL_Window)
00197     {
00198         return 0;
00199     }
00200 
00201     if (OpenClipboard(SDL_Window))
00202     {
00203         SIZE_T i, size;
00204         HANDLE hMem;
00205 
00206         /* Find out the size of the data. */
00207         for (size = 0, i = 0; str[i] != '\0'; i++, size++)
00208         {
00209             if (str[i] == '\n' && (i == 0 || str[i - 1] != '\r'))
00210             {
00211                 /* We're going to insert a carriage return. */
00212                 size++;
00213             }
00214         }
00215 
00216         size += 1;
00217 
00218         hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
00219 
00220         if (hMem)
00221         {
00222             LPTSTR dst = (LPTSTR) GlobalLock(hMem);
00223 
00224             /* Copy the text over, adding carriage returns as necessary. */
00225             for (i = 0; str[i] != '\0'; i++)
00226             {
00227                 if (str[i] == '\n' && (i == 0 || str[i - 1] != '\r'))
00228                 {
00229                     *dst++ = '\r';
00230                 }
00231 
00232                 *dst++ = str[i];
00233             }
00234 
00235             *dst = '\0';
00236             GlobalUnlock(hMem);
00237 
00238             EmptyClipboard();
00239 
00240             if (!SetClipboardData(CF_TEXT, hMem))
00241             {
00242                 CloseClipboard();
00243                 return 0;
00244             }
00245         }
00246 
00247         CloseClipboard();
00248     }
00249 
00250     return 1;
00251 #else
00252     (void) str;
00253     return 0;
00254 #endif
00255 }
00256 
00261 char *clipboard_get()
00262 {
00263     char *result;
00264 #if defined(HAVE_X11)
00265     Window owner;
00266     Atom selection, seln_type;
00267     int seln_format;
00268     unsigned long nbytes, overflow;
00269     char *src;
00270 
00271     if (!SDL_Display)
00272     {
00273         return NULL;
00274     }
00275 
00276     owner = XGetSelectionOwner(SDL_Display, XA_PRIMARY);
00277     result = NULL;
00278 
00279     if (owner == None || owner == SDL_Window)
00280     {
00281         owner = DefaultRootWindow(SDL_Display);
00282         selection = XA_CUT_BUFFER0;
00283     }
00284     else
00285     {
00286         int selection_response = 0;
00287         SDL_Event event;
00288 
00289         owner = SDL_Window;
00290         selection = XInternAtom(SDL_Display, "SDL_SELECTION", False);
00291         XConvertSelection(SDL_Display, XA_PRIMARY, XA_STRING, selection, owner, CurrentTime);
00292 
00293         while (!selection_response)
00294         {
00295             SDL_WaitEvent(&event);
00296 
00297             if (event.type == SDL_SYSWMEVENT)
00298             {
00299                 XEvent xevent = event.syswm.msg->event.xevent;
00300 
00301                 if ((xevent.type == SelectionNotify) && (xevent.xselection.requestor == owner))
00302                 {
00303                     selection_response = 1;
00304                 }
00305             }
00306         }
00307     }
00308 
00309     if (XGetWindowProperty(SDL_Display, owner, selection, 0, INT_MAX / 4, False, XA_STRING, &seln_type, &seln_format, &nbytes, &overflow, (unsigned char **) &src) == Success)
00310     {
00311         if (seln_type == XA_STRING)
00312         {
00313             result = strdup(src);
00314         }
00315 
00316         XFree(src);
00317     }
00318 #elif defined(WIN32)
00319     if (!SDL_Window)
00320     {
00321         return NULL;
00322     }
00323 
00324     if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(SDL_Window))
00325     {
00326         HANDLE hMem;
00327         char *src;
00328 
00329         hMem = GetClipboardData(CF_TEXT);
00330 
00331         if (hMem)
00332         {
00333             src = (char *) GlobalLock(hMem);
00334             result = strdup(src);
00335             GlobalUnlock(hMem);
00336         }
00337 
00338         CloseClipboard();
00339     }
00340 #else
00341     result = NULL;
00342 #endif
00343 
00344     return result;
00345 }