Blender V2.61 - r43446

GHOST_SystemX11.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * Part of this code has been taken from Qt, under LGPL license
00026  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
00027  *
00028  * ***** END GPL LICENSE BLOCK *****
00029  */
00030 
00036 #include "GHOST_SystemX11.h"
00037 #include "GHOST_WindowX11.h"
00038 #include "GHOST_WindowManager.h"
00039 #include "GHOST_TimerManager.h"
00040 #include "GHOST_EventCursor.h"
00041 #include "GHOST_EventKey.h"
00042 #include "GHOST_EventButton.h"
00043 #include "GHOST_EventWheel.h"
00044 #include "GHOST_DisplayManagerX11.h"
00045 #ifdef WITH_INPUT_NDOF
00046 #include "GHOST_NDOFManagerX11.h"
00047 #endif
00048 
00049 #include "GHOST_Debug.h"
00050 
00051 #include <X11/Xatom.h>
00052 #include <X11/keysym.h>
00053 #include <X11/XKBlib.h> /* allow detectable autorepeate */
00054 
00055 #ifdef WITH_XF86KEYSYM
00056 #include <X11/XF86keysym.h>
00057 #endif
00058 
00059 // For timing
00060 
00061 #include <sys/time.h>
00062 #include <unistd.h>
00063 
00064 #include <iostream>
00065 #include <vector>
00066 #include <stdio.h> // for fprintf only
00067 #include <cstdlib> // for exit
00068 
00069 static GHOST_TKey
00070 convertXKey(KeySym key);
00071 
00072 //these are for copy and select copy
00073 static char *txt_cut_buffer= NULL;
00074 static char *txt_select_buffer= NULL;
00075 
00076 using namespace std;
00077 
00078 GHOST_SystemX11::
00079 GHOST_SystemX11(
00080 ) : 
00081     GHOST_System(),
00082     m_start_time(0)
00083 {
00084     m_display = XOpenDisplay(NULL);
00085     
00086     if (!m_display) {
00087         std::cerr << "Unable to open a display" << std::endl;
00088         abort(); //was return before, but this would just mean it will crash later
00089     }
00090 
00091     /* Open a connection to the X input manager */
00092 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
00093     m_xim = XOpenIM(m_display, NULL, (char *)GHOST_X11_RES_NAME, (char *)GHOST_X11_RES_CLASS);
00094 #endif
00095 
00096     m_delete_window_atom 
00097       = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
00098 
00099     m_wm_protocols= XInternAtom(m_display, "WM_PROTOCOLS", False);
00100     m_wm_take_focus= XInternAtom(m_display, "WM_TAKE_FOCUS", False);
00101     m_wm_state= XInternAtom(m_display, "WM_STATE", False);
00102     m_wm_change_state= XInternAtom(m_display, "WM_CHANGE_STATE", False);
00103     m_net_state= XInternAtom(m_display, "_NET_WM_STATE", False);
00104     m_net_max_horz= XInternAtom(m_display,
00105                     "_NET_WM_STATE_MAXIMIZED_HORZ", False);
00106     m_net_max_vert= XInternAtom(m_display,
00107                     "_NET_WM_STATE_MAXIMIZED_VERT", False);
00108     m_net_fullscreen= XInternAtom(m_display,
00109                     "_NET_WM_STATE_FULLSCREEN", False);
00110     m_motif= XInternAtom(m_display, "_MOTIF_WM_HINTS", False);
00111     m_targets= XInternAtom(m_display, "TARGETS", False);
00112     m_string= XInternAtom(m_display, "STRING", False);
00113     m_compound_text= XInternAtom(m_display, "COMPOUND_TEXT", False);
00114     m_text= XInternAtom(m_display, "TEXT", False);
00115     m_clipboard= XInternAtom(m_display, "CLIPBOARD", False);
00116     m_primary= XInternAtom(m_display, "PRIMARY", False);
00117     m_xclip_out= XInternAtom(m_display, "XCLIP_OUT", False);
00118     m_incr= XInternAtom(m_display, "INCR", False);
00119     m_utf8_string= XInternAtom(m_display, "UTF8_STRING", False);
00120     m_last_warp = 0;
00121 
00122 
00123     // compute the initial time
00124     timeval tv;
00125     if (gettimeofday(&tv,NULL) == -1) {
00126         GHOST_ASSERT(false,"Could not instantiate timer!");
00127     }
00128     
00129     // Taking care not to overflow the tv.tv_sec*1000
00130     m_start_time = GHOST_TUns64(tv.tv_sec)*1000 + tv.tv_usec/1000;
00131     
00132     
00133     /* use detectable autorepeate, mac and windows also do this */
00134     int use_xkb;
00135     int xkb_opcode, xkb_event, xkb_error;
00136     int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
00137     
00138     use_xkb = XkbQueryExtension(m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor);
00139     if (use_xkb) {
00140         XkbSetDetectableAutoRepeat(m_display, true, NULL);
00141     }
00142     
00143 }
00144 
00145 GHOST_SystemX11::
00146 ~GHOST_SystemX11()
00147 {
00148 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
00149     XCloseIM(m_xim);
00150 #endif
00151 
00152     XCloseDisplay(m_display);
00153 }
00154 
00155 
00156     GHOST_TSuccess 
00157 GHOST_SystemX11::
00158 init(
00159 ){
00160     GHOST_TSuccess success = GHOST_System::init();
00161 
00162     if (success) {
00163 #ifdef WITH_INPUT_NDOF
00164         m_ndofManager = new GHOST_NDOFManagerX11(*this);
00165 #endif
00166         m_displayManager = new GHOST_DisplayManagerX11(this);
00167 
00168         if (m_displayManager) {
00169             return GHOST_kSuccess;
00170         }
00171     }
00172 
00173     return GHOST_kFailure;
00174 }
00175 
00176     GHOST_TUns64
00177 GHOST_SystemX11::
00178 getMilliSeconds(
00179 ) const {
00180     timeval tv;
00181     if (gettimeofday(&tv,NULL) == -1) {
00182         GHOST_ASSERT(false,"Could not compute time!");
00183     }
00184 
00185     // Taking care not to overflow the tv.tv_sec*1000
00186     return  GHOST_TUns64(tv.tv_sec)*1000 + tv.tv_usec/1000 - m_start_time;
00187 }
00188     
00189     GHOST_TUns8 
00190 GHOST_SystemX11::
00191 getNumDisplays(
00192 ) const {
00193     return GHOST_TUns8(1);
00194 }
00195 
00200     void 
00201 GHOST_SystemX11::
00202 getMainDisplayDimensions(
00203     GHOST_TUns32& width,
00204     GHOST_TUns32& height
00205 ) const {   
00206     if (m_display) {
00207         width  = DisplayWidth(m_display, DefaultScreen(m_display));
00208         height = DisplayHeight(m_display, DefaultScreen(m_display));
00209     }
00210 }
00211 
00228     GHOST_IWindow* 
00229 GHOST_SystemX11::
00230 createWindow(
00231     const STR_String& title,
00232     GHOST_TInt32 left,
00233     GHOST_TInt32 top,
00234     GHOST_TUns32 width,
00235     GHOST_TUns32 height,
00236     GHOST_TWindowState state,
00237     GHOST_TDrawingContextType type,
00238     bool stereoVisual,
00239     const GHOST_TUns16 numOfAASamples,
00240     const GHOST_TEmbedderWindowID parentWindow
00241 ){
00242     GHOST_WindowX11 * window = 0;
00243     
00244     if (!m_display) return 0;
00245     
00246 
00247     
00248 
00249     window = new GHOST_WindowX11 (
00250         this,m_display,title, left, top, width, height, state, parentWindow, type, stereoVisual
00251     );
00252 
00253     if (window) {
00254         // Both are now handle in GHOST_WindowX11.cpp
00255         // Focus and Delete atoms.
00256 
00257         if (window->getValid()) {
00258             // Store the pointer to the window 
00259             m_windowManager->addWindow(window);
00260             m_windowManager->setActiveWindow(window);
00261             pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
00262         }
00263         else {
00264             delete window;
00265             window = 0;
00266         }
00267     }
00268     return window;
00269 }
00270 
00271     GHOST_WindowX11 * 
00272 GHOST_SystemX11::
00273 findGhostWindow(
00274     Window xwind
00275 ) const {
00276     
00277     if (xwind == 0) return NULL;
00278 
00279     // It is not entirely safe to do this as the backptr may point
00280     // to a window that has recently been removed. 
00281     // We should always check the window manager's list of windows 
00282     // and only process events on these windows.
00283 
00284     vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
00285 
00286     vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
00287     vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
00288     
00289     for (; win_it != win_end; ++win_it) {
00290         GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
00291         if (window->getXWindow() == xwind) {
00292             return window;
00293         }
00294     }
00295     return NULL;
00296     
00297 }
00298 
00299 static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep)
00300 {
00301     int fd = ConnectionNumber(display);
00302     fd_set fds;
00303     
00304     FD_ZERO(&fds);
00305     FD_SET(fd, &fds);
00306 
00307     if (maxSleep == -1) {
00308         select(fd + 1, &fds, NULL, NULL, NULL);
00309     }
00310     else {
00311         timeval tv;
00312 
00313         tv.tv_sec = maxSleep/1000;
00314         tv.tv_usec = (maxSleep - tv.tv_sec*1000)*1000;
00315     
00316         select(fd + 1, &fds, NULL, NULL, &tv);
00317     }
00318 }
00319 
00320 /* This function borrowed from Qt's X11 support
00321  * qclipboard_x11.cpp
00322  *  */
00323 struct init_timestamp_data
00324 {
00325     Time timestamp;
00326 };
00327 
00328 static Bool init_timestamp_scanner(Display*, XEvent *event, XPointer arg)
00329 {
00330     init_timestamp_data *data =
00331         reinterpret_cast<init_timestamp_data*>(arg);
00332     switch(event->type)
00333     {
00334     case ButtonPress:
00335     case ButtonRelease:
00336         data->timestamp = event->xbutton.time;
00337         break;
00338     case MotionNotify:
00339         data->timestamp = event->xmotion.time;
00340         break;
00341     case KeyPress:
00342     case KeyRelease:
00343         data->timestamp = event->xkey.time;
00344         break;
00345     case PropertyNotify:
00346         data->timestamp = event->xproperty.time;
00347         break;
00348     case EnterNotify:
00349     case LeaveNotify:
00350         data->timestamp = event->xcrossing.time;
00351         break;
00352     case SelectionClear:
00353         data->timestamp = event->xselectionclear.time;
00354         break;
00355     default:
00356         break;
00357     }
00358 
00359     return false;
00360 }
00361 
00362 Time
00363 GHOST_SystemX11::
00364 lastEventTime(Time default_time) {
00365     init_timestamp_data data;
00366     data.timestamp = default_time;
00367     XEvent ev;
00368     XCheckIfEvent(m_display, &ev, &init_timestamp_scanner, (XPointer)&data);
00369 
00370     return data.timestamp;
00371 }
00372 
00373     bool 
00374 GHOST_SystemX11::
00375 processEvents(
00376     bool waitForEvent
00377 ){
00378     // Get all the current events -- translate them into 
00379     // ghost events and call base class pushEvent() method.
00380     
00381     bool anyProcessed = false;
00382     
00383     do {
00384         GHOST_TimerManager* timerMgr = getTimerManager();
00385         
00386         if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) {
00387             GHOST_TUns64 next = timerMgr->nextFireTime();
00388             
00389             if (next==GHOST_kFireTimeNever) {
00390                 SleepTillEvent(m_display, -1);
00391             } else {
00392                 GHOST_TInt64 maxSleep = next - getMilliSeconds();
00393 
00394                 if(maxSleep >= 0)
00395                     SleepTillEvent(m_display, next - getMilliSeconds());
00396             }
00397         }
00398         
00399         if (timerMgr->fireTimers(getMilliSeconds())) {
00400             anyProcessed = true;
00401         }
00402         
00403         while (XPending(m_display)) {
00404             XEvent xevent;
00405             XNextEvent(m_display, &xevent);
00406             processEvent(&xevent);
00407             anyProcessed = true;
00408         }
00409         
00410         if (generateWindowExposeEvents()) {
00411             anyProcessed = true;
00412         }
00413 
00414 #ifdef WITH_INPUT_NDOF
00415         if (dynamic_cast<GHOST_NDOFManagerX11*>(m_ndofManager)->processEvents()) {
00416             anyProcessed = true;
00417         }
00418 #endif
00419         
00420     } while (waitForEvent && !anyProcessed);
00421     
00422     return anyProcessed;
00423 }
00424 
00425     void
00426 GHOST_SystemX11::processEvent(XEvent *xe)
00427 {
00428     GHOST_WindowX11 * window = findGhostWindow(xe->xany.window);    
00429     GHOST_Event * g_event = NULL;
00430 
00431     if (!window) {
00432         return;
00433     }
00434     
00435     switch (xe->type) {
00436         case Expose:
00437         {
00438             XExposeEvent & xee = xe->xexpose;
00439 
00440             if (xee.count == 0) {
00441                 // Only generate a single expose event
00442                 // per read of the event queue.
00443 
00444                 g_event = new
00445                 GHOST_Event(
00446                     getMilliSeconds(),
00447                     GHOST_kEventWindowUpdate,
00448                     window
00449                 );
00450             }
00451             break;
00452         }
00453 
00454         case MotionNotify:
00455         {
00456             XMotionEvent &xme = xe->xmotion;
00457             
00458             if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
00459             {
00460                 GHOST_TInt32 x_new= xme.x_root;
00461                 GHOST_TInt32 y_new= xme.y_root;
00462                 GHOST_TInt32 x_accum, y_accum;
00463                 GHOST_Rect bounds;
00464 
00465                 /* fallback to window bounds */
00466                 if(window->getCursorGrabBounds(bounds)==GHOST_kFailure)
00467                     window->getClientBounds(bounds);
00468 
00469                 /* could also clamp to screen bounds
00470                  * wrap with a window outside the view will fail atm  */
00471                 bounds.wrapPoint(x_new, y_new, 8); /* offset of one incase blender is at screen bounds */
00472                 window->getCursorGrabAccum(x_accum, y_accum);
00473 
00474                 if(x_new != xme.x_root || y_new != xme.y_root) {
00475                     if (xme.time > m_last_warp) {
00476                         /* when wrapping we don't need to add an event because the
00477                          * setCursorPosition call will cause a new event after */
00478                         setCursorPosition(x_new, y_new); /* wrap */
00479                         window->setCursorGrabAccum(x_accum + (xme.x_root - x_new), y_accum + (xme.y_root - y_new));
00480                         m_last_warp = lastEventTime(xme.time);
00481                     } else {
00482                         setCursorPosition(x_new, y_new); /* wrap but don't accumulate */
00483                     }
00484                 }
00485                 else {
00486                     g_event = new
00487                     GHOST_EventCursor(
00488                         getMilliSeconds(),
00489                         GHOST_kEventCursorMove,
00490                         window,
00491                         xme.x_root + x_accum,
00492                         xme.y_root + y_accum
00493                     );
00494                 }
00495             }
00496             else {
00497                 g_event = new
00498                 GHOST_EventCursor(
00499                     getMilliSeconds(),
00500                     GHOST_kEventCursorMove,
00501                     window,
00502                     xme.x_root,
00503                     xme.y_root
00504                 );
00505             }
00506             break;
00507         }
00508 
00509         case KeyPress:
00510         case KeyRelease:
00511         {
00512             XKeyEvent *xke = &(xe->xkey);
00513             KeySym key_sym = XLookupKeysym(xke,0);
00514             char ascii;
00515             char utf8_buf[6]; /* 6 is enough for a utf8 char */
00516             
00517             GHOST_TKey gkey = convertXKey(key_sym);
00518             GHOST_TEventType type = (xke->type == KeyPress) ? 
00519                 GHOST_kEventKeyDown : GHOST_kEventKeyUp;
00520             
00521             if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
00522                 ascii = '\0';
00523             }
00524             
00525 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
00526             /* getting unicode on key-up events gives XLookupNone status */
00527             if (xke->type == KeyPress) {
00528                 Status status;
00529                 int len;
00530 
00531                 /* use utf8 because its not locale depentant, from xorg docs */
00532                 if (!(len= Xutf8LookupString(window->getX11_XIC(), xke, utf8_buf, sizeof(utf8_buf), &key_sym, &status))) {
00533                     utf8_buf[0]= '\0';
00534                 }
00535 
00536                 if ((status == XLookupChars || status == XLookupBoth)) {
00537                     if ((unsigned char)utf8_buf[0] >= 32) { /* not an ascii control character */
00538                         /* do nothing for now, this is valid utf8 */
00539                     }
00540                     else {
00541                         utf8_buf[0]= '\0';
00542                     }
00543                 }
00544                 else if (status == XLookupKeySym) {
00545                     /* this key doesn't have a text representation, it is a command
00546                        key of some sort */;
00547                 }
00548                 else {
00549                     printf("Bad keycode lookup. Keysym 0x%x Status: %s\n",
00550                               (unsigned int) key_sym,
00551                               (status == XBufferOverflow ? "BufferOverflow" :
00552                                status == XLookupNone ? "XLookupNone" :
00553                                status == XLookupKeySym ? "XLookupKeySym" :
00554                                "Unknown status"));
00555 
00556                     printf("'%.*s' %p %p\n", len, utf8_buf, window->getX11_XIC(), m_xim);
00557                 }
00558             }
00559             else {
00560                 utf8_buf[0]= '\0';
00561             }
00562 #else
00563             utf8_buf[0]= '\0';
00564 #endif
00565 
00566             g_event = new
00567             GHOST_EventKey(
00568                 getMilliSeconds(),
00569                 type,
00570                 window,
00571                 gkey,
00572                 ascii,
00573                 utf8_buf
00574             );
00575             
00576         break;
00577         }
00578 
00579         case ButtonPress:
00580         case ButtonRelease:
00581         {
00582             XButtonEvent & xbe = xe->xbutton;
00583             GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
00584             GHOST_TEventType type = (xbe.type == ButtonPress) ? 
00585                 GHOST_kEventButtonDown : GHOST_kEventButtonUp;
00586 
00587             /* process wheel mouse events and break, only pass on press events */
00588             if(xbe.button == Button4) {
00589                 if(xbe.type == ButtonPress)
00590                     g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
00591                 break;
00592             }
00593             else if(xbe.button == Button5) {
00594                 if(xbe.type == ButtonPress)
00595                     g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
00596                 break;
00597             }
00598             
00599             /* process rest of normal mouse buttons */
00600             if(xbe.button == Button1)
00601                 gbmask = GHOST_kButtonMaskLeft;
00602             else if(xbe.button == Button2)
00603                 gbmask = GHOST_kButtonMaskMiddle;
00604             else if(xbe.button == Button3)
00605                 gbmask = GHOST_kButtonMaskRight;
00606             /* It seems events 6 and 7 are for horizontal scrolling.
00607             * you can re-order button mapping like this... (swaps 6,7 with 8,9)
00608             *   xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7" 
00609             */
00610             else if(xbe.button == 8)
00611                 gbmask = GHOST_kButtonMaskButton4;
00612             else if(xbe.button == 9)
00613                 gbmask = GHOST_kButtonMaskButton5;
00614             else
00615                 break;
00616 
00617             g_event = new
00618             GHOST_EventButton(
00619                 getMilliSeconds(),
00620                 type,
00621                 window,
00622                 gbmask
00623             );
00624             break;
00625         }
00626             
00627             // change of size, border, layer etc.
00628         case ConfigureNotify:
00629         {
00630             /* XConfigureEvent & xce = xe->xconfigure; */
00631 
00632             g_event = new 
00633             GHOST_Event(
00634                 getMilliSeconds(),
00635                 GHOST_kEventWindowSize,
00636                 window
00637             );          
00638             break;
00639         }
00640 
00641         case FocusIn:
00642         case FocusOut:
00643         {
00644             XFocusChangeEvent &xfe = xe->xfocus;
00645 
00646             // TODO: make sure this is the correct place for activate/deactivate
00647             // printf("X: focus %s for window %d\n", xfe.type == FocusIn ? "in" : "out", (int) xfe.window);
00648         
00649             // May have to look at the type of event and filter some
00650             // out.
00651                                     
00652             GHOST_TEventType gtype = (xfe.type == FocusIn) ? 
00653                 GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate;
00654 
00655             g_event = new 
00656             GHOST_Event(    
00657                 getMilliSeconds(),
00658                 gtype,
00659                 window
00660             );
00661             break;
00662 
00663         }
00664         case ClientMessage:
00665         {
00666             XClientMessageEvent & xcme = xe->xclient;
00667 
00668             if (((Atom)xcme.data.l[0]) == m_delete_window_atom) {
00669                 g_event = new 
00670                 GHOST_Event(    
00671                     getMilliSeconds(),
00672                     GHOST_kEventWindowClose,
00673                     window
00674                 );
00675             }
00676             else if (((Atom)xcme.data.l[0]) == m_wm_take_focus) {
00677                 XWindowAttributes attr;
00678                 Window fwin;
00679                 int revert_to;
00680 
00681                 /* as ICCCM say, we need reply this event
00682                  * with a SetInputFocus, the data[1] have
00683                  * the valid timestamp (send by the wm).
00684                  *
00685                  * Some WM send this event before the
00686                  * window is really mapped (for example
00687                  * change from virtual desktop), so we need
00688                  * to be sure that our windows is mapped
00689                  * or this call fail and close blender.
00690                  */
00691                 if (XGetWindowAttributes(m_display, xcme.window, &attr) == True) {
00692                     if (XGetInputFocus(m_display, &fwin, &revert_to) == True) {
00693                         if (attr.map_state == IsViewable) {
00694                             if (fwin != xcme.window)
00695                                 XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
00696                         }
00697                     }
00698                 }
00699             } else {
00700                 /* Unknown client message, ignore */
00701             }
00702             break;
00703         }
00704         
00705         case DestroyNotify:
00706 			::exit(-1);  
00707         // We're not interested in the following things.(yet...)
00708         case NoExpose : 
00709         case GraphicsExpose :
00710             break;
00711         
00712         case EnterNotify:
00713         case LeaveNotify:
00714         {
00715             /* XCrossingEvents pointer leave enter window.
00716                also do cursor move here, MotionNotify only
00717                happens when motion starts & ends inside window.
00718                we only do moves when the crossing mode is 'normal'
00719                (really crossing between windows) since some windowmanagers
00720                also send grab/ungrab crossings for mousewheel events.
00721             */
00722             XCrossingEvent &xce = xe->xcrossing;
00723             if( xce.mode == NotifyNormal ) {
00724                 g_event = new 
00725                 GHOST_EventCursor(
00726                     getMilliSeconds(),
00727                     GHOST_kEventCursorMove,
00728                     window,
00729                     xce.x_root,
00730                     xce.y_root
00731                 );
00732             }
00733 
00734             // printf("X: %s window %d\n", xce.type == EnterNotify ? "entering" : "leaving", (int) xce.window);
00735 
00736             if (xce.type == EnterNotify)
00737                 m_windowManager->setActiveWindow(window);
00738             else
00739                 m_windowManager->setWindowInactive(window);
00740 
00741             break;
00742         }
00743         case MapNotify:
00744             /*
00745              * From ICCCM:
00746              * [ Clients can select for StructureNotify on their
00747              *   top-level windows to track transition between
00748              *   Normal and Iconic states. Receipt of a MapNotify
00749              *   event will indicate a transition to the Normal
00750              *   state, and receipt of an UnmapNotify event will
00751              *   indicate a transition to the Iconic state. ]
00752              */
00753             if (window->m_post_init == True) {
00754                 /*
00755                  * Now we are sure that the window is
00756                  * mapped, so only need change the state.
00757                  */
00758                 window->setState (window->m_post_state);
00759                 window->m_post_init = False;
00760             }
00761             break;
00762         case UnmapNotify:
00763             break;
00764         case MappingNotify:
00765         case ReparentNotify:
00766             break;
00767         case SelectionRequest:
00768         {
00769             XEvent nxe;
00770             Atom target, utf8_string, string, compound_text, c_string;
00771             XSelectionRequestEvent *xse = &xe->xselectionrequest;
00772             
00773             target = XInternAtom(m_display, "TARGETS", False);
00774             utf8_string = XInternAtom(m_display, "UTF8_STRING", False);
00775             string = XInternAtom(m_display, "STRING", False);
00776             compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
00777             c_string = XInternAtom(m_display, "C_STRING", False);
00778             
00779             /* support obsolete clients */
00780             if (xse->property == None) {
00781                 xse->property = xse->target;
00782             }
00783             
00784             nxe.xselection.type = SelectionNotify;
00785             nxe.xselection.requestor = xse->requestor;
00786             nxe.xselection.property = xse->property;
00787             nxe.xselection.display = xse->display;
00788             nxe.xselection.selection = xse->selection;
00789             nxe.xselection.target = xse->target;
00790             nxe.xselection.time = xse->time;
00791             
00792             /*Check to see if the requestor is asking for String*/
00793             if(xse->target == utf8_string || xse->target == string || xse->target == compound_text || xse->target == c_string) {
00794                 if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
00795                     XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace,
00796                                     (unsigned char*)txt_select_buffer, strlen(txt_select_buffer));
00797                 } else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) {
00798                     XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace,
00799                                     (unsigned char*)txt_cut_buffer, strlen(txt_cut_buffer));
00800                 }
00801             } else if (xse->target == target) {
00802                 Atom alist[5];
00803                 alist[0] = target;
00804                 alist[1] = utf8_string;
00805                 alist[2] = string;
00806                 alist[3] = compound_text;
00807                 alist[4] = c_string;
00808                 XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 32, PropModeReplace,
00809                                 (unsigned char*)alist, 5);
00810                 XFlush(m_display);
00811             } else  {
00812                 //Change property to None because we do not support anything but STRING
00813                 nxe.xselection.property = None;
00814             }
00815             
00816             //Send the event to the client 0 0 == False, SelectionNotify
00817             XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
00818             XFlush(m_display);
00819             break;
00820         }
00821         
00822         default: {
00823 #ifdef WITH_X11_XINPUT
00824             if(xe->type == window->GetXTablet().MotionEvent) 
00825             {
00826                 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
00827                 window->GetXTablet().CommonData.Pressure= 
00828                     data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
00829             
00830             /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
00831              * but I got garbage data without it. Found it in the xidump.c source --matt */
00832                 window->GetXTablet().CommonData.Xtilt= 
00833                     (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
00834                 window->GetXTablet().CommonData.Ytilt= 
00835                     (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
00836             }
00837             else if(xe->type == window->GetXTablet().ProxInEvent) 
00838             {
00839                 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
00840                 if(data->deviceid == window->GetXTablet().StylusID)
00841                     window->GetXTablet().CommonData.Active= GHOST_kTabletModeStylus;
00842                 else if(data->deviceid == window->GetXTablet().EraserID)
00843                     window->GetXTablet().CommonData.Active= GHOST_kTabletModeEraser;
00844             }
00845             else if(xe->type == window->GetXTablet().ProxOutEvent)
00846                 window->GetXTablet().CommonData.Active= GHOST_kTabletModeNone;
00847 #endif // WITH_X11_XINPUT
00848             break;
00849         }
00850     }
00851 
00852     if (g_event) {
00853         pushEvent(g_event);
00854     }
00855 }
00856 
00857     GHOST_TSuccess 
00858 GHOST_SystemX11::
00859 getModifierKeys(
00860     GHOST_ModifierKeys& keys
00861 ) const {
00862 
00863     // analyse the masks retuned from XQueryPointer.
00864 
00865     memset((void *)m_keyboard_vector,0,sizeof(m_keyboard_vector));
00866 
00867     XQueryKeymap(m_display,(char *)m_keyboard_vector);
00868 
00869     // now translate key symobols into keycodes and
00870     // test with vector.
00871 
00872     const static KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
00873     const static KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
00874     const static KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
00875     const static KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
00876     const static KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
00877     const static KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
00878     const static KeyCode super_l = XKeysymToKeycode(m_display,XK_Super_L);
00879     const static KeyCode super_r = XKeysymToKeycode(m_display,XK_Super_R);
00880 
00881     // shift
00882     keys.set(GHOST_kModifierKeyLeftShift, ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) != 0);
00883     keys.set(GHOST_kModifierKeyRightShift, ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) != 0);
00884     // control
00885     keys.set(GHOST_kModifierKeyLeftControl, ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) != 0);
00886     keys.set(GHOST_kModifierKeyRightControl, ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) != 0);
00887     // alt
00888     keys.set(GHOST_kModifierKeyLeftAlt, ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) != 0);
00889     keys.set(GHOST_kModifierKeyRightAlt, ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) != 0);
00890     // super (windows) - only one GHOST-kModifierKeyOS, so mapping to either
00891     keys.set(GHOST_kModifierKeyOS, ( ((m_keyboard_vector[super_l >> 3] >> (super_l & 7)) & 1) ||
00892                                      ((m_keyboard_vector[super_r >> 3] >> (super_r & 7)) & 1) ) != 0);
00893 
00894     return GHOST_kSuccess;
00895 }
00896 
00897     GHOST_TSuccess 
00898 GHOST_SystemX11::
00899 getButtons(
00900     GHOST_Buttons& buttons
00901 ) const {
00902 
00903     Window root_return, child_return;
00904     int rx,ry,wx,wy;
00905     unsigned int mask_return;
00906 
00907     if (XQueryPointer(m_display,
00908                       RootWindow(m_display,DefaultScreen(m_display)),
00909                       &root_return,
00910                       &child_return,
00911                       &rx,&ry,
00912                       &wx,&wy,
00913                       &mask_return) == True)
00914     {
00915         buttons.set(GHOST_kButtonMaskLeft,   (mask_return & Button1Mask) != 0);
00916         buttons.set(GHOST_kButtonMaskMiddle, (mask_return & Button2Mask) != 0);
00917         buttons.set(GHOST_kButtonMaskRight,  (mask_return & Button3Mask) != 0);
00918     }
00919     else {
00920         return GHOST_kFailure;
00921     }   
00922 
00923     return GHOST_kSuccess;
00924 }
00925 
00926 
00927     GHOST_TSuccess 
00928 GHOST_SystemX11::
00929 getCursorPosition(
00930     GHOST_TInt32& x,
00931     GHOST_TInt32& y
00932 ) const {
00933 
00934     Window root_return, child_return;
00935     int rx,ry,wx,wy;
00936     unsigned int mask_return;
00937 
00938     if (XQueryPointer(
00939         m_display,
00940         RootWindow(m_display,DefaultScreen(m_display)),
00941         &root_return,
00942         &child_return,
00943         &rx,&ry,
00944         &wx,&wy,
00945         &mask_return
00946     ) == False) {
00947         return GHOST_kFailure;
00948     } else {
00949         x = rx;
00950         y = ry;
00951     }   
00952     return GHOST_kSuccess;
00953 }
00954 
00955 
00956     GHOST_TSuccess 
00957 GHOST_SystemX11::
00958 setCursorPosition(
00959     GHOST_TInt32 x,
00960     GHOST_TInt32 y
00961 ) {
00962 
00963     // This is a brute force move in screen coordinates
00964     // XWarpPointer does relative moves so first determine the
00965     // current pointer position.
00966 
00967     int cx,cy;
00968     if (getCursorPosition(cx,cy) == GHOST_kFailure) {
00969         return GHOST_kFailure;
00970     }
00971 
00972     int relx = x-cx;
00973     int rely = y-cy;
00974 
00975     XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
00976     XSync(m_display, 0); /* Sync to process all requests */
00977     
00978     return GHOST_kSuccess;
00979 }
00980 
00981 
00982     void
00983 GHOST_SystemX11::
00984 addDirtyWindow(
00985     GHOST_WindowX11 * bad_wind
00986 ){
00987 
00988     GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
00989     
00990     m_dirty_windows.push_back(bad_wind);
00991 }
00992 
00993 
00994     bool
00995 GHOST_SystemX11::
00996 generateWindowExposeEvents(
00997 ){
00998 
00999     vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
01000     vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
01001     bool anyProcessed = false;
01002     
01003     for (;w_start != w_end; ++w_start) {
01004         GHOST_Event * g_event = new 
01005             GHOST_Event(
01006                 getMilliSeconds(),
01007                 GHOST_kEventWindowUpdate,
01008                 *w_start
01009             );          
01010 
01011         (*w_start)->validate(); 
01012         
01013         if (g_event) {
01014             pushEvent(g_event);
01015             anyProcessed = true;
01016         }
01017     }
01018 
01019     m_dirty_windows.clear();
01020     return anyProcessed;
01021 }
01022 
01023 #define GXMAP(k,x,y) case x: k = y; break; 
01024 
01025 static GHOST_TKey
01026 convertXKey(KeySym key)
01027 {
01028     GHOST_TKey type;
01029 
01030     if ((key >= XK_A) && (key <= XK_Z)) {
01031         type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
01032     } else if ((key >= XK_a) && (key <= XK_z)) {
01033         type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
01034     } else if ((key >= XK_0) && (key <= XK_9)) {
01035         type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
01036     } else if ((key >= XK_F1) && (key <= XK_F24)) {
01037         type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
01038 #if defined(__sun) || defined(__sun__) 
01039         /* This is a bit of a hack, but it looks like sun
01040            Used F11 and friends for its special keys Stop,again etc..
01041            So this little patch enables F11 and F12 to work as expected
01042            following link has documentation on it: 
01043            http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
01044            also from /usr/include/X11/Sunkeysym.h 
01045 #define SunXK_F36               0x1005FF10      // Labeled F11
01046 #define SunXK_F37               0x1005FF11      // Labeled F12 
01047 
01048                 mein@cs.umn.edu
01049          */
01050         
01051     } else if (key == 268828432) {
01052         type = GHOST_kKeyF11;
01053     } else if (key == 268828433) {
01054         type = GHOST_kKeyF12;
01055 #endif
01056     } else {
01057         switch(key) {
01058             GXMAP(type,XK_BackSpace,    GHOST_kKeyBackSpace);
01059             GXMAP(type,XK_Tab,          GHOST_kKeyTab);
01060             GXMAP(type,XK_Return,       GHOST_kKeyEnter);
01061             GXMAP(type,XK_Escape,       GHOST_kKeyEsc);
01062             GXMAP(type,XK_space,        GHOST_kKeySpace);
01063             
01064             GXMAP(type,XK_Linefeed,     GHOST_kKeyLinefeed);
01065             GXMAP(type,XK_semicolon,    GHOST_kKeySemicolon);
01066             GXMAP(type,XK_period,       GHOST_kKeyPeriod);
01067             GXMAP(type,XK_comma,        GHOST_kKeyComma);
01068             GXMAP(type,XK_quoteright,   GHOST_kKeyQuote);
01069             GXMAP(type,XK_quoteleft,    GHOST_kKeyAccentGrave);
01070             GXMAP(type,XK_minus,        GHOST_kKeyMinus);
01071             GXMAP(type,XK_slash,        GHOST_kKeySlash);
01072             GXMAP(type,XK_backslash,    GHOST_kKeyBackslash);
01073             GXMAP(type,XK_equal,        GHOST_kKeyEqual);
01074             GXMAP(type,XK_bracketleft,  GHOST_kKeyLeftBracket);
01075             GXMAP(type,XK_bracketright, GHOST_kKeyRightBracket);
01076             GXMAP(type,XK_Pause,        GHOST_kKeyPause);
01077             
01078             GXMAP(type,XK_Shift_L,      GHOST_kKeyLeftShift);
01079             GXMAP(type,XK_Shift_R,      GHOST_kKeyRightShift);
01080             GXMAP(type,XK_Control_L,    GHOST_kKeyLeftControl);
01081             GXMAP(type,XK_Control_R,    GHOST_kKeyRightControl);
01082             GXMAP(type,XK_Alt_L,        GHOST_kKeyLeftAlt);
01083             GXMAP(type,XK_Alt_R,        GHOST_kKeyRightAlt);
01084             GXMAP(type,XK_Super_L,      GHOST_kKeyOS);
01085             GXMAP(type,XK_Super_R,      GHOST_kKeyOS);
01086 
01087             GXMAP(type,XK_Insert,       GHOST_kKeyInsert);
01088             GXMAP(type,XK_Delete,       GHOST_kKeyDelete);
01089             GXMAP(type,XK_Home,         GHOST_kKeyHome);
01090             GXMAP(type,XK_End,          GHOST_kKeyEnd);
01091             GXMAP(type,XK_Page_Up,      GHOST_kKeyUpPage);
01092             GXMAP(type,XK_Page_Down,    GHOST_kKeyDownPage);
01093 
01094             GXMAP(type,XK_Left,         GHOST_kKeyLeftArrow);
01095             GXMAP(type,XK_Right,        GHOST_kKeyRightArrow);
01096             GXMAP(type,XK_Up,           GHOST_kKeyUpArrow);
01097             GXMAP(type,XK_Down,         GHOST_kKeyDownArrow);
01098 
01099             GXMAP(type,XK_Caps_Lock,    GHOST_kKeyCapsLock);
01100             GXMAP(type,XK_Scroll_Lock,  GHOST_kKeyScrollLock);
01101             GXMAP(type,XK_Num_Lock,     GHOST_kKeyNumLock);
01102             
01103                 /* keypad events */
01104                 
01105             GXMAP(type,XK_KP_0,         GHOST_kKeyNumpad0);
01106             GXMAP(type,XK_KP_1,         GHOST_kKeyNumpad1);
01107             GXMAP(type,XK_KP_2,         GHOST_kKeyNumpad2);
01108             GXMAP(type,XK_KP_3,         GHOST_kKeyNumpad3);
01109             GXMAP(type,XK_KP_4,         GHOST_kKeyNumpad4);
01110             GXMAP(type,XK_KP_5,         GHOST_kKeyNumpad5);
01111             GXMAP(type,XK_KP_6,         GHOST_kKeyNumpad6);
01112             GXMAP(type,XK_KP_7,         GHOST_kKeyNumpad7);
01113             GXMAP(type,XK_KP_8,         GHOST_kKeyNumpad8);
01114             GXMAP(type,XK_KP_9,         GHOST_kKeyNumpad9);
01115             GXMAP(type,XK_KP_Decimal,   GHOST_kKeyNumpadPeriod);
01116 
01117             GXMAP(type,XK_KP_Insert,    GHOST_kKeyNumpad0);
01118             GXMAP(type,XK_KP_End,       GHOST_kKeyNumpad1);
01119             GXMAP(type,XK_KP_Down,      GHOST_kKeyNumpad2);
01120             GXMAP(type,XK_KP_Page_Down, GHOST_kKeyNumpad3);
01121             GXMAP(type,XK_KP_Left,      GHOST_kKeyNumpad4);
01122             GXMAP(type,XK_KP_Begin,     GHOST_kKeyNumpad5);
01123             GXMAP(type,XK_KP_Right,     GHOST_kKeyNumpad6);
01124             GXMAP(type,XK_KP_Home,      GHOST_kKeyNumpad7);
01125             GXMAP(type,XK_KP_Up,        GHOST_kKeyNumpad8);
01126             GXMAP(type,XK_KP_Page_Up,   GHOST_kKeyNumpad9);
01127             GXMAP(type,XK_KP_Delete,    GHOST_kKeyNumpadPeriod);
01128 
01129             GXMAP(type,XK_KP_Enter,     GHOST_kKeyNumpadEnter);
01130             GXMAP(type,XK_KP_Add,       GHOST_kKeyNumpadPlus);
01131             GXMAP(type,XK_KP_Subtract,  GHOST_kKeyNumpadMinus);
01132             GXMAP(type,XK_KP_Multiply,  GHOST_kKeyNumpadAsterisk);
01133             GXMAP(type,XK_KP_Divide,    GHOST_kKeyNumpadSlash);
01134 
01135             /* Media keys in some keyboards and laptops with XFree86/Xorg */
01136 #ifdef WITH_XF86KEYSYM
01137             GXMAP(type,XF86XK_AudioPlay,    GHOST_kKeyMediaPlay);
01138             GXMAP(type,XF86XK_AudioStop,    GHOST_kKeyMediaStop);
01139             GXMAP(type,XF86XK_AudioPrev,    GHOST_kKeyMediaFirst);
01140             GXMAP(type,XF86XK_AudioRewind,  GHOST_kKeyMediaFirst);
01141             GXMAP(type,XF86XK_AudioNext,    GHOST_kKeyMediaLast);
01142 #ifdef XF86XK_AudioForward /* Debian lenny's XF86keysym.h has no XF86XK_AudioForward define */
01143             GXMAP(type,XF86XK_AudioForward, GHOST_kKeyMediaLast);
01144 #endif
01145 #endif
01146 
01147                 /* some extra sun cruft (NICE KEYBOARD!) */
01148 #ifdef __sun__
01149             GXMAP(type,0xffde,          GHOST_kKeyNumpad1);
01150             GXMAP(type,0xffe0,          GHOST_kKeyNumpad3);
01151             GXMAP(type,0xffdc,          GHOST_kKeyNumpad5);
01152             GXMAP(type,0xffd8,          GHOST_kKeyNumpad7);
01153             GXMAP(type,0xffda,          GHOST_kKeyNumpad9);
01154 
01155             GXMAP(type,0xffd6,          GHOST_kKeyNumpadSlash);
01156             GXMAP(type,0xffd7,          GHOST_kKeyNumpadAsterisk);
01157 #endif
01158 
01159             default :
01160                 type = GHOST_kKeyUnknown;
01161                 break;
01162         }
01163     }
01164 
01165     return type;
01166 }
01167 
01168 #undef GXMAP
01169 
01170 /* from xclip.c xcout() v0.11 */
01171 
01172 #define XCLIB_XCOUT_NONE        0 /* no context */
01173 #define XCLIB_XCOUT_SENTCONVSEL     1 /* sent a request */
01174 #define XCLIB_XCOUT_INCR        2 /* in an incr loop */
01175 #define XCLIB_XCOUT_FALLBACK        3 /* STRING failed, need fallback to UTF8 */
01176 #define XCLIB_XCOUT_FALLBACK_UTF8   4 /* UTF8 failed, move to compouned */
01177 #define XCLIB_XCOUT_FALLBACK_COMP   5 /* compouned failed, move to text. */
01178 #define XCLIB_XCOUT_FALLBACK_TEXT   6
01179 
01180 // Retrieves the contents of a selections.
01181 void GHOST_SystemX11::getClipboard_xcout(XEvent evt,
01182     Atom sel, Atom target, unsigned char **txt,
01183     unsigned long *len, unsigned int *context) const
01184 {
01185     Atom pty_type;
01186     int pty_format;
01187     unsigned char *buffer;
01188     unsigned long pty_size, pty_items;
01189     unsigned char *ltxt= *txt;
01190 
01191     vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
01192     vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
01193     GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
01194     Window win = window->getXWindow();
01195 
01196     switch (*context) {
01197         // There is no context, do an XConvertSelection()
01198         case XCLIB_XCOUT_NONE:
01199             // Initialise return length to 0
01200             if (*len > 0) {
01201                 free(*txt);
01202                 *len = 0;
01203             }
01204 
01205             // Send a selection request
01206             XConvertSelection(m_display, sel, target, m_xclip_out, win, CurrentTime);
01207             *context = XCLIB_XCOUT_SENTCONVSEL;
01208             return;
01209 
01210         case XCLIB_XCOUT_SENTCONVSEL:
01211             if (evt.type != SelectionNotify)
01212                 return;
01213 
01214             if (target == m_utf8_string && evt.xselection.property == None) {
01215                 *context= XCLIB_XCOUT_FALLBACK_UTF8;
01216                 return;
01217             }
01218             else if (target == m_compound_text && evt.xselection.property == None) {
01219                 *context= XCLIB_XCOUT_FALLBACK_COMP;
01220                 return;
01221             }
01222             else if (target == m_text && evt.xselection.property == None) {
01223                 *context= XCLIB_XCOUT_FALLBACK_TEXT;
01224                 return;
01225             }
01226 
01227             // find the size and format of the data in property
01228             XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
01229                 AnyPropertyType, &pty_type, &pty_format,
01230                 &pty_items, &pty_size, &buffer);
01231             XFree(buffer);
01232 
01233             if (pty_type == m_incr) {
01234                 // start INCR mechanism by deleting property
01235                 XDeleteProperty(m_display, win, m_xclip_out);
01236                 XFlush(m_display);
01237                 *context = XCLIB_XCOUT_INCR;
01238                 return;
01239             }
01240 
01241             // if it's not incr, and not format == 8, then there's
01242             // nothing in the selection (that xclip understands, anyway)
01243 
01244             if (pty_format != 8) {
01245                 *context = XCLIB_XCOUT_NONE;
01246                 return;
01247             }
01248 
01249             // not using INCR mechanism, just read the property
01250             XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
01251                     False, AnyPropertyType, &pty_type,
01252                     &pty_format, &pty_items, &pty_size, &buffer);
01253 
01254             // finished with property, delete it
01255             XDeleteProperty(m_display, win, m_xclip_out);
01256 
01257             // copy the buffer to the pointer for returned data
01258             ltxt = (unsigned char *) malloc(pty_items);
01259             memcpy(ltxt, buffer, pty_items);
01260 
01261             // set the length of the returned data
01262             *len = pty_items;
01263             *txt = ltxt;
01264 
01265             // free the buffer
01266             XFree(buffer);
01267 
01268             *context = XCLIB_XCOUT_NONE;
01269 
01270             // complete contents of selection fetched, return 1
01271             return;
01272 
01273         case XCLIB_XCOUT_INCR:
01274             // To use the INCR method, we basically delete the
01275             // property with the selection in it, wait for an
01276             // event indicating that the property has been created,
01277             // then read it, delete it, etc.
01278 
01279             // make sure that the event is relevant
01280             if (evt.type != PropertyNotify)
01281                 return;
01282 
01283             // skip unless the property has a new value
01284             if (evt.xproperty.state != PropertyNewValue)
01285                 return;
01286 
01287             // check size and format of the property
01288             XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
01289                 AnyPropertyType, &pty_type, &pty_format,
01290                 &pty_items, &pty_size, (unsigned char **) &buffer);
01291 
01292             if (pty_format != 8) {
01293                 // property does not contain text, delete it
01294                 // to tell the other X client that we have read 
01295                 // it and to send the next property
01296                 XFree(buffer);
01297                 XDeleteProperty(m_display, win, m_xclip_out);
01298                 return;
01299             }
01300 
01301             if (pty_size == 0) {
01302                 // no more data, exit from loop
01303                 XFree(buffer);
01304                 XDeleteProperty(m_display, win, m_xclip_out);
01305                 *context = XCLIB_XCOUT_NONE;
01306 
01307                 // this means that an INCR transfer is now
01308                 // complete, return 1
01309                 return;
01310             }
01311 
01312             XFree(buffer);
01313 
01314             // if we have come this far, the propery contains
01315             // text, we know the size.
01316             XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
01317                 False, AnyPropertyType, &pty_type, &pty_format,
01318                 &pty_items, &pty_size, (unsigned char **) &buffer);
01319 
01320             // allocate memory to accommodate data in *txt
01321             if (*len == 0) {
01322                 *len = pty_items;
01323                 ltxt = (unsigned char *) malloc(*len);
01324             }
01325             else {
01326                 *len += pty_items;
01327                 ltxt = (unsigned char *) realloc(ltxt, *len);
01328             }
01329 
01330             // add data to ltxt
01331             memcpy(&ltxt[*len - pty_items], buffer, pty_items);
01332 
01333             *txt = ltxt;
01334             XFree(buffer);
01335 
01336             // delete property to get the next item
01337             XDeleteProperty(m_display, win, m_xclip_out);
01338             XFlush(m_display);
01339             return;
01340     }
01341     return;
01342 }
01343 
01344 GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
01345 {
01346     Atom sseln;
01347     Atom target= m_utf8_string;
01348     Window owner;
01349 
01350     // from xclip.c doOut() v0.11
01351     unsigned char *sel_buf;
01352     unsigned long sel_len= 0;
01353     XEvent evt;
01354     unsigned int context= XCLIB_XCOUT_NONE;
01355 
01356     if (selection == True)
01357         sseln= m_primary;
01358     else
01359         sseln= m_clipboard;
01360 
01361     vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
01362     vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
01363     GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
01364     Window win = window->getXWindow();
01365 
01366     /* check if we are the owner. */
01367     owner= XGetSelectionOwner(m_display, sseln);
01368     if (owner == win) {
01369         if (sseln == m_clipboard) {
01370             sel_buf= (unsigned char *)malloc(strlen(txt_cut_buffer)+1);
01371             strcpy((char *)sel_buf, txt_cut_buffer);
01372             return((GHOST_TUns8*)sel_buf);
01373         }
01374         else {
01375             sel_buf= (unsigned char *)malloc(strlen(txt_select_buffer)+1);
01376             strcpy((char *)sel_buf, txt_select_buffer);
01377             return((GHOST_TUns8*)sel_buf);
01378         }
01379     }
01380     else if (owner == None)
01381         return(NULL);
01382 
01383     while (1) {
01384         /* only get an event if xcout() is doing something */
01385         if (context != XCLIB_XCOUT_NONE)
01386             XNextEvent(m_display, &evt);
01387 
01388         /* fetch the selection, or part of it */
01389         getClipboard_xcout(evt, sseln, target, &sel_buf, &sel_len, &context);
01390 
01391         /* fallback is needed. set XA_STRING to target and restart the loop. */
01392         if (context == XCLIB_XCOUT_FALLBACK) {
01393             context= XCLIB_XCOUT_NONE;
01394             target= m_string;
01395             continue;
01396         }
01397         else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
01398             /* utf8 fail, move to compouned text. */
01399             context= XCLIB_XCOUT_NONE;
01400             target= m_compound_text;
01401             continue;
01402         }
01403         else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
01404             /* compouned text faile, move to text. */
01405             context= XCLIB_XCOUT_NONE;
01406             target= m_text;
01407             continue;
01408         }
01409 
01410         /* only continue if xcout() is doing something */
01411         if (context == XCLIB_XCOUT_NONE)
01412             break;
01413     }
01414 
01415     if (sel_len) {
01416         /* only print the buffer out, and free it, if it's not
01417          * empty
01418          */
01419         unsigned char *tmp_data = (unsigned char*) malloc(sel_len+1);
01420         memcpy((char*)tmp_data, (char*)sel_buf, sel_len);
01421         tmp_data[sel_len] = '\0';
01422         
01423         if (sseln == m_string)
01424             XFree(sel_buf);
01425         else
01426             free(sel_buf);
01427         
01428         return (GHOST_TUns8*)tmp_data;
01429     }
01430     return(NULL);
01431 }
01432 
01433 void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
01434 {
01435     Window m_window, owner;
01436 
01437     vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();  
01438     vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
01439     GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
01440     m_window = window->getXWindow();
01441 
01442     if (buffer) {
01443         if (selection == False) {
01444             XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime);
01445             owner= XGetSelectionOwner(m_display, m_clipboard);
01446             if (txt_cut_buffer)
01447                 free((void*)txt_cut_buffer);
01448 
01449             txt_cut_buffer = (char*) malloc(strlen(buffer)+1);
01450             strcpy(txt_cut_buffer, buffer);
01451         } else {
01452             XSetSelectionOwner(m_display, m_primary, m_window, CurrentTime);
01453             owner= XGetSelectionOwner(m_display, m_primary);
01454             if (txt_select_buffer)
01455                 free((void*)txt_select_buffer);
01456 
01457             txt_select_buffer = (char*) malloc(strlen(buffer)+1);
01458             strcpy(txt_select_buffer, buffer);
01459         }
01460 
01461         if (owner != m_window)
01462             fprintf(stderr, "failed to own primary\n");
01463     }
01464 }