Added null check to prevent crashing on paste.
[plumiferos.git] / intern / ghost / intern / GHOST_SystemX11.cpp
blob82704be8ba5cde37a07bc27ed4c06ee653b22167
1 /**
2 * $Id: GHOST_SystemX11.cpp 10348 2007-03-24 18:41:54Z scourage $
3 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version. The Blender
9 * Foundation also sells licenses for use in proprietary software under
10 * the Blender License. See http://www.blender.org/BL/ for information
11 * about this.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23 * All rights reserved.
25 * The Original Code is: all of this file.
27 * Contributor(s): none yet.
29 * ***** END GPL/BL DUAL LICENSE BLOCK *****
32 /**
33 * $Id: GHOST_SystemX11.cpp 10348 2007-03-24 18:41:54Z scourage $
34 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
36 * This program is free software; you can redistribute it and/or
37 * modify it under the terms of the GNU General Public License
38 * as published by the Free Software Foundation; either version 2
39 * of the License, or (at your option) any later version. The Blender
40 * Foundation also sells licenses for use in proprietary software under
41 * the Blender License. See http://www.blender.org/BL/ for information
42 * about this.
44 * This program is distributed in the hope that it will be useful,
45 * but WITHOUT ANY WARRANTY; without even the implied warranty of
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47 * GNU General Public License for more details.
49 * You should have received a copy of the GNU General Public License
50 * along with this program; if not, write to the Free Software Foundation,
51 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
53 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
54 * All rights reserved.
56 * The Original Code is: all of this file.
58 * Contributor(s): none yet.
60 * ***** END GPL/BL DUAL LICENSE BLOCK *****
63 #ifdef HAVE_CONFIG_H
64 #include <config.h>
65 #endif
67 #include "GHOST_SystemX11.h"
68 #include "GHOST_WindowX11.h"
69 #include "GHOST_WindowManager.h"
70 #include "GHOST_TimerManager.h"
71 #include "GHOST_EventCursor.h"
72 #include "GHOST_EventKey.h"
73 #include "GHOST_EventButton.h"
74 #include "GHOST_EventWheel.h"
75 #include "GHOST_DisplayManagerX11.h"
77 #include "GHOST_Debug.h"
79 #include <X11/Xatom.h>
80 #include <X11/keysym.h>
82 #ifdef __sgi
84 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
85 #include <X11/SGIFastAtom.h>
86 #else
87 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
88 #endif
90 #endif
92 // For timing
94 #include <sys/time.h>
95 #include <unistd.h>
97 #include <vector>
99 #include <stdio.h> // for fprintf only
101 //these are for copy and select copy
102 static char *txt_cut_buffer= NULL;
103 static char *txt_select_buffer= NULL;
105 using namespace std;
107 GHOST_SystemX11::
108 GHOST_SystemX11(
109 ) :
110 GHOST_System(),
111 m_start_time(0)
113 m_display = XOpenDisplay(NULL);
115 if (!m_display) return;
117 #ifdef __sgi
118 m_delete_window_atom
119 = XSGIFastInternAtom(m_display,
120 "WM_DELETE_WINDOW",
121 SGI_XA_WM_DELETE_WINDOW, False);
122 #else
123 m_delete_window_atom
124 = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
125 #endif
127 // compute the initial time
128 timeval tv;
129 if (gettimeofday(&tv,NULL) == -1) {
130 GHOST_ASSERT(false,"Could not instantiate timer!");
133 m_start_time = GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000);
136 GHOST_TSuccess
137 GHOST_SystemX11::
138 init(
140 GHOST_TSuccess success = GHOST_System::init();
142 if (success) {
143 m_keyboard_vector = new char[32];
145 m_displayManager = new GHOST_DisplayManagerX11(this);
147 if (m_keyboard_vector && m_displayManager) {
148 return GHOST_kSuccess;
152 return GHOST_kFailure;
157 GHOST_TUns64
158 GHOST_SystemX11::
159 getMilliSeconds(
160 ) const {
161 timeval tv;
162 if (gettimeofday(&tv,NULL) == -1) {
163 GHOST_ASSERT(false,"Could not compute time!");
166 return GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000) - m_start_time;
169 GHOST_TUns8
170 GHOST_SystemX11::
171 getNumDisplays(
172 ) const {
173 return GHOST_TUns8(1);
177 * Returns the dimensions of the main display on this system.
178 * @return The dimension of the main display.
180 void
181 GHOST_SystemX11::
182 getMainDisplayDimensions(
183 GHOST_TUns32& width,
184 GHOST_TUns32& height
185 ) const {
186 if (m_display) {
187 width = DisplayWidth(m_display, DefaultScreen(m_display));
188 height = DisplayHeight(m_display, DefaultScreen(m_display));
193 * Create a new window.
194 * The new window is added to the list of windows managed.
195 * Never explicitly delete the window, use disposeWindow() instead.
196 * @param title The name of the window (displayed in the title bar of the window if the OS supports it).
197 * @param left The coordinate of the left edge of the window.
198 * @param top The coordinate of the top edge of the window.
199 * @param width The width the window.
200 * @param height The height the window.
201 * @param state The state of the window when opened.
202 * @param type The type of drawing context installed in this window.
203 * @return The new window (or 0 if creation failed).
205 GHOST_IWindow*
206 GHOST_SystemX11::
207 createWindow(
208 const STR_String& title,
209 GHOST_TInt32 left,
210 GHOST_TInt32 top,
211 GHOST_TUns32 width,
212 GHOST_TUns32 height,
213 GHOST_TWindowState state,
214 GHOST_TDrawingContextType type,
215 bool stereoVisual
217 GHOST_WindowX11 * window = 0;
219 if (!m_display) return 0;
221 window = new GHOST_WindowX11 (
222 this,m_display,title, left, top, width, height, state, type, stereoVisual
225 if (window) {
227 // Install a new protocol for this window - so we can overide
228 // the default window closure mechanism.
230 XSetWMProtocols(m_display, window->getXWindow(), &m_delete_window_atom, 1);
232 if (window->getValid()) {
233 // Store the pointer to the window
234 m_windowManager->addWindow(window);
236 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
238 else {
239 delete window;
240 window = 0;
243 return window;
247 GHOST_WindowX11 *
248 GHOST_SystemX11::
249 findGhostWindow(
250 Window xwind
251 ) const {
253 if (xwind == 0) return NULL;
255 // It is not entirely safe to do this as the backptr may point
256 // to a window that has recently been removed.
257 // We should always check the window manager's list of windows
258 // and only process events on these windows.
260 vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
262 vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
263 vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
265 for (; win_it != win_end; ++win_it) {
266 GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
267 if (window->getXWindow() == xwind) {
268 return window;
271 return NULL;
275 static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) {
276 int fd = ConnectionNumber(display);
277 fd_set fds;
279 FD_ZERO(&fds);
280 FD_SET(fd, &fds);
282 if (maxSleep == -1) {
283 select(fd + 1, &fds, NULL, NULL, NULL);
284 } else {
285 timeval tv;
287 tv.tv_sec = maxSleep/1000;
288 tv.tv_usec = (maxSleep - tv.tv_sec*1000)*1000;
290 select(fd + 1, &fds, NULL, NULL, &tv);
294 bool
295 GHOST_SystemX11::
296 processEvents(
297 bool waitForEvent
299 // Get all the current events -- translate them into
300 // ghost events and call base class pushEvent() method.
302 bool anyProcessed = false;
304 do {
305 GHOST_TimerManager* timerMgr = getTimerManager();
307 if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) {
308 GHOST_TUns64 next = timerMgr->nextFireTime();
310 if (next==GHOST_kFireTimeNever) {
311 SleepTillEvent(m_display, -1);
312 } else {
313 SleepTillEvent(m_display, next - getMilliSeconds());
317 if (timerMgr->fireTimers(getMilliSeconds())) {
318 anyProcessed = true;
321 while (XPending(m_display)) {
322 XEvent xevent;
323 XNextEvent(m_display, &xevent);
324 processEvent(&xevent);
325 anyProcessed = true;
328 if (generateWindowExposeEvents()) {
329 anyProcessed = true;
331 } while (waitForEvent && !anyProcessed);
333 return anyProcessed;
336 void
337 GHOST_SystemX11::processEvent(XEvent *xe)
339 GHOST_WindowX11 * window = findGhostWindow(xe->xany.window);
340 GHOST_Event * g_event = NULL;
342 if (!window) {
343 return;
346 switch (xe->type) {
347 case Expose:
349 XExposeEvent & xee = xe->xexpose;
351 if (xee.count == 0) {
352 // Only generate a single expose event
353 // per read of the event queue.
355 g_event = new
356 GHOST_Event(
357 getMilliSeconds(),
358 GHOST_kEventWindowUpdate,
359 window
362 break;
365 case MotionNotify:
367 XMotionEvent &xme = xe->xmotion;
369 g_event = new
370 GHOST_EventCursor(
371 getMilliSeconds(),
372 GHOST_kEventCursorMove,
373 window,
374 xme.x_root,
375 xme.y_root
377 break;
380 case KeyPress:
381 case KeyRelease:
383 XKeyEvent *xke = &(xe->xkey);
385 KeySym key_sym = XLookupKeysym(xke,0);
386 char ascii;
388 GHOST_TKey gkey = convertXKey(key_sym);
389 GHOST_TEventType type = (xke->type == KeyPress) ?
390 GHOST_kEventKeyDown : GHOST_kEventKeyUp;
392 if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
393 ascii = '\0';
396 g_event = new
397 GHOST_EventKey(
398 getMilliSeconds(),
399 type,
400 window,
401 gkey,
402 ascii
405 break;
408 case ButtonPress:
410 /* process wheel mouse events and break */
411 if (xe->xbutton.button == 4) {
412 g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
413 break;
415 if (xe->xbutton.button == 5) {
416 g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
417 break;
420 case ButtonRelease:
423 XButtonEvent & xbe = xe->xbutton;
424 GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
426 switch (xbe.button) {
427 case Button1 : gbmask = GHOST_kButtonMaskLeft; break;
428 case Button3 : gbmask = GHOST_kButtonMaskRight; break;
429 default:
430 case Button2 : gbmask = GHOST_kButtonMaskMiddle; break;
433 GHOST_TEventType type = (xbe.type == ButtonPress) ?
434 GHOST_kEventButtonDown : GHOST_kEventButtonUp;
436 g_event = new
437 GHOST_EventButton(
438 getMilliSeconds(),
439 type,
440 window,
441 gbmask
443 break;
446 // change of size, border, layer etc.
447 case ConfigureNotify:
449 /* XConfigureEvent & xce = xe->xconfigure; */
451 g_event = new
452 GHOST_Event(
453 getMilliSeconds(),
454 GHOST_kEventWindowSize,
455 window
457 break;
460 case FocusIn:
461 case FocusOut:
463 XFocusChangeEvent &xfe = xe->xfocus;
465 // May have to look at the type of event and filter some
466 // out.
468 GHOST_TEventType gtype = (xfe.type == FocusIn) ?
469 GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate;
471 g_event = new
472 GHOST_Event(
473 getMilliSeconds(),
474 gtype,
475 window
477 break;
480 case ClientMessage:
482 XClientMessageEvent & xcme = xe->xclient;
484 #ifndef __sgi
485 if ((Atom) xcme.data.l[0] == m_delete_window_atom) {
486 g_event = new
487 GHOST_Event(
488 getMilliSeconds(),
489 GHOST_kEventWindowClose,
490 window
492 } else {
493 /* Unknown client message, ignore */
495 #endif
496 break;
499 // We're not interested in the following things.(yet...)
500 case NoExpose :
501 case GraphicsExpose :
503 case EnterNotify:
504 case LeaveNotify:
505 // XCrossingEvents pointer leave enter window.
506 break;
507 case MapNotify:
508 case UnmapNotify:
509 break;
510 case MappingNotify:
511 case ReparentNotify:
512 break;
513 case SelectionRequest:
515 XEvent nxe;
516 Atom target, string, compound_text, c_string;
517 XSelectionRequestEvent *xse = &xe->xselectionrequest;
519 target = XInternAtom(m_display, "TARGETS", False);
520 string = XInternAtom(m_display, "STRING", False);
521 compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
522 c_string = XInternAtom(m_display, "C_STRING", False);
524 /* support obsolete clients */
525 if (xse->property == None) {
526 xse->property = xse->target;
529 nxe.xselection.type = SelectionNotify;
530 nxe.xselection.requestor = xse->requestor;
531 nxe.xselection.property = xse->property;
532 nxe.xselection.display = xse->display;
533 nxe.xselection.selection = xse->selection;
534 nxe.xselection.target = xse->target;
535 nxe.xselection.time = xse->time;
537 /*Check to see if the requestor is asking for String*/
538 if(xse->target == string || xse->target == compound_text || xse->target == c_string) {
539 if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
540 XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_select_buffer, strlen(txt_select_buffer));
541 } else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) {
542 XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_cut_buffer, strlen(txt_cut_buffer));
544 } else if (xse->target == target) {
545 Atom alist[4];
546 alist[0] = target;
547 alist[1] = string;
548 alist[2] = compound_text;
549 alist[3] = c_string;
550 XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 32, PropModeReplace, (unsigned char*)alist, 4);
551 XFlush(m_display);
552 } else {
553 //Change property to None because we do not support anything but STRING
554 nxe.xselection.property = None;
557 //Send the event to the client 0 0 == False, SelectionNotify
558 XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
559 XFlush(m_display);
560 break;
563 default: {
564 if(xe->type == window->GetXTablet().MotionEvent)
566 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
567 window->GetXTablet().CommonData.Pressure=
568 data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
570 /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
571 * but I got garbage data without it. Found it in the xidump.c source --matt */
572 window->GetXTablet().CommonData.Xtilt=
573 (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
574 window->GetXTablet().CommonData.Ytilt=
575 (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
577 else if(xe->type == window->GetXTablet().ProxInEvent)
579 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
580 if(data->deviceid == window->GetXTablet().StylusID)
581 window->GetXTablet().CommonData.Active= 1;
582 else if(data->deviceid == window->GetXTablet().EraserID)
583 window->GetXTablet().CommonData.Active= 2;
585 else if(xe->type == window->GetXTablet().ProxOutEvent)
586 window->GetXTablet().CommonData.Active= 0;
588 break;
592 if (g_event) {
593 pushEvent(g_event);
598 GHOST_TSuccess
599 GHOST_SystemX11::
600 getModifierKeys(
601 GHOST_ModifierKeys& keys
602 ) const {
604 // analyse the masks retuned from XQueryPointer.
606 memset(m_keyboard_vector,0,sizeof(m_keyboard_vector));
608 XQueryKeymap(m_display,m_keyboard_vector);
610 // now translate key symobols into keycodes and
611 // test with vector.
613 const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
614 const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
615 const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
616 const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
617 const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
618 const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
620 // Shift
621 if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
622 keys.set(GHOST_kModifierKeyLeftShift,true);
623 } else {
624 keys.set(GHOST_kModifierKeyLeftShift,false);
626 if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
628 keys.set(GHOST_kModifierKeyRightShift,true);
629 } else {
630 keys.set(GHOST_kModifierKeyRightShift,false);
633 // control (weep)
634 if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
635 keys.set(GHOST_kModifierKeyLeftControl,true);
636 } else {
637 keys.set(GHOST_kModifierKeyLeftControl,false);
639 if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
640 keys.set(GHOST_kModifierKeyRightControl,true);
641 } else {
642 keys.set(GHOST_kModifierKeyRightControl,false);
645 // Alt (yawn)
646 if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
647 keys.set(GHOST_kModifierKeyLeftAlt,true);
648 } else {
649 keys.set(GHOST_kModifierKeyLeftAlt,false);
651 if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
652 keys.set(GHOST_kModifierKeyRightAlt,true);
653 } else {
654 keys.set(GHOST_kModifierKeyRightAlt,false);
656 return GHOST_kSuccess;
659 GHOST_TSuccess
660 GHOST_SystemX11::
661 getButtons(
662 GHOST_Buttons& buttons
663 ) const {
665 Window root_return, child_return;
666 int rx,ry,wx,wy;
667 unsigned int mask_return;
669 if (XQueryPointer(
670 m_display,
671 RootWindow(m_display,DefaultScreen(m_display)),
672 &root_return,
673 &child_return,
674 &rx,&ry,
675 &wx,&wy,
676 &mask_return
677 ) == False) {
678 return GHOST_kFailure;
679 } else {
681 if (mask_return & Button1Mask) {
682 buttons.set(GHOST_kButtonMaskLeft,true);
683 } else {
684 buttons.set(GHOST_kButtonMaskLeft,false);
687 if (mask_return & Button2Mask) {
688 buttons.set(GHOST_kButtonMaskMiddle,true);
689 } else {
690 buttons.set(GHOST_kButtonMaskMiddle,false);
693 if (mask_return & Button3Mask) {
694 buttons.set(GHOST_kButtonMaskRight,true);
695 } else {
696 buttons.set(GHOST_kButtonMaskRight,false);
700 return GHOST_kSuccess;
704 GHOST_TSuccess
705 GHOST_SystemX11::
706 getCursorPosition(
707 GHOST_TInt32& x,
708 GHOST_TInt32& y
709 ) const {
711 Window root_return, child_return;
712 int rx,ry,wx,wy;
713 unsigned int mask_return;
715 if (XQueryPointer(
716 m_display,
717 RootWindow(m_display,DefaultScreen(m_display)),
718 &root_return,
719 &child_return,
720 &rx,&ry,
721 &wx,&wy,
722 &mask_return
723 ) == False) {
724 return GHOST_kFailure;
725 } else {
726 x = rx;
727 y = ry;
729 return GHOST_kSuccess;
733 GHOST_TSuccess
734 GHOST_SystemX11::
735 setCursorPosition(
736 GHOST_TInt32 x,
737 GHOST_TInt32 y
738 ) const {
740 // This is a brute force move in screen coordinates
741 // XWarpPointer does relative moves so first determine the
742 // current pointer position.
744 int cx,cy;
745 if (getCursorPosition(cx,cy) == GHOST_kFailure) {
746 return GHOST_kFailure;
749 int relx = x-cx;
750 int rely = y-cy;
752 XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
753 XFlush(m_display);
755 return GHOST_kSuccess;
759 void
760 GHOST_SystemX11::
761 addDirtyWindow(
762 GHOST_WindowX11 * bad_wind
765 GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
767 m_dirty_windows.push_back(bad_wind);
771 bool
772 GHOST_SystemX11::
773 generateWindowExposeEvents(
776 vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
777 vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
778 bool anyProcessed = false;
780 for (;w_start != w_end; ++w_start) {
781 GHOST_Event * g_event = new
782 GHOST_Event(
783 getMilliSeconds(),
784 GHOST_kEventWindowUpdate,
785 *w_start
788 (*w_start)->validate();
790 if (g_event) {
791 pushEvent(g_event);
792 anyProcessed = true;
796 m_dirty_windows.clear();
797 return anyProcessed;
800 #define GXMAP(k,x,y) case x: k = y; break;
802 GHOST_TKey
803 GHOST_SystemX11::
804 convertXKey(
805 KeySym key
807 GHOST_TKey type;
809 if ((key >= XK_A) && (key <= XK_Z)) {
810 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
811 } else if ((key >= XK_a) && (key <= XK_z)) {
812 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
813 } else if ((key >= XK_0) && (key <= XK_9)) {
814 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
815 } else if ((key >= XK_F1) && (key <= XK_F24)) {
816 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
817 #if defined(__sun) || defined(__sun__)
818 /* This is a bit of a hack, but it looks like sun
819 Used F11 and friends for its special keys Stop,again etc..
820 So this little patch enables F11 and F12 to work as expected
821 following link has documentation on it:
822 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
823 also from /usr/include/X11/Sunkeysym.h
824 #define SunXK_F36 0x1005FF10 // Labeled F11
825 #define SunXK_F37 0x1005FF11 // Labeled F12
827 mein@cs.umn.edu
830 } else if (key == 268828432) {
831 type = GHOST_kKeyF11;
832 } else if (key == 268828433) {
833 type = GHOST_kKeyF12;
834 #endif
835 } else {
836 switch(key) {
837 GXMAP(type,XK_BackSpace, GHOST_kKeyBackSpace);
838 GXMAP(type,XK_Tab, GHOST_kKeyTab);
839 GXMAP(type,XK_Return, GHOST_kKeyEnter);
840 GXMAP(type,XK_Escape, GHOST_kKeyEsc);
841 GXMAP(type,XK_space, GHOST_kKeySpace);
843 GXMAP(type,XK_Linefeed, GHOST_kKeyLinefeed);
844 GXMAP(type,XK_semicolon, GHOST_kKeySemicolon);
845 GXMAP(type,XK_period, GHOST_kKeyPeriod);
846 GXMAP(type,XK_comma, GHOST_kKeyComma);
847 GXMAP(type,XK_quoteright, GHOST_kKeyQuote);
848 GXMAP(type,XK_quoteleft, GHOST_kKeyAccentGrave);
849 GXMAP(type,XK_minus, GHOST_kKeyMinus);
850 GXMAP(type,XK_slash, GHOST_kKeySlash);
851 GXMAP(type,XK_backslash, GHOST_kKeyBackslash);
852 GXMAP(type,XK_equal, GHOST_kKeyEqual);
853 GXMAP(type,XK_bracketleft, GHOST_kKeyLeftBracket);
854 GXMAP(type,XK_bracketright, GHOST_kKeyRightBracket);
855 GXMAP(type,XK_Pause, GHOST_kKeyPause);
857 GXMAP(type,XK_Shift_L, GHOST_kKeyLeftShift);
858 GXMAP(type,XK_Shift_R, GHOST_kKeyRightShift);
859 GXMAP(type,XK_Control_L, GHOST_kKeyLeftControl);
860 GXMAP(type,XK_Control_R, GHOST_kKeyRightControl);
861 GXMAP(type,XK_Alt_L, GHOST_kKeyLeftAlt);
862 GXMAP(type,XK_Alt_R, GHOST_kKeyRightAlt);
864 GXMAP(type,XK_Insert, GHOST_kKeyInsert);
865 GXMAP(type,XK_Delete, GHOST_kKeyDelete);
866 GXMAP(type,XK_Home, GHOST_kKeyHome);
867 GXMAP(type,XK_End, GHOST_kKeyEnd);
868 GXMAP(type,XK_Page_Up, GHOST_kKeyUpPage);
869 GXMAP(type,XK_Page_Down, GHOST_kKeyDownPage);
871 GXMAP(type,XK_Left, GHOST_kKeyLeftArrow);
872 GXMAP(type,XK_Right, GHOST_kKeyRightArrow);
873 GXMAP(type,XK_Up, GHOST_kKeyUpArrow);
874 GXMAP(type,XK_Down, GHOST_kKeyDownArrow);
876 GXMAP(type,XK_Caps_Lock, GHOST_kKeyCapsLock);
877 GXMAP(type,XK_Scroll_Lock, GHOST_kKeyScrollLock);
878 GXMAP(type,XK_Num_Lock, GHOST_kKeyNumLock);
880 /* keypad events */
882 GXMAP(type,XK_KP_0, GHOST_kKeyNumpad0);
883 GXMAP(type,XK_KP_1, GHOST_kKeyNumpad1);
884 GXMAP(type,XK_KP_2, GHOST_kKeyNumpad2);
885 GXMAP(type,XK_KP_3, GHOST_kKeyNumpad3);
886 GXMAP(type,XK_KP_4, GHOST_kKeyNumpad4);
887 GXMAP(type,XK_KP_5, GHOST_kKeyNumpad5);
888 GXMAP(type,XK_KP_6, GHOST_kKeyNumpad6);
889 GXMAP(type,XK_KP_7, GHOST_kKeyNumpad7);
890 GXMAP(type,XK_KP_8, GHOST_kKeyNumpad8);
891 GXMAP(type,XK_KP_9, GHOST_kKeyNumpad9);
892 GXMAP(type,XK_KP_Decimal, GHOST_kKeyNumpadPeriod);
894 GXMAP(type,XK_KP_Insert, GHOST_kKeyNumpad0);
895 GXMAP(type,XK_KP_End, GHOST_kKeyNumpad1);
896 GXMAP(type,XK_KP_Down, GHOST_kKeyNumpad2);
897 GXMAP(type,XK_KP_Page_Down, GHOST_kKeyNumpad3);
898 GXMAP(type,XK_KP_Left, GHOST_kKeyNumpad4);
899 GXMAP(type,XK_KP_Begin, GHOST_kKeyNumpad5);
900 GXMAP(type,XK_KP_Right, GHOST_kKeyNumpad6);
901 GXMAP(type,XK_KP_Home, GHOST_kKeyNumpad7);
902 GXMAP(type,XK_KP_Up, GHOST_kKeyNumpad8);
903 GXMAP(type,XK_KP_Page_Up, GHOST_kKeyNumpad9);
904 GXMAP(type,XK_KP_Delete, GHOST_kKeyNumpadPeriod);
906 GXMAP(type,XK_KP_Enter, GHOST_kKeyNumpadEnter);
907 GXMAP(type,XK_KP_Add, GHOST_kKeyNumpadPlus);
908 GXMAP(type,XK_KP_Subtract, GHOST_kKeyNumpadMinus);
909 GXMAP(type,XK_KP_Multiply, GHOST_kKeyNumpadAsterisk);
910 GXMAP(type,XK_KP_Divide, GHOST_kKeyNumpadSlash);
912 /* some extra sun cruft (NICE KEYBOARD!) */
913 #ifdef __sun__
914 GXMAP(type,0xffde, GHOST_kKeyNumpad1);
915 GXMAP(type,0xffe0, GHOST_kKeyNumpad3);
916 GXMAP(type,0xffdc, GHOST_kKeyNumpad5);
917 GXMAP(type,0xffd8, GHOST_kKeyNumpad7);
918 GXMAP(type,0xffda, GHOST_kKeyNumpad9);
920 GXMAP(type,0xffd6, GHOST_kKeyNumpadSlash);
921 GXMAP(type,0xffd7, GHOST_kKeyNumpadAsterisk);
922 #endif
924 default :
925 type = GHOST_kKeyUnknown;
926 break;
930 return type;
933 #undef GXMAP
935 GHOST_TUns8*
936 GHOST_SystemX11::
937 getClipboard(int flag
938 ) const {
939 //Flag
940 //0 = Regular clipboard 1 = selection
941 static Atom Primary_atom, clip_String, compound_text;
942 Atom rtype;
943 Window m_window, owner;
944 unsigned char *data, *tmp_data;
945 int bits;
946 unsigned long len, bytes;
947 XEvent xevent;
949 vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
950 vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
951 GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
952 m_window = window->getXWindow();
954 clip_String = XInternAtom(m_display, "_BLENDER_STRING", False);
955 compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
957 //lets check the owner and if it is us then return the static buffer
958 if(flag == 0) {
959 Primary_atom = XInternAtom(m_display, "CLIPBOARD", False);
960 owner = XGetSelectionOwner(m_display, Primary_atom);
961 if (owner == m_window) {
962 data = (unsigned char*) malloc(strlen(txt_cut_buffer));
963 strcpy((char*)data, txt_cut_buffer);
964 return (GHOST_TUns8*)data;
965 } else if (owner == None) {
966 return NULL;
968 } else {
969 Primary_atom = XInternAtom(m_display, "PRIMARY", False);
970 owner = XGetSelectionOwner(m_display, Primary_atom);
971 if (owner == m_window) {
972 data = (unsigned char*) malloc(strlen(txt_select_buffer));
973 strcpy((char*)data, txt_select_buffer);
974 return (GHOST_TUns8*)data;
975 } else if (owner == None) {
976 return NULL;
980 if(!Primary_atom) {
981 return NULL;
984 XDeleteProperty(m_display, m_window, Primary_atom);
985 XConvertSelection(m_display, Primary_atom, compound_text, clip_String, m_window, CurrentTime); //XA_STRING
986 XFlush(m_display);
988 //This needs to change so we do not wait for ever or check owner first
989 while(1) {
990 XNextEvent(m_display, &xevent);
991 if(xevent.type == SelectionNotify) {
992 if(XGetWindowProperty(m_display, m_window, xevent.xselection.property, 0L, 4096L, False, AnyPropertyType, &rtype, &bits, &len, &bytes, &data) == Success) {
993 if (data) {
994 tmp_data = (unsigned char*) malloc(strlen((char*)data));
995 strcpy((char*)tmp_data, (char*)data);
996 XFree(data);
997 return (GHOST_TUns8*)tmp_data;
1000 return NULL;
1005 void
1006 GHOST_SystemX11::
1007 putClipboard(
1008 GHOST_TInt8 *buffer, int flag) const
1010 static Atom Primary_atom;
1011 Window m_window, owner;
1013 if(!buffer) {return;}
1015 if(flag == 0) {
1016 Primary_atom = XInternAtom(m_display, "CLIPBOARD", False);
1017 if(txt_cut_buffer) { free((void*)txt_cut_buffer); }
1019 txt_cut_buffer = (char*) malloc(strlen(buffer));
1020 strcpy(txt_cut_buffer, buffer);
1021 } else {
1022 Primary_atom = XInternAtom(m_display, "PRIMARY", False);
1023 if(txt_select_buffer) { free((void*)txt_select_buffer); }
1025 txt_select_buffer = (char*) malloc(strlen(buffer));
1026 strcpy(txt_select_buffer, buffer);
1029 vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1030 vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1031 GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1032 m_window = window->getXWindow();
1034 if(!Primary_atom) {
1035 return;
1038 XSetSelectionOwner(m_display, Primary_atom, m_window, CurrentTime);
1039 owner = XGetSelectionOwner(m_display, Primary_atom);
1040 if (owner != m_window)
1041 fprintf(stderr, "failed to own primary\n");
1043 return;