Blender V2.61 - r43446
|
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(<xt[*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 }