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