2
* $Id: GHOST_SystemX11.cpp 30396 2010-07-15 20:25:09Z campbellbarton $
3
* ***** BEGIN GPL 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.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20
* All rights reserved.
22
* The Original Code is: all of this file.
24
* Contributor(s): none yet.
26
* Part of this code has been taken from Qt, under LGPL license
27
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
29
* ***** END GPL LICENSE BLOCK *****
32
#include "GHOST_SystemX11.h"
33
#include "GHOST_WindowX11.h"
34
#include "GHOST_WindowManager.h"
35
#include "GHOST_TimerManager.h"
36
#include "GHOST_EventCursor.h"
37
#include "GHOST_EventKey.h"
38
#include "GHOST_EventButton.h"
39
#include "GHOST_EventWheel.h"
40
#include "GHOST_EventNDOF.h"
41
#include "GHOST_NDOFManager.h"
42
#include "GHOST_DisplayManagerX11.h"
44
#include "GHOST_Debug.h"
46
#include <X11/Xatom.h>
47
#include <X11/keysym.h>
48
#include <X11/XKBlib.h> /* allow detectable autorepeate */
52
#if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
53
#include <X11/SGIFastAtom.h>
55
#define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
67
#include <stdio.h> // for fprintf only
68
#include <cstdlib> // for exit
71
# define PREFIX "/usr/local"
74
typedef struct NDOFPlatformInfo {
77
volatile GHOST_TEventNDOFData *currValues;
84
static NDOFPlatformInfo sNdofInfo = {NULL, 0, NULL, 0, 0, 0, 0};
87
//these are for copy and select copy
88
static char *txt_cut_buffer= NULL;
89
static char *txt_select_buffer= NULL;
99
m_display = XOpenDisplay(NULL);
102
std::cerr << "Unable to open a display" << std::endl;
103
abort(); //was return before, but this would just mean it will crash later
108
= XSGIFastInternAtom(m_display,
110
SGI_XA_WM_DELETE_WINDOW, False);
113
= XInternAtom(m_display, "WM_DELETE_WINDOW", True);
116
m_wm_protocols= XInternAtom(m_display, "WM_PROTOCOLS", False);
117
m_wm_take_focus= XInternAtom(m_display, "WM_TAKE_FOCUS", False);
118
m_wm_state= XInternAtom(m_display, "WM_STATE", False);
119
m_wm_change_state= XInternAtom(m_display, "WM_CHANGE_STATE", False);
120
m_net_state= XInternAtom(m_display, "_NET_WM_STATE", False);
121
m_net_max_horz= XInternAtom(m_display,
122
"_NET_WM_STATE_MAXIMIZED_HORZ", False);
123
m_net_max_vert= XInternAtom(m_display,
124
"_NET_WM_STATE_MAXIMIZED_VERT", False);
125
m_net_fullscreen= XInternAtom(m_display,
126
"_NET_WM_STATE_FULLSCREEN", False);
127
m_motif= XInternAtom(m_display, "_MOTIF_WM_HINTS", False);
128
m_targets= XInternAtom(m_display, "TARGETS", False);
129
m_string= XInternAtom(m_display, "STRING", False);
130
m_compound_text= XInternAtom(m_display, "COMPOUND_TEXT", False);
131
m_text= XInternAtom(m_display, "TEXT", False);
132
m_clipboard= XInternAtom(m_display, "CLIPBOARD", False);
133
m_primary= XInternAtom(m_display, "PRIMARY", False);
134
m_xclip_out= XInternAtom(m_display, "XCLIP_OUT", False);
135
m_incr= XInternAtom(m_display, "INCR", False);
136
m_utf8_string= XInternAtom(m_display, "UTF8_STRING", False);
140
// compute the initial time
142
if (gettimeofday(&tv,NULL) == -1) {
143
GHOST_ASSERT(false,"Could not instantiate timer!");
146
m_start_time = GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000);
149
/* use detectable autorepeate, mac and windows also do this */
151
int xkb_opcode, xkb_event, xkb_error;
152
int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
154
use_xkb = XkbQueryExtension(m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor);
156
XkbSetDetectableAutoRepeat(m_display, true, NULL);
164
XCloseDisplay(m_display);
172
GHOST_TSuccess success = GHOST_System::init();
175
m_displayManager = new GHOST_DisplayManagerX11(this);
177
if (m_displayManager) {
178
return GHOST_kSuccess;
182
return GHOST_kFailure;
190
if (gettimeofday(&tv,NULL) == -1) {
191
GHOST_ASSERT(false,"Could not compute time!");
194
return GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000) - m_start_time;
201
return GHOST_TUns8(1);
205
* Returns the dimensions of the main display on this system.
206
* @return The dimension of the main display.
210
getMainDisplayDimensions(
215
width = DisplayWidth(m_display, DefaultScreen(m_display));
216
height = DisplayHeight(m_display, DefaultScreen(m_display));
221
* Create a new window.
222
* The new window is added to the list of windows managed.
223
* Never explicitly delete the window, use disposeWindow() instead.
224
* @param title The name of the window (displayed in the title bar of the window if the OS supports it).
225
* @param left The coordinate of the left edge of the window.
226
* @param top The coordinate of the top edge of the window.
227
* @param width The width the window.
228
* @param height The height the window.
229
* @param state The state of the window when opened.
230
* @param type The type of drawing context installed in this window.
231
* @param stereoVisual Stereo visual for quad buffered stereo.
232
* @param numOfAASamples Number of samples used for AA (zero if no AA)
233
* @param parentWindow Parent (embedder) window
234
* @return The new window (or 0 if creation failed).
239
const STR_String& title,
244
GHOST_TWindowState state,
245
GHOST_TDrawingContextType type,
247
const GHOST_TUns16 numOfAASamples,
248
const GHOST_TEmbedderWindowID parentWindow
250
GHOST_WindowX11 * window = 0;
252
if (!m_display) return 0;
257
window = new GHOST_WindowX11 (
258
this,m_display,title, left, top, width, height, state, parentWindow, type, stereoVisual
262
// Both are now handle in GHOST_WindowX11.cpp
263
// Focus and Delete atoms.
265
if (window->getValid()) {
266
// Store the pointer to the window
267
m_windowManager->addWindow(window);
269
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
285
if (xwind == 0) return NULL;
287
// It is not entirely safe to do this as the backptr may point
288
// to a window that has recently been removed.
289
// We should always check the window manager's list of windows
290
// and only process events on these windows.
292
vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
294
vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
295
vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
297
for (; win_it != win_end; ++win_it) {
298
GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
299
if (window->getXWindow() == xwind) {
307
static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) {
308
int fd = ConnectionNumber(display);
314
if (maxSleep == -1) {
315
select(fd + 1, &fds, NULL, NULL, NULL);
319
tv.tv_sec = maxSleep/1000;
320
tv.tv_usec = (maxSleep - tv.tv_sec*1000)*1000;
322
select(fd + 1, &fds, NULL, NULL, &tv);
326
/* This function borrowed from Qt's X11 support
329
struct init_timestamp_data
334
static Bool init_timestamp_scanner(Display*, XEvent *event, XPointer arg)
336
init_timestamp_data *data =
337
reinterpret_cast<init_timestamp_data*>(arg);
342
data->timestamp = event->xbutton.time;
345
data->timestamp = event->xmotion.time;
349
data->timestamp = event->xkey.time;
352
data->timestamp = event->xproperty.time;
356
data->timestamp = event->xcrossing.time;
359
data->timestamp = event->xselectionclear.time;
370
lastEventTime(Time default_time) {
371
init_timestamp_data data;
372
data.timestamp = default_time;
374
XCheckIfEvent(m_display, &ev, &init_timestamp_scanner, (XPointer)&data);
376
return data.timestamp;
386
// Get all the current events -- translate them into
387
// ghost events and call base class pushEvent() method.
389
bool anyProcessed = false;
392
GHOST_TimerManager* timerMgr = getTimerManager();
394
if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) {
395
GHOST_TUns64 next = timerMgr->nextFireTime();
397
if (next==GHOST_kFireTimeNever) {
398
SleepTillEvent(m_display, -1);
400
GHOST_TInt64 maxSleep = next - getMilliSeconds();
403
SleepTillEvent(m_display, next - getMilliSeconds());
407
if (timerMgr->fireTimers(getMilliSeconds())) {
411
while (XPending(m_display)) {
413
XNextEvent(m_display, &xevent);
414
processEvent(&xevent);
418
if (generateWindowExposeEvents()) {
421
} while (waitForEvent && !anyProcessed);
427
GHOST_SystemX11::processEvent(XEvent *xe)
429
GHOST_WindowX11 * window = findGhostWindow(xe->xany.window);
430
GHOST_Event * g_event = NULL;
439
XExposeEvent & xee = xe->xexpose;
441
if (xee.count == 0) {
442
// Only generate a single expose event
443
// per read of the event queue.
448
GHOST_kEventWindowUpdate,
457
XMotionEvent &xme = xe->xmotion;
459
if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
461
GHOST_TInt32 x_new= xme.x_root;
462
GHOST_TInt32 y_new= xme.y_root;
463
GHOST_TInt32 x_accum, y_accum;
466
/* fallback to window bounds */
467
if(window->getCursorGrabBounds(bounds)==GHOST_kFailure)
468
window->getClientBounds(bounds);
470
/* could also clamp to screen bounds
471
* wrap with a window outside the view will fail atm */
472
bounds.wrapPoint(x_new, y_new, 8); /* offset of one incase blender is at screen bounds */
473
window->getCursorGrabAccum(x_accum, y_accum);
475
if(x_new != xme.x_root || y_new != xme.y_root) {
476
if (xme.time > m_last_warp) {
477
/* when wrapping we don't need to add an event because the
478
* setCursorPosition call will cause a new event after */
479
setCursorPosition(x_new, y_new); /* wrap */
480
window->setCursorGrabAccum(x_accum + (xme.x_root - x_new), y_accum + (xme.y_root - y_new));
481
m_last_warp = lastEventTime(xme.time);
483
setCursorPosition(x_new, y_new); /* wrap but don't accumulate */
490
GHOST_kEventCursorMove,
492
xme.x_root + x_accum,
501
GHOST_kEventCursorMove,
513
XKeyEvent *xke = &(xe->xkey);
515
KeySym key_sym = XLookupKeysym(xke,0);
518
GHOST_TKey gkey = convertXKey(key_sym);
519
GHOST_TEventType type = (xke->type == KeyPress) ?
520
GHOST_kEventKeyDown : GHOST_kEventKeyUp;
522
if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
541
XButtonEvent & xbe = xe->xbutton;
542
GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
543
GHOST_TEventType type = (xbe.type == ButtonPress) ?
544
GHOST_kEventButtonDown : GHOST_kEventButtonUp;
546
/* process wheel mouse events and break, only pass on press events */
547
if(xbe.button == Button4) {
548
if(xbe.type == ButtonPress)
549
g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
552
else if(xbe.button == Button5) {
553
if(xbe.type == ButtonPress)
554
g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
558
/* process rest of normal mouse buttons */
559
if(xbe.button == Button1)
560
gbmask = GHOST_kButtonMaskLeft;
561
else if(xbe.button == Button2)
562
gbmask = GHOST_kButtonMaskMiddle;
563
else if(xbe.button == Button3)
564
gbmask = GHOST_kButtonMaskRight;
565
/* It seems events 6 and 7 are for horizontal scrolling.
566
* you can re-order button mapping like this... (swaps 6,7 with 8,9)
567
* xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7"
569
else if(xbe.button == 8)
570
gbmask = GHOST_kButtonMaskButton4;
571
else if(xbe.button == 9)
572
gbmask = GHOST_kButtonMaskButton5;
586
// change of size, border, layer etc.
587
case ConfigureNotify:
589
/* XConfigureEvent & xce = xe->xconfigure; */
594
GHOST_kEventWindowSize,
603
XFocusChangeEvent &xfe = xe->xfocus;
605
// May have to look at the type of event and filter some
608
GHOST_TEventType gtype = (xfe.type == FocusIn) ?
609
GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate;
622
XClientMessageEvent & xcme = xe->xclient;
625
if (((Atom)xcme.data.l[0]) == m_delete_window_atom) {
629
GHOST_kEventWindowClose,
634
if (sNdofInfo.currValues) {
635
static GHOST_TEventNDOFData data = {0,0,0,0,0,0,0,0,0,0,0};
636
if (xcme.message_type == sNdofInfo.motionAtom)
639
data.delta = xcme.data.s[8] - data.time;
640
data.time = xcme.data.s[8];
641
data.tx = xcme.data.s[2] >> 2;
642
data.ty = xcme.data.s[3] >> 2;
643
data.tz = xcme.data.s[4] >> 2;
644
data.rx = xcme.data.s[5];
645
data.ry = xcme.data.s[6];
646
data.rz =-xcme.data.s[7];
647
g_event = new GHOST_EventNDOF(getMilliSeconds(),
648
GHOST_kEventNDOFMotion,
650
} else if (xcme.message_type == sNdofInfo.btnPressAtom) {
652
data.delta = xcme.data.s[8] - data.time;
653
data.time = xcme.data.s[8];
654
data.buttons = xcme.data.s[2];
655
g_event = new GHOST_EventNDOF(getMilliSeconds(),
656
GHOST_kEventNDOFButton,
659
} else if (((Atom)xcme.data.l[0]) == m_wm_take_focus) {
660
XWindowAttributes attr;
664
/* as ICCCM say, we need reply this event
665
* with a SetInputFocus, the data[1] have
666
* the valid timestamp (send by the wm).
668
* Some WM send this event before the
669
* window is really mapped (for example
670
* change from virtual desktop), so we need
671
* to be sure that our windows is mapped
672
* or this call fail and close blender.
674
if (XGetWindowAttributes(m_display, xcme.window, &attr) == True) {
675
if (XGetInputFocus(m_display, &fwin, &revert_to) == True) {
676
if (attr.map_state == IsViewable) {
677
if (fwin != xcme.window)
678
XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
683
/* Unknown client message, ignore */
690
// We're not interested in the following things.(yet...)
692
case GraphicsExpose :
698
// XCrossingEvents pointer leave enter window.
699
// also do cursor move here, MotionNotify only
700
// happens when motion starts & ends inside window
701
XCrossingEvent &xce = xe->xcrossing;
706
GHOST_kEventCursorMove,
716
* [ Clients can select for StructureNotify on their
717
* top-level windows to track transition between
718
* Normal and Iconic states. Receipt of a MapNotify
719
* event will indicate a transition to the Normal
720
* state, and receipt of an UnmapNotify event will
721
* indicate a transition to the Iconic state. ]
723
if (window->m_post_init == True) {
725
* Now we are sure that the window is
726
* mapped, so only need change the state.
728
window->setState (window->m_post_state);
729
window->m_post_init = False;
737
case SelectionRequest:
740
Atom target, string, compound_text, c_string;
741
XSelectionRequestEvent *xse = &xe->xselectionrequest;
743
target = XInternAtom(m_display, "TARGETS", False);
744
string = XInternAtom(m_display, "STRING", False);
745
compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
746
c_string = XInternAtom(m_display, "C_STRING", False);
748
/* support obsolete clients */
749
if (xse->property == None) {
750
xse->property = xse->target;
753
nxe.xselection.type = SelectionNotify;
754
nxe.xselection.requestor = xse->requestor;
755
nxe.xselection.property = xse->property;
756
nxe.xselection.display = xse->display;
757
nxe.xselection.selection = xse->selection;
758
nxe.xselection.target = xse->target;
759
nxe.xselection.time = xse->time;
761
/*Check to see if the requestor is asking for String*/
762
if(xse->target == string || xse->target == compound_text || xse->target == c_string) {
763
if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
764
XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_select_buffer, strlen(txt_select_buffer));
765
} else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) {
766
XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 8, PropModeReplace, (unsigned char*)txt_cut_buffer, strlen(txt_cut_buffer));
768
} else if (xse->target == target) {
772
alist[2] = compound_text;
774
XChangeProperty(m_display, xse->requestor, xse->property, xse->target, 32, PropModeReplace, (unsigned char*)alist, 4);
777
//Change property to None because we do not support anything but STRING
778
nxe.xselection.property = None;
781
//Send the event to the client 0 0 == False, SelectionNotify
782
XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
788
if(xe->type == window->GetXTablet().MotionEvent)
790
XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
791
window->GetXTablet().CommonData.Pressure=
792
data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
794
/* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
795
* but I got garbage data without it. Found it in the xidump.c source --matt */
796
window->GetXTablet().CommonData.Xtilt=
797
(short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
798
window->GetXTablet().CommonData.Ytilt=
799
(short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
801
else if(xe->type == window->GetXTablet().ProxInEvent)
803
XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
804
if(data->deviceid == window->GetXTablet().StylusID)
805
window->GetXTablet().CommonData.Active= GHOST_kTabletModeStylus;
806
else if(data->deviceid == window->GetXTablet().EraserID)
807
window->GetXTablet().CommonData.Active= GHOST_kTabletModeEraser;
809
else if(xe->type == window->GetXTablet().ProxOutEvent)
810
window->GetXTablet().CommonData.Active= GHOST_kTabletModeNone;
823
prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
825
const vector<GHOST_IWindow*>& v(m_windowManager->getWindows());
827
sNdofInfo.window = static_cast<GHOST_WindowX11*>(v[0])->getXWindow();
828
sNdofInfo.display = m_display;
829
sNdofInfo.currValues = currentNdofValues;
830
return (void*)&sNdofInfo;
836
GHOST_ModifierKeys& keys
839
// analyse the masks retuned from XQueryPointer.
841
memset((void *)m_keyboard_vector,0,sizeof(m_keyboard_vector));
843
XQueryKeymap(m_display,(char *)m_keyboard_vector);
845
// now translate key symobols into keycodes and
848
const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
849
const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
850
const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
851
const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
852
const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
853
const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
856
if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
857
keys.set(GHOST_kModifierKeyLeftShift,true);
859
keys.set(GHOST_kModifierKeyLeftShift,false);
861
if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
863
keys.set(GHOST_kModifierKeyRightShift,true);
865
keys.set(GHOST_kModifierKeyRightShift,false);
869
if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
870
keys.set(GHOST_kModifierKeyLeftControl,true);
872
keys.set(GHOST_kModifierKeyLeftControl,false);
874
if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
875
keys.set(GHOST_kModifierKeyRightControl,true);
877
keys.set(GHOST_kModifierKeyRightControl,false);
881
if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
882
keys.set(GHOST_kModifierKeyLeftAlt,true);
884
keys.set(GHOST_kModifierKeyLeftAlt,false);
886
if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
887
keys.set(GHOST_kModifierKeyRightAlt,true);
889
keys.set(GHOST_kModifierKeyRightAlt,false);
891
return GHOST_kSuccess;
897
GHOST_Buttons& buttons
900
Window root_return, child_return;
902
unsigned int mask_return;
906
RootWindow(m_display,DefaultScreen(m_display)),
913
return GHOST_kFailure;
916
if (mask_return & Button1Mask) {
917
buttons.set(GHOST_kButtonMaskLeft,true);
919
buttons.set(GHOST_kButtonMaskLeft,false);
922
if (mask_return & Button2Mask) {
923
buttons.set(GHOST_kButtonMaskMiddle,true);
925
buttons.set(GHOST_kButtonMaskMiddle,false);
928
if (mask_return & Button3Mask) {
929
buttons.set(GHOST_kButtonMaskRight,true);
931
buttons.set(GHOST_kButtonMaskRight,false);
935
return GHOST_kSuccess;
946
Window root_return, child_return;
948
unsigned int mask_return;
952
RootWindow(m_display,DefaultScreen(m_display)),
959
return GHOST_kFailure;
964
return GHOST_kSuccess;
975
// This is a brute force move in screen coordinates
976
// XWarpPointer does relative moves so first determine the
977
// current pointer position.
980
if (getCursorPosition(cx,cy) == GHOST_kFailure) {
981
return GHOST_kFailure;
987
XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
988
XSync(m_display, 0); /* Sync to process all requests */
990
return GHOST_kSuccess;
997
GHOST_WindowX11 * bad_wind
1000
GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
1002
m_dirty_windows.push_back(bad_wind);
1008
generateWindowExposeEvents(
1011
vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
1012
vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
1013
bool anyProcessed = false;
1015
for (;w_start != w_end; ++w_start) {
1016
GHOST_Event * g_event = new
1019
GHOST_kEventWindowUpdate,
1023
(*w_start)->validate();
1027
anyProcessed = true;
1031
m_dirty_windows.clear();
1032
return anyProcessed;
1035
#define GXMAP(k,x,y) case x: k = y; break;
1044
if ((key >= XK_A) && (key <= XK_Z)) {
1045
type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
1046
} else if ((key >= XK_a) && (key <= XK_z)) {
1047
type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
1048
} else if ((key >= XK_0) && (key <= XK_9)) {
1049
type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
1050
} else if ((key >= XK_F1) && (key <= XK_F24)) {
1051
type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
1052
#if defined(__sun) || defined(__sun__)
1053
/* This is a bit of a hack, but it looks like sun
1054
Used F11 and friends for its special keys Stop,again etc..
1055
So this little patch enables F11 and F12 to work as expected
1056
following link has documentation on it:
1057
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
1058
also from /usr/include/X11/Sunkeysym.h
1059
#define SunXK_F36 0x1005FF10 // Labeled F11
1060
#define SunXK_F37 0x1005FF11 // Labeled F12
1065
} else if (key == 268828432) {
1066
type = GHOST_kKeyF11;
1067
} else if (key == 268828433) {
1068
type = GHOST_kKeyF12;
1072
GXMAP(type,XK_BackSpace, GHOST_kKeyBackSpace);
1073
GXMAP(type,XK_Tab, GHOST_kKeyTab);
1074
GXMAP(type,XK_Return, GHOST_kKeyEnter);
1075
GXMAP(type,XK_Escape, GHOST_kKeyEsc);
1076
GXMAP(type,XK_space, GHOST_kKeySpace);
1078
GXMAP(type,XK_Linefeed, GHOST_kKeyLinefeed);
1079
GXMAP(type,XK_semicolon, GHOST_kKeySemicolon);
1080
GXMAP(type,XK_period, GHOST_kKeyPeriod);
1081
GXMAP(type,XK_comma, GHOST_kKeyComma);
1082
GXMAP(type,XK_quoteright, GHOST_kKeyQuote);
1083
GXMAP(type,XK_quoteleft, GHOST_kKeyAccentGrave);
1084
GXMAP(type,XK_minus, GHOST_kKeyMinus);
1085
GXMAP(type,XK_slash, GHOST_kKeySlash);
1086
GXMAP(type,XK_backslash, GHOST_kKeyBackslash);
1087
GXMAP(type,XK_equal, GHOST_kKeyEqual);
1088
GXMAP(type,XK_bracketleft, GHOST_kKeyLeftBracket);
1089
GXMAP(type,XK_bracketright, GHOST_kKeyRightBracket);
1090
GXMAP(type,XK_Pause, GHOST_kKeyPause);
1092
GXMAP(type,XK_Shift_L, GHOST_kKeyLeftShift);
1093
GXMAP(type,XK_Shift_R, GHOST_kKeyRightShift);
1094
GXMAP(type,XK_Control_L, GHOST_kKeyLeftControl);
1095
GXMAP(type,XK_Control_R, GHOST_kKeyRightControl);
1096
GXMAP(type,XK_Alt_L, GHOST_kKeyLeftAlt);
1097
GXMAP(type,XK_Alt_R, GHOST_kKeyRightAlt);
1099
GXMAP(type,XK_Insert, GHOST_kKeyInsert);
1100
GXMAP(type,XK_Delete, GHOST_kKeyDelete);
1101
GXMAP(type,XK_Home, GHOST_kKeyHome);
1102
GXMAP(type,XK_End, GHOST_kKeyEnd);
1103
GXMAP(type,XK_Page_Up, GHOST_kKeyUpPage);
1104
GXMAP(type,XK_Page_Down, GHOST_kKeyDownPage);
1106
GXMAP(type,XK_Left, GHOST_kKeyLeftArrow);
1107
GXMAP(type,XK_Right, GHOST_kKeyRightArrow);
1108
GXMAP(type,XK_Up, GHOST_kKeyUpArrow);
1109
GXMAP(type,XK_Down, GHOST_kKeyDownArrow);
1111
GXMAP(type,XK_Caps_Lock, GHOST_kKeyCapsLock);
1112
GXMAP(type,XK_Scroll_Lock, GHOST_kKeyScrollLock);
1113
GXMAP(type,XK_Num_Lock, GHOST_kKeyNumLock);
1117
GXMAP(type,XK_KP_0, GHOST_kKeyNumpad0);
1118
GXMAP(type,XK_KP_1, GHOST_kKeyNumpad1);
1119
GXMAP(type,XK_KP_2, GHOST_kKeyNumpad2);
1120
GXMAP(type,XK_KP_3, GHOST_kKeyNumpad3);
1121
GXMAP(type,XK_KP_4, GHOST_kKeyNumpad4);
1122
GXMAP(type,XK_KP_5, GHOST_kKeyNumpad5);
1123
GXMAP(type,XK_KP_6, GHOST_kKeyNumpad6);
1124
GXMAP(type,XK_KP_7, GHOST_kKeyNumpad7);
1125
GXMAP(type,XK_KP_8, GHOST_kKeyNumpad8);
1126
GXMAP(type,XK_KP_9, GHOST_kKeyNumpad9);
1127
GXMAP(type,XK_KP_Decimal, GHOST_kKeyNumpadPeriod);
1129
GXMAP(type,XK_KP_Insert, GHOST_kKeyNumpad0);
1130
GXMAP(type,XK_KP_End, GHOST_kKeyNumpad1);
1131
GXMAP(type,XK_KP_Down, GHOST_kKeyNumpad2);
1132
GXMAP(type,XK_KP_Page_Down, GHOST_kKeyNumpad3);
1133
GXMAP(type,XK_KP_Left, GHOST_kKeyNumpad4);
1134
GXMAP(type,XK_KP_Begin, GHOST_kKeyNumpad5);
1135
GXMAP(type,XK_KP_Right, GHOST_kKeyNumpad6);
1136
GXMAP(type,XK_KP_Home, GHOST_kKeyNumpad7);
1137
GXMAP(type,XK_KP_Up, GHOST_kKeyNumpad8);
1138
GXMAP(type,XK_KP_Page_Up, GHOST_kKeyNumpad9);
1139
GXMAP(type,XK_KP_Delete, GHOST_kKeyNumpadPeriod);
1141
GXMAP(type,XK_KP_Enter, GHOST_kKeyNumpadEnter);
1142
GXMAP(type,XK_KP_Add, GHOST_kKeyNumpadPlus);
1143
GXMAP(type,XK_KP_Subtract, GHOST_kKeyNumpadMinus);
1144
GXMAP(type,XK_KP_Multiply, GHOST_kKeyNumpadAsterisk);
1145
GXMAP(type,XK_KP_Divide, GHOST_kKeyNumpadSlash);
1147
/* some extra sun cruft (NICE KEYBOARD!) */
1149
GXMAP(type,0xffde, GHOST_kKeyNumpad1);
1150
GXMAP(type,0xffe0, GHOST_kKeyNumpad3);
1151
GXMAP(type,0xffdc, GHOST_kKeyNumpad5);
1152
GXMAP(type,0xffd8, GHOST_kKeyNumpad7);
1153
GXMAP(type,0xffda, GHOST_kKeyNumpad9);
1155
GXMAP(type,0xffd6, GHOST_kKeyNumpadSlash);
1156
GXMAP(type,0xffd7, GHOST_kKeyNumpadAsterisk);
1160
type = GHOST_kKeyUnknown;
1170
/* from xclip.c xcout() v0.11 */
1172
#define XCLIB_XCOUT_NONE 0 /* no context */
1173
#define XCLIB_XCOUT_SENTCONVSEL 1 /* sent a request */
1174
#define XCLIB_XCOUT_INCR 2 /* in an incr loop */
1175
#define XCLIB_XCOUT_FALLBACK 3 /* STRING failed, need fallback to UTF8 */
1176
#define XCLIB_XCOUT_FALLBACK_UTF8 4 /* UTF8 failed, move to compouned */
1177
#define XCLIB_XCOUT_FALLBACK_COMP 5 /* compouned failed, move to text. */
1178
#define XCLIB_XCOUT_FALLBACK_TEXT 6
1180
// Retrieves the contents of a selections.
1181
void GHOST_SystemX11::getClipboard_xcout(XEvent evt,
1182
Atom sel, Atom target, unsigned char **txt,
1183
unsigned long *len, unsigned int *context) const
1187
unsigned char *buffer;
1188
unsigned long pty_size, pty_items;
1189
unsigned char *ltxt= *txt;
1191
vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1192
vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1193
GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1194
Window win = window->getXWindow();
1197
// There is no context, do an XConvertSelection()
1198
case XCLIB_XCOUT_NONE:
1199
// Initialise return length to 0
1205
// Send a selection request
1206
XConvertSelection(m_display, sel, target, m_xclip_out, win, CurrentTime);
1207
*context = XCLIB_XCOUT_SENTCONVSEL;
1210
case XCLIB_XCOUT_SENTCONVSEL:
1211
if (evt.type != SelectionNotify)
1214
if (target == m_utf8_string && evt.xselection.property == None) {
1215
*context= XCLIB_XCOUT_FALLBACK_UTF8;
1218
else if (target == m_compound_text && evt.xselection.property == None) {
1219
*context= XCLIB_XCOUT_FALLBACK_COMP;
1222
else if (target == m_text && evt.xselection.property == None) {
1223
*context= XCLIB_XCOUT_FALLBACK_TEXT;
1227
// find the size and format of the data in property
1228
XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1229
AnyPropertyType, &pty_type, &pty_format,
1230
&pty_items, &pty_size, &buffer);
1233
if (pty_type == m_incr) {
1234
// start INCR mechanism by deleting property
1235
XDeleteProperty(m_display, win, m_xclip_out);
1237
*context = XCLIB_XCOUT_INCR;
1241
// if it's not incr, and not format == 8, then there's
1242
// nothing in the selection (that xclip understands, anyway)
1244
if (pty_format != 8) {
1245
*context = XCLIB_XCOUT_NONE;
1249
// not using INCR mechanism, just read the property
1250
XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1251
False, AnyPropertyType, &pty_type,
1252
&pty_format, &pty_items, &pty_size, &buffer);
1254
// finished with property, delete it
1255
XDeleteProperty(m_display, win, m_xclip_out);
1257
// copy the buffer to the pointer for returned data
1258
ltxt = (unsigned char *) malloc(pty_items);
1259
memcpy(ltxt, buffer, pty_items);
1261
// set the length of the returned data
1268
*context = XCLIB_XCOUT_NONE;
1270
// complete contents of selection fetched, return 1
1273
case XCLIB_XCOUT_INCR:
1274
// To use the INCR method, we basically delete the
1275
// property with the selection in it, wait for an
1276
// event indicating that the property has been created,
1277
// then read it, delete it, etc.
1279
// make sure that the event is relevant
1280
if (evt.type != PropertyNotify)
1283
// skip unless the property has a new value
1284
if (evt.xproperty.state != PropertyNewValue)
1287
// check size and format of the property
1288
XGetWindowProperty(m_display, win, m_xclip_out, 0, 0, False,
1289
AnyPropertyType, &pty_type, &pty_format,
1290
&pty_items, &pty_size, (unsigned char **) &buffer);
1292
if (pty_format != 8) {
1293
// property does not contain text, delete it
1294
// to tell the other X client that we have read
1295
// it and to send the next property
1297
XDeleteProperty(m_display, win, m_xclip_out);
1301
if (pty_size == 0) {
1302
// no more data, exit from loop
1304
XDeleteProperty(m_display, win, m_xclip_out);
1305
*context = XCLIB_XCOUT_NONE;
1307
// this means that an INCR transfer is now
1308
// complete, return 1
1314
// if we have come this far, the propery contains
1315
// text, we know the size.
1316
XGetWindowProperty(m_display, win, m_xclip_out, 0, (long) pty_size,
1317
False, AnyPropertyType, &pty_type, &pty_format,
1318
&pty_items, &pty_size, (unsigned char **) &buffer);
1320
// allocate memory to accommodate data in *txt
1323
ltxt = (unsigned char *) malloc(*len);
1327
ltxt = (unsigned char *) realloc(ltxt, *len);
1331
memcpy(<xt[*len - pty_items], buffer, pty_items);
1336
// delete property to get the next item
1337
XDeleteProperty(m_display, win, m_xclip_out);
1344
GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
1347
Atom target= m_string;
1350
// from xclip.c doOut() v0.11
1351
unsigned char *sel_buf;
1352
unsigned long sel_len= 0;
1354
unsigned int context= XCLIB_XCOUT_NONE;
1356
if (selection == True)
1361
vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1362
vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1363
GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1364
Window win = window->getXWindow();
1366
/* check if we are the owner. */
1367
owner= XGetSelectionOwner(m_display, sseln);
1369
if (sseln == m_clipboard) {
1370
sel_buf= (unsigned char *)malloc(strlen(txt_cut_buffer)+1);
1371
strcpy((char *)sel_buf, txt_cut_buffer);
1372
return((GHOST_TUns8*)sel_buf);
1375
sel_buf= (unsigned char *)malloc(strlen(txt_select_buffer)+1);
1376
strcpy((char *)sel_buf, txt_select_buffer);
1377
return((GHOST_TUns8*)sel_buf);
1380
else if (owner == None)
1384
/* only get an event if xcout() is doing something */
1385
if (context != XCLIB_XCOUT_NONE)
1386
XNextEvent(m_display, &evt);
1388
/* fetch the selection, or part of it */
1389
getClipboard_xcout(evt, sseln, target, &sel_buf, &sel_len, &context);
1391
/* fallback is needed. set XA_STRING to target and restart the loop. */
1392
if (context == XCLIB_XCOUT_FALLBACK) {
1393
context= XCLIB_XCOUT_NONE;
1397
else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
1398
/* utf8 fail, move to compouned text. */
1399
context= XCLIB_XCOUT_NONE;
1400
target= m_compound_text;
1403
else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
1404
/* compouned text faile, move to text. */
1405
context= XCLIB_XCOUT_NONE;
1410
/* only continue if xcout() is doing something */
1411
if (context == XCLIB_XCOUT_NONE)
1416
/* only print the buffer out, and free it, if it's not
1419
unsigned char *tmp_data = (unsigned char*) malloc(sel_len+1);
1420
memcpy((char*)tmp_data, (char*)sel_buf, sel_len);
1421
tmp_data[sel_len] = '\0';
1423
if (sseln == m_string)
1428
return (GHOST_TUns8*)tmp_data;
1433
void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1435
Window m_window, owner;
1437
vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
1438
vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1439
GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
1440
m_window = window->getXWindow();
1443
if (selection == False) {
1444
XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime);
1445
owner= XGetSelectionOwner(m_display, m_clipboard);
1447
free((void*)txt_cut_buffer);
1449
txt_cut_buffer = (char*) malloc(strlen(buffer)+1);
1450
strcpy(txt_cut_buffer, buffer);
1452
XSetSelectionOwner(m_display, m_primary, m_window, CurrentTime);
1453
owner= XGetSelectionOwner(m_display, m_primary);
1454
if (txt_select_buffer)
1455
free((void*)txt_select_buffer);
1457
txt_select_buffer = (char*) malloc(strlen(buffer)+1);
1458
strcpy(txt_select_buffer, buffer);
1461
if (owner != m_window)
1462
fprintf(stderr, "failed to own primary\n");
1466
const GHOST_TUns8* GHOST_SystemX11::getSystemDir() const
1468
return (GHOST_TUns8*) PREFIX "/share";
1471
const GHOST_TUns8* GHOST_SystemX11::getUserDir() const
1473
char* env = getenv("HOME");
1475
return (GHOST_TUns8*) env;
1481
const GHOST_TUns8* GHOST_SystemX11::getBinaryDir() const