Mercurial > projects > dynamin
annotate dynamin/gui/x_window.d @ 32:b48d3f2f570d
Implement mouseTurned event with X.
author | Jordan Miner <jminer7@gmail.com> |
---|---|
date | Sat, 25 Jul 2009 22:47:05 -0500 |
parents | 0577e8738dc8 |
children | 329ce1001936 |
rev | line source |
---|---|
0 | 1 // Written in the D programming language |
2 // www.digitalmars.com/d/ | |
3 | |
4 /* | |
5 * The contents of this file are subject to the Mozilla Public License Version | |
6 * 1.1 (the "License"); you may not use this file except in compliance with | |
7 * the License. You may obtain a copy of the License at | |
8 * http://www.mozilla.org/MPL/ | |
9 * | |
10 * Software distributed under the License is distributed on an "AS IS" basis, | |
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
12 * for the specific language governing rights and limitations under the | |
13 * License. | |
14 * | |
15 * The Original Code is the Dynamin library. | |
16 * | |
17 * The Initial Developer of the Original Code is Jordan Miner. | |
18 * Portions created by the Initial Developer are Copyright (C) 2007-2009 | |
19 * the Initial Developer. All Rights Reserved. | |
20 * | |
21 * Contributor(s): | |
22 * Jordan Miner <jminer7@gmail.com> | |
23 * | |
24 */ | |
25 | |
26 module dynamin.gui.x_window; | |
27 | |
28 public import dynamin.core.string; | |
29 public import dynamin.core.global; | |
30 public import dynamin.core.math; | |
31 public import dynamin.gui.window; | |
24
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
32 public import dynamin.gui.key; |
0 | 33 public import dynamin.c.xlib; |
34 public import dynamin.c.xlib : XWindow = Window; | |
35 public import dynamin.c.xmu; | |
36 public import dynamin.c.cairo; | |
37 public import dynamin.c.cairo_xlib; | |
38 public import tango.stdc.string; | |
39 public import tango.io.Stdout; | |
40 | |
41 /* | |
42 ** Window property: | |
43 ** _NET_FRAME_EXTENTS(CARDINAL) = 4, 4, 23, 4 | |
44 ** left, right, top and bottom border sizes | |
45 */ | |
46 | |
47 Window[XWindow] windows; | |
48 void setControl(XWindow handle, Window win) { | |
49 if(win is null) | |
50 windows.remove(handle); | |
51 else | |
52 windows[handle] = win; | |
53 } | |
54 | |
55 Window getControl(XWindow handle) { | |
56 auto tmp = handle in windows; | |
57 return tmp is null ? null : *tmp; | |
58 } | |
59 | |
60 /** | |
61 * A simpler method that returns all the data in a property. | |
62 * NOTE: the returned data still has to be freed with XFree() | |
63 */ | |
64 void* getXWindowProperty(XDisplay* d, XWindow w, XAtom prop, int* numRet = null) { | |
65 XAtom actualType; | |
66 int actualFormat; | |
67 uint nitems, bytesAfter; | |
68 void* ptr; | |
69 XGetWindowProperty(d, w, prop, | |
70 0, 0xFFFFFFFF, false, AnyPropertyType, | |
71 &actualType, &actualFormat, &nitems, &bytesAfter, | |
72 &ptr); | |
73 if(numRet) *numRet = nitems; | |
74 return ptr; | |
75 } | |
76 bool isWMPropertySupported(XAtom prop) { | |
77 int count; | |
78 XAtom* atoms = cast(XAtom*)getXWindowProperty(display, | |
79 root, XA._NET_SUPPORTED, &count); | |
80 scope(exit) XFree(atoms); | |
81 for(int i = 0; i < count; ++i) | |
82 if(atoms[i] == prop) | |
83 return true; | |
84 return false; | |
85 } | |
86 bool isTopLevelReparented(XWindow w) { | |
87 XWindow root, parent; | |
88 XWindow* children; | |
89 uint numChildren; | |
90 XQueryTree(display, w, | |
91 &root, &parent, &children, &numChildren); | |
92 return parent != root; | |
93 } | |
94 | |
95 XDisplay* display; | |
96 XWindow root; | |
97 XWindow msgWin; | |
98 abstract class XA { // X atoms | |
99 static: | |
100 XAtom _NET_SUPPORTED, _NET_WM_NAME, _NET_WORKAREA, _NET_FRAME_EXTENTS; | |
101 XAtom _NET_REQUEST_FRAME_EXTENTS; | |
102 XAtom _NET_MOVERESIZE_WINDOW; | |
103 XAtom _NET_WM_WINDOW_TYPE; | |
104 XAtom _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_UTILITY; | |
105 XAtom _NET_WM_WINDOW_TYPE_SPLASH; | |
106 XAtom _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_WINDOW_TYPE_NORMAL; | |
107 XAtom WM_PROTOCOLS, WM_DELETE_WINDOW, _NET_WM_SYNC_REQUEST; | |
108 XAtom UTF8_STRING, ATOM; | |
109 XAtom _MOTIF_WM_HINTS; | |
110 XAtom CLIPBOARD, PRIMARY, TARGETS, CLIPBOARD_MANAGER, SAVE_TARGETS; | |
111 XAtom DYNAMIN_SELECTION; | |
112 } | |
113 static this() { | |
114 display = XOpenDisplay(null); | |
115 if(!display) | |
116 Stdout("XOpenDisplay() failed").newline; | |
117 root = XRootWindow(display, XDefaultScreen(display)); | |
118 | |
119 msgWin = XCreateSimpleWindow(display, root, 0, 0, 1, 1, 0, 0, 0); | |
120 | |
121 XA._NET_SUPPORTED = XInternAtom(display, "_NET_SUPPORTED", false); | |
122 XA._NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", false); | |
123 XA._NET_WORKAREA = XInternAtom(display, "_NET_WORKAREA", false); | |
124 XA._NET_FRAME_EXTENTS = XInternAtom(display, "_NET_FRAME_EXTENTS", false); | |
125 XA._NET_REQUEST_FRAME_EXTENTS = | |
126 XInternAtom(display, "_NET_REQUEST_FRAME_EXTENTS", false); | |
127 XA._NET_MOVERESIZE_WINDOW = | |
128 XInternAtom(display, "_NET_MOVERESIZE_WINDOW", false); | |
129 XA._NET_WM_WINDOW_TYPE = | |
130 XInternAtom(display, "_NET_WM_WINDOW_TYPE", false); | |
131 XA._NET_WM_WINDOW_TYPE_MENU = | |
132 XInternAtom(display, "_NET_WM_WINDOW_TYPE_MENU", false); | |
133 XA._NET_WM_WINDOW_TYPE_UTILITY = | |
134 XInternAtom(display, "_NET_WM_WINDOW_TYPE_UTILITY", false); | |
135 XA._NET_WM_WINDOW_TYPE_SPLASH = | |
136 XInternAtom(display, "_NET_WM_WINDOW_TYPE_SPLASH", false); | |
137 XA._NET_WM_WINDOW_TYPE_DIALOG = | |
138 XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", false); | |
139 XA._NET_WM_WINDOW_TYPE_NORMAL = | |
140 XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", false); | |
141 XA.WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", false); | |
142 XA.WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", false); | |
143 XA._NET_WM_SYNC_REQUEST = | |
144 XInternAtom(display, "_NET_WM_SYNC_REQUEST", false); | |
145 XA.UTF8_STRING = XInternAtom(display, "UTF8_STRING", false); | |
146 XA.ATOM = XInternAtom(display, "ATOM", false); | |
147 XA._MOTIF_WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", false); | |
148 XA.CLIPBOARD = XInternAtom(display, "CLIPBOARD", false); | |
149 XA.PRIMARY = XInternAtom(display, "PRIMARY", false); | |
150 XA.TARGETS = XInternAtom(display, "TARGETS", false); | |
151 XA.CLIPBOARD_MANAGER = XInternAtom(display, "CLIPBOARD_MANAGER", false); | |
152 XA.SAVE_TARGETS = XInternAtom(display, "SAVE_TARGETS", false); | |
153 | |
154 XA.DYNAMIN_SELECTION = XInternAtom(display, "DYNAMIN_SELECTION", false); | |
155 if(!isWMPropertySupported(XA._NET_WM_NAME)) | |
156 Stdout("warning: WM does not support _NET_WM_NAME").newline; | |
157 if(!isWMPropertySupported(XA._NET_WORKAREA)) | |
158 Stdout("warning: WM does not support _NET_WORKAREA").newline; | |
159 if(!isWMPropertySupported(XA._NET_FRAME_EXTENTS)) | |
160 Stdout("warning: WM does not support _NET_FRAME_EXTENTS").newline; | |
161 if(!isWMPropertySupported(XA._NET_WORKAREA)) | |
162 Stdout("warning: WM does not support _NET_WORKAREA").newline; | |
163 } | |
164 | |
165 struct _InvalidRect { | |
166 XWindow window; | |
167 int x, y, width, height; | |
168 _InvalidRect getUnion(_InvalidRect rect) { | |
169 auto x2 = min(x, rect.x); | |
170 auto y2 = min(y, rect.y); | |
171 _InvalidRect rect2; | |
172 rect2.window = window; | |
173 rect2.width = max(x+width, rect.x+rect.width)-x2; | |
174 rect2.height = max(y+height, rect.y+rect.height)-y2; | |
175 rect2.x = x2; | |
176 rect2.y = y2; | |
177 return rect2; | |
178 } | |
179 } | |
180 /+struct InvalidRect { | |
181 XWindow window; | |
182 int x, y, width, height; | |
183 } | |
184 | |
185 static class PaintQueue { | |
186 static: | |
187 //LinkedList!(InvalidRect) rects; | |
188 InvalidRect[] rects; | |
189 static this() { | |
190 //rects = new LinkedList!(InvalidRect)(20); | |
191 rects.length = 20; | |
192 rects.length = 0; | |
193 } | |
194 void add(XWindow win, int x, int y, int width, int height) { | |
195 rects.length = rects.length + 1; | |
196 rects[$-1].window = win; | |
197 rects[$-1].x = x; | |
198 rects[$-1].y = y; | |
199 rects[$-1].width = width; | |
200 rects[$-1].height = height; | |
201 } | |
202 bool shouldMerge(int x1, int y1, int width1, int height1, | |
203 int x2, int y2, int width2, int height2) { | |
204 return x2 <= x1 + width1 && y2 <= y1 + height1 && | |
205 x2 + width2 >= x1 && y2 + height2 >= y1; | |
206 } | |
207 void Union(inout int x, inout int y, inout int width, inout int height, | |
208 int x2, int y2, int width2, int height2) { | |
209 } | |
210 void compress() { | |
211 } | |
212 }+/ | |
213 | |
24
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
214 Key prevKey = Key.None; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
215 |
0 | 216 //{{{ ApplicationBackend |
217 template ApplicationBackend() { | |
218 void backend_run(Window w) { | |
219 bool isWindowVisible() { | |
220 if(w is null) return true; | |
221 return w.visible; | |
222 } | |
223 XEvent ev; | |
224 while(isWindowVisible()) { | |
225 if(XEventsQueued(display, QueuedAlready) == 0) { | |
226 _InvalidRect[] rects = Window.invalidRects; | |
227 Window.invalidRects.length = 0; | |
228 while(rects.length > 0) { | |
229 auto rect = rects[0]; | |
230 // TODO: fix this...right now it gens one Expose with | |
231 // the union of invalid rects | |
232 for(int i = rects.length-1; i >= 0; --i) { | |
233 if(rect.window == rects[i].window) { | |
234 rect = rect.getUnion(rects[i]); | |
235 | |
236 arrayCopy!(_InvalidRect)(rects, i+1, rects, i, rects.length-i-1); | |
237 rects.length = rects.length-1; | |
238 } | |
239 } | |
240 ev.xexpose.type = Expose; | |
241 ev.xexpose.display = display; | |
242 ev.xexpose.window = rect.window; | |
243 ev.xexpose.x = rect.x; | |
244 ev.xexpose.y = rect.y; | |
245 ev.xexpose.width = rect.width; | |
246 ev.xexpose.height = rect.height; | |
247 ev.xexpose.count = -2; // came from here | |
248 XPutBackEvent(display, &ev); | |
249 } | |
250 } | |
251 XNextEvent(display, &ev); | |
252 auto evDisplay = ev.xany.display; | |
253 auto evWindow = ev.xany.window; | |
254 Window c = getControl(evWindow); | |
255 // c will be null for SelectionRequest events | |
256 //if(c is null) | |
257 // continue; | |
258 //{{{ helper functions | |
259 void createMouseEvent(void delegate(MouseEventArgs args) func) { | |
260 MouseButton button; | |
261 auto buttonEv = ev.xbutton; | |
262 switch(buttonEv.button) { | |
263 case 1: button = MouseButton.Left; break; | |
264 case 2: button = MouseButton.Middle; break; | |
265 case 3: button = MouseButton.Right; break; | |
266 default: return; | |
267 } | |
268 scope args = new MouseEventArgs(buttonEv.x+c._borderSize.left, buttonEv.y+c._borderSize.top, button); | |
269 func(args); | |
270 } | |
24
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
271 bool isKeyDown(uint keycode) { |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
272 ubyte[32] keys; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
273 XQueryKeymap(display, keys.ptr); |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
274 return cast(bool)( (keys[keycode / 8] >> (keycode % 8)) & 1 ); |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
275 } |
0 | 276 //}}} |
277 switch(ev.type) { | |
278 case MapNotify: | |
279 c.mapped = true; | |
280 break; | |
281 case UnmapNotify: | |
282 _InvalidRect[] rects = Window.invalidRects; | |
283 for(int i = rects.length-1; i >= 0; --i) { | |
284 if(rects[i].window == evWindow) { | |
285 arrayCopy!(_InvalidRect)( | |
286 rects, i+1, rects, i, rects.length-i-1); | |
287 rects.length = rects.length-1; | |
288 } | |
289 } | |
290 Window.invalidRects = rects; | |
291 c.mapped = false; | |
292 break; | |
293 case DestroyNotify: | |
294 setControl(evWindow, null); | |
295 break; | |
296 case ClientMessage: | |
297 auto clientEv = ev.xclient; | |
298 if(clientEv.message_type != XA.WM_PROTOCOLS) | |
299 break; | |
300 if(clientEv.data.l[0] == XA.WM_DELETE_WINDOW) { | |
301 XDestroyWindow(evDisplay, evWindow); | |
302 return; // TODO: check event, and figure out what to do | |
303 } | |
304 break; | |
305 case KeyPress: | |
24
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
306 auto sym = XLookupKeysym(&ev.xkey, 0); |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
307 if(sym == NoSymbol) |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
308 break; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
309 // Since X gives no way to tell if a KeyPress is generated by |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
310 // auto-repeat, prevKey is used here to tell. |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
311 auto k = KeysymToKey(sym); |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
312 scope args = new KeyEventArgs(k, k == prevKey); |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
313 prevKey = k; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
314 Control focused = c.focusedControl ? c.focusedControl : c; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
315 focused.keyDown(args); |
0 | 316 break; |
317 case KeyRelease: | |
24
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
318 // When X does auto-repeat for a held down key, it sends |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
319 // a KeyPress and KeyRelease every time, even though the key is |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
320 // down constantly. Here we check if the key is down, and if so, |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
321 // not send a keyUp event. |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
322 if(isKeyDown(ev.xkey.keycode)) |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
323 break; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
324 auto sym = XLookupKeysym(&ev.xkey, 0); |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
325 if(sym == NoSymbol) |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
326 break; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
327 auto k = KeysymToKey(sym); |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
328 if(k == prevKey) |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
329 prevKey = Key.None; // can't repeat after released |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
330 scope args = new KeyEventArgs(k, false); |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
331 Control focused = c.focusedControl ? c.focusedControl : c; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
332 focused.keyUp(args); |
0 | 333 break; |
334 case ButtonPress: | |
32
b48d3f2f570d
Implement mouseTurned event with X.
Jordan Miner <jminer7@gmail.com>
parents:
25
diff
changeset
|
335 // 4 = scroll up, 5 = scroll down |
b48d3f2f570d
Implement mouseTurned event with X.
Jordan Miner <jminer7@gmail.com>
parents:
25
diff
changeset
|
336 // 6 = scroll left, 7 = scroll right |
b48d3f2f570d
Implement mouseTurned event with X.
Jordan Miner <jminer7@gmail.com>
parents:
25
diff
changeset
|
337 auto b = ev.xbutton.button; |
b48d3f2f570d
Implement mouseTurned event with X.
Jordan Miner <jminer7@gmail.com>
parents:
25
diff
changeset
|
338 if(b == 4 || b == 5) { |
b48d3f2f570d
Implement mouseTurned event with X.
Jordan Miner <jminer7@gmail.com>
parents:
25
diff
changeset
|
339 scope args = new MouseTurnedEventArgs(b == 4 ? -3:3, false); |
b48d3f2f570d
Implement mouseTurned event with X.
Jordan Miner <jminer7@gmail.com>
parents:
25
diff
changeset
|
340 c.getDescendantAtPoint( |
b48d3f2f570d
Implement mouseTurned event with X.
Jordan Miner <jminer7@gmail.com>
parents:
25
diff
changeset
|
341 ev.xbutton.x+c._borderSize.left, |
b48d3f2f570d
Implement mouseTurned event with X.
Jordan Miner <jminer7@gmail.com>
parents:
25
diff
changeset
|
342 ev.xbutton.y+c._borderSize.top).mouseTurned(args); |
b48d3f2f570d
Implement mouseTurned event with X.
Jordan Miner <jminer7@gmail.com>
parents:
25
diff
changeset
|
343 break; |
b48d3f2f570d
Implement mouseTurned event with X.
Jordan Miner <jminer7@gmail.com>
parents:
25
diff
changeset
|
344 } |
0 | 345 createMouseEvent((MouseEventArgs args) { c.mouseDown(args); }); |
346 break; | |
347 case ButtonRelease: | |
348 createMouseEvent((MouseEventArgs args) { c.mouseUp(args); }); | |
349 break; | |
350 case MotionNotify: | |
351 auto motionEv = ev.xmotion; | |
352 Control captor = getCaptorControl(); | |
353 Point pt = Point(motionEv.x+c.borderSize.left, motionEv.y+c.borderSize.top); | |
354 if(captor) | |
355 pt = c.contentToContent(pt, captor); | |
356 else | |
357 captor = c; | |
358 scope args = new MouseEventArgs(pt.x, pt.y, MouseButton.None); | |
359 if(motionEv.state & | |
360 (Button1Mask | Button2Mask | Button3Mask)) { | |
361 captor.mouseDragged(args); | |
362 } else | |
363 captor.mouseMoved(args); | |
364 break; | |
365 case EnterNotify: | |
25
0577e8738dc8
Handle EnterNotify and LeaveNotify in the X backend,
Jordan Miner <jminer7@gmail.com>
parents:
24
diff
changeset
|
366 auto enterEv = ev.xcrossing; |
0577e8738dc8
Handle EnterNotify and LeaveNotify in the X backend,
Jordan Miner <jminer7@gmail.com>
parents:
24
diff
changeset
|
367 scope args = new MouseEventArgs(enterEv.x+c.borderSize.left, |
0577e8738dc8
Handle EnterNotify and LeaveNotify in the X backend,
Jordan Miner <jminer7@gmail.com>
parents:
24
diff
changeset
|
368 enterEv.y+c.borderSize.top, MouseButton.None); |
0577e8738dc8
Handle EnterNotify and LeaveNotify in the X backend,
Jordan Miner <jminer7@gmail.com>
parents:
24
diff
changeset
|
369 c.mouseMoved(args); |
0 | 370 break; |
371 case LeaveNotify: | |
25
0577e8738dc8
Handle EnterNotify and LeaveNotify in the X backend,
Jordan Miner <jminer7@gmail.com>
parents:
24
diff
changeset
|
372 setHotControl(null); |
0 | 373 break; |
374 case FocusIn: | |
375 break; | |
376 case FocusOut: | |
377 break; | |
378 case Expose: | |
379 // TODO: move the painting code out of here and: | |
380 // make a PaintQueue class and put this here: | |
381 // PaintQueue.add(c, exposeEv.x, exposeEv.y, exposeEv.width, exposeEv.height); | |
382 // then, in Window.repaint(), have this: | |
383 // PaintQueue.add(this, cast(int)x, cast(int)exposeEv.y, cast(int)exposeEv.width, cast(int)exposeEv.height); | |
384 // Have a PaintQueue.Compress method that merges | |
385 // all invalidated rects that touch or overlap. | |
386 // In the if(!XPending(..)) above, just loop over all the | |
387 // rects in the PaintQueue, painting them. | |
388 auto exposeEv = ev.xexpose; | |
389 if(exposeEv.count != -2) { | |
390 c.repaint(exposeEv.x, exposeEv.y, exposeEv.width, exposeEv.height); | |
391 break; | |
392 } | |
393 //printf("repainting x=%d, y=%d, width=%d, height=%d\n", | |
394 // exposeEv.x, exposeEv.y, exposeEv.width, exposeEv.height); | |
395 | |
396 auto surfaceWin = cairo_xlib_surface_create( | |
397 evDisplay, evWindow, | |
398 XDefaultVisual(evDisplay, XDefaultScreen(evDisplay)), | |
399 cast(int)c.width, cast(int)c.height); | |
400 // TODO: ^ should be contentWidth/height or got from evWindow | |
401 auto crWin = cairo_create(surfaceWin); | |
402 cairo_surface_destroy(surfaceWin); | |
403 | |
404 auto surfaceBuff = cairo_surface_create_similar(surfaceWin, CAIRO_CONTENT_COLOR, exposeEv.width, exposeEv.height); | |
405 // TODO: use cairo_translate instead, I guess, as | |
406 // I had to change the Windows backend to it... | |
407 cairo_surface_set_device_offset(surfaceBuff, -exposeEv.x-c._borderSize.left, -exposeEv.y-c._borderSize.top); | |
408 auto crBuff = cairo_create(surfaceBuff); | |
409 cairo_surface_destroy(surfaceBuff); | |
410 | |
411 cairo_set_source_rgb(crBuff, w.content.backColor.R/255.0, w.content.backColor.G/255.0, w.content.backColor.B/255.0); | |
412 cairo_paint(crBuff); | |
413 | |
414 cairo_set_source_rgb(crBuff, 0, 0, 0); | |
415 cairo_set_line_width(crBuff, 1.0); | |
416 | |
417 auto g = new Graphics(crBuff); | |
418 scope args = new PaintingEventArgs(g); | |
419 c.painting(args); | |
420 delete g; | |
421 | |
422 cairo_surface_set_device_offset(surfaceBuff, -exposeEv.x, -exposeEv.y); | |
423 cairo_set_source_surface(crWin, surfaceBuff, 0, 0); | |
424 cairo_rectangle(crWin, exposeEv.x, exposeEv.y, exposeEv.width, exposeEv.height); | |
425 cairo_fill(crWin); | |
426 | |
427 cairo_destroy(crBuff); | |
428 cairo_destroy(crWin); | |
429 break; | |
430 case PropertyNotify: | |
431 auto propertyEv = ev.xproperty; | |
432 if(propertyEv.atom == XA._NET_FRAME_EXTENTS && | |
433 propertyEv.state != PropertyDelete) | |
434 c.backend_nativeToBorderSize(); | |
435 break; | |
436 case ConfigureNotify: | |
437 auto configureEv = ev.xconfigure; | |
438 c.repaint(); | |
439 c.backend_nativeToLocationSize(); | |
440 break; | |
441 case SelectionRequest: | |
442 auto selReqEv = ev.xselectionrequest; | |
443 XEvent fullEv; | |
444 auto selEv = &fullEv.xselection; | |
445 selEv.type = SelectionNotify; | |
446 selEv.requestor = selReqEv.requestor; | |
447 selEv.selection = selReqEv.selection; | |
448 selEv.target = selReqEv.target; | |
449 if(selReqEv.property != None) | |
450 selEv.property = selReqEv.property; | |
451 else | |
452 selEv.property = XA.DYNAMIN_SELECTION; | |
453 selEv.time = selReqEv.time; | |
454 Stdout.format("requestor: {}", selReqEv.requestor).newline; | |
455 Stdout.format("target: {}", selReqEv.target).newline; | |
456 ClipboardData* data; // change to array when supporting multiple | |
457 if(selReqEv.selection == XA.CLIPBOARD) | |
458 data = &Clipboard.data; | |
459 else if(selReqEv.selection == XA.PRIMARY) | |
460 data = &Selection.data; | |
461 else { | |
462 selEv.property = None; | |
463 XSendEvent(display, selEv.requestor, false, 0, &fullEv); | |
464 break; | |
465 } | |
466 if(selReqEv.target == XA.TARGETS) { | |
467 XChangeProperty(display, selEv.requestor, selEv.property, | |
468 selEv.target, 32, PropModeReplace, &data.target, 1); | |
469 XSendEvent(display, selEv.requestor, false, 0, &fullEv); | |
470 break; | |
471 } else if(selReqEv.target != data.target) { | |
472 selEv.property = None; | |
473 XSendEvent(display, selEv.requestor, false, 0, &fullEv); | |
474 break; | |
475 } | |
476 XChangeProperty(display, selEv.requestor, selEv.property, | |
477 data.target, 8, PropModeReplace, data.data, data.length); | |
478 XSendEvent(display, selEv.requestor, false, 0, &fullEv); | |
479 break; | |
24
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
480 case MappingNotify: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
481 XRefreshKeyboardMapping(&ev.xmapping); |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
482 break; |
0 | 483 default: |
484 break; | |
485 } | |
486 } | |
487 } | |
18
836a064828e8
Implement FileDialog/DirectoryDialog with GTK
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
488 void backend_invoke(void delegate() dg) { |
836a064828e8
Implement FileDialog/DirectoryDialog with GTK
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
489 // TODO: |
836a064828e8
Implement FileDialog/DirectoryDialog with GTK
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
490 } |
836a064828e8
Implement FileDialog/DirectoryDialog with GTK
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
491 void backend_invokeNow(void delegate() dg) { |
836a064828e8
Implement FileDialog/DirectoryDialog with GTK
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
492 // TODO: |
836a064828e8
Implement FileDialog/DirectoryDialog with GTK
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
493 } |
836a064828e8
Implement FileDialog/DirectoryDialog with GTK
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
494 |
0 | 495 } |
496 //}}} | |
497 | |
24
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
498 //{{{ KeysymToKey() |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
499 Key KeysymToKey(int sym) { |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
500 switch(sym) { |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
501 case XK_parenright: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
502 case XK_0: return Key.D0; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
503 case XK_exclam: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
504 case XK_1: return Key.D1; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
505 case XK_at: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
506 case XK_2: return Key.D2; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
507 case XK_numbersign: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
508 case XK_3: return Key.D3; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
509 case XK_dollar: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
510 case XK_4: return Key.D4; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
511 case XK_percent: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
512 case XK_5: return Key.D5; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
513 case XK_asciicircum: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
514 case XK_6: return Key.D6; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
515 case XK_ampersand: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
516 case XK_7: return Key.D7; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
517 case XK_asterisk: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
518 case XK_8: return Key.D8; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
519 case XK_parenleft: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
520 case XK_9: return Key.D9; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
521 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
522 case XK_F1: return Key.F1; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
523 case XK_F2: return Key.F2; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
524 case XK_F3: return Key.F3; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
525 case XK_F4: return Key.F4; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
526 case XK_F5: return Key.F5; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
527 case XK_F6: return Key.F6; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
528 case XK_F7: return Key.F7; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
529 case XK_F8: return Key.F8; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
530 case XK_F9: return Key.F9; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
531 case XK_F10: return Key.F10; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
532 case XK_F11: return Key.F11; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
533 case XK_F12: return Key.F12; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
534 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
535 case XK_Escape: return Key.Escape; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
536 case XK_Tab: return Key.Tab; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
537 case XK_BackSpace: return Key.Backspace; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
538 case XK_Return: return Key.Enter; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
539 case XK_KP_Enter: return Key.Enter; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
540 case XK_space: return Key.Space; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
541 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
542 case XK_KP_Left: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
543 case XK_Left: return Key.Left; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
544 case XK_KP_Right: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
545 case XK_Right: return Key.Right; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
546 case XK_KP_Up: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
547 case XK_Up: return Key.Up; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
548 case XK_KP_Down: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
549 case XK_Down: return Key.Down; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
550 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
551 case XK_KP_Insert: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
552 case XK_Insert: return Key.Insert; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
553 case XK_KP_Delete: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
554 case XK_Delete: return Key.Delete; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
555 case XK_KP_Home: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
556 case XK_Home: return Key.Home; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
557 case XK_KP_End: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
558 case XK_End: return Key.End; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
559 case XK_KP_Prior: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
560 case XK_Prior: return Key.PageUp; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
561 case XK_KP_Next: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
562 case XK_Next: return Key.PageDown; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
563 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
564 case XK_Print: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
565 case XK_Sys_Req: return Key.PrintScreen; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
566 case XK_Pause: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
567 case XK_Break: return Key.Pause; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
568 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
569 case XK_Caps_Lock: return Key.CapsLock; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
570 case XK_Num_Lock: return Key.NumLock; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
571 case XK_Scroll_Lock: return Key.ScrollLock; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
572 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
573 case XK_KP_0: return Key.NumPad0; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
574 case XK_KP_1: return Key.NumPad1; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
575 case XK_KP_2: return Key.NumPad2; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
576 case XK_KP_3: return Key.NumPad3; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
577 case XK_KP_4: return Key.NumPad4; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
578 case XK_KP_5: return Key.NumPad5; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
579 case XK_KP_6: return Key.NumPad6; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
580 case XK_KP_7: return Key.NumPad7; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
581 case XK_KP_8: return Key.NumPad8; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
582 case XK_KP_9: return Key.NumPad9; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
583 case XK_KP_Divide: return Key.NumPadDivide; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
584 case XK_KP_Multiply: return Key.NumPadMultiply; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
585 case XK_KP_Subtract: return Key.NumPadSubtract; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
586 case XK_KP_Add: return Key.NumPadAdd; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
587 case XK_KP_Decimal: return Key.NumPadDecimal; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
588 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
589 case XK_grave: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
590 case XK_asciitilde: return Key.Backquote; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
591 case XK_minus: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
592 case XK_underscore: return Key.Minus; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
593 case XK_equal: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
594 case XK_plus: return Key.Equals; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
595 case XK_bracketleft: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
596 case XK_braceleft: return Key.OpenBracket; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
597 case XK_bracketright: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
598 case XK_braceright: return Key.CloseBracket; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
599 case XK_backslash: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
600 case XK_bar: return Key.Backslash; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
601 case XK_semicolon: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
602 case XK_colon: return Key.Semicolon; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
603 case XK_apostrophe: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
604 case XK_quotedbl: return Key.Quote; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
605 case XK_comma: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
606 case XK_less: return Key.Comma; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
607 case XK_period: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
608 case XK_greater: return Key.Period; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
609 case XK_slash: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
610 case XK_question: return Key.Slash; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
611 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
612 //case XK_Menu: return Key.Menu; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
613 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
614 case XK_Shift_L: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
615 case XK_Shift_R: return Key.Shift; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
616 case XK_Control_L: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
617 case XK_Control_R: return Key.Control; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
618 case XK_Alt_L: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
619 case XK_Alt_R: return Key.Alt; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
620 |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
621 //case XK_: return Key.; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
622 default: |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
623 if(sym >= 0x41 && sym <= 0x5A) // Key.A - Key.Z |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
624 return cast(Key)sym; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
625 if(sym >= 0x61 && sym <= 0x7A) // Key.A - Key.Z |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
626 return cast(Key)(sym-32); |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
627 return cast(Key)0; |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
628 } |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
629 } |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
630 //}}} |
43a88caead16
Implement keyDown and keyUp events with X.
Jordan Miner <jminer7@gmail.com>
parents:
23
diff
changeset
|
631 |
0 | 632 public import tango.stdc.time; |
633 template WindowBackend() { | |
634 invariant { | |
635 //if(_handle == 0) | |
636 // return; | |
637 //XWindow root, parent; | |
638 //XWindow* children; | |
639 //uint numChildren; | |
640 //XQueryTree(display, _handle, | |
641 // &root, &parent, &children, &numChildren); | |
642 //XFree(children); | |
643 //int x, y; | |
644 //XWindow child; | |
645 //XTranslateCoordinates(display, _handle, root, 0, 0, &x, &y, &child); | |
646 //assert(_location.X == x-_borderSize.Left); | |
647 //assert(_location.Y == y-_borderSize.Top); | |
648 //XWindowAttributes attribs; | |
649 //XGetWindowAttributes(display, _handle, &attribs); | |
650 } | |
651 XWindow _handle; | |
652 bool mapped = false; | |
653 bool backend_handleCreated() { return _handle > 0; } | |
654 void backend_recreateHandle() { | |
655 auto primaryScreenNum = XDefaultScreen(display); | |
656 //XColor color; | |
657 //color.red = 65535*backColor.R/255; | |
658 //color.green = 65535*backColor.G/255; | |
659 //color.blue = 65535*backColor.B/255; | |
660 //if(XAllocColor(display, XDefaultColormap(display, primaryScreenNum), &color)) | |
661 // printf("XAllocColor() failed\n"); | |
662 | |
663 XSetWindowAttributes attribs; | |
664 attribs.bit_gravity = NorthWestGravity; | |
665 // TODO: should be backColor, and should change when backColor changes | |
666 // call XSetWindowBackground() for this | |
667 attribs.background_pixel = XWhitePixel(display, primaryScreenNum); | |
668 attribs.event_mask = | |
669 KeyPressMask | | |
670 KeyReleaseMask | | |
671 ButtonPressMask | | |
672 ButtonReleaseMask | | |
673 EnterWindowMask | | |
674 LeaveWindowMask | | |
675 PointerMotionMask | | |
676 ButtonMotionMask | | |
677 ExposureMask | | |
678 FocusChangeMask | | |
679 StructureNotifyMask | | |
680 PropertyChangeMask; | |
681 XWindow newHandle = XCreateWindow( | |
682 display, root, | |
683 cast(int)x, cast(int)y, | |
684 backend_insideWidth, backend_insideHeight, | |
685 0, CopyFromParent, InputOutput, null, | |
686 CWBitGravity | CWBackPixel | CWEventMask, &attribs); | |
687 | |
688 setControl(newHandle, this); | |
689 auto protocols = [XA.WM_DELETE_WINDOW]; | |
690 XSetWMProtocols(display, newHandle, protocols.ptr, protocols.length); | |
691 if(handleCreated) { | |
692 XDestroyWindow(display, _handle); | |
693 XSync(display, false); | |
694 } | |
695 _handle = newHandle; | |
696 text = _text; // move the text over to the new window | |
697 visible = _visible; | |
698 borderStyle = _borderStyle; | |
699 //backend_nativeToBorderSize(); | |
700 } | |
701 Graphics backend_quickCreateGraphics() { | |
702 auto surface = cairo_xlib_surface_create(display, _handle, | |
703 XDefaultVisual(display, XDefaultScreen(display)), | |
704 cast(int)width, cast(int)height); | |
705 auto cr = cairo_create(surface); | |
706 cairo_surface_destroy(surface); | |
707 cairo_translate(cr, -borderSize.left, -borderSize.top); | |
708 auto g = new Graphics(cr); | |
709 cairo_destroy(cr); | |
710 return g; | |
711 } | |
712 void backend_visible(bool b) { | |
713 if(b) | |
714 // if not created, create the handle by calling handle() | |
715 XMapWindow(display, handle); | |
716 else | |
717 XUnmapWindow(display, _handle); | |
718 } | |
719 void backend_borderStyle(WindowBorderStyle border) { | |
720 backend_update_NET_WM_WINDOW_TYPE(); | |
721 backend_update_MOTIF_WM_HINTS(); | |
722 backend_nativeToBorderSize(); | |
723 } | |
23
d55b5b998412
Implement built-in mouse cursors with X.
Jordan Miner <jminer7@gmail.com>
parents:
18
diff
changeset
|
724 void backend_setCurrentCursor(Cursor cur) { |
d55b5b998412
Implement built-in mouse cursors with X.
Jordan Miner <jminer7@gmail.com>
parents:
18
diff
changeset
|
725 XDefineCursor(display, _handle, cur.handle); |
d55b5b998412
Implement built-in mouse cursors with X.
Jordan Miner <jminer7@gmail.com>
parents:
18
diff
changeset
|
726 } |
d55b5b998412
Implement built-in mouse cursors with X.
Jordan Miner <jminer7@gmail.com>
parents:
18
diff
changeset
|
727 |
0 | 728 static _InvalidRect[] invalidRects; |
729 void backend_repaint(Rect rect) { | |
730 invalidRects.length = invalidRects.length+1; | |
731 invalidRects[$-1].window = _handle; | |
732 invalidRects[$-1].x = cast(int)(rect.x-borderSize.left); | |
733 invalidRects[$-1].y = cast(int)(rect.y-borderSize.top); | |
734 invalidRects[$-1].width = cast(int)rect.width+1; | |
735 invalidRects[$-1].height = cast(int)rect.height+1; | |
736 //printf("invalidating x=%.1f, y=%.1f, width=%.1f, height=%.1f\n", rect.X, rect.Y, rect.width, rect.height); | |
737 } | |
738 void backend_resizable(bool b) { | |
739 backend_updateWM_NORMAL_HINTS(); | |
740 } | |
741 void backend_contentMinSizeChanged() { | |
742 backend_updateWM_NORMAL_HINTS(); | |
743 } | |
744 void backend_contentMaxSizeChanged() { | |
745 backend_updateWM_NORMAL_HINTS(); | |
746 } | |
747 void backend_location(Point pt) { | |
748 backend_updateWM_NORMAL_HINTS(); | |
749 backend_locationSizeToNative(); | |
750 } | |
751 void backend_size(Size size) { | |
752 backend_updateWM_NORMAL_HINTS(); | |
753 backend_locationSizeToNative(); | |
754 } | |
755 void backend_text(string str) { | |
756 //auto tmp = str.ToCharPtr(); | |
757 //XTextProperty strProperty; | |
758 //if(!XStringListToTextProperty(&tmp, 1, &strProperty)) | |
759 //printf("XStringListToTextProperty() failed - out of memory\n"); | |
760 //XSetWMName(display, _handle, &strProperty); | |
761 XChangeProperty(display, _handle, XA._NET_WM_NAME, XA.UTF8_STRING, 8, PropModeReplace, str.ptr, str.length); | |
762 } | |
763 //{{{ backend specific | |
764 void backend_updateWM_NORMAL_HINTS() { | |
765 XSizeHints* sizeHints = XAllocSizeHints(); | |
766 scope(exit) XFree(sizeHints); | |
767 sizeHints.flags = PMinSize | PMaxSize | PPosition | PSize; | |
768 if(resizable) { | |
769 sizeHints.min_width = cast(int)content.minWidth; | |
770 sizeHints.min_height = cast(int)content.minHeight; | |
771 sizeHints.max_width = | |
772 content.maxWidth > 0 ? cast(int)content.maxWidth : 30_000; | |
773 sizeHints.max_height = | |
774 content.maxHeight > 0 ? cast(int)content.maxHeight : 30_000; | |
775 } else { | |
776 sizeHints.min_width = sizeHints.max_width = backend_insideWidth; | |
777 sizeHints.min_height = sizeHints.max_height = backend_insideHeight; | |
778 } | |
779 sizeHints.x = cast(int)x; | |
780 sizeHints.y = cast(int)y; | |
781 sizeHints.width = backend_insideWidth; | |
782 sizeHints.height = backend_insideHeight; | |
783 XSetWMNormalHints(display, _handle, sizeHints); | |
784 } | |
785 void backend_update_MOTIF_WM_HINTS() { | |
786 int[4] mwmHints; | |
787 mwmHints[0] = 1 << 1; // flags | |
788 mwmHints[2] = borderStyle == WindowBorderStyle.None ? 0 : 1; // decor | |
789 XChangeProperty(display, _handle, | |
790 XA._MOTIF_WM_HINTS, XA._MOTIF_WM_HINTS, 32, PropModeReplace, mwmHints.ptr, mwmHints.length); | |
791 } | |
792 void backend_update_NET_WM_WINDOW_TYPE() { | |
793 XAtom[] atoms; | |
794 // with Metacity, the decor is not being repainted from normal>dialog | |
795 // because they are the same size | |
796 if(borderStyle == WindowBorderStyle.Dialog) | |
797 atoms = [XA._NET_WM_WINDOW_TYPE_DIALOG]; | |
798 else if(borderStyle == WindowBorderStyle.Tool) | |
799 atoms = [XA._NET_WM_WINDOW_TYPE_UTILITY]; | |
800 else | |
801 atoms = [XA._NET_WM_WINDOW_TYPE_NORMAL]; | |
802 XChangeProperty(display, _handle, | |
803 XA._NET_WM_WINDOW_TYPE, XA.ATOM, 32, PropModeReplace, atoms.ptr, atoms.length); | |
804 } | |
805 // returns what width the x window should be...not including borders | |
806 int backend_insideWidth() { | |
807 return cast(int)(size.width-borderSize.left-borderSize.right); | |
808 } | |
809 // returns what height the x window should be...not including borders | |
810 int backend_insideHeight() { | |
811 return cast(int)(size.height-borderSize.top-borderSize.bottom); | |
812 } | |
813 // applies the currently set location and size to the native X Window | |
814 void backend_locationSizeToNative() { | |
815 Point pt = _location; | |
816 if(!isTopLevelReparented(_handle)) { | |
817 pt.x = pt.x + _borderSize.left; | |
818 pt.y = pt.y + _borderSize.top; | |
819 } | |
820 XMoveResizeWindow(display, _handle, cast(int)pt.x, cast(int)pt.y, | |
821 backend_insideWidth, backend_insideHeight); | |
822 // XMoveWindow: | |
823 // Under Metacity, sets the location of the WM's frame. | |
824 // Under Compiz, sets the location of the window. | |
825 // XResizeWindow: | |
826 // Under Metacity and Compiz, sets the size of the window not | |
827 // including the WM's frame. | |
828 } | |
829 // sets location and size based on where the native X Window is | |
830 void backend_nativeToLocationSize() { | |
831 XWindow root, parent; | |
832 XWindow* children; | |
833 uint numChildren; | |
834 XQueryTree(display, _handle, | |
835 &root, &parent, &children, &numChildren); | |
836 XFree(children); | |
837 | |
838 int x, y; | |
839 XWindow child; | |
840 XTranslateCoordinates(display, _handle, root, 0, 0, &x, &y, &child); | |
841 _location.x = x - _borderSize.left; | |
842 _location.y = y - _borderSize.top; | |
843 scope args = new EventArgs; | |
844 moved(args); | |
845 XWindowAttributes attribs; | |
846 XGetWindowAttributes(display, _handle, &attribs); | |
847 _size.width = attribs.width+_borderSize.left+_borderSize.right; | |
848 _size.height = attribs.height+_borderSize.top+_borderSize.bottom; | |
849 resized(args); | |
850 | |
851 //content._location = Point(_borderSize.Left, _borderSize.Top); | |
852 //content._size = Size(attribs.width, attribs.height); | |
853 //Stdout.format("location updated to {}", _location).newline; | |
854 //Stdout.format("size updated to {}", _size).newline; | |
855 } | |
856 void backend_nativeToBorderSize() { | |
857 _borderSize = backend_getBorderSize(); | |
858 //Stdout("borderSize updated to ", _borderSize).newline; | |
859 backend_nativeToLocationSize(); | |
860 } | |
861 BorderSize backend_getBorderSize() { | |
862 if(!isWMPropertySupported(XA._NET_FRAME_EXTENTS) || | |
863 borderStyle == WindowBorderStyle.None) | |
864 return BorderSize(); | |
865 // create handle if necessary | |
866 auto reqHandle = handle; | |
867 bool requested = false; | |
868 | |
869 //{{{ requestExtents() | |
870 void requestExtents() { | |
871 if(isWMPropertySupported(XA._NET_REQUEST_FRAME_EXTENTS)) { | |
872 XEvent ev; | |
873 ev.xclient.type = ClientMessage; | |
874 ev.xclient.window = handle; | |
875 ev.xclient.message_type = XA._NET_REQUEST_FRAME_EXTENTS; | |
876 ev.xclient.format = 8; | |
877 XSendEvent(display, root, false, | |
878 SubstructureNotifyMask | SubstructureRedirectMask, &ev); | |
879 } else { // compiz and beryl do not yet support requesting | |
880 XSetWindowAttributes attribs; | |
881 reqHandle = XCreateWindow(display, | |
882 root, 0, 0, 1, 1, | |
883 0, CopyFromParent, InputOnly, null, 0, &attribs); | |
884 | |
885 XWMHints* hints = XAllocWMHints(); | |
886 scope(exit) XFree(hints); | |
887 hints.flags = InputHint; | |
888 hints.input = false; | |
889 XSetWMHints(display, reqHandle, hints); | |
890 | |
891 auto mainHandle = _handle; | |
892 _handle = reqHandle; | |
893 backend_updateWM_NORMAL_HINTS(); | |
894 backend_update_NET_WM_WINDOW_TYPE(); | |
895 backend_update_MOTIF_WM_HINTS(); | |
896 backend_visible = true; | |
897 backend_visible = false; | |
898 _handle = mainHandle; | |
899 } | |
900 requested = true; | |
901 } | |
902 //}}} | |
903 | |
904 if(!mapped) | |
905 requestExtents(); | |
906 int* extents; | |
907 while(true) { | |
908 XSync(display, false); | |
909 extents = cast(int*)getXWindowProperty(display, reqHandle, | |
910 XA._NET_FRAME_EXTENTS); | |
911 if(extents !is null) | |
912 break; | |
913 if(!requested) | |
914 requestExtents(); | |
915 } | |
916 scope(exit) XFree(extents); | |
917 if(reqHandle != _handle) | |
918 XDestroyWindow(display, reqHandle); | |
919 return BorderSize(extents[0], extents[2], extents[1], extents[3]); | |
920 } | |
921 //}}} | |
922 } | |
923 |