1 /***************************************************************************
2  *   Copyright (C) 2011~2012 by CSSlayer                                   *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
18  ***************************************************************************/
19 
20 #ifndef __FCITX_INPUT_CONTEXT_H_
21 #define __FCITX_INPUT_CONTEXT_H_
22 
23 #include "config.h"
24 
25 #include <QApplication>
26 #include <QDBusConnection>
27 #include <QDir>
28 #include <QInputContext>
29 #include <QList>
30 #include <QWeakPointer>
31 
32 #include "fcitx-config/hotkey.h"
33 #include "fcitx/ime.h"
34 #include "fcitxinputcontextproxy.h"
35 #include "fcitxwatcher.h"
36 #include <xkbcommon/xkbcommon-compose.h>
37 
38 #include "fcitx/frontend.h"
39 #include <X11/Xlib.h>
40 
41 struct FcitxQtICData {
FcitxQtICDataFcitxQtICData42     FcitxQtICData(FcitxWatcher *watcher)
43         : capacity(0), proxy(new FcitxInputContextProxy(watcher, watcher)),
44           surroundingAnchor(-1), surroundingCursor(-1) {}
~FcitxQtICDataFcitxQtICData45     ~FcitxQtICData() { delete proxy; }
46     QFlags<FcitxCapacityFlags> capacity;
47     FcitxInputContextProxy *proxy;
48     QRect rect;
49     QString surroundingText;
50     int surroundingAnchor;
51     int surroundingCursor;
52 };
53 
54 class FcitxQtConnection;
55 
56 class ProcessKeyWatcher : public QDBusPendingCallWatcher {
57     Q_OBJECT
58 public:
59     ProcessKeyWatcher(XEvent *e, KeySym s, const QDBusPendingCall &call,
60                       QObject *parent = 0)
QDBusPendingCallWatcher(call,parent)61         : QDBusPendingCallWatcher(call, parent) {
62         event = static_cast<XEvent *>(malloc(sizeof(XEvent)));
63         *event = *e;
64         sym = s;
65     }
66 
~ProcessKeyWatcher()67     virtual ~ProcessKeyWatcher() { free(event); }
68 
69 public slots:
processEvent()70     void processEvent() {
71         qApp->x11ProcessEvent(event);
72         deleteLater();
73     }
74 
75 public:
76     XEvent *event;
77     KeySym sym;
78 };
79 
80 #define FCITX_IDENTIFIER_NAME "fcitx"
81 
82 struct XkbContextDeleter {
cleanupXkbContextDeleter83     static inline void cleanup(struct xkb_context *pointer) {
84         if (pointer)
85             xkb_context_unref(pointer);
86     }
87 };
88 
89 struct XkbComposeTableDeleter {
cleanupXkbComposeTableDeleter90     static inline void cleanup(struct xkb_compose_table *pointer) {
91         if (pointer)
92             xkb_compose_table_unref(pointer);
93     }
94 };
95 
96 struct XkbComposeStateDeleter {
cleanupXkbComposeStateDeleter97     static inline void cleanup(struct xkb_compose_state *pointer) {
98         if (pointer)
99             xkb_compose_state_unref(pointer);
100     }
101 };
102 
103 class QFcitxInputContext : public QInputContext {
104     Q_OBJECT
105 public:
106     QFcitxInputContext();
107     ~QFcitxInputContext();
108 
109     virtual QString identifierName();
110     virtual QString language();
111     virtual void reset();
112     virtual bool isComposing() const;
113     virtual void update();
114     virtual void setFocusWidget(QWidget *w);
115 
116     virtual void widgetDestroyed(QWidget *w);
117 
118     virtual bool x11FilterEvent(QWidget *keywidget, XEvent *event);
119     virtual void mouseHandler(int x, QMouseEvent *event);
120 
121 private Q_SLOTS:
122     void createInputContextFinished();
123     void cleanUp();
124     void commitString(const QString &str);
125     void updateFormattedPreedit(const FcitxFormattedPreeditList &preeditList,
126                                 int cursorPos);
127     void forwardKey(uint keyval, uint state, bool isRelease);
128     void deleteSurroundingText(int offset, uint nchar);
129     void updateCursor();
130     void x11ProcessKeyEventCallback(QDBusPendingCallWatcher *watcher);
131 
132 private:
133     QWidget *validFocusWidget();
134     bool processCompose(uint keyval, uint state, FcitxKeyEventType event);
135     bool x11FilterEventFallback(XEvent *event, KeySym sym);
136     XEvent *createXEvent(Display *dpy, WId wid, uint keyval, uint state,
137                          bool isRelease);
138     bool isValid();
139     FcitxInputContextProxy *validIC();
140     FcitxInputContextProxy *validICByWidget(QWidget *w);
141 
142     void addCapacity(FcitxQtICData *data, QFlags<FcitxCapacityFlags> capacity,
143                      bool forceUpdate = false) {
144         QFlags<FcitxCapacityFlags> newcaps = data->capacity | capacity;
145         if (data->capacity != newcaps || forceUpdate) {
146             data->capacity = newcaps;
147             updateCapacity(data);
148         }
149     }
150 
151     void removeCapacity(FcitxQtICData *data,
152                         QFlags<FcitxCapacityFlags> capacity,
153                         bool forceUpdate = false) {
154         QFlags<FcitxCapacityFlags> newcaps = data->capacity & (~capacity);
155         if (data->capacity != newcaps || forceUpdate) {
156             data->capacity = newcaps;
157             updateCapacity(data);
158         }
159     }
160 
161     void updateCapacity(FcitxQtICData *data);
162     void commitPreedit();
163     void createICData(QWidget *w);
164 
165     QString m_preedit;
166     QString m_commitPreedit;
167     FcitxFormattedPreeditList m_preeditList;
168     int m_cursorPos;
169     bool m_useSurroundingText;
170     bool m_syncMode;
171     FcitxWatcher *m_watcher;
172     QHash<WId, FcitxQtICData *> m_icMap;
173     QScopedPointer<struct xkb_context, XkbContextDeleter> m_xkbContext;
174     QScopedPointer<struct xkb_compose_table, XkbComposeTableDeleter>
175         m_xkbComposeTable;
176     QScopedPointer<struct xkb_compose_state, XkbComposeStateDeleter>
177         m_xkbComposeState;
178 };
179 
180 #endif //__FCITX_INPUT_CONTEXT_H_
181 
182 // kate: indent-mode cstyle; space-indent on; indent-width 0;
183