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