GTK+ and 3Dconnexion [SOLVED]

Post questions, comments and feedback to our 3Dconnexion UNIX and Linux Development Team.

Moderator: Moderators

Post Reply
sergyi
Posts: 3
Joined: Mon Oct 31, 2011 5:29 am
Location: Ukraine, Kyiv
Contact:

GTK+ and 3Dconnexion [SOLVED]

Post by sergyi »

Hello! I would like to share code snippet, which demonstrates how to receive events from 3Dconnexion Space Navigator device under Linux within GTK+ application. The official 3Dconnexion Linux SDK contains example, which uses X Server. That code is redundant and outdated.
Please note before reviewing the code:
“comms” is namespace of our engine;
class “cVec3” is vector with 3 float components;
class “cVec2i” is vector with 2 int components;
“cThread::ThreadMutex” is alias for “pthread_mutex_t”;
“cLinuxMain_Window” has type “GtkWidget *” and points to the main window;
“cLinuxMain_Display” has been defined as:
static Display *cLinuxMain_Display = NULL;
cLinuxMain_Display = GDK_DISPLAY();

Code: Select all

// cLinuxMain_3Dconnexion
class cLinuxMain_3Dconnexion {
public:
    comms::cVec3 Translation;
    comms::cVec3 Rotation;
    comms::cVec2i ButtonState;
    comms::cThread::ThreadMutex Mutex;
    
    cLinuxMain_3Dconnexion() {
        Translation.SetZero();
        Rotation.SetZero();
        ButtonState.Set(0);
    }
    void Free() {
        comms::cThread::DeleteMutex(Mutex);
    }
    void Init();
private:
    Atom m_MotionEvent, m_ButtonPressEvent, m_ButtonReleaseEvent;
    bool InitEvents();
    bool HandleEvent(const XEvent &Event);
    static GdkFilterReturn FilterProc(GdkXEvent *Xevent, GdkEvent *, gpointer);
};
cLinuxMain_3Dconnexion g_3Dconnexion;

// cMain_GetTdxState
void cMain_GetTdxState(comms::cVec3 *Translation, comms::cVec3 *Rotation, comms::cVec2i *ButtonState) {
    comms::cThread::LockMutex(g_3Dconnexion.Mutex);
    if(Translation != NULL) {
        *Translation = g_3Dconnexion.Translation;
    }
    if(Rotation != NULL) {
        *Rotation = g_3Dconnexion.Rotation;
    }
    if(ButtonState != NULL) {
        *ButtonState = g_3Dconnexion.ButtonState;
    }
    comms::cThread::UnlockMutex(g_3Dconnexion.Mutex);
}

// cLinuxMain_3Dconnexion::Init
void cLinuxMain_3Dconnexion::Init() {
    comms::cThread::CreateMutex(Mutex);
    if(InitEvents()) {
        comms::cLog::Message("3Dconnexion driver has been found");
        gdk_window_add_filter(cLinuxMain_Window->window, FilterProc, NULL);
    } else {
        comms::cLog::Message("No 3Dconnexion driver");
    }
}

// cLinuxMain_3Dconnexion::InitEvents
bool cLinuxMain_3Dconnexion::InitEvents() {
    m_MotionEvent = XInternAtom(cLinuxMain_Display, "MotionEvent", TRUE);
    m_ButtonPressEvent = XInternAtom(cLinuxMain_Display, "ButtonPressEvent", TRUE);
    m_ButtonReleaseEvent = XInternAtom(cLinuxMain_Display, "ButtonReleaseEvent", TRUE);
    return (m_MotionEvent != 0) && (m_ButtonPressEvent != 0) && (m_ButtonReleaseEvent != 0);
}

// cLinuxMain_3Dconnexion::HandleEvent
bool cLinuxMain_3Dconnexion::HandleEvent(const XEvent &Event) {
    int Index;
    if(Event.type == ClientMessage) {
        if(Event.xclient.message_type == m_MotionEvent) {
            comms::cThread::LockMutex(Mutex);
            Translation.Set(Event.xclient.data.s[2], Event.xclient.data.s[3], Event.xclient.data.s[4]);
            Rotation.Set(Event.xclient.data.s[5], Event.xclient.data.s[6], Event.xclient.data.s[7]);
            comms::cThread::UnlockMutex(Mutex);
            return true;
        } else if(Event.xclient.message_type == m_ButtonPressEvent) {
            Index = Event.xclient.data.s[2] - 1;
            if(Index >= 0 && Index < 2) {
                comms::cThread::LockMutex(Mutex);
                ButtonState[Index] = 1;
                comms::cThread::UnlockMutex(Mutex);
            }
            return true;
        } else if(Event.xclient.message_type == m_ButtonReleaseEvent) {
            Index = Event.xclient.data.s[2] - 1;
            if(Index >= 0 && Index < 2) {
                comms::cThread::LockMutex(Mutex);
                ButtonState[Index] = 0;
                comms::cThread::UnlockMutex(Mutex);
            }
            return true;
        }
    }
    return false;
}

// cLinuxMain_3Dconnexion::FilterProc
GdkFilterReturn cLinuxMain_3Dconnexion::FilterProc(GdkXEvent *Xevent, GdkEvent *, gpointer) {
    XEvent *E = (XEvent *)Xevent;
    if(g_3Dconnexion.HandleEvent(*E)) {
        return GDK_FILTER_REMOVE;
    }
    return GDK_FILTER_CONTINUE;
}
ksingh
Posts: 1
Joined: Wed Dec 10, 2014 5:02 am

Re: GTK+ and 3Dconnexion [SOLVED]

Post by ksingh »

Hi,

Could you please provide some example,how to plug these events to the gtk widget?
I mean how by using gtk_signal_connect/g_signal_connect methods?

Thanks
sergyi
Posts: 3
Joined: Mon Oct 31, 2011 5:29 am
Location: Ukraine, Kyiv
Contact:

Re: GTK+ and 3Dconnexion [SOLVED]

Post by sergyi »

ksingh wrote: how to plug these events to the gtk widget?
This class automatically connects to the window of type “GtkWidget *” using function “gdk_window_add_filter” within method “cLinuxMain_3Dconnexion::Init()”. Here is example how to use this class:

Code: Select all

int main(int argc, char** argv) {
	gtk_init(NULL, NULL);
	// Create your main window and store it as global variable “GtkWidget *cLinuxMain_Window”
	...
	g_3Dconnexion.Init(); // This method uses global variable “cLinuxMain_Window” and connects to it
	...
	g_3Dconnexion.Free();
	return 0;
}
Post Reply