1 /***********************************************************/
2 /* */
3 /* System dependent event management (unix, x11) */
4 /* */
5 /***********************************************************/
6
7 #include "unix/guts.h"
8 #include "AbstractMenu.h"
9 #include "Application.h"
10 #include "Window.h"
11 #include "File.h"
12 #define XK_MISCELLANY
13 #define XK_LATIN1
14 #define XK_XKB_KEYS
15 #include <X11/keysymdef.h>
16
17 #define SELF_MESSAGE(_eventrec) {\
18 guts.currentFocusTime=guts.last_time;\
19 CComponent(self)-> message(self,&_eventrec);\
20 guts.currentFocusTime=CurrentTime;\
21 }
22
23 void
prima_send_create_event(XWindow win)24 prima_send_create_event( XWindow win)
25 {
26 XClientMessageEvent ev;
27
28 bzero( &ev, sizeof(ev));
29 ev. type = ClientMessage;
30 ev. display = DISP;
31 ev. window = win;
32 ev. message_type = CREATE_EVENT;
33 ev. format = 32;
34 ev. data. l[0] = 0;
35 XSendEvent( DISP, win, false, 0, (XEvent*)&ev);
36 XCHECKPOINT;
37 }
38
39 Handle
prima_xw2h(XWindow win)40 prima_xw2h( XWindow win)
41 /*
42 tries to map X window to Prima's native handle
43 */
44 {
45 Handle self;
46 self = (Handle)hash_fetch( guts.windows, (void*)&win, sizeof(win));
47 if (!self)
48 self = (Handle)hash_fetch( guts.menu_windows, (void*)&win, sizeof(win));
49 return self;
50 }
51
52 extern Bool appDead;
53
54 /* x11 keysym to unicode: from http://cvsweb.xfree86.org/cvsweb/xc/lib/X11/imKStoUCS.c */
55
56 static unsigned short const keysym_to_unicode_1a1_1ff[] = {
57 0x0104, 0x02d8, 0x0141, 0x0000, 0x013d, 0x015a, 0x0000, /* 0x01a0-0x01a7 */
58 0x0000, 0x0160, 0x015e, 0x0164, 0x0179, 0x0000, 0x017d, 0x017b, /* 0x01a8-0x01af */
59 0x0000, 0x0105, 0x02db, 0x0142, 0x0000, 0x013e, 0x015b, 0x02c7, /* 0x01b0-0x01b7 */
60 0x0000, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, /* 0x01b8-0x01bf */
61 0x0154, 0x0000, 0x0000, 0x0102, 0x0000, 0x0139, 0x0106, 0x0000, /* 0x01c0-0x01c7 */
62 0x010c, 0x0000, 0x0118, 0x0000, 0x011a, 0x0000, 0x0000, 0x010e, /* 0x01c8-0x01cf */
63 0x0110, 0x0143, 0x0147, 0x0000, 0x0000, 0x0150, 0x0000, 0x0000, /* 0x01d0-0x01d7 */
64 0x0158, 0x016e, 0x0000, 0x0170, 0x0000, 0x0000, 0x0162, 0x0000, /* 0x01d8-0x01df */
65 0x0155, 0x0000, 0x0000, 0x0103, 0x0000, 0x013a, 0x0107, 0x0000, /* 0x01e0-0x01e7 */
66 0x010d, 0x0000, 0x0119, 0x0000, 0x011b, 0x0000, 0x0000, 0x010f, /* 0x01e8-0x01ef */
67 0x0111, 0x0144, 0x0148, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, /* 0x01f0-0x01f7 */
68 0x0159, 0x016f, 0x0000, 0x0171, 0x0000, 0x0000, 0x0163, 0x02d9 /* 0x01f8-0x01ff */
69 };
70
71 static unsigned short const keysym_to_unicode_2a1_2fe[] = {
72 0x0126, 0x0000, 0x0000, 0x0000, 0x0000, 0x0124, 0x0000, /* 0x02a0-0x02a7 */
73 0x0000, 0x0130, 0x0000, 0x011e, 0x0134, 0x0000, 0x0000, 0x0000, /* 0x02a8-0x02af */
74 0x0000, 0x0127, 0x0000, 0x0000, 0x0000, 0x0000, 0x0125, 0x0000, /* 0x02b0-0x02b7 */
75 0x0000, 0x0131, 0x0000, 0x011f, 0x0135, 0x0000, 0x0000, 0x0000, /* 0x02b8-0x02bf */
76 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010a, 0x0108, 0x0000, /* 0x02c0-0x02c7 */
77 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02c8-0x02cf */
78 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0120, 0x0000, 0x0000, /* 0x02d0-0x02d7 */
79 0x011c, 0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x015c, 0x0000, /* 0x02d8-0x02df */
80 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010b, 0x0109, 0x0000, /* 0x02e0-0x02e7 */
81 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02e8-0x02ef */
82 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0121, 0x0000, 0x0000, /* 0x02f0-0x02f7 */
83 0x011d, 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x015d /* 0x02f8-0x02ff */
84 };
85
86 static unsigned short const keysym_to_unicode_3a2_3fe[] = {
87 0x0138, 0x0156, 0x0000, 0x0128, 0x013b, 0x0000, /* 0x03a0-0x03a7 */
88 0x0000, 0x0000, 0x0112, 0x0122, 0x0166, 0x0000, 0x0000, 0x0000, /* 0x03a8-0x03af */
89 0x0000, 0x0000, 0x0000, 0x0157, 0x0000, 0x0129, 0x013c, 0x0000, /* 0x03b0-0x03b7 */
90 0x0000, 0x0000, 0x0113, 0x0123, 0x0167, 0x014a, 0x0000, 0x014b, /* 0x03b8-0x03bf */
91 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012e, /* 0x03c0-0x03c7 */
92 0x0000, 0x0000, 0x0000, 0x0000, 0x0116, 0x0000, 0x0000, 0x012a, /* 0x03c8-0x03cf */
93 0x0000, 0x0145, 0x014c, 0x0136, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03d0-0x03d7 */
94 0x0000, 0x0172, 0x0000, 0x0000, 0x0000, 0x0168, 0x016a, 0x0000, /* 0x03d8-0x03df */
95 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012f, /* 0x03e0-0x03e7 */
96 0x0000, 0x0000, 0x0000, 0x0000, 0x0117, 0x0000, 0x0000, 0x012b, /* 0x03e8-0x03ef */
97 0x0000, 0x0146, 0x014d, 0x0137, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03f0-0x03f7 */
98 0x0000, 0x0173, 0x0000, 0x0000, 0x0000, 0x0169, 0x016b /* 0x03f8-0x03ff */
99 };
100
101 static unsigned short const keysym_to_unicode_4a1_4df[] = {
102 0x3002, 0x3008, 0x3009, 0x3001, 0x30fb, 0x30f2, 0x30a1, /* 0x04a0-0x04a7 */
103 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3, /* 0x04a8-0x04af */
104 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad, /* 0x04b0-0x04b7 */
105 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd, /* 0x04b8-0x04bf */
106 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc, /* 0x04c0-0x04c7 */
107 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de, /* 0x04c8-0x04cf */
108 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9, /* 0x04d0-0x04d7 */
109 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c /* 0x04d8-0x04df */
110 };
111
112 static unsigned short const keysym_to_unicode_590_5fe[] = {
113 0x06f0, 0x06f1, 0x06f2, 0x06f3, 0x06f4, 0x06f5, 0x06f6, 0x06f7, /* 0x0590-0x0597 */
114 0x06f8, 0x06f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x0598-0x059f */
115 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x066a, 0x0670, 0x0679, /* 0x05a0-0x05a7 */
116
117 0x067e, 0x0686, 0x0688, 0x0691, 0x060c, 0x0000, 0x06d4, 0x0000, /* 0x05ac-0x05af */
118 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, /* 0x05b0-0x05b7 */
119 0x0668, 0x0669, 0x0000, 0x061b, 0x0000, 0x0000, 0x0000, 0x061f, /* 0x05b8-0x05bf */
120 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, /* 0x05c0-0x05c7 */
121 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, /* 0x05c8-0x05cf */
122 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, /* 0x05d0-0x05d7 */
123 0x0638, 0x0639, 0x063a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x05d8-0x05df */
124 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, /* 0x05e0-0x05e7 */
125 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, /* 0x05e8-0x05ef */
126 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0698, 0x06a4, /* 0x05f0-0x05f7 */
127 0x06a9, 0x06af, 0x06ba, 0x06be, 0x06cc, 0x06d2, 0x06c1 /* 0x05f8-0x05fe */
128 };
129
130 static unsigned short keysym_to_unicode_680_6ff[] = {
131 0x0492, 0x0496, 0x049a, 0x049c, 0x04a2, 0x04ae, 0x04b0, 0x04b2, /* 0x0680-0x0687 */
132 0x04b6, 0x04b8, 0x04ba, 0x0000, 0x04d8, 0x04e2, 0x04e8, 0x04ee, /* 0x0688-0x068f */
133 0x0493, 0x0497, 0x049b, 0x049d, 0x04a3, 0x04af, 0x04b1, 0x04b3, /* 0x0690-0x0697 */
134 0x04b7, 0x04b9, 0x04bb, 0x0000, 0x04d9, 0x04e3, 0x04e9, 0x04ef, /* 0x0698-0x069f */
135 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, /* 0x06a0-0x06a7 */
136 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0491, 0x045e, 0x045f, /* 0x06a8-0x06af */
137 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, /* 0x06b0-0x06b7 */
138 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0490, 0x040e, 0x040f, /* 0x06b8-0x06bf */
139 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, /* 0x06c0-0x06c7 */
140 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, /* 0x06c8-0x06cf */
141 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, /* 0x06d0-0x06d7 */
142 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a, /* 0x06d8-0x06df */
143 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, /* 0x06e0-0x06e7 */
144 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, /* 0x06e8-0x06ef */
145 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, /* 0x06f0-0x06f7 */
146 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a /* 0x06f8-0x06ff */
147 };
148
149 static unsigned short const keysym_to_unicode_7a1_7f9[] = {
150 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, /* 0x07a0-0x07a7 */
151 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, /* 0x07a8-0x07af */
152 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, /* 0x07b0-0x07b7 */
153 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07b8-0x07bf */
154 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, /* 0x07c0-0x07c7 */
155 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, /* 0x07c8-0x07cf */
156 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7, /* 0x07d0-0x07d7 */
157 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07d8-0x07df */
158 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, /* 0x07e0-0x07e7 */
159 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, /* 0x07e8-0x07ef */
160 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, /* 0x07f0-0x07f7 */
161 0x03c8, 0x03c9 /* 0x07f8-0x07ff */
162 };
163
164 static unsigned short const keysym_to_unicode_8a4_8fe[] = {
165 0x2320, 0x2321, 0x0000, 0x231c, /* 0x08a0-0x08a7 */
166 0x231d, 0x231e, 0x231f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08a8-0x08af */
167 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08b0-0x08b7 */
168 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222b, /* 0x08b8-0x08bf */
169 0x2234, 0x0000, 0x221e, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000, /* 0x08c0-0x08c7 */
170 0x2245, 0x2246, 0x0000, 0x0000, 0x0000, 0x0000, 0x22a2, 0x0000, /* 0x08c8-0x08cf */
171 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221a, 0x0000, /* 0x08d0-0x08d7 */
172 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, /* 0x08d8-0x08df */
173 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08e0-0x08e7 */
174 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08e8-0x08ef */
175 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, /* 0x08f0-0x08f7 */
176 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193 /* 0x08f8-0x08ff */
177 };
178
179 static unsigned short const keysym_to_unicode_9df_9f8[] = {
180 0x2422, /* 0x09d8-0x09df */
181 0x2666, 0x25a6, 0x2409, 0x240c, 0x240d, 0x240a, 0x0000, 0x0000, /* 0x09e0-0x09e7 */
182 0x240a, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x2500, /* 0x09e8-0x09ef */
183 0x0000, 0x0000, 0x0000, 0x0000, 0x251c, 0x2524, 0x2534, 0x252c, /* 0x09f0-0x09f7 */
184 0x2502 /* 0x09f8-0x09ff */
185 };
186
187 static unsigned short const keysym_to_unicode_aa1_afe[] = {
188 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, /* 0x0aa0-0x0aa7 */
189 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, /* 0x0aa8-0x0aaf */
190 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, /* 0x0ab0-0x0ab7 */
191 0x2105, 0x0000, 0x0000, 0x2012, 0x2039, 0x2024, 0x203a, 0x0000, /* 0x0ab8-0x0abf */
192 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000, /* 0x0ac0-0x0ac7 */
193 0x0000, 0x2122, 0x2120, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25ad, /* 0x0ac8-0x0acf */
194 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033, /* 0x0ad0-0x0ad7 */
195 0x0000, 0x271d, 0x0000, 0x220e, 0x25c2, 0x2023, 0x25cf, 0x25ac, /* 0x0ad8-0x0adf */
196 0x25e6, 0x25ab, 0x25ae, 0x25b5, 0x25bf, 0x2606, 0x2022, 0x25aa, /* 0x0ae0-0x0ae7 */
197 0x25b4, 0x25be, 0x261a, 0x261b, 0x2663, 0x2666, 0x2665, 0x0000, /* 0x0ae8-0x0aef */
198 0x2720, 0x2020, 0x2021, 0x2713, 0x2612, 0x266f, 0x266d, 0x2642, /* 0x0af0-0x0af7 */
199 0x2640, 0x2121, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e /* 0x0af8-0x0aff */
200 };
201
202 /* none of the APL keysyms match the Unicode characters */
203
204 static unsigned short const keysym_to_unicode_cdf_cfa[] = {
205 0x2017, /* 0x0cd8-0x0cdf */
206 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, /* 0x0ce0-0x0ce7 */
207 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, /* 0x0ce8-0x0cef */
208 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, /* 0x0cf0-0x0cf7 */
209 0x05e8, 0x05e9, 0x05ea /* 0x0cf8-0x0cff */
210 };
211
212 static unsigned short const keysym_to_unicode_da1_df9[] = {
213 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, /* 0x0da0-0x0da7 */
214 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, /* 0x0da8-0x0daf */
215 0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, /* 0x0db0-0x0db7 */
216 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, /* 0x0db8-0x0dbf */
217 0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, /* 0x0dc0-0x0dc7 */
218 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, /* 0x0dc8-0x0dcf */
219 0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37, /* 0x0dd0-0x0dd7 */
220 0x0e38, 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0e3e, 0x0e3f, /* 0x0dd8-0x0ddf */
221 0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, /* 0x0de0-0x0de7 */
222 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0000, 0x0000, /* 0x0de8-0x0def */
223 0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, /* 0x0df0-0x0df7 */
224 0x0e58, 0x0e59 /* 0x0df8-0x0dff */
225 };
226
227 static unsigned short const keysym_to_unicode_ea0_eff[] = {
228 0x0000, 0x1101, 0x1101, 0x11aa, 0x1102, 0x11ac, 0x11ad, 0x1103, /* 0x0ea0-0x0ea7 */
229 0x1104, 0x1105, 0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4, 0x11b5, /* 0x0ea8-0x0eaf */
230 0x11b6, 0x1106, 0x1107, 0x1108, 0x11b9, 0x1109, 0x110a, 0x110b, /* 0x0eb0-0x0eb7 */
231 0x110c, 0x110d, 0x110e, 0x110f, 0x1110, 0x1111, 0x1112, 0x1161, /* 0x0eb8-0x0ebf */
232 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, /* 0x0ec0-0x0ec7 */
233 0x116a, 0x116b, 0x116c, 0x116d, 0x116e, 0x116f, 0x1170, 0x1171, /* 0x0ec8-0x0ecf */
234 0x1172, 0x1173, 0x1174, 0x1175, 0x11a8, 0x11a9, 0x11aa, 0x11ab, /* 0x0ed0-0x0ed7 */
235 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3, /* 0x0ed8-0x0edf */
236 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, /* 0x0ee0-0x0ee7 */
237 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x0000, /* 0x0ee8-0x0eef */
238 0x0000, 0x0000, 0x1140, 0x0000, 0x0000, 0x1159, 0x119e, 0x0000, /* 0x0ef0-0x0ef7 */
239 0x11eb, 0x0000, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9, /* 0x0ef8-0x0eff */
240 };
241
242 static unsigned short keysym_to_unicode_12a1_12fe[] = {
243 0x1e02, 0x1e03, 0x0000, 0x0000, 0x0000, 0x1e0a, 0x0000, /* 0x12a0-0x12a7 */
244 0x1e80, 0x0000, 0x1e82, 0x1e0b, 0x1ef2, 0x0000, 0x0000, 0x0000, /* 0x12a8-0x12af */
245 0x1e1e, 0x1e1f, 0x0000, 0x0000, 0x1e40, 0x1e41, 0x0000, 0x1e56, /* 0x12b0-0x12b7 */
246 0x1e81, 0x1e57, 0x1e83, 0x1e60, 0x1ef3, 0x1e84, 0x1e85, 0x1e61, /* 0x12b8-0x12bf */
247 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c0-0x12c7 */
248 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c8-0x12cf */
249 0x0174, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6a, /* 0x12d0-0x12d7 */
250 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0176, 0x0000, /* 0x12d8-0x12df */
251 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e0-0x12e7 */
252 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e8-0x12ef */
253 0x0175, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6b, /* 0x12f0-0x12f7 */
254 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0177 /* 0x12f0-0x12ff */
255 };
256
257 static unsigned short const keysym_to_unicode_13bc_13be[] = {
258 0x0152, 0x0153, 0x0178 /* 0x13b8-0x13bf */
259 };
260
261 static unsigned short keysym_to_unicode_14a1_14ff[] = {
262 0x2741, 0x00a7, 0x0589, 0x0029, 0x0028, 0x00bb, 0x00ab, /* 0x14a0-0x14a7 */
263 0x2014, 0x002e, 0x055d, 0x002c, 0x2013, 0x058a, 0x2026, 0x055c, /* 0x14a8-0x14af */
264 0x055b, 0x055e, 0x0531, 0x0561, 0x0532, 0x0562, 0x0533, 0x0563, /* 0x14b0-0x14b7 */
265 0x0534, 0x0564, 0x0535, 0x0565, 0x0536, 0x0566, 0x0537, 0x0567, /* 0x14b8-0x14bf */
266 0x0538, 0x0568, 0x0539, 0x0569, 0x053a, 0x056a, 0x053b, 0x056b, /* 0x14c0-0x14c7 */
267 0x053c, 0x056c, 0x053d, 0x056d, 0x053e, 0x056e, 0x053f, 0x056f, /* 0x14c8-0x14cf */
268 0x0540, 0x0570, 0x0541, 0x0571, 0x0542, 0x0572, 0x0543, 0x0573, /* 0x14d0-0x14d7 */
269 0x0544, 0x0574, 0x0545, 0x0575, 0x0546, 0x0576, 0x0547, 0x0577, /* 0x14d8-0x14df */
270 0x0548, 0x0578, 0x0549, 0x0579, 0x054a, 0x057a, 0x054b, 0x057b, /* 0x14e0-0x14e7 */
271 0x054c, 0x057c, 0x054d, 0x057d, 0x054e, 0x057e, 0x054f, 0x057f, /* 0x14e8-0x14ef */
272 0x0550, 0x0580, 0x0551, 0x0581, 0x0552, 0x0582, 0x0553, 0x0583, /* 0x14f0-0x14f7 */
273 0x0554, 0x0584, 0x0555, 0x0585, 0x0556, 0x0586, 0x2019, 0x0027, /* 0x14f8-0x14ff */
274 };
275
276 static unsigned short keysym_to_unicode_15d0_15f6[] = {
277 0x10d0, 0x10d1, 0x10d2, 0x10d3, 0x10d4, 0x10d5, 0x10d6, 0x10d7, /* 0x15d0-0x15d7 */
278 0x10d8, 0x10d9, 0x10da, 0x10db, 0x10dc, 0x10dd, 0x10de, 0x10df, /* 0x15d8-0x15df */
279 0x10e0, 0x10e1, 0x10e2, 0x10e3, 0x10e4, 0x10e5, 0x10e6, 0x10e7, /* 0x15e0-0x15e7 */
280 0x10e8, 0x10e9, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x10ee, 0x10ef, /* 0x15e8-0x15ef */
281 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6 /* 0x15f0-0x15f7 */
282 };
283
284 static unsigned short keysym_to_unicode_16a0_16f6[] = {
285 0x0000, 0x0000, 0xf0a2, 0x1e8a, 0x0000, 0xf0a5, 0x012c, 0xf0a7, /* 0x16a0-0x16a7 */
286 0xf0a8, 0x01b5, 0x01e6, 0x0000, 0x0000, 0x0000, 0x0000, 0x019f, /* 0x16a8-0x16af */
287 0x0000, 0x0000, 0xf0b2, 0x1e8b, 0x01d1, 0xf0b5, 0x012d, 0xf0b7, /* 0x16b0-0x16b7 */
288 0xf0b8, 0x01b6, 0x01e7, 0x0000, 0x0000, 0x01d2, 0x0000, 0x0275, /* 0x16b8-0x16bf */
289 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x018f, 0x0000, /* 0x16c0-0x16c7 */
290 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16c8-0x16cf */
291 0x0000, 0x1e36, 0xf0d2, 0xf0d3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d0-0x16d7 */
292 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d8-0x16df */
293 0x0000, 0x1e37, 0xf0e2, 0xf0e3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e0-0x16e7 */
294 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e8-0x16ef */
295 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0259 /* 0x16f0-0x16f6 */
296 };
297
298 static unsigned short const keysym_to_unicode_1e9f_1eff[] = {
299 0x0303,
300 0x1ea0, 0x1ea1, 0x1ea2, 0x1ea3, 0x1ea4, 0x1ea5, 0x1ea6, 0x1ea7, /* 0x1ea0-0x1ea7 */
301 0x1ea8, 0x1ea9, 0x1eaa, 0x1eab, 0x1eac, 0x1ead, 0x1eae, 0x1eaf, /* 0x1ea8-0x1eaf */
302 0x1eb0, 0x1eb1, 0x1eb2, 0x1eb3, 0x1eb4, 0x1eb5, 0x1eb6, 0x1eb7, /* 0x1eb0-0x1eb7 */
303 0x1eb8, 0x1eb9, 0x1eba, 0x1ebb, 0x1ebc, 0x1ebd, 0x1ebe, 0x1ebf, /* 0x1eb8-0x1ebf */
304 0x1ec0, 0x1ec1, 0x1ec2, 0x1ec3, 0x1ec4, 0x1ec5, 0x1ec6, 0x1ec7, /* 0x1ec0-0x1ec7 */
305 0x1ec8, 0x1ec9, 0x1eca, 0x1ecb, 0x1ecc, 0x1ecd, 0x1ece, 0x1ecf, /* 0x1ec8-0x1ecf */
306 0x1ed0, 0x1ed1, 0x1ed2, 0x1ed3, 0x1ed4, 0x1ed5, 0x1ed6, 0x1ed7, /* 0x1ed0-0x1ed7 */
307 0x1ed8, 0x1ed9, 0x1eda, 0x1edb, 0x1edc, 0x1edd, 0x1ede, 0x1edf, /* 0x1ed8-0x1edf */
308 0x1ee0, 0x1ee1, 0x1ee2, 0x1ee3, 0x1ee4, 0x1ee5, 0x1ee6, 0x1ee7, /* 0x1ee0-0x1ee7 */
309 0x1ee8, 0x1ee9, 0x1eea, 0x1eeb, 0x1eec, 0x1eed, 0x1eee, 0x1eef, /* 0x1ee8-0x1eef */
310 0x1ef0, 0x1ef1, 0x0300, 0x0301, 0x1ef4, 0x1ef5, 0x1ef6, 0x1ef7, /* 0x1ef0-0x1ef7 */
311 0x1ef8, 0x1ef9, 0x01a0, 0x01a1, 0x01af, 0x01b0, 0x0309, 0x0323 /* 0x1ef8-0x1eff */
312 };
313
314 static unsigned short const keysym_to_unicode_20a0_20ac[] = {
315 0x20a0, 0x20a1, 0x20a2, 0x20a3, 0x20a4, 0x20a5, 0x20a6, 0x20a7, /* 0x20a0-0x20a7 */
316 0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac /* 0x20a8-0x20af */
317 };
318
319 static unsigned short const keysym_to_unicode_ff00_ff1f[] = {
320 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xff00-0xff07 */
321 0x0008, 0x0009, 0x000a, 0x0000, 0x0000, 0x000d, 0x0000, 0x0000, /* 0xff08-0xff0f */
322 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xff10-0xff17 */
323 0x0000, 0x0000, 0x0000, 0x001b, 0x0000, 0x0000, 0x0000, 0x0000 /* 0xff18-0xff1f */
324 };
325
326 static unsigned short const keysym_to_unicode_ff80_ffbb[] = {
327 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xff80-0xff87 */
328 0x0000, 0x0009, 0x0000, 0x0000, 0x0000, 0x000D, 0x0000, 0x0000, /* 0xff88-0xff8f */
329 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xff90-0xff97 */
330 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xff98-0xff9f */
331 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xffa0-0xffa7 */
332 0x0000, 0x0000, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, /* 0xffa8-0xffaf */
333 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, /* 0xffb0-0xffb7 */
334 0x0038, 0x0033, 0x0000, 0x003d /* 0xffb8-0xffbb */
335 };
336
337 static unsigned int
KeySymToUcs4(KeySym keysym)338 KeySymToUcs4(KeySym keysym)
339 {
340 /* 'Unicode keysym' */
341 if ((keysym & 0xff000000) == 0x01000000)
342 return (keysym & 0x00ffffff);
343
344 if (keysym > 0 && keysym < 0x100)
345 return keysym;
346 else if (keysym > 0x1a0 && keysym < 0x200)
347 return keysym_to_unicode_1a1_1ff[keysym - 0x1a1];
348 else if (keysym > 0x2a0 && keysym < 0x2ff)
349 return keysym_to_unicode_2a1_2fe[keysym - 0x2a1];
350 else if (keysym > 0x3a1 && keysym < 0x3ff)
351 return keysym_to_unicode_3a2_3fe[keysym - 0x3a2];
352 else if (keysym > 0x4a0 && keysym < 0x4e0)
353 return keysym_to_unicode_4a1_4df[keysym - 0x4a1];
354 else if (keysym > 0x589 && keysym < 0x5ff)
355 return keysym_to_unicode_590_5fe[keysym - 0x590];
356 else if (keysym > 0x67f && keysym < 0x700)
357 return keysym_to_unicode_680_6ff[keysym - 0x680];
358 else if (keysym > 0x7a0 && keysym < 0x7fa)
359 return keysym_to_unicode_7a1_7f9[keysym - 0x7a1];
360 else if (keysym > 0x8a3 && keysym < 0x8ff)
361 return keysym_to_unicode_8a4_8fe[keysym - 0x8a4];
362 else if (keysym > 0x9de && keysym < 0x9f9)
363 return keysym_to_unicode_9df_9f8[keysym - 0x9df];
364 else if (keysym > 0xaa0 && keysym < 0xaff)
365 return keysym_to_unicode_aa1_afe[keysym - 0xaa1];
366 else if (keysym > 0xcde && keysym < 0xcfb)
367 return keysym_to_unicode_cdf_cfa[keysym - 0xcdf];
368 else if (keysym > 0xda0 && keysym < 0xdfa)
369 return keysym_to_unicode_da1_df9[keysym - 0xda1];
370 else if (keysym > 0xe9f && keysym < 0xf00)
371 return keysym_to_unicode_ea0_eff[keysym - 0xea0];
372 else if (keysym > 0x12a0 && keysym < 0x12ff)
373 return keysym_to_unicode_12a1_12fe[keysym - 0x12a1];
374 else if (keysym > 0x13bb && keysym < 0x13bf)
375 return keysym_to_unicode_13bc_13be[keysym - 0x13bc];
376 else if (keysym > 0x14a0 && keysym < 0x1500)
377 return keysym_to_unicode_14a1_14ff[keysym - 0x14a1];
378 else if (keysym > 0x15cf && keysym < 0x15f7)
379 return keysym_to_unicode_15d0_15f6[keysym - 0x15d0];
380 else if (keysym > 0x169f && keysym < 0x16f7)
381 return keysym_to_unicode_16a0_16f6[keysym - 0x16a0];
382 else if (keysym > 0x1e9e && keysym < 0x1f00)
383 return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f];
384 else if (keysym > 0x209f && keysym < 0x20ad)
385 return keysym_to_unicode_20a0_20ac[keysym - 0x20a0];
386 /* added by dk */
387 else if (keysym > 0xfeff && keysym < 0xff20)
388 return keysym_to_unicode_ff00_ff1f[keysym - 0xff00];
389 else if (keysym > 0xff80 && keysym < 0xffbc)
390 return keysym_to_unicode_ff80_ffbb[keysym - 0xff80];
391 else
392 return 0;
393 }
394 /* end unicode map */
395
396 #define UNICODE_HEX_CTRL 0x0001
397 #define UNICODE_HEX_SHIFT 0x0002
398 #define UNICODE_HEX_U 0x0004
399 #define UNICODE_HEX_ENTER 0x0008
400 #define UNICODE_HEX_KEYMASK 0x000F
401 #define UNICODE_HEX_PRESS 0x0010
402 #define UNICODE_HEX_RELEASE 0x0020
403 #define UNICODE_HEX_PRESSMASK 0x0030
404 #define UNICODE_HEX_METHOD_WANTED 0x0100
405 #define UNICODE_HEX_ENTER_WANTED 0x0200
406 #define UNICODE_HEX_RELEASE_WANTED 0x0400
407 #define UNICODE_HEX_WANT_MASK 0x0700
408
409 static void
feed_unicode_character(Handle self,PEvent ev)410 feed_unicode_character(Handle self, PEvent ev)
411 {
412 char *x;
413 int r;
414
415 r = strtol( guts.unicode_hex_input_buffer, &x, 16);
416 guts.unicode_hex_input_flags = 0;
417 *guts.unicode_hex_input_buffer = 0;
418
419 if (*x) return;
420 if ( r > 0x10ffff ) return;
421
422 ev-> cmd = cmKeyDown;
423 ev-> key.mod = kmUnicode;
424 ev-> key.key = kbNoKey;
425 ev-> key.code = r;
426 }
427
428 static void
handle_key_event(Handle self,XKeyEvent * ev,Event * e,KeySym * sym,Bool release)429 handle_key_event( Handle self, XKeyEvent *ev, Event *e, KeySym * sym, Bool release)
430 {
431 /* if e-> cmd is unset on exit, the event will not be passed to the system-independent part */
432 char str_buf[ 256];
433 KeySym keysym, keysym2;
434 U32 keycode;
435 int str_len;
436
437 str_len = XLookupString( ev, str_buf, 256, &keysym, NULL);
438 *sym = keysym;
439 Edebug( "event: keysym: %08lx/%08lx 0: %08lx, 1: %08lx, 2: %08lx, 3: %08lx\n", keysym,
440 KeySymToUcs4( keysym),
441 XLookupKeysym(ev,0),
442 XLookupKeysym(ev,1),
443 XLookupKeysym(ev,2),
444 XLookupKeysym(ev,3)
445 );
446
447 switch (keysym) {
448 /* virtual keys-modifiers */
449 case XK_Shift_L: keycode = kbShiftL; break;
450 case XK_Shift_R: keycode = kbShiftR; break;
451 case XK_Control_L: keycode = kbCtrlL; break;
452 case XK_Control_R: keycode = kbCtrlR; break;
453 case XK_Alt_L: keycode = kbAltL; break;
454 case XK_Alt_R: keycode = kbAltR; break;
455 case XK_Meta_L: keycode = kbMetaL; break;
456 case XK_Meta_R: keycode = kbMetaR; break;
457 case XK_Super_L: keycode = kbSuperL; break;
458 case XK_Super_R: keycode = kbSuperR; break;
459 case XK_Hyper_L: keycode = kbHyperL; break;
460 case XK_Hyper_R: keycode = kbHyperR; break;
461 case XK_Caps_Lock: keycode = kbCapsLock; break;
462 case XK_Num_Lock: keycode = kbNumLock; break;
463 case XK_Scroll_Lock: keycode = kbScrollLock; break;
464 case XK_Shift_Lock: keycode = kbShiftLock; break;
465 /* virtual keys with charcode */
466 case XK_BackSpace: keycode = kbBackspace; break;
467 case XK_Tab: keycode = kbTab; break;
468 case XK_KP_Tab: keycode = kbKPTab; break;
469 case XK_Linefeed: keycode = kbLinefeed; break;
470 case XK_Return: keycode = kbEnter; break;
471 case XK_KP_Enter: keycode = kbKPEnter; break;
472 case XK_Escape: keycode = kbEscape; break;
473 case XK_KP_Space: keycode = kbKPSpace; break;
474 case XK_KP_Equal: keycode = kbKPEqual; break;
475 case XK_KP_Multiply: keycode = kbKPMultiply; break;
476 case XK_KP_Add: keycode = kbKPAdd; break;
477 case XK_KP_Separator: keycode = kbKPSeparator;break;
478 case XK_KP_Subtract: keycode = kbKPSubtract; break;
479 case XK_KP_Decimal: keycode = kbKPDecimal; break;
480 case XK_KP_Divide: keycode = kbKPDivide; break;
481 case XK_KP_0: keycode = kbKP0; break;
482 case XK_KP_1: keycode = kbKP1; break;
483 case XK_KP_2: keycode = kbKP2; break;
484 case XK_KP_3: keycode = kbKP3; break;
485 case XK_KP_4: keycode = kbKP4; break;
486 case XK_KP_5: keycode = kbKP5; break;
487 case XK_KP_6: keycode = kbKP6; break;
488 case XK_KP_7: keycode = kbKP7; break;
489 case XK_KP_8: keycode = kbKP8; break;
490 case XK_KP_9: keycode = kbKP9; break;
491 /* Other virtual keys */
492 case XK_Clear: keycode = kbClear; break;
493 case XK_Pause: keycode = kbPause; break;
494 case XK_Sys_Req: keycode = kbSysReq; break;
495 case XK_Delete: keycode = kbDelete; break;
496 case XK_KP_Delete: keycode = kbKPDelete; break;
497 case XK_Home: keycode = kbHome; break;
498 case XK_KP_Home: keycode = kbKPHome; break;
499 case XK_Left: keycode = kbLeft; break;
500 case XK_KP_Left: keycode = kbKPLeft; break;
501 case XK_Up: keycode = kbUp; break;
502 case XK_KP_Up: keycode = kbKPUp; break;
503 case XK_Right: keycode = kbRight; break;
504 case XK_KP_Right: keycode = kbKPRight; break;
505 case XK_Down: keycode = kbDown; break;
506 case XK_KP_Down: keycode = kbKPDown; break;
507 case XK_Prior: keycode = kbPrior; break;
508 case XK_KP_Prior: keycode = kbKPPrior; break;
509 case XK_Next: keycode = kbNext; break;
510 case XK_KP_Next: keycode = kbKPNext; break;
511 case XK_End: keycode = kbEnd; break;
512 case XK_KP_End: keycode = kbKPEnd; break;
513 case XK_Begin: keycode = kbBegin; break;
514 case XK_KP_Begin: keycode = kbKPBegin; break;
515 case XK_Select: keycode = kbSelect; break;
516 case XK_Print: keycode = kbPrint; break;
517 case XK_Execute: keycode = kbExecute; break;
518 case XK_Insert: keycode = kbInsert; break;
519 case XK_KP_Insert: keycode = kbKPInsert; break;
520 case XK_Undo: keycode = kbUndo; break;
521 case XK_Redo: keycode = kbRedo; break;
522 case XK_Menu: keycode = kbMenu; break;
523 case XK_Find: keycode = kbFind; break;
524 case XK_Cancel: keycode = kbCancel; break;
525 case XK_Help: keycode = kbHelp; break;
526 case XK_Break: keycode = kbBreak; break;
527 case XK_ISO_Left_Tab: keycode = kbBackTab; break;
528 /* Virtual function keys */
529 case XK_F1: keycode = kbF1; break;
530 case XK_KP_F1: keycode = kbKPF1; break;
531 case XK_F2: keycode = kbF2; break;
532 case XK_KP_F2: keycode = kbKPF2; break;
533 case XK_F3: keycode = kbF3; break;
534 case XK_KP_F3: keycode = kbKPF3; break;
535 case XK_F4: keycode = kbF4; break;
536 case XK_KP_F4: keycode = kbKPF4; break;
537 case XK_F5: keycode = kbF5; break;
538 case XK_F6: keycode = kbF6; break;
539 case XK_F7: keycode = kbF7; break;
540 case XK_F8: keycode = kbF8; break;
541 case XK_F9: keycode = kbF9; break;
542 case XK_F10: keycode = kbF10; break;
543 case XK_F11: keycode = kbF11; break;
544 case XK_F12: keycode = kbF12; break;
545 case XK_F13: keycode = kbF13; break;
546 case XK_F14: keycode = kbF14; break;
547 case XK_F15: keycode = kbF15; break;
548 case XK_F16: keycode = kbF16; break;
549 case XK_F17: keycode = kbF17; break;
550 case XK_F18: keycode = kbF18; break;
551 case XK_F19: keycode = kbF19; break;
552 case XK_F20: keycode = kbF20; break;
553 case XK_F21: keycode = kbF21; break;
554 case XK_F22: keycode = kbF22; break;
555 case XK_F23: keycode = kbF23; break;
556 case XK_F24: keycode = kbF24; break;
557 case XK_F25: keycode = kbF25; break;
558 case XK_F26: keycode = kbF26; break;
559 case XK_F27: keycode = kbF27; break;
560 case XK_F28: keycode = kbF28; break;
561 case XK_F29: keycode = kbF29; break;
562 case XK_F30: keycode = kbF30; break;
563 case XK_space: keycode = kbSpace; break;
564 default: keycode = kbNoKey;
565 }
566 if (( keycode == kbTab || keycode == kbKPTab) && ( ev-> state & ShiftMask))
567 keycode = kbBackTab;
568 if ( keycode == kbNoKey) {
569 if ( keysym <= 0x0000007f && !isalpha(keysym & 0x000000ff))
570 keycode = keysym & 0x000000ff;
571 else if (
572 ( ev-> state & ControlMask) && keysym > 0x0000007f
573 && (keysym2 = XLookupKeysym( ev, 0)) <= 0x0000007f
574 && isalpha(keysym2 & 0x0000007f)
575 )
576 keycode = toupper(keysym2 & 0x0000007f) - '@';
577 else if ( str_len == 1)
578 keycode = (uint8_t)*str_buf;
579 else if ( keysym < 0xFD00)
580 keycode = keysym & 0x000000ff;
581 else
582 return; /* don't generate an event */
583 }
584 if (( keycode & kbCodeCharMask) == kbCodeCharMask)
585 keycode |= (keycode >> 8) & 0xFF;
586 e-> cmd = release ? cmKeyUp : cmKeyDown;
587 e-> key. key = keycode & kbCodeMask;
588 if ( !e-> key. key) e-> key. key = kbNoKey;
589 e-> key. mod = keycode & kbModMask;
590 e-> key. repeat = 1;
591 /* ShiftMask LockMask ControlMask Mod1Mask Mod2Mask Mod3Mask Mod4Mask Mod5Mask */
592 if ( ev-> state & ShiftMask) e-> key. mod |= kmShift;
593 if ( ev-> state & ControlMask) e-> key. mod |= kmCtrl;
594 if ( ev-> state & Mod1Mask) e-> key. mod |= kmAlt;
595 if ( PApplication(application)-> wantUnicodeInput) {
596 e-> key. mod |= kmUnicode;
597 e-> key. code = KeySymToUcs4( keysym);
598 if (( ev-> state & ControlMask) && isalpha( e-> key. code))
599 e-> key. code = toupper( e-> key. code) - '@';
600 } else {
601 e-> key. code = keycode & kbCharMask;
602 }
603
604 /* unicode hex treatment */
605 switch(e->key.key) {
606 case kbShiftL:
607 case kbShiftR:
608 case kbCtrlL:
609 case kbCtrlR:
610 if (( e->key.mod & kmAlt) == 0) {
611 int flag = ( e->key.key == kbShiftL || e->key.key == kbShiftR) ?
612 UNICODE_HEX_SHIFT : UNICODE_HEX_CTRL;
613 if ( e-> key.cmd == cmKeyDown ) {
614 if (( guts.unicode_hex_input_flags & UNICODE_HEX_WANT_MASK) == UNICODE_HEX_ENTER_WANTED)
615 goto _default;
616 guts.unicode_hex_input_flags |= flag;
617 } else if ( guts.unicode_hex_input_flags ) {
618 guts.unicode_hex_input_flags &= ~flag;
619 switch ( guts.unicode_hex_input_flags) {
620 case UNICODE_HEX_RELEASE_WANTED:
621 feed_unicode_character(self, e);
622 break;
623 case UNICODE_HEX_METHOD_WANTED:
624 guts.unicode_hex_input_flags = UNICODE_HEX_ENTER_WANTED;
625 break;
626 }
627 }
628 break;
629 }
630 goto _default;
631
632 case kbNoKey: if (guts.unicode_hex_input_flags) {
633 int code = XLookupKeysym( ev, 0);
634 switch ( code ) {
635 case 'u':
636 case 'U':
637 if ((guts.unicode_hex_input_flags & UNICODE_HEX_WANT_MASK) == 0) {
638 int keys = (guts.unicode_hex_input_flags & UNICODE_HEX_KEYMASK);
639 if ( e-> key.cmd == cmKeyDown ) {
640 if (keys != (UNICODE_HEX_CTRL|UNICODE_HEX_SHIFT))
641 goto _default;
642 guts.unicode_hex_input_flags |= UNICODE_HEX_U;
643 } else {
644 if (keys != (UNICODE_HEX_CTRL|UNICODE_HEX_SHIFT|UNICODE_HEX_U))
645 goto _default;
646 guts.unicode_hex_input_flags &= ~UNICODE_HEX_U;
647 guts.unicode_hex_input_flags |= UNICODE_HEX_METHOD_WANTED;
648 }
649 break;
650 }
651 goto _default;
652 case '0': case '1': case '2': case '3':
653 case '4': case '5': case '6': case '7':
654 case '8': case '9': case 'a': case 'A':
655 case 'b': case 'B': case 'c': case 'C':
656 case 'd': case 'D': case 'e': case 'E':
657 case 'f': case 'F':
658 if ((guts.unicode_hex_input_flags & UNICODE_HEX_WANT_MASK) != 0) {
659 int len;
660 if ( e-> key.cmd != cmKeyDown ) break;
661 if ((guts.unicode_hex_input_flags & UNICODE_HEX_WANT_MASK) == UNICODE_HEX_METHOD_WANTED) {
662 guts.unicode_hex_input_flags &= ~UNICODE_HEX_WANT_MASK;
663 guts.unicode_hex_input_flags |= UNICODE_HEX_RELEASE_WANTED;
664 }
665 len = strlen(guts.unicode_hex_input_buffer);
666 if ( len >= MAX_UNICODE_HEX_LENGTH )
667 goto _default;
668 guts.unicode_hex_input_buffer[len++] = tolower(code);
669 guts.unicode_hex_input_buffer[len++] = 0;
670 break;
671 }
672 goto _default;
673 default:
674 goto _default;
675 }
676 break;
677 }
678 case kbEnter:
679 if ((guts.unicode_hex_input_flags & UNICODE_HEX_WANT_MASK) == UNICODE_HEX_ENTER_WANTED) {
680 if ( e-> key.cmd != cmKeyUp ) break;
681 feed_unicode_character(self, e);
682 }
683
684 _default:
685 default:
686 guts.unicode_hex_input_flags = 0;
687 }
688
689 if ( guts.unicode_hex_input_flags & UNICODE_HEX_WANT_MASK )
690 e-> cmd = 0;
691 /* printf("%x %s\n", guts.unicode_hex_input_flags, guts.unicode_hex_input_buffer); */
692 }
693
694 static Bool
input_disabled(PDrawableSysData XX,Bool ignore_horizon)695 input_disabled( PDrawableSysData XX, Bool ignore_horizon)
696 {
697 Handle horizon = application;
698
699 if ( guts. message_boxes) return true;
700 if ( guts. modal_count > 0 && !ignore_horizon) {
701 horizon = CApplication(application)-> map_focus( application, XX-> self);
702 if ( XX-> self == horizon) return !XF_ENABLED(XX);
703 }
704 while (XX->self && XX-> self != horizon && XX-> self != application) {
705 if (!XF_ENABLED(XX)) return true;
706 XX = X(PWidget(XX->self)->owner);
707 }
708 return XX->self && XX-> self != horizon;
709 }
710
711 Bool
prima_no_input(PDrawableSysData XX,Bool ignore_horizon,Bool beep)712 prima_no_input( PDrawableSysData XX, Bool ignore_horizon, Bool beep)
713 {
714 if ( input_disabled(XX, ignore_horizon)) {
715 if ( beep) {
716 apc_beep( mbWarning);
717 }
718 return true;
719 }
720 return false;
721 }
722
723 static void
syntetic_mouse_move(void)724 syntetic_mouse_move( void)
725 {
726 XMotionEvent e, last;
727 e. root = guts. root;
728 last. window = e. window = None;
729 while ( 1) {
730 Bool ret;
731 last = e;
732 ret = XQueryPointer( DISP, e.root, &e. root, &e. window, &e.x_root,
733 &e.y_root, &e.x, &e.y, &e. state);
734 XCHECKPOINT;
735 if ( !ret || e. window == None) {
736 e. window = last. window;
737 break;
738 }
739 e. root = e. window;
740 }
741 if ( prima_xw2h( e. window)) {
742 e. type = MotionNotify;
743 e. send_event = true;
744 e. display = DISP;
745 e. subwindow = e. window;
746 e. root = guts. root;
747 e. time = guts. last_time;
748 e. same_screen = true;
749 e. is_hint = false;
750 XSendEvent( DISP, e. window, false, 0, ( XEvent*) &e);
751 }
752 }
753
754 typedef struct _WMSyncData
755 {
756 Point origin;
757 Point size;
758 XWindow above;
759 Bool mapped;
760 Bool allow_cmSize;
761 } WMSyncData;
762
763 static void
wm_sync_data_from_event(Handle self,WMSyncData * wmsd,XConfigureEvent * cev,Bool mapped)764 wm_sync_data_from_event( Handle self, WMSyncData * wmsd, XConfigureEvent * cev, Bool mapped)
765 {
766 wmsd-> above = cev-> above;
767 wmsd-> size. x = cev-> width;
768 wmsd-> size. y = cev-> height;
769
770 if ( X(self)-> real_parent) { /* trust no one */
771 XWindow dummy;
772 XTranslateCoordinates( DISP, X_WINDOW, guts. root,
773 0, 0, &cev-> x, &cev-> y, &dummy);
774 }
775 wmsd-> origin. x = cev-> x;
776 wmsd-> origin. y = X(X(self)-> owner)-> size. y - wmsd-> size. y - cev-> y;
777 wmsd-> mapped = mapped;
778 }
779
780 static void
open_wm_sync_data(Handle self,WMSyncData * wmsd)781 open_wm_sync_data( Handle self, WMSyncData * wmsd)
782 {
783 DEFXX;
784 wmsd-> size. x = XX-> size. x;
785 wmsd-> size. y = XX-> size. y + XX-> menuHeight;
786 wmsd-> origin = PWidget( self)-> pos;
787 wmsd-> above = XX-> above;
788 wmsd-> mapped = XX-> flags. mapped ? true : false;
789 wmsd-> allow_cmSize = false;
790 }
791
792 static Bool
process_wm_sync_data(Handle self,WMSyncData * wmsd)793 process_wm_sync_data( Handle self, WMSyncData * wmsd)
794 {
795 DEFXX;
796 Event e;
797 Bool size_changed = false;
798 Point old_size = XX-> size, old_pos = XX-> origin;
799
800 if ( wmsd-> origin. x != PWidget(self)-> pos. x || wmsd-> origin. y != PWidget(self)-> pos. y) {
801 Edebug("event: GOT move to %d %d / %d %d\n", wmsd-> origin.x, wmsd-> origin.y, PWidget(self)->pos. x, PWidget(self)->pos. y);
802 bzero( &e, sizeof( Event));
803 e. cmd = cmMove;
804 e. gen. P = XX-> origin = wmsd-> origin;
805 e. gen. source = self;
806 SELF_MESSAGE(e);
807 if ( PObject( self)-> stage == csDead) return false;
808 }
809
810 if ( wmsd-> allow_cmSize &&
811 ( wmsd-> size. x != XX-> size. x || wmsd-> size. y != XX-> size. y + XX-> menuHeight)) {
812 XX-> size. x = wmsd-> size. x;
813 XX-> size. y = wmsd-> size. y - XX-> menuHeight;
814 PWidget( self)-> virtualSize = XX-> size;
815 Edebug("event: got size to %d %d\n", XX-> size.x, XX-> size.y);
816 prima_send_cmSize( self, old_size);
817 if ( PObject( self)-> stage == csDead) return false;
818 size_changed = true;
819 }
820
821 if ( wmsd-> above != XX-> above) {
822 XX-> above = wmsd-> above;
823 bzero( &e, sizeof( Event));
824 e. cmd = cmZOrderChanged;
825 SELF_MESSAGE(e);
826 if ( PObject( self)-> stage == csDead) return false;
827 }
828
829 if ( size_changed && XX-> flags. want_visible && !guts. net_wm_maximization) {
830 int qx = guts. displaySize.x * 4 / 5, qy = guts. displaySize.y * 4 / 5;
831 bzero( &e, sizeof( Event));
832 if ( !XX-> flags. zoomed) {
833 if ( XX-> size. x > qx && XX-> size. y > qy) {
834 e. cmd = cmWindowState;
835 e. gen. i = wsMaximized;
836 XX-> zoomRect.left = old_pos.x;
837 XX-> zoomRect.bottom = old_pos.y;
838 XX-> zoomRect.right = old_size.x;
839 XX-> zoomRect.top = old_size.y;
840 XX-> flags. zoomed = 1;
841 }
842 } else {
843 if ( old_size.x > XX-> size.x && old_size.y > XX-> size.y) {
844 e. cmd = cmWindowState;
845 e. gen. i = wsNormal;
846 XX-> flags. zoomed = 0;
847 } else {
848 XX-> zoomRect.left = XX-> origin.x;
849 XX-> zoomRect.bottom = XX-> origin.y;
850 XX-> zoomRect.right = XX-> size.x;
851 XX-> zoomRect.top = XX-> size.y;
852 }
853 }
854 if ( e. cmd) SELF_MESSAGE(e);
855 if ( PObject( self)-> stage == csDead) return false;
856 }
857
858 if ( !XX-> flags. mapped && wmsd-> mapped) {
859 Event f;
860 bzero( &e, sizeof( Event));
861 bzero( &f, sizeof( Event));
862 if ( XX-> type. window && XX-> flags. iconic) {
863 f. cmd = cmWindowState;
864 f. gen. i = XX-> flags. zoomed ? wsMaximized : wsNormal;
865 f. gen. source = self;
866 XX-> flags. iconic = 0;
867 }
868 if ( XX-> flags. withdrawn)
869 XX-> flags. withdrawn = 0;
870 XX-> flags. mapped = 1;
871 e. cmd = cmShow;
872 SELF_MESSAGE(e);
873 if ( PObject( self)-> stage == csDead) return false;
874 if ( f. cmd) {
875 SELF_MESSAGE(f);
876 if ( PObject( self)-> stage == csDead) return false;
877 }
878 } else if ( XX-> flags. mapped && !wmsd-> mapped) {
879 Event f;
880 bzero( &e, sizeof( Event));
881 bzero( &f, sizeof( Event));
882 if ( !XX-> flags. iconic && XX-> type. window) {
883 f. cmd = cmWindowState;
884 f. gen. i = wsMinimized;
885 f. gen. source = self;
886 XX-> flags. iconic = 1;
887 }
888 e. cmd = cmHide;
889 XX-> flags. mapped = 0;
890 SELF_MESSAGE(e);
891 if ( PObject( self)-> stage == csDead) return false;
892 if ( f. cmd) {
893 SELF_MESSAGE(f);
894 if ( PObject( self)-> stage == csDead) return false;
895 }
896 }
897 return true;
898 }
899
900 static Bool
wm_event(Handle self,XEvent * xev,PEvent ev)901 wm_event( Handle self, XEvent *xev, PEvent ev)
902 {
903
904 switch ( xev-> xany. type) {
905 case ClientMessage:
906 if ( xev-> xclient. message_type == WM_PROTOCOLS) {
907 if ((Atom) xev-> xclient. data. l[0] == WM_DELETE_WINDOW) {
908 if ( guts. message_boxes) return false;
909 if ( self != CApplication(application)-> map_focus( application, self))
910 return false;
911 ev-> cmd = cmClose;
912 return true;
913 } else if ((Atom) xev-> xclient. data. l[0] == WM_TAKE_FOCUS) {
914 Handle selectee;
915 if ( guts. message_boxes) {
916 struct MsgDlg * md = guts. message_boxes;
917 while ( md) {
918 if ( md-> w) XMapRaised( DISP, md-> w);
919 md = md-> next;
920 }
921 return false;
922 }
923
924 selectee = CApplication(application)-> map_focus( application, self);
925
926 /* under modal window? */
927
928 if ( selectee && selectee != self)
929 XMapRaised( DISP, PWidget(selectee)-> handle);
930
931 if ( !guts. currentMenu) {
932 if ( selectee) {
933 int rev;
934 XWindow focus = None;
935 Handle selectee2 = Widget_get_selectee( selectee);
936 if ( selectee2) {
937 XGetInputFocus( DISP, &focus, &rev);
938 /* protection against openbox who fires WM_TAKE_FOCUS no matter what */
939 if ( selectee2 && focus != None && focus == PWidget(selectee2)-> handle)
940 return false;
941 }
942 }
943 guts. currentFocusTime = xev-> xclient. data. l[1];
944 /* Refuse to take focus unless there are no modal windows above */
945 if ( !selectee || selectee == self)
946 XSetInputFocus( DISP, X_WINDOW, RevertToParent, xev-> xclient. data. l[1]);
947 if ( selectee)
948 Widget_selected( selectee, true, true);
949 guts. currentFocusTime = CurrentTime;
950 }
951 return false;
952 }
953 }
954 break;
955 case PropertyNotify:
956 if ( xev-> xproperty. atom == NET_WM_STATE && xev-> xproperty. state == PropertyNewValue) {
957 DEFXX;
958 ev-> cmd = cmWindowState;
959 ev-> gen. source = self;
960 if ( prima_wm_net_state_read_maximization( xev-> xproperty. window, NET_WM_STATE)) {
961 if ( !XX-> flags. zoomed) {
962 ev-> gen. i = wsMaximized;
963 XX-> flags. zoomed = 1;
964 } else
965 ev-> cmd = 0;
966 } else {
967 if ( XX-> flags. zoomed) {
968 ev-> gen. i = wsNormal;
969 XX-> flags. zoomed = 0;
970 } else
971 ev-> cmd = 0;
972 }
973 }
974 break;
975 }
976
977 return false;
978 }
979
980 static int
compress_configure_events(XEvent * ev)981 compress_configure_events( XEvent *ev)
982 /*
983 This reads as many ConfigureNotify events so these do not
984 trash us down. This can happen when the WM allows dynamic
985 top-level windows resizing, and large amount of ConfigureNotify
986 events are sent as the user resizes the window.
987
988 Xlib has many functions to peek into event queue, but all
989 either block or XFlush() implicitly, which isn't a good
990 idea - so the code uses XNextEvent/XPutBackEvent calls.
991 */
992 {
993 Handle self;
994 XEvent * set, *x;
995 XWindow win = ev-> xconfigure. window;
996 int i, skipped = 0, read_events = 0,
997 queued_events = XEventsQueued( DISP, QueuedAlready);
998
999 if (
1000 ( queued_events <= 0) ||
1001 !( set = malloc( sizeof( XEvent) * queued_events))
1002 ) return 0;
1003
1004 for ( i = 0, x = set; i < queued_events; i++, x++) {
1005 XNextEvent( DISP, x);
1006 read_events++;
1007
1008 switch ( x-> type) {
1009 case KeyPress: case KeyRelease:
1010 case ButtonPress: case ButtonRelease:
1011 case MotionNotify: case DestroyNotify:
1012 case ReparentNotify: case PropertyNotify:
1013 case FocusIn: case FocusOut:
1014 case EnterNotify: case LeaveNotify:
1015 goto STOP;
1016 case MapNotify:
1017 case UnmapNotify:
1018 self = prima_xw2h( x-> xconfigure. window);
1019 /* stop only after top-level events */
1020 if ( self && XT_IS_WINDOW(X(self)) && x-> xconfigure. window == X_WINDOW)
1021 goto STOP;
1022 break;
1023 case ClientMessage:
1024 if ( x-> xclient. message_type == WM_PROTOCOLS &&
1025 (Atom) x-> xclient. data. l[0] == WM_DELETE_WINDOW)
1026 goto STOP;
1027 break;
1028 case ConfigureNotify:
1029 /* check if it's Widget event, which is anyway not passed to perl */
1030 self = prima_xw2h( x-> xconfigure. window);
1031 if ( self && XT_IS_WINDOW(X(self)) && x-> xconfigure. window == X_WINDOW) {
1032 /* other top-level's configure? */
1033 if ( x-> xconfigure. window != win) goto STOP;
1034 /* or, discard the previous ConfigureNotify */
1035 ev-> type = 0;
1036 ev = x;
1037 skipped++;
1038 }
1039 break;
1040 }
1041 }
1042 STOP:;
1043
1044 for ( i = read_events - 1, x = set + read_events - 1; i >= 0; i--, x--)
1045 if ( x-> type != 0)
1046 XPutBackEvent( DISP, x);
1047 free( set);
1048 return skipped;
1049 }
1050
1051 static char * xevdefs[] = { "0", "1"
1052 ,"KeyPress" ,"KeyRelease" ,"ButtonPress" ,"ButtonRelease" ,"MotionNotify" ,"EnterNotify"
1053 ,"LeaveNotify" ,"FocusIn" ,"FocusOut" ,"KeymapNotify" ,"Expose" ,"GraphicsExpose"
1054 ,"NoExpose" ,"VisibilityNotify" ,"CreateNotify" ,"DestroyNotify" ,"UnmapNotify"
1055 ,"MapNotify" ,"MapRequest" ,"ReparentNotify" ,"ConfigureNotify" ,"ConfigureRequest"
1056 ,"GravityNotify" ,"ResizeRequest" ,"CirculateNotify" ,"CirculateRequest" ,"PropertyNotify"
1057 ,"SelectionClear" ,"SelectionRequest" ,"SelectionNotify" ,"ColormapNotify" ,"ClientMessage"
1058 ,"MappingNotify"};
1059
1060 void
prima_handle_event(XEvent * ev,XEvent * next_event)1061 prima_handle_event( XEvent *ev, XEvent *next_event)
1062 {
1063 XWindow win;
1064 Handle self;
1065 Bool was_sent;
1066 Event e, secondary;
1067 PDrawableSysData selfxx;
1068 XButtonEvent *bev;
1069 KeySym keysym = 0;
1070 int cmd;
1071
1072 XCHECKPOINT;
1073 if ( ev-> type == guts. shared_image_completion_event) {
1074 prima_ximage_event( ev);
1075 return;
1076 }
1077
1078 if ( guts. message_boxes) {
1079 struct MsgDlg * md = guts. message_boxes;
1080 XWindow win = ev-> xany. window;
1081 while ( md) {
1082 if ( md-> w == win) {
1083 prima_msgdlg_event( ev, md);
1084 return;
1085 }
1086 md = md-> next;
1087 }
1088 }
1089
1090 if ( appDead)
1091 return;
1092
1093 bzero( &e, sizeof( e));
1094 bzero( &secondary, sizeof( secondary));
1095
1096 /* Get a window, including special cases */
1097 switch ( ev-> type) {
1098 case ConfigureNotify:
1099 case -ConfigureNotify:
1100 win = ev-> xconfigure. window;
1101 break;
1102 case ReparentNotify:
1103 win = ev-> xreparent. window;
1104 break;
1105 case MapNotify:
1106 win = ev-> xmap. window;
1107 break;
1108 case UnmapNotify:
1109 win = ev-> xunmap. window;
1110 break;
1111 case DestroyNotify:
1112 if ( guts. clipboard_xfers &&
1113 hash_fetch( guts. clipboard_xfers, &ev-> xdestroywindow. window, sizeof( XWindow))) {
1114 prima_handle_selection_event( ev, ev-> xproperty. window, NULL_HANDLE);
1115 return;
1116 }
1117 goto DEFAULT;
1118 case PropertyNotify:
1119 guts. last_time = ev-> xproperty. time;
1120 if ( guts. clipboard_xfers) {
1121 Handle value;
1122 ClipboardXferKey key;
1123 CLIPBOARD_XFER_KEY( key, ev-> xproperty. window, ev-> xproperty. atom);
1124 value = ( Handle) hash_fetch( guts. clipboard_xfers, key, sizeof( key));
1125 if ( value) {
1126 prima_handle_selection_event( ev, ev-> xproperty. window, value);
1127 return;
1128 }
1129 }
1130 goto DEFAULT;
1131 DEFAULT:
1132 default:
1133 win = ev-> xany. window;
1134 }
1135
1136 /* possibly skip this event */
1137 if ( next_event) {
1138 if (next_event-> type == ev-> type
1139 && ev-> type == MotionNotify
1140 && win == next_event-> xany. window) {
1141 guts. skipped_events++;
1142 return;
1143 } else if ( ev-> type == KeyRelease
1144 && next_event-> type == KeyPress
1145 && ev-> xkey. time == next_event-> xkey. time
1146 && ev-> xkey. display == next_event-> xkey. display
1147 && ev-> xkey. window == next_event-> xkey. window
1148 && ev-> xkey. root == next_event-> xkey. root
1149 && ev-> xkey. subwindow == next_event-> xkey. subwindow
1150 && ev-> xkey. x == next_event-> xkey. x
1151 && ev-> xkey. y == next_event-> xkey. y
1152 && ev-> xkey. state == next_event-> xkey. state
1153 && ev-> xkey. keycode == next_event-> xkey. keycode) {
1154 guts. skipped_events++;
1155 return;
1156 }
1157 }
1158
1159 if ( win == guts. root && guts. grab_redirect)
1160 win = guts. grab_redirect;
1161
1162 self = prima_xw2h( win);
1163 if ( ev-> type > 0)
1164 Edebug("event: %d:%s of %s\n", ev-> type,
1165 ((ev-> type >= LASTEvent) ? "?" : xevdefs[ev-> type]),
1166 self ? PWidget(self)-> name : "(NULL)");
1167
1168 if (!self)
1169 return;
1170 if ( XT_IS_MENU(X(self))) {
1171 prima_handle_menu_event( ev, win, self);
1172 return;
1173 }
1174 e. gen. source = self;
1175 secondary. gen. source = self;
1176 XX = X(self);
1177
1178 was_sent = ev-> xany. send_event;
1179
1180 switch ( ev-> type) {
1181 case KeyPress:
1182 if (guts.xdnds_widget) {
1183 char str_buf[ 256];
1184 KeySym keysym = 0;
1185 XLookupString( &ev-> xkey, str_buf, 256, &keysym, NULL);
1186 if ( keysym == XK_Escape ) {
1187 guts. xdnds_escape_key = true;
1188 return;
1189 }
1190 }
1191 case KeyRelease: {
1192 guts. last_time = ev-> xkey. time;
1193 if ( !ev-> xkey. send_event && self != guts. focused && guts. focused) {
1194 /* bypass pointer-driven input */
1195 Handle newself = self;
1196 while ( PComponent(newself)-> owner && newself != guts. focused)
1197 newself = PComponent(newself)-> owner;
1198 if ( newself == guts. focused) XX = X(self = newself);
1199 }
1200 if (prima_no_input(XX, false, ev-> type == KeyPress)) return;
1201 handle_key_event( self, &ev-> xkey, &e, &keysym, ev-> type == KeyRelease);
1202 break;
1203 }
1204 case ButtonPress: {
1205 guts. last_time = ev-> xbutton. time;
1206 if ( guts. currentMenu) prima_end_menu();
1207 if (prima_no_input(XX, false, true)) return;
1208 if ( guts. grab_widget != NULL_HANDLE && self != guts. grab_widget) {
1209 XWindow rx;
1210 XTranslateCoordinates( DISP, XX-> client, PWidget(guts. grab_widget)-> handle,
1211 ev-> xbutton.x, ev-> xbutton.y,
1212 &ev-> xbutton.x, &ev-> xbutton.y, &rx);
1213 self = guts. grab_widget;
1214 XX = X(self);
1215 }
1216 bev = &ev-> xbutton;
1217 e. cmd = cmMouseDown;
1218 ButtonEvent:
1219 bev-> x -= XX-> origin. x - XX-> ackOrigin. x;
1220 bev-> y += XX-> origin. y - XX-> ackOrigin. y;
1221 if ( ev-> xany. window == guts. root && guts. grab_redirect) {
1222 bev-> x -= guts. grab_translate_mouse. x;
1223 bev-> y -= guts. grab_translate_mouse. y;
1224 }
1225 switch (bev-> button) {
1226 case Button1:
1227 e. pos. button = mb1;
1228 break;
1229 case Button2:
1230 e. pos. button = mb2;
1231 break;
1232 case Button3:
1233 e. pos. button = mb3;
1234 break;
1235 case Button4:
1236 e. pos. button = mb4;
1237 break;
1238 case Button5:
1239 e. pos. button = mb5;
1240 break;
1241 case Button6:
1242 e. pos. button = mb6;
1243 break;
1244 case Button7:
1245 e. pos. button = mb7;
1246 break;
1247 case Button8:
1248 e. pos. button = mb8;
1249 break;
1250 case Button9:
1251 e. pos. button = mb9;
1252 break;
1253 case Button10:
1254 e. pos. button = mb10;
1255 break;
1256 case Button11:
1257 e. pos. button = mb11;
1258 break;
1259 case Button12:
1260 e. pos. button = mb12;
1261 break;
1262 case Button13:
1263 e. pos. button = mb13;
1264 break;
1265 case Button14:
1266 e. pos. button = mb14;
1267 break;
1268 case Button15:
1269 e. pos. button = mb15;
1270 break;
1271 case Button16:
1272 e. pos. button = mb16;
1273 break;
1274 default:
1275 return;
1276 }
1277 e. pos. where. x = bev-> x;
1278 e. pos. where. y = XX-> size. y - bev-> y - 1;
1279 if ( bev-> state & ShiftMask) e.pos.mod |= kmShift;
1280 if ( bev-> state & ControlMask) e.pos.mod |= kmCtrl;
1281 if ( bev-> state & Mod1Mask) e.pos.mod |= kmAlt;
1282 if ( bev-> state & Button1Mask) e.pos.mod |= mb1;
1283 if ( bev-> state & Button2Mask) e.pos.mod |= mb2;
1284 if ( bev-> state & Button3Mask) e.pos.mod |= mb3;
1285 if ( bev-> state & Button4Mask) e.pos.mod |= mb4;
1286 if ( bev-> state & Button5Mask) e.pos.mod |= mb5;
1287 if ( bev-> state & Button6Mask) e.pos.mod |= mb6;
1288 if ( bev-> state & Button7Mask) e.pos.mod |= mb7;
1289
1290 if ( e. cmd == cmMouseDown &&
1291 guts.last_button_event.type == cmMouseUp &&
1292 bev-> window == guts.last_button_event.window &&
1293 bev-> button == guts.last_button_event.button &&
1294 bev-> button != guts. mouse_wheel_up &&
1295 bev-> button != guts. mouse_wheel_down &&
1296 bev-> time - guts.last_button_event.time <= guts.click_time_frame) {
1297 e. cmd = cmMouseClick;
1298 e. pos. dblclk = true;
1299 }
1300
1301 if ( e. cmd == cmMouseDown
1302 && (( guts. mouse_wheel_up != 0 && bev-> button == guts. mouse_wheel_up)
1303 || ( guts. mouse_wheel_down != 0 && bev-> button == guts. mouse_wheel_down)))
1304 {
1305 e. cmd = cmMouseWheel;
1306 e. pos. button = bev-> button == guts. mouse_wheel_up ? WHEEL_DELTA : -WHEEL_DELTA;
1307 } else if ( e.cmd == cmMouseUp &&
1308 guts.last_button_event.type == cmMouseDown &&
1309 bev-> window == guts.last_button_event.window &&
1310 bev-> button == guts.last_button_event.button &&
1311 bev-> time - guts.last_button_event.time <= guts.click_time_frame) {
1312 secondary. cmd = cmMouseClick;
1313 secondary. pos. where. x = e. pos. where. x;
1314 secondary. pos. where. y = e. pos. where. y;
1315 secondary. pos. mod = e. pos. mod;
1316 secondary. pos. button = e. pos. button;
1317 memcpy( &guts.last_click, bev, sizeof(guts.last_click));
1318 if ( e. pos. button == mbRight) {
1319 Event ev;
1320 bzero( &ev, sizeof(ev));
1321 ev. cmd = cmPopup;
1322 ev. gen. B = true;
1323 ev. gen. P. x = e. pos. where. x;
1324 ev. gen. P. y = e. pos. where. y;
1325 apc_message( self, &ev, true);
1326 if ( PObject( self)-> stage == csDead) return;
1327 }
1328 } else if ( e.cmd == cmMouseUp &&
1329 (guts.last_button_event.type == (cmMouseClick | 0x8000)) &&
1330 bev-> window == guts.last_button_event.window &&
1331 bev-> button == guts.last_button_event.button &&
1332 bev-> time - guts.last_button_event.time <= guts.click_time_frame
1333 ) {
1334 e.pos.dblclk = 1;
1335 }
1336 memcpy( &guts.last_button_event, bev, sizeof(*bev));
1337 guts. last_button_event.type = e.cmd;
1338 if (e.pos.dblclk)
1339 guts.last_button_event.type |= 0x8000;
1340
1341 if ( e. cmd == cmMouseDown) {
1342 if ( XX-> flags. first_click) {
1343 if ( ! is_opt( optSelectable)) {
1344 Handle x = self, f = guts. focused ? guts. focused : application;
1345 while ( f && !X(f)-> type. window && ( f != application)) f = (( PWidget) f)-> owner;
1346 while ( !X(x)-> type. window && X(x)-> flags. clip_owner &&
1347 x != application) x = (( PWidget) x)-> owner;
1348 if ( x && x != f && X(x)-> type. window)
1349 XSetInputFocus( DISP, PWidget(x)-> handle, RevertToParent, bev-> time);
1350 }
1351 } else {
1352 Handle x = self, f = guts. focused ? guts. focused : application;
1353 while ( !X(x)-> type. window && ( x != application)) x = (( PWidget) x)-> owner;
1354 while ( !X(f)-> type. window && ( f != application)) f = (( PWidget) f)-> owner;
1355 if ( x != f) {
1356 e. cmd = 0;
1357 if ((( PApplication) application)-> hintUnder == self)
1358 CWidget(self)-> set_hintVisible( self, 0);
1359 if (( PWidget(self)-> options. optSelectable) && ( PWidget(self)-> selectingButtons & e. pos. button))
1360 apc_widget_set_focused( self);
1361 }
1362 }
1363 }
1364 break;
1365 }
1366 case ButtonRelease: {
1367 guts. last_time = ev-> xbutton. time;
1368 if (prima_no_input(XX, false, false)) return;
1369 if ( guts. grab_widget != NULL_HANDLE && self != guts. grab_widget) {
1370 XWindow rx;
1371 XTranslateCoordinates( DISP, XX-> client, PWidget(guts. grab_widget)-> handle,
1372 ev-> xbutton.x, ev-> xbutton.y,
1373 &ev-> xbutton.x, &ev-> xbutton.y, &rx);
1374 self = guts. grab_widget;
1375 XX = X(self);
1376 }
1377 bev = &ev-> xbutton;
1378 e. cmd = cmMouseUp;
1379 goto ButtonEvent;
1380 }
1381 case MotionNotify: {
1382 guts. last_time = ev-> xmotion. time;
1383 if ( guts. grab_widget != NULL_HANDLE && self != guts. grab_widget) {
1384 XWindow rx;
1385 XTranslateCoordinates( DISP, XX-> client, PWidget(guts. grab_widget)-> handle,
1386 ev-> xmotion.x, ev-> xmotion.y,
1387 &ev-> xmotion.x, &ev-> xmotion.y, &rx);
1388 self = guts. grab_widget;
1389 XX = X(self);
1390 }
1391 ev-> xmotion. x -= XX-> origin. x - XX-> ackOrigin. x;
1392 ev-> xmotion. y += XX-> origin. y - XX-> ackOrigin. y;
1393 e. cmd = cmMouseMove;
1394 if ( ev-> xany. window == guts. root && guts. grab_redirect) {
1395 ev-> xmotion. x -= guts. grab_translate_mouse. x;
1396 ev-> xmotion. y -= guts. grab_translate_mouse. y;
1397 }
1398 e. pos. where. x = ev-> xmotion. x;
1399 e. pos. where. y = XX-> size. y - ev-> xmotion. y - 1;
1400 if ( ev-> xmotion. state & ShiftMask) e.pos.mod |= kmShift;
1401 if ( ev-> xmotion. state & ControlMask) e.pos.mod |= kmCtrl;
1402 if ( ev-> xmotion. state & Mod1Mask) e.pos.mod |= kmAlt;
1403 if ( ev-> xmotion. state & Button1Mask) e.pos.mod |= mb1;
1404 if ( ev-> xmotion. state & Button2Mask) e.pos.mod |= mb2;
1405 if ( ev-> xmotion. state & Button3Mask) e.pos.mod |= mb3;
1406 if ( ev-> xmotion. state & Button4Mask) e.pos.mod |= mb4;
1407 if ( ev-> xmotion. state & Button5Mask) e.pos.mod |= mb5;
1408 if ( ev-> xmotion. state & Button6Mask) e.pos.mod |= mb6;
1409 if ( ev-> xmotion. state & Button7Mask) e.pos.mod |= mb7;
1410 break;
1411 }
1412 case EnterNotify: {
1413 if (( guts. pointer_invisible_count == 0) && XX-> flags. pointer_obscured) {
1414 XX-> flags. pointer_obscured = 0;
1415 XDefineCursor( DISP, XX-> udrawable, prima_get_cursor(self));
1416 } else if (( guts. pointer_invisible_count < 0) && !XX-> flags. pointer_obscured) {
1417 XX-> flags. pointer_obscured = 1;
1418 XDefineCursor( DISP, XX-> udrawable, guts. null_pointer);
1419 }
1420 guts. last_time = ev-> xcrossing. time;
1421 e. cmd = cmMouseEnter;
1422 CrossingEvent:
1423 if ( ev-> xcrossing. subwindow != None) return;
1424 e. pos. where. x = ev-> xcrossing. x;
1425 e. pos. where. y = XX-> size. y - ev-> xcrossing. y - 1;
1426 break;
1427 }
1428 case LeaveNotify: {
1429 guts. last_time = ev-> xcrossing. time;
1430 e. cmd = cmMouseLeave;
1431 goto CrossingEvent;
1432 }
1433 case FocusIn: {
1434 Handle frame = self;
1435 switch ( ev-> xfocus. detail) {
1436 case NotifyVirtual:
1437 case NotifyPointer:
1438 case NotifyPointerRoot:
1439 case NotifyDetailNone:
1440 return;
1441 case NotifyNonlinearVirtual:
1442 if (!XT_IS_WINDOW(XX)) return;
1443 break;
1444 }
1445
1446 if ( guts. message_boxes) {
1447 struct MsgDlg * md = guts. message_boxes;
1448 while ( md) {
1449 XSetInputFocus( DISP, md-> w, RevertToNone, CurrentTime);
1450 md = md-> next;
1451 }
1452 return;
1453 }
1454
1455 syntetic_mouse_move(); /* XXX - simulated MouseMove event for compatibility reasons */
1456
1457 if (!XT_IS_WINDOW(XX))
1458 frame = CApplication(application)-> top_frame( application, self);
1459 if ( CApplication(application)-> map_focus( application, frame) != frame) {
1460 CApplication(application)-> popup_modal( application);
1461 break;
1462 }
1463
1464 if ( XT_IS_WINDOW(XX)) {
1465 e. cmd = cmActivate;
1466 SELF_MESSAGE(e);
1467 if (( PObject( self)-> stage == csDead) ||
1468 ( ev-> xfocus. detail == NotifyNonlinearVirtual)) return;
1469 }
1470
1471 if ( guts. focused) prima_no_cursor( guts. focused);
1472 guts. focused = self;
1473 prima_update_cursor( guts. focused);
1474 e. cmd = cmReceiveFocus;
1475
1476 break;
1477 }
1478 case FocusOut: {
1479 switch ( ev-> xfocus. detail) {
1480 case NotifyVirtual:
1481 case NotifyPointer:
1482 case NotifyPointerRoot:
1483 case NotifyDetailNone:
1484 return;
1485 case NotifyNonlinearVirtual:
1486 if (!XT_IS_WINDOW(XX)) return;
1487 break;
1488 }
1489
1490 if ( XT_IS_WINDOW(XX)) {
1491 e. cmd = cmDeactivate;
1492 SELF_MESSAGE(e);
1493 if (( PObject( self)-> stage == csDead) ||
1494 ( ev-> xfocus. detail == NotifyNonlinearVirtual)) return;
1495 }
1496
1497 if ( guts. focused) prima_no_cursor( guts. focused);
1498 if ( self == guts. focused) guts. focused = NULL_HANDLE;
1499 e. cmd = cmReleaseFocus;
1500 break;
1501 }
1502 case KeymapNotify: {
1503 break;
1504 }
1505 case GraphicsExpose:
1506 case Expose: {
1507 XRectangle r;
1508 if ( !was_sent) {
1509 r. x = ev-> xexpose. x;
1510 r. y = ev-> xexpose. y;
1511 r. width = ev-> xexpose. width;
1512 r. height = ev-> xexpose. height;
1513 if ( !XX-> invalid_region)
1514 XX-> invalid_region = XCreateRegion();
1515 XUnionRectWithRegion( &r, XX-> invalid_region, XX-> invalid_region);
1516 }
1517
1518 if ( ev-> xexpose. count == 0 && !XX-> flags. paint_pending) {
1519 TAILQ_INSERT_TAIL( &guts.paintq, XX, paintq_link);
1520 XX-> flags. paint_pending = true;
1521 }
1522
1523 process_transparents(self);
1524 return;
1525 }
1526 case NoExpose: {
1527 break;
1528 }
1529 case VisibilityNotify: {
1530 XX-> flags. exposed = ( ev-> xvisibility. state != VisibilityFullyObscured);
1531 break;
1532 }
1533 case CreateNotify: {
1534 break;
1535 }
1536 case DestroyNotify: {
1537 break;
1538 }
1539 case UnmapNotify: {
1540 if ( XT_IS_WINDOW(XX) && win != XX-> client) {
1541 WMSyncData wmsd;
1542 open_wm_sync_data( self, &wmsd);
1543 wmsd. mapped = false;
1544 process_wm_sync_data( self, &wmsd);
1545 }
1546 if ( !XT_IS_WINDOW(XX) || win != XX-> client) {
1547 XX-> flags. mapped = false;
1548 }
1549 break;
1550 }
1551 case MapNotify: {
1552 if ( XT_IS_WINDOW(XX) && win != XX-> client) {
1553 WMSyncData wmsd;
1554 open_wm_sync_data( self, &wmsd);
1555 wmsd. mapped = true;
1556 process_wm_sync_data( self, &wmsd);
1557 }
1558 if ( !XT_IS_WINDOW(XX) || win != XX-> client) {
1559 XX-> flags. mapped = true;
1560 }
1561 break;
1562 }
1563 case MapRequest: {
1564 break;
1565 }
1566
1567 case ReparentNotify: {
1568 XWindow p = ev-> xreparent. parent;
1569 if ( !XX-> type. window) return;
1570 XX-> real_parent = ( p == guts. root) ? NULL_HANDLE : p;
1571 if ( XX-> real_parent) {
1572 XWindow dummy;
1573 XTranslateCoordinates( DISP, X_WINDOW, XX-> real_parent,
1574 0, 0, &XX-> decorationSize.x, &XX-> decorationSize.y, &dummy);
1575 } else
1576 XX-> decorationSize. x = XX-> decorationSize. y = 0;
1577 }
1578 return;
1579
1580 case -ConfigureNotify:
1581 if ( XT_IS_WINDOW(XX)) {
1582 if ( win != XX-> client) {
1583 int nh;
1584 WMSyncData wmsd;
1585 Bool size_changed =
1586 XX-> ackFrameSize. x != ev-> xconfigure. width ||
1587 XX-> ackFrameSize. y != ev-> xconfigure. height;
1588 wmsd. allow_cmSize = true;
1589 XX-> ackOrigin. x = ev-> xconfigure. x;
1590 XX-> ackOrigin. y = X(X(self)-> owner)-> size. y - ev-> xconfigure. height - ev-> xconfigure. y;
1591 XX-> ackFrameSize. x = ev-> xconfigure. width;
1592 XX-> ackFrameSize. y = ev-> xconfigure. height;
1593 nh = ev-> xconfigure. height - XX-> menuHeight;
1594 if ( nh < 1 ) nh = 1;
1595 XMoveResizeWindow( DISP, XX-> client, 0, XX-> menuHeight, ev-> xconfigure. width, nh);
1596 if ( PWindow( self)-> menu) {
1597 if ( size_changed) {
1598 M(PWindow( self)-> menu)-> paint_pending = true;
1599 XResizeWindow( DISP, PComponent(PWindow( self)-> menu)-> handle,
1600 ev-> xconfigure. width, XX-> menuHeight);
1601 }
1602 M(PWindow( self)-> menu)-> w-> pos. x = ev-> xconfigure. x;
1603 M(PWindow( self)-> menu)-> w-> pos. y = ev-> xconfigure. y;
1604 prima_end_menu();
1605 }
1606 wm_sync_data_from_event( self, &wmsd, &ev-> xconfigure, XX-> flags. mapped);
1607 process_wm_sync_data( self, &wmsd);
1608 } else {
1609 XX-> ackSize. x = ev-> xconfigure. width;
1610 XX-> ackSize. y = ev-> xconfigure. height;
1611 }
1612 } else {
1613 XX-> ackSize. x = ev-> xconfigure. width;
1614 XX-> ackSize. y = ev-> xconfigure. height;
1615 XX-> ackOrigin. x = ev-> xconfigure. x;
1616 XX-> ackOrigin. y = X(X(self)-> owner)-> size. y - ev-> xconfigure. height - ev-> xconfigure. y;
1617 }
1618 return;
1619 case ConfigureNotify:
1620 if ( XT_IS_WINDOW(XX)) {
1621 if ( win != XX-> client) {
1622 int nh;
1623 WMSyncData wmsd;
1624 ConfigureEventPair *n1, *n2;
1625 Bool match = false, size_changed;
1626
1627 if ( compress_configure_events( ev)) return;
1628
1629 size_changed =
1630 XX-> ackFrameSize. x != ev-> xconfigure. width ||
1631 XX-> ackFrameSize. y != ev-> xconfigure. height;
1632 nh = ev-> xconfigure. height - XX-> menuHeight;
1633 if ( nh < 1 ) nh = 1;
1634 XMoveResizeWindow( DISP, XX-> client, 0, XX-> menuHeight, ev-> xconfigure. width, nh);
1635
1636 wmsd. allow_cmSize = true;
1637 wm_sync_data_from_event( self, &wmsd, &ev-> xconfigure, XX-> flags. mapped);
1638 XX-> ackOrigin. x = wmsd. origin. x;
1639 XX-> ackOrigin. y = wmsd. origin. y;
1640 XX-> ackFrameSize. x = ev-> xconfigure. width;
1641 XX-> ackFrameSize. y = ev-> xconfigure. height;
1642
1643 if (( n1 = TAILQ_FIRST( &XX-> configure_pairs))) {
1644 if ( n1-> w == ev-> xconfigure. width &&
1645 n1-> h == ev-> xconfigure. height) {
1646 n1-> match = true;
1647 wmsd. size. x = XX-> size.x;
1648 wmsd. size. y = XX-> size.y + XX-> menuHeight;
1649 match = true;
1650 } else if ( n1-> match && (n2 = TAILQ_NEXT( n1, link)) &&
1651 n2-> w == ev-> xconfigure. width &&
1652 n2-> h == ev-> xconfigure. height) {
1653 n2-> match = true;
1654 wmsd. size. x = XX-> size.x;
1655 wmsd. size. y = XX-> size.y + XX-> menuHeight;
1656 TAILQ_REMOVE( &XX-> configure_pairs, n1, link);
1657 free( n1);
1658 match = true;
1659 }
1660
1661 if ( !match) {
1662 while ( n1 != NULL) {
1663 n2 = TAILQ_NEXT(n1, link);
1664 free( n1);
1665 n1 = n2;
1666 }
1667 TAILQ_INIT( &XX-> configure_pairs);
1668 }
1669 }
1670
1671 Edebug("event: configure: %d --> %d %d\n", ev-> xany.serial, ev-> xconfigure. width, ev-> xconfigure. height);
1672 XX-> flags. configured = 1;
1673 process_wm_sync_data( self, &wmsd);
1674
1675 if ( PWindow( self)-> menu) {
1676 if ( size_changed) {
1677 XEvent e;
1678 Handle menu = PWindow( self)-> menu;
1679 M(PWindow( self)-> menu)-> paint_pending = true;
1680 XResizeWindow( DISP, PComponent(PWindow( self)-> menu)-> handle,
1681 ev-> xconfigure. width, XX-> menuHeight);
1682 e. type = ConfigureNotify;
1683 e. xconfigure. width = ev-> xconfigure. width;
1684 e. xconfigure. height = XX-> menuHeight;
1685 prima_handle_menu_event( &e, PAbstractMenu(menu)-> handle, menu);
1686 }
1687 M(PWindow( self)-> menu)-> w-> pos. x = ev-> xconfigure. x;
1688 M(PWindow( self)-> menu)-> w-> pos. y = ev-> xconfigure. y;
1689 }
1690 prima_end_menu();
1691 } else {
1692 XX-> ackSize. x = ev-> xconfigure. width;
1693 XX-> ackSize. y = ev-> xconfigure. height;
1694 }
1695 } else {
1696 XX-> ackOrigin. x = ev-> xconfigure. x;
1697 XX-> ackOrigin. y = X(X(self)-> owner)-> ackSize. y - ev-> xconfigure. height - ev-> xconfigure. y;
1698 XX-> ackSize. x = ev-> xconfigure. width;
1699 XX-> ackSize. y = ev-> xconfigure. height;
1700 XX-> flags. configured = 1;
1701 }
1702 return;
1703 case ConfigureRequest: {
1704 break;
1705 }
1706 case GravityNotify: {
1707 break;
1708 }
1709 case ResizeRequest: {
1710 break;
1711 }
1712 case CirculateNotify: {
1713 break;
1714 }
1715 case CirculateRequest: {
1716 break;
1717 }
1718 case PropertyNotify: {
1719 wm_event( self, ev, &e);
1720 break;
1721 }
1722 case SelectionClear:
1723 case SelectionRequest: {
1724 prima_handle_selection_event( ev, win, self);
1725 break;
1726 }
1727 case SelectionNotify: {
1728 guts. last_time = ev-> xselection. time;
1729 break;
1730 }
1731 case ColormapNotify: {
1732 break;
1733 }
1734 case ClientMessage: {
1735 if ( ev-> xclient. message_type == CREATE_EVENT) {
1736 e. cmd = cmSetup;
1737 } else {
1738 wm_event( self, ev, &e);
1739 prima_handle_dnd_event( self, ev);
1740 }
1741 break;
1742 }
1743 case MappingNotify: {
1744 XRefreshKeyboardMapping( &ev-> xmapping);
1745 break;
1746 }
1747 }
1748
1749 if ( e. cmd) {
1750 guts. handled_events++;
1751 cmd = e. cmd;
1752 SELF_MESSAGE(e);
1753 if ( PObject( self)-> stage == csDead ) return;
1754 if ( e. cmd) {
1755 switch ( cmd) {
1756 case cmClose:
1757 if ( XX-> type. window && PWindow(self)-> modal)
1758 CWindow(self)-> cancel( self);
1759 else
1760 Object_destroy( self);
1761 break;
1762 case cmKeyDown:
1763 if ( prima_handle_menu_shortcuts( self, ev, keysym) < 0) return;
1764 break;
1765 }
1766 }
1767 if ( secondary. cmd) {
1768 SELF_MESSAGE(secondary);
1769 if ( PObject( self)-> stage == csDead) return;
1770 }
1771 } else {
1772 /* Unhandled event, do nothing */
1773 guts. unhandled_events++;
1774 }
1775 }
1776
1777 #define DEAD_BEEF 0xDEADBEEF
1778
1779 static int
copy_events(Handle self,PList events,WMSyncData * w,int eventType)1780 copy_events( Handle self, PList events, WMSyncData * w, int eventType)
1781 {
1782 int ret = 0;
1783 int queued_events = XEventsQueued( DISP, QueuedAlready);
1784 if ( queued_events <= 0) return 0;
1785 while ( queued_events--) {
1786 XEvent * x = malloc( sizeof( XEvent));
1787 if ( !x) {
1788 list_delete_all( events, true);
1789 plist_destroy( events);
1790 return -1;
1791 }
1792 XNextEvent( DISP, x);
1793
1794 switch ( x-> type) {
1795 case ReparentNotify:
1796 if ( X(self)-> type. window && ( x-> xreparent. window == PWidget(self)-> handle)) {
1797 X(self)-> real_parent = ( x-> xreparent. parent == guts. root) ?
1798 NULL_HANDLE : x-> xreparent. parent;
1799 x-> type = DEAD_BEEF;
1800 if ( X(self)-> real_parent) {
1801 XWindow dummy;
1802 XTranslateCoordinates( DISP, X_WINDOW, X(self)-> real_parent,
1803 0, 0, &X(self)-> decorationSize.x, &X(self)-> decorationSize.y, &dummy);
1804 } else
1805 X(self)-> decorationSize. x = X(self)-> decorationSize. y = 0;
1806 }
1807 break;
1808 }
1809
1810 {
1811 Bool ok = false;
1812 switch ( x-> type) {
1813 case ConfigureNotify:
1814 if ( x-> xconfigure. window == PWidget(self)-> handle) {
1815 wm_sync_data_from_event( self, w, &x-> xconfigure, w-> mapped);
1816 Edebug("event: configure copy %d %d\n", x-> xconfigure. width, x-> xconfigure. height);
1817 ok = true;
1818 }
1819 break;
1820 case UnmapNotify:
1821 if ( x-> xmap. window == PWidget(self)-> handle) {
1822 w-> mapped = false;
1823 ok = true;
1824 }
1825 break;
1826 case MapNotify:
1827 if ( x-> xmap. window == PWidget(self)-> handle) {
1828 w-> mapped = true;
1829 ok = true;
1830 }
1831 break;
1832 }
1833 if ( ok) {
1834 if ( x-> type == eventType) ret++;
1835 x-> type = -x-> type;
1836 }
1837 }
1838 if ( x-> type != DEAD_BEEF)
1839 list_add( events, ( Handle) x);
1840 else
1841 free( x);
1842 }
1843 return ret;
1844 }
1845
1846 void
prima_wm_sync(Handle self,int eventType)1847 prima_wm_sync( Handle self, int eventType)
1848 {
1849 int r;
1850 long diff, delay, evx;
1851 fd_set zero_r, zero_w, read;
1852 struct timeval start_time, timeout;
1853 PList events;
1854 WMSyncData wmsd;
1855
1856 open_wm_sync_data( self, &wmsd);
1857
1858 Edebug("event: enter syncer for %d. current size: %d %d\n", eventType, X(self)-> size.x, X(self)-> size.y);
1859 gettimeofday( &start_time, NULL);
1860
1861 /* browse & copy queued events */
1862 evx = XEventsQueued( DISP, QueuedAlready);
1863 if ( !( events = plist_create( evx + 32, 32)))
1864 return;
1865 r = copy_events( self, events, &wmsd, eventType);
1866 if ( r < 0) return;
1867 Edebug("event: copied %ld events %s\n", evx, r ? "GOT CONF!" : "");
1868
1869 /* measuring round-trip time */
1870 XSync( DISP, false);
1871 gettimeofday( &timeout, NULL);
1872 delay = 2 * (( timeout. tv_sec - start_time. tv_sec) * 1000 +
1873 ( timeout. tv_usec - start_time. tv_usec) / 1000) + guts. wm_event_timeout;
1874 Edebug("event: sync took %ld.%03ld sec\n", timeout. tv_sec - start_time. tv_sec, (timeout. tv_usec - start_time. tv_usec) / 1000);
1875 if ( guts. is_xwayland) delay *= 2; /* because of extra roundtrip between xwayland and wayland */
1876
1877 /* got response already? happens if no wm present or */
1878 /* sometimes if wm is local to server */
1879 evx = XEventsQueued( DISP, QueuedAlready);
1880 r = copy_events( self, events, &wmsd, eventType);
1881 if ( r < 0) return;
1882 Edebug("event: pass 1, copied %ld events %s\n", evx, r ? "GOT CONF!" : "");
1883 if ( delay < 50) delay = 50; /* wait 50 ms just in case */
1884 /* waiting for ConfigureNotify or timeout */
1885 Edebug("event: enter cycle, size: %d %d\n", wmsd.size.x, wmsd.size.y);
1886 start_time = timeout;
1887 while ( 1) {
1888 gettimeofday( &timeout, NULL);
1889 diff = ( timeout. tv_sec - start_time. tv_sec) * 1000 +
1890 ( timeout. tv_usec - start_time. tv_usec) / 1000;
1891 if ( delay <= diff)
1892 break;
1893 timeout. tv_sec = ( delay - diff) / 1000;
1894 timeout. tv_usec = (( delay - diff) % 1000) * 1000;
1895 Edebug("event: want timeout:%g\n", (double)( delay - diff) / 1000);
1896 FD_ZERO( &zero_r);
1897 FD_ZERO( &zero_w);
1898 FD_ZERO( &read);
1899 FD_SET( guts.connection, &read);
1900 r = select( guts.connection+1, &read, &zero_r, &zero_w, &timeout);
1901 if ( r < 0) {
1902 warn("server connection error");
1903 return;
1904 }
1905 if ( r == 0) {
1906 Edebug("event: timeout\n");
1907 break;
1908 }
1909 if (( evx = XEventsQueued( DISP, QueuedAfterFlush)) <= 0) {
1910 /* just like tcl/perl tk do, to avoid an infinite loop */
1911 RETSIGTYPE oldHandler = signal( SIGPIPE, SIG_IGN);
1912 XNoOp( DISP);
1913 XFlush( DISP);
1914 (void) signal( SIGPIPE, oldHandler);
1915 }
1916
1917 /* copying new events */
1918 r = copy_events( self, events, &wmsd, eventType);
1919 if ( r < 0) return;
1920 Edebug("event: copied %ld events %s\n", evx, r ? "GOT CONF!" : "");
1921 if ( r > 0) break; /* has come ConfigureNotify */
1922 }
1923 Edebug("event:exit cycle\n");
1924
1925 /* put events back */
1926 Edebug("event: put back %d events\n", events-> count);
1927 for ( r = events-> count - 1; r >= 0; r--) {
1928 XPutBackEvent( DISP, ( XEvent*) events-> items[ r]);
1929 free(( void*) events-> items[ r]);
1930 }
1931 plist_destroy( events);
1932 evx = XEventsQueued( DISP, QueuedAlready);
1933
1934 Edebug("event: exit syncer, size: %d %d\n", wmsd.size.x, wmsd.size.y);
1935 process_wm_sync_data( self, &wmsd);
1936 X(self)-> flags. configured = 1;
1937 }
1938
1939
1940 static Bool
purge_invalid_watchers(Handle self,void * dummy)1941 purge_invalid_watchers( Handle self, void *dummy)
1942 {
1943 ((PFile)self)->self->is_active(self,true);
1944 return false;
1945 }
1946
1947 static int
perform_pending_paints(void)1948 perform_pending_paints( void)
1949 {
1950 PDrawableSysData selfxx;
1951 int i, events = 0;
1952 List list;
1953
1954 if ( !application ) return 0;
1955
1956 list_create(&list, 256, 1024);
1957 for ( XX = TAILQ_FIRST( &guts.paintq); XX != NULL; ) {
1958 PDrawableSysData next = TAILQ_NEXT( XX, paintq_link);
1959 if ( XX-> flags. paint_pending && (guts. appLock == 0) &&
1960 (PWidget( XX->self)-> stage == csNormal)) {
1961 TAILQ_REMOVE( &guts.paintq, XX, paintq_link);
1962 XX-> flags. paint_pending = false;
1963 list_add( &list, (Handle) XX->self);
1964 list_add( &list, (Handle) XX);
1965 protect_object(XX->self);
1966 }
1967 XX = next;
1968 }
1969
1970 for ( i = 0; i < list.count; i+=2) {
1971 Handle self;
1972
1973 self = list_at(&list, i);
1974 if ( PWidget( self)-> stage != csNormal)
1975 goto NEXT;
1976
1977 selfxx = (PDrawableSysData) list_at(&list, i+1);
1978 if ( XX-> flags. paint_pending) {
1979 TAILQ_REMOVE( &guts.paintq, XX, paintq_link);
1980 XX-> flags. paint_pending = false;
1981 }
1982 prima_simple_message( self, cmPaint, false);
1983 events++;
1984
1985 if ( (PWidget( self)-> stage != csNormal)) goto NEXT;
1986
1987 /* handle the case where this widget is locked */
1988 if (XX->invalid_region) {
1989 XDestroyRegion(XX->invalid_region);
1990 XX->invalid_region = NULL;
1991 }
1992
1993 NEXT:
1994 unprotect_object(self);
1995 }
1996 list_destroy(&list);
1997
1998 return events;
1999 }
2000
2001 static int
send_pending_events(void)2002 send_pending_events( void)
2003 {
2004 PendingEvent *pe, *next;
2005 int stage, events = 0;
2006
2007 if ( !application ) return 0;
2008
2009 for ( pe = TAILQ_FIRST( &guts.peventq); pe != NULL; ) {
2010 next = TAILQ_NEXT( pe, peventq_link);
2011 if (( stage = PComponent( pe->recipient)-> stage) != csConstructing) {
2012 TAILQ_REMOVE( &guts.peventq, pe, peventq_link);
2013 }
2014 if ( stage == csNormal) {
2015 apc_message( pe-> recipient, &pe-> event, false);
2016 events++;
2017 }
2018 if ( stage != csConstructing) {
2019 free( pe);
2020 }
2021 pe = next;
2022 }
2023
2024 return events;
2025 }
2026
2027 static int
send_queued_x_events(int careOfApplication)2028 send_queued_x_events(int careOfApplication)
2029 {
2030 int events = 0, queued_events;
2031 XEvent ev, next_event;
2032
2033 if ( !application && careOfApplication ) return 0;
2034
2035 if (( queued_events = XEventsQueued( DISP, QueuedAlready)) <= 0)
2036 return 0;
2037
2038 XNextEvent( DISP, &ev);
2039 XCHECKPOINT;
2040 queued_events--;
2041 while ( queued_events > 0) {
2042 if (!application && careOfApplication) return false;
2043 XNextEvent( DISP, &next_event);
2044 XCHECKPOINT;
2045 prima_handle_event( &ev, &next_event);
2046 events++;
2047 queued_events = XEventsQueued( DISP, QueuedAlready);
2048 memcpy( &ev, &next_event, sizeof( XEvent));
2049 }
2050 if (!application && careOfApplication) return events;
2051 prima_handle_event( &ev, NULL);
2052 events++;
2053 return events;
2054 }
2055
2056 static int
process_timers(void)2057 process_timers(void)
2058 {
2059 int events = 0;
2060 struct timeval t;
2061 PTimerSysData timer;
2062
2063 gettimeofday( &t, NULL);
2064 while (1) {
2065 if ( !guts. oldest) return 0;
2066
2067 if ( guts. oldest-> when. tv_sec > t. tv_sec || (
2068 guts. oldest-> when. tv_sec == t. tv_sec &&
2069 guts. oldest-> when. tv_usec > t. tv_usec
2070 ))
2071 return 0;
2072
2073 timer = guts. oldest;
2074 apc_timer_start( timer-> who);
2075 if ( timer-> who == CURSOR_TIMER) {
2076 prima_cursor_tick();
2077 } else if ( timer-> who == MENU_TIMER) {
2078 apc_timer_stop( MENU_TIMER);
2079 if ( guts. currentMenu) {
2080 XEvent ev;
2081 ev. type = MenuTimerMessage;
2082 prima_handle_menu_event( &ev, M(guts. currentMenu)-> w-> w, guts. currentMenu);
2083 events++;
2084 }
2085 } else if ( timer-> who == MENU_UNFOCUS_TIMER) {
2086 prima_end_menu();
2087 } else {
2088 prima_simple_message( timer-> who, cmTimer, false);
2089 events++;
2090 }
2091 }
2092 return events;
2093 }
2094
2095 static int
process_file_events(Bool * x_events_pending,struct timeval * t)2096 process_file_events(Bool * x_events_pending, struct timeval * t)
2097 {
2098 int i, r, events = 0, files = 0;
2099 fd_set read_set, write_set, excpt_set;
2100 struct {
2101 Handle file;
2102 Bool r;
2103 Bool w;
2104 Bool e;
2105 } queue[FD_SETSIZE], *cur;
2106
2107 if ( x_events_pending )
2108 *x_events_pending = 0;
2109 if ( !application ) return 0;
2110
2111 read_set = guts.read_set;
2112 write_set = guts.write_set;
2113 excpt_set = guts.excpt_set;
2114 r = select( guts.max_fd+1, &read_set, &write_set, &excpt_set, t);
2115 if ( r == 0 ) return 0;
2116 if ( r < 0 ) {
2117 list_first_that( guts.files, (void*)purge_invalid_watchers, NULL);
2118 return 0;
2119 }
2120
2121 if ( x_events_pending )
2122 *x_events_pending = FD_ISSET( guts.connection, &read_set);
2123
2124 for ( i = 0; i < guts. files->count; i++) {
2125 Bool r = false, w = false, e = false;
2126 PFile f = (PFile)list_at( guts. files, i);
2127 if ( FD_ISSET( f->fd, &read_set) && (f->eventMask & feRead))
2128 r = true;
2129 if ( FD_ISSET( f->fd, &write_set) && (f->eventMask & feWrite))
2130 w = true;
2131 if ( FD_ISSET( f->fd, &excpt_set) && (f->eventMask & feException))
2132 e = true;
2133 if ( r || w || e ) {
2134 if ( files >= FD_SETSIZE - 1 ) break;
2135 cur = queue + files++;
2136 cur-> file = (Handle) f;
2137 cur-> r = r;
2138 cur-> w = w;
2139 cur-> e = e;
2140 protect_object((Handle) f);
2141 }
2142 }
2143
2144 for ( i = 0, cur = queue; i < files; i++, cur++) {
2145 if ( cur-> r ) {
2146 prima_simple_message( cur-> file, cmFileRead, false);
2147 events++;
2148 }
2149 if ( cur-> w ) {
2150 prima_simple_message( cur-> file, cmFileWrite, false);
2151 events++;
2152 }
2153 if ( cur-> e ) {
2154 prima_simple_message( cur-> file, cmFileException, false);
2155 events++;
2156 }
2157 unprotect_object( cur-> file );
2158 }
2159
2160 return events;
2161 }
2162
2163 static void
x_flush(void)2164 x_flush(void)
2165 {
2166 if ( XEventsQueued( DISP, QueuedAfterFlush) <= 0) {
2167 /* just like tcl/perl tk do, to avoid an infinite loop */
2168 RETSIGTYPE oldHandler = signal( SIGPIPE, SIG_IGN);
2169 XNoOp( DISP);
2170 XFlush( DISP);
2171 (void) signal( SIGPIPE, oldHandler);
2172 }
2173 }
2174
2175 static struct timeval *
select_timeout(struct timeval * timeout)2176 select_timeout(struct timeval * timeout)
2177 {
2178 if ( guts. application_stop_signal ) {
2179 timeout-> tv_sec = 0;
2180 timeout-> tv_usec = 0;
2181 return timeout;
2182 }
2183
2184 if ( !guts. oldest) return NULL;
2185
2186 gettimeofday( timeout, NULL);
2187 if ( guts. oldest-> when. tv_sec < timeout-> tv_sec) {
2188 timeout-> tv_sec = 0;
2189 timeout-> tv_usec = 0;
2190 } else {
2191 timeout-> tv_sec = guts. oldest-> when. tv_sec - timeout-> tv_sec;
2192 if ( guts. oldest-> when. tv_usec < timeout-> tv_usec) {
2193 if ( timeout-> tv_sec == 0) {
2194 timeout-> tv_sec = 0;
2195 timeout-> tv_usec = 0;
2196 } else {
2197 timeout-> tv_sec--;
2198 timeout-> tv_usec = 1000000 - (timeout-> tv_usec - guts. oldest-> when. tv_usec);
2199 }
2200 } else {
2201 timeout-> tv_usec = guts. oldest-> when. tv_usec - timeout-> tv_usec;
2202 }
2203 }
2204
2205 return timeout;
2206 }
2207
2208 static int
handle_queued_events(Bool careOfApplication)2209 handle_queued_events( Bool careOfApplication )
2210 {
2211 int events = 0;
2212
2213 events += send_queued_x_events(careOfApplication);
2214 events += perform_pending_paints();
2215 events += send_pending_events();
2216 events += process_timers();
2217
2218 return events;
2219 }
2220
2221 Bool
prima_one_loop_round(int wait,Bool careOfApplication)2222 prima_one_loop_round( int wait, Bool careOfApplication)
2223 {
2224 struct timeval timeout;
2225 Bool x_events_pending;
2226 struct timeval t;
2227
2228 if ( guts. applicationClose) return false;
2229 prima_kill_zombies();
2230
2231 /* handle queued events */
2232 while ( 1 ) {
2233 int events;
2234 events = handle_queued_events(careOfApplication);
2235 t. tv_sec = 0;
2236 t. tv_usec = 0;
2237 events += process_file_events(&x_events_pending, &t);
2238 if ( x_events_pending && ( application || !careOfApplication) ) {
2239 x_flush();
2240 events += handle_queued_events(careOfApplication);
2241 }
2242 if ( wait == WAIT_NEVER || ( events > 0 && wait == WAIT_IF_NONE))
2243 return true;
2244 if ( !application || guts. applicationClose || guts. application_stop_signal)
2245 return false;
2246 if ( events == 0 )
2247 break;
2248 }
2249
2250 /* wait for events */
2251 prima_simple_message( application, cmIdle, false);
2252 process_file_events(&x_events_pending, select_timeout(&timeout));
2253 if ( x_events_pending && ( application || !careOfApplication) )
2254 x_flush();
2255 handle_queued_events(careOfApplication);
2256
2257 return application != NULL_HANDLE;
2258 }
2259
2260 Bool
prima_simple_message(Handle self,int cmd,Bool is_post)2261 prima_simple_message( Handle self, int cmd, Bool is_post)
2262 {
2263 Event e;
2264
2265 bzero( &e, sizeof(e));
2266 e. cmd = cmd;
2267 e. gen. source = self;
2268 return apc_message( self, &e, is_post);
2269 }
2270
2271 Bool
apc_message(Handle self,PEvent e,Bool is_post)2272 apc_message( Handle self, PEvent e, Bool is_post)
2273 {
2274 PendingEvent *pe;
2275
2276 if ( is_post) {
2277 if (!( pe = alloc1(PendingEvent))) return false;
2278 memcpy( &pe->event, e, sizeof(pe->event));
2279 pe-> recipient = self;
2280 TAILQ_INSERT_TAIL( &guts.peventq, pe, peventq_link);
2281 } else {
2282 guts. total_events++;
2283 CComponent(self)->message( self, e);
2284 if ( PObject( self)-> stage == csDead) return false;
2285 }
2286 return true;
2287 }
2288
2289