]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Unix/Host/X11GraphicsWindow.c
EmulatorPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / EmulatorPkg / Unix / Host / X11GraphicsWindow.c
CommitLineData
79e4f2a5
RN
1/*++ @file\r
2\r
3Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
4Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>\r
5\r
e3ba31da 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
79e4f2a5
RN
7\r
8**/\r
9\r
10#include "Host.h"\r
11\r
12#include <sys/ipc.h>\r
13#include <sys/shm.h>\r
14\r
15#include <X11/Xlib.h>\r
16#include <X11/Xutil.h>\r
17#include <X11/Xos.h>\r
18#include <X11/extensions/XShm.h>\r
19#include <X11/keysym.h>\r
20#include <X11/cursorfont.h>\r
21\r
22#define KEYSYM_LOWER 0\r
23#define KEYSYM_UPPER 1\r
24\r
25\r
26struct uga_drv_shift_mask {\r
27 unsigned char shift;\r
28 unsigned char size;\r
29 unsigned char csize;\r
30};\r
31\r
32#define NBR_KEYS 32\r
33typedef struct {\r
34 EMU_GRAPHICS_WINDOW_PROTOCOL GraphicsIo;\r
35\r
36 Display *display;\r
37 int screen; // values for window_size in main\r
38 Window win;\r
39 GC gc;\r
40 Visual *visual;\r
41\r
42 int depth;\r
43 unsigned int width;\r
44 unsigned int height;\r
45 unsigned int line_bytes;\r
46 unsigned int pixel_shift;\r
47 unsigned char *image_data;\r
48\r
49 struct uga_drv_shift_mask r, g, b;\r
50\r
51 int use_shm;\r
52 XShmSegmentInfo xshm_info;\r
53 XImage *image;\r
54 char *Title;\r
55\r
56 unsigned int key_rd;\r
57 unsigned int key_wr;\r
58 unsigned int key_count;\r
59 EFI_KEY_DATA keys[NBR_KEYS];\r
60\r
61 EFI_KEY_STATE KeyState;\r
62\r
63 EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeRegisterdKeyCallback;\r
64 EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakRegisterdKeyCallback;\r
65 VOID *RegisterdKeyCallbackContext;\r
66\r
67 int previous_x;\r
68 int previous_y;\r
69 EFI_SIMPLE_POINTER_STATE pointer_state;\r
70 int pointer_state_changed;\r
71} GRAPHICS_IO_PRIVATE;\r
72\r
73void\r
74HandleEvents(\r
75 IN GRAPHICS_IO_PRIVATE *Drv\r
76 );\r
77\r
78void\r
79fill_shift_mask (\r
80 IN struct uga_drv_shift_mask *sm,\r
81 IN unsigned long mask\r
82 )\r
83{\r
84 sm->shift = 0;\r
85 sm->size = 0;\r
86 while ((mask & 1) == 0) {\r
87 mask >>= 1;\r
88 sm->shift++;\r
89 }\r
90 while (mask & 1) {\r
91 sm->size++;\r
92 mask >>= 1;\r
93 }\r
94 sm->csize = 8 - sm->size;\r
95}\r
96\r
97int\r
98TryCreateShmImage (\r
99 IN GRAPHICS_IO_PRIVATE *Drv\r
100 )\r
101{\r
102 Drv->image = XShmCreateImage (\r
103 Drv->display, Drv->visual,\r
104 Drv->depth, ZPixmap, NULL, &Drv->xshm_info,\r
105 Drv->width, Drv->height\r
106 );\r
107 if (Drv->image == NULL) {\r
108 return 0;\r
109 }\r
110\r
111 switch (Drv->image->bitmap_unit) {\r
112 case 32:\r
113 Drv->pixel_shift = 2;\r
114 break;\r
115 case 16:\r
116 Drv->pixel_shift = 1;\r
117 break;\r
118 case 8:\r
119 Drv->pixel_shift = 0;\r
120 break;\r
121 }\r
122\r
123 Drv->xshm_info.shmid = shmget (\r
124 IPC_PRIVATE, Drv->image->bytes_per_line * Drv->image->height,\r
125 IPC_CREAT | 0777\r
126 );\r
127 if (Drv->xshm_info.shmid < 0) {\r
128 XDestroyImage(Drv->image);\r
129 return 0;\r
130 }\r
131\r
132 Drv->image_data = shmat (Drv->xshm_info.shmid, NULL, 0);\r
133 if(!Drv->image_data) {\r
134 shmctl (Drv->xshm_info.shmid, IPC_RMID, NULL);\r
135 XDestroyImage(Drv->image);\r
136 return 0;\r
137 }\r
138\r
139#ifndef __APPLE__\r
140 //\r
141 // This closes shared memory in real time on OS X. Only closes after folks quit using\r
142 // it on Linux.\r
143 //\r
144 shmctl (Drv->xshm_info.shmid, IPC_RMID, NULL);\r
145#endif\r
146\r
147 Drv->xshm_info.shmaddr = (char*)Drv->image_data;\r
148 Drv->image->data = (char*)Drv->image_data;\r
149\r
150 if (!XShmAttach (Drv->display, &Drv->xshm_info)) {\r
151 shmdt (Drv->image_data);\r
152 XDestroyImage(Drv->image);\r
153 return 0;\r
154 }\r
155 return 1;\r
156}\r
157\r
158\r
159EFI_STATUS\r
160X11Size (\r
161 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,\r
162 IN UINT32 Width,\r
163 IN UINT32 Height\r
164 )\r
165{\r
166 GRAPHICS_IO_PRIVATE *Drv;\r
167 XSizeHints size_hints;\r
168\r
169 // Destroy current buffer if created.\r
170 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;\r
171 if (Drv->image != NULL) {\r
172 // Before destroy buffer, need to make sure the buffer available for access.\r
173 XDestroyImage (Drv->image);\r
174\r
175 if (Drv->use_shm) {\r
176 shmdt (Drv->image_data);\r
177 }\r
178\r
179 Drv->image_data = NULL;\r
180 Drv->image = NULL;\r
181 }\r
182\r
183 Drv->width = Width;\r
184 Drv->height = Height;\r
185 XResizeWindow (Drv->display, Drv->win, Width, Height);\r
186\r
187 // Allocate image.\r
188 if (XShmQueryExtension(Drv->display) && TryCreateShmImage(Drv)) {\r
189 Drv->use_shm = 1;\r
190 } else {\r
191 Drv->use_shm = 0;\r
192 if (Drv->depth > 16) {\r
193 Drv->pixel_shift = 2;\r
194 } else if (Drv->depth > 8) {\r
195 Drv->pixel_shift = 1;\r
196 } else {\r
197 Drv->pixel_shift = 0;\r
198 }\r
199\r
200 Drv->image_data = malloc ((Drv->width * Drv->height) << Drv->pixel_shift);\r
201 Drv->image = XCreateImage (\r
202 Drv->display, Drv->visual, Drv->depth,\r
203 ZPixmap, 0, (char *)Drv->image_data,\r
204 Drv->width, Drv->height,\r
205 8 << Drv->pixel_shift, 0\r
206 );\r
207 }\r
208\r
209 Drv->line_bytes = Drv->image->bytes_per_line;\r
210\r
211 fill_shift_mask (&Drv->r, Drv->image->red_mask);\r
212 fill_shift_mask (&Drv->g, Drv->image->green_mask);\r
213 fill_shift_mask (&Drv->b, Drv->image->blue_mask);\r
214\r
215 // Set WM hints.\r
216 size_hints.flags = PSize | PMinSize | PMaxSize;\r
217 size_hints.min_width = size_hints.max_width = size_hints.base_width = Width;\r
218 size_hints.min_height = size_hints.max_height = size_hints.base_height = Height;\r
219 XSetWMNormalHints (Drv->display, Drv->win, &size_hints);\r
220\r
221 XMapWindow (Drv->display, Drv->win);\r
222 HandleEvents (Drv);\r
223 return EFI_SUCCESS;\r
224}\r
225\r
226void\r
227handleKeyEvent (\r
228 IN GRAPHICS_IO_PRIVATE *Drv,\r
229 IN XEvent *ev,\r
230 IN BOOLEAN Make\r
231 )\r
232{\r
233 KeySym *KeySym;\r
234 EFI_KEY_DATA KeyData;\r
235 int KeySymArraySize;\r
236\r
237 if (Make) {\r
238 if (Drv->key_count == NBR_KEYS) {\r
239 return;\r
240 }\r
241 }\r
242\r
243 // keycode is a physical key on the keyboard\r
244 // KeySym is a mapping of a physical key\r
245 // KeyboardMapping is the array of KeySym for a given keycode. key, shifted key, option key, command key, ...\r
246 //\r
247 // Returns an array of KeySymArraySize of KeySym for the keycode. [0] is lower case, [1] is upper case,\r
248 // [2] and [3] are based on option and command modifiers. The problem we have is command V\r
249 // could be mapped to a crazy Unicode character so the old scheme of returning a string.\r
250 //\r
251 KeySym = XGetKeyboardMapping (Drv->display, ev->xkey.keycode, 1, &KeySymArraySize);\r
252\r
253 KeyData.Key.ScanCode = 0;\r
254 KeyData.Key.UnicodeChar = 0;\r
255 KeyData.KeyState.KeyShiftState = 0;\r
256\r
257 //\r
258 // Skipping EFI_SCROLL_LOCK_ACTIVE & EFI_NUM_LOCK_ACTIVE since they are not on Macs\r
259 //\r
260 if ((ev->xkey.state & LockMask) == 0) {\r
261 Drv->KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;\r
262 } else {\r
263 if (Make) {\r
264 Drv->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;\r
265 }\r
266 }\r
267\r
268 // Skipping EFI_MENU_KEY_PRESSED and EFI_SYS_REQ_PRESSED\r
269\r
270 switch (*KeySym) {\r
271 case XK_Control_R:\r
272 if (Make) {\r
273 Drv->KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;\r
274 } else {\r
275 Drv->KeyState.KeyShiftState &= ~EFI_RIGHT_CONTROL_PRESSED;\r
276 }\r
277 break;\r
278 case XK_Control_L:\r
279 if (Make) {\r
280 Drv->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;\r
281 } else {\r
282 Drv->KeyState.KeyShiftState &= ~EFI_LEFT_CONTROL_PRESSED;\r
283 }\r
284 break;\r
285\r
286 case XK_Shift_R:\r
287 if (Make) {\r
288 Drv->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;\r
289 } else {\r
290 Drv->KeyState.KeyShiftState &= ~EFI_RIGHT_SHIFT_PRESSED;\r
291 }\r
292 break;\r
293 case XK_Shift_L:\r
294 if (Make) {\r
295 Drv->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;\r
296 } else {\r
297 Drv->KeyState.KeyShiftState &= ~EFI_LEFT_SHIFT_PRESSED;\r
298 }\r
299 break;\r
300\r
301 case XK_Mode_switch:\r
302 if (Make) {\r
303 Drv->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;\r
304 } else {\r
305 Drv->KeyState.KeyShiftState &= ~EFI_LEFT_ALT_PRESSED;\r
306 }\r
307 break;\r
308\r
309 case XK_Meta_R:\r
310 if (Make) {\r
311 Drv->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;\r
312 } else {\r
313 Drv->KeyState.KeyShiftState &= ~EFI_RIGHT_LOGO_PRESSED;\r
314 }\r
315 break;\r
316 case XK_Meta_L:\r
317 if (Make) {\r
318 Drv->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED;\r
319 } else {\r
320 Drv->KeyState.KeyShiftState &= ~EFI_LEFT_LOGO_PRESSED;\r
321 }\r
322 break;\r
323\r
324 case XK_KP_Home:\r
325 case XK_Home: KeyData.Key.ScanCode = SCAN_HOME; break;\r
326\r
327 case XK_KP_End:\r
328 case XK_End: KeyData.Key.ScanCode = SCAN_END; break;\r
329\r
330 case XK_KP_Left:\r
331 case XK_Left: KeyData.Key.ScanCode = SCAN_LEFT; break;\r
332\r
333 case XK_KP_Right:\r
334 case XK_Right: KeyData.Key.ScanCode = SCAN_RIGHT; break;\r
335\r
336 case XK_KP_Up:\r
337 case XK_Up: KeyData.Key.ScanCode = SCAN_UP; break;\r
338\r
339 case XK_KP_Down:\r
340 case XK_Down: KeyData.Key.ScanCode = SCAN_DOWN; break;\r
341\r
342 case XK_KP_Delete:\r
343 case XK_Delete: KeyData.Key.ScanCode = SCAN_DELETE; break;\r
344\r
345 case XK_KP_Insert:\r
346 case XK_Insert: KeyData.Key.ScanCode = SCAN_INSERT; break;\r
347\r
348 case XK_KP_Page_Up:\r
349 case XK_Page_Up: KeyData.Key.ScanCode = SCAN_PAGE_UP; break;\r
350\r
351 case XK_KP_Page_Down:\r
352 case XK_Page_Down: KeyData.Key.ScanCode = SCAN_PAGE_DOWN; break;\r
353\r
354 case XK_Escape: KeyData.Key.ScanCode = SCAN_ESC; break;\r
355\r
356 case XK_Pause: KeyData.Key.ScanCode = SCAN_PAUSE; break;\r
357\r
358 case XK_KP_F1:\r
359 case XK_F1: KeyData.Key.ScanCode = SCAN_F1; break;\r
360\r
361 case XK_KP_F2:\r
362 case XK_F2: KeyData.Key.ScanCode = SCAN_F2; break;\r
363\r
364 case XK_KP_F3:\r
365 case XK_F3: KeyData.Key.ScanCode = SCAN_F3; break;\r
366\r
367 case XK_KP_F4:\r
368 case XK_F4: KeyData.Key.ScanCode = SCAN_F4; break;\r
369\r
370 case XK_F5: KeyData.Key.ScanCode = SCAN_F5; break;\r
371 case XK_F6: KeyData.Key.ScanCode = SCAN_F6; break;\r
372 case XK_F7: KeyData.Key.ScanCode = SCAN_F7; break;\r
373\r
374 // Don't map into X11 by default on a Mac\r
375 // System Preferences->Keyboard->Keyboard Shortcuts can be configured\r
376 // to not use higher function keys as shortcuts and the will show up\r
377 // in X11.\r
378 case XK_F8: KeyData.Key.ScanCode = SCAN_F8; break;\r
379 case XK_F9: KeyData.Key.ScanCode = SCAN_F9; break;\r
380 case XK_F10: KeyData.Key.ScanCode = SCAN_F10; break;\r
381\r
382 case XK_F11: KeyData.Key.ScanCode = SCAN_F11; break;\r
383 case XK_F12: KeyData.Key.ScanCode = SCAN_F12; break;\r
384\r
385 case XK_F13: KeyData.Key.ScanCode = SCAN_F13; break;\r
386 case XK_F14: KeyData.Key.ScanCode = SCAN_F14; break;\r
387 case XK_F15: KeyData.Key.ScanCode = SCAN_F15; break;\r
388 case XK_F16: KeyData.Key.ScanCode = SCAN_F16; break;\r
389 case XK_F17: KeyData.Key.ScanCode = SCAN_F17; break;\r
390 case XK_F18: KeyData.Key.ScanCode = SCAN_F18; break;\r
391 case XK_F19: KeyData.Key.ScanCode = SCAN_F19; break;\r
392 case XK_F20: KeyData.Key.ScanCode = SCAN_F20; break;\r
393 case XK_F21: KeyData.Key.ScanCode = SCAN_F21; break;\r
394 case XK_F22: KeyData.Key.ScanCode = SCAN_F22; break;\r
395 case XK_F23: KeyData.Key.ScanCode = SCAN_F23; break;\r
396 case XK_F24: KeyData.Key.ScanCode = SCAN_F24; break;\r
397\r
398 // No mapping in X11\r
399 //case XK_: KeyData.Key.ScanCode = SCAN_MUTE; break;\r
400 //case XK_: KeyData.Key.ScanCode = SCAN_VOLUME_UP; break;\r
401 //case XK_: KeyData.Key.ScanCode = SCAN_VOLUME_DOWN; break;\r
402 //case XK_: KeyData.Key.ScanCode = SCAN_BRIGHTNESS_UP; break;\r
403 //case XK_: KeyData.Key.ScanCode = SCAN_BRIGHTNESS_DOWN; break;\r
404 //case XK_: KeyData.Key.ScanCode = SCAN_SUSPEND; break;\r
405 //case XK_: KeyData.Key.ScanCode = SCAN_HIBERNATE; break;\r
406 //case XK_: KeyData.Key.ScanCode = SCAN_TOGGLE_DISPLAY; break;\r
407 //case XK_: KeyData.Key.ScanCode = SCAN_RECOVERY; break;\r
408 //case XK_: KeyData.Key.ScanCode = SCAN_EJECT; break;\r
409\r
410 case XK_BackSpace: KeyData.Key.UnicodeChar = 0x0008; break;\r
411\r
412 case XK_KP_Tab:\r
413 case XK_Tab: KeyData.Key.UnicodeChar = 0x0009; break;\r
414\r
415 case XK_Linefeed: KeyData.Key.UnicodeChar = 0x000a; break;\r
416\r
417 case XK_KP_Enter:\r
418 case XK_Return: KeyData.Key.UnicodeChar = 0x000d; break;\r
419\r
420 case XK_KP_Equal : KeyData.Key.UnicodeChar = L'='; break;\r
421 case XK_KP_Multiply : KeyData.Key.UnicodeChar = L'*'; break;\r
422 case XK_KP_Add : KeyData.Key.UnicodeChar = L'+'; break;\r
423 case XK_KP_Separator : KeyData.Key.UnicodeChar = L'~'; break;\r
424 case XK_KP_Subtract : KeyData.Key.UnicodeChar = L'-'; break;\r
425 case XK_KP_Decimal : KeyData.Key.UnicodeChar = L'.'; break;\r
426 case XK_KP_Divide : KeyData.Key.UnicodeChar = L'/'; break;\r
427\r
428 case XK_KP_0 : KeyData.Key.UnicodeChar = L'0'; break;\r
429 case XK_KP_1 : KeyData.Key.UnicodeChar = L'1'; break;\r
430 case XK_KP_2 : KeyData.Key.UnicodeChar = L'2'; break;\r
431 case XK_KP_3 : KeyData.Key.UnicodeChar = L'3'; break;\r
432 case XK_KP_4 : KeyData.Key.UnicodeChar = L'4'; break;\r
433 case XK_KP_5 : KeyData.Key.UnicodeChar = L'5'; break;\r
434 case XK_KP_6 : KeyData.Key.UnicodeChar = L'6'; break;\r
435 case XK_KP_7 : KeyData.Key.UnicodeChar = L'7'; break;\r
436 case XK_KP_8 : KeyData.Key.UnicodeChar = L'8'; break;\r
437 case XK_KP_9 : KeyData.Key.UnicodeChar = L'9'; break;\r
438\r
439 default:\r
440 ;\r
441 }\r
442\r
443 // The global state is our state\r
444 KeyData.KeyState.KeyShiftState = Drv->KeyState.KeyShiftState;\r
445 KeyData.KeyState.KeyToggleState = Drv->KeyState.KeyToggleState;\r
446\r
447 if (*KeySym < XK_BackSpace) {\r
448 if (((Drv->KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) ||\r
449 ((Drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0) ) {\r
450\r
451 KeyData.Key.UnicodeChar = (CHAR16)KeySym[KEYSYM_UPPER];\r
452\r
453 // Per UEFI spec since we converted the Unicode clear the shift bits we pass up\r
454 KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);\r
455 } else {\r
456 KeyData.Key.UnicodeChar = (CHAR16)KeySym[KEYSYM_LOWER];\r
457 }\r
458 } else {\r
459 // XK_BackSpace is the start of XK_MISCELLANY. These are the XK_? keys we process in this file\r
460 ;\r
461 }\r
462\r
463 if (Make) {\r
464 memcpy (&Drv->keys[Drv->key_wr], &KeyData, sizeof (EFI_KEY_DATA));\r
465 Drv->key_wr = (Drv->key_wr + 1) % NBR_KEYS;\r
466 Drv->key_count++;\r
467 if (Drv->MakeRegisterdKeyCallback != NULL) {\r
468 ReverseGasketUint64Uint64 (Drv->MakeRegisterdKeyCallback ,Drv->RegisterdKeyCallbackContext, &KeyData);\r
469 }\r
470 } else {\r
471 if (Drv->BreakRegisterdKeyCallback != NULL) {\r
472 ReverseGasketUint64Uint64 (Drv->BreakRegisterdKeyCallback ,Drv->RegisterdKeyCallbackContext, &KeyData);\r
473 }\r
474 }\r
475}\r
476\r
477\r
478void\r
479handleMouseMoved(\r
480 IN GRAPHICS_IO_PRIVATE *Drv,\r
481 IN XEvent *ev\r
482 )\r
483{\r
484 if (ev->xmotion.x != Drv->previous_x) {\r
485 Drv->pointer_state.RelativeMovementX += ( ev->xmotion.x - Drv->previous_x );\r
486 Drv->previous_x = ev->xmotion.x;\r
487 Drv->pointer_state_changed = 1;\r
488 }\r
489\r
490 if (ev->xmotion.y != Drv->previous_y) {\r
491 Drv->pointer_state.RelativeMovementY += ( ev->xmotion.y - Drv->previous_y );\r
492 Drv->previous_y = ev->xmotion.y;\r
493 Drv->pointer_state_changed = 1;\r
494 }\r
495\r
496 Drv->pointer_state.RelativeMovementZ = 0;\r
497}\r
498\r
499void\r
500handleMouseDown (\r
501 IN GRAPHICS_IO_PRIVATE *Drv,\r
502 IN XEvent *ev,\r
503 IN BOOLEAN Pressed\r
504 )\r
505{\r
506 if (ev->xbutton.button == Button1) {\r
507 Drv->pointer_state_changed = (Drv->pointer_state.LeftButton != Pressed);\r
508 Drv->pointer_state.LeftButton = Pressed;\r
509 }\r
510 if ( ev->xbutton.button == Button2 ) {\r
511 Drv->pointer_state_changed = (Drv->pointer_state.RightButton != Pressed);\r
512 Drv->pointer_state.RightButton = Pressed;\r
513 }\r
514}\r
515\r
516void\r
517Redraw (\r
518 IN GRAPHICS_IO_PRIVATE *Drv,\r
519 IN UINTN X,\r
520 IN UINTN Y,\r
521 IN UINTN Width,\r
522 IN UINTN Height\r
523 )\r
524{\r
525 if (Drv->use_shm) {\r
526 XShmPutImage (\r
527 Drv->display, Drv->win, Drv->gc, Drv->image, X, Y, X, Y, Width, Height, False\r
528 );\r
529 } else {\r
530 XPutImage (\r
531 Drv->display, Drv->win, Drv->gc, Drv->image, X, Y, X, Y, Width, Height\r
532 );\r
533 }\r
534 XFlush(Drv->display);\r
535}\r
536\r
537void\r
538HandleEvent(GRAPHICS_IO_PRIVATE *Drv, XEvent *ev)\r
539{\r
540 switch (ev->type) {\r
541 case Expose:\r
542 Redraw (Drv, ev->xexpose.x, ev->xexpose.y,\r
543 ev->xexpose.width, ev->xexpose.height);\r
544 break;\r
545 case GraphicsExpose:\r
546 Redraw (Drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,\r
547 ev->xgraphicsexpose.width, ev->xgraphicsexpose.height);\r
548 break;\r
549 case KeyPress:\r
550 handleKeyEvent (Drv, ev, TRUE);\r
551 break;\r
552 case KeyRelease:\r
553 handleKeyEvent (Drv, ev, FALSE);\r
554 break;\r
555 case MappingNotify:\r
556 XRefreshKeyboardMapping (&ev->xmapping);\r
557 break;\r
558 case MotionNotify:\r
559 handleMouseMoved (Drv, ev);\r
560 break;\r
561 case ButtonPress:\r
562 handleMouseDown (Drv, ev, TRUE);\r
563 break;\r
564 case ButtonRelease:\r
565 handleMouseDown (Drv, ev, FALSE);\r
566 break;\r
567#if 0\r
568 case DestroyNotify:\r
569 XCloseDisplay (Drv->display);\r
570 exit (1);\r
571 break;\r
572#endif\r
573 case NoExpose:\r
574 default:\r
575 break;\r
576 }\r
577}\r
578\r
579void\r
580HandleEvents (\r
581 IN GRAPHICS_IO_PRIVATE *Drv\r
582 )\r
583{\r
584 XEvent ev;\r
585\r
586 while (XPending (Drv->display) != 0) {\r
587 XNextEvent (Drv->display, &ev);\r
588 HandleEvent (Drv, &ev);\r
589 }\r
590}\r
591\r
592unsigned long\r
593X11PixelToColor (\r
594 IN GRAPHICS_IO_PRIVATE *Drv,\r
595 IN EFI_UGA_PIXEL pixel\r
596 )\r
597{\r
598 return ((pixel.Red >> Drv->r.csize) << Drv->r.shift)\r
599 | ((pixel.Green >> Drv->g.csize) << Drv->g.shift)\r
600 | ((pixel.Blue >> Drv->b.csize) << Drv->b.shift);\r
601}\r
602\r
603EFI_UGA_PIXEL\r
604X11ColorToPixel (\r
605 IN GRAPHICS_IO_PRIVATE *Drv,\r
606 IN unsigned long val\r
607 )\r
608{\r
609 EFI_UGA_PIXEL Pixel;\r
610\r
611 memset (&Pixel, 0, sizeof (EFI_UGA_PIXEL));\r
612\r
613 // Truncation not an issue since X11 and EFI are both using 8 bits per color\r
614 Pixel.Red = (val >> Drv->r.shift) << Drv->r.csize;\r
615 Pixel.Green = (val >> Drv->g.shift) << Drv->g.csize;\r
616 Pixel.Blue = (val >> Drv->b.shift) << Drv->b.csize;\r
617\r
618 return Pixel;\r
619}\r
620\r
621\r
622EFI_STATUS\r
623X11CheckKey (\r
624 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo\r
625 )\r
626{\r
627 GRAPHICS_IO_PRIVATE *Drv;\r
628\r
629 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;\r
630\r
631 HandleEvents (Drv);\r
632\r
633 if (Drv->key_count != 0) {\r
634 return EFI_SUCCESS;\r
635 }\r
636\r
637 return EFI_NOT_READY;\r
638}\r
639\r
640EFI_STATUS\r
641X11GetKey (\r
642 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,\r
643 IN EFI_KEY_DATA *KeyData\r
644 )\r
645{\r
646 EFI_STATUS EfiStatus;\r
647 GRAPHICS_IO_PRIVATE *Drv;\r
648\r
649 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;\r
650\r
651 EfiStatus = X11CheckKey (GraphicsIo);\r
652 if (EFI_ERROR (EfiStatus)) {\r
653 return EfiStatus;\r
654 }\r
655\r
656 CopyMem (KeyData, &Drv->keys[Drv->key_rd], sizeof (EFI_KEY_DATA));\r
657 Drv->key_rd = (Drv->key_rd + 1) % NBR_KEYS;\r
658 Drv->key_count--;\r
659\r
660 return EFI_SUCCESS;\r
661}\r
662\r
663\r
664EFI_STATUS\r
665X11KeySetState (\r
666 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,\r
667 IN EFI_KEY_TOGGLE_STATE *KeyToggleState\r
668 )\r
669{\r
670 GRAPHICS_IO_PRIVATE *Drv;\r
671\r
672 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;\r
673\r
674 if (*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) {\r
675 if ((Drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == 0) {\r
676 //\r
677 // We could create an XKeyEvent and send a XK_Caps_Lock to\r
678 // the UGA/GOP Window\r
679 //\r
680 }\r
681 }\r
682\r
683 Drv->KeyState.KeyToggleState = *KeyToggleState;\r
684 return EFI_SUCCESS;\r
685}\r
686\r
687\r
688EFI_STATUS\r
689X11RegisterKeyNotify (\r
690 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,\r
691 IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeCallBack,\r
692 IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakCallBack,\r
693 IN VOID *Context\r
694 )\r
695{\r
696 GRAPHICS_IO_PRIVATE *Drv;\r
697\r
698 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;\r
699\r
700 Drv->MakeRegisterdKeyCallback = MakeCallBack;\r
701 Drv->BreakRegisterdKeyCallback = BreakCallBack;\r
702 Drv->RegisterdKeyCallbackContext = Context;\r
703\r
704 return EFI_SUCCESS;\r
705}\r
706\r
707\r
708EFI_STATUS\r
709X11Blt (\r
710 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,\r
711 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,\r
712 IN EFI_UGA_BLT_OPERATION BltOperation,\r
713 IN EMU_GRAPHICS_WINDOWS__BLT_ARGS *Args\r
714 )\r
715{\r
716 GRAPHICS_IO_PRIVATE *Private;\r
717 UINTN DstY;\r
718 UINTN SrcY;\r
719 UINTN DstX;\r
720 UINTN SrcX;\r
721 UINTN Index;\r
722 EFI_UGA_PIXEL *Blt;\r
723 UINT8 *Dst;\r
724 UINT8 *Src;\r
725 UINTN Nbr;\r
726 unsigned long Color;\r
727 XEvent ev;\r
728\r
729 Private = (GRAPHICS_IO_PRIVATE *)GraphicsIo;\r
730\r
731\r
732 //\r
733 // Check bounds\r
734 //\r
735 if (BltOperation == EfiUgaVideoToBltBuffer\r
736 || BltOperation == EfiUgaVideoToVideo) {\r
737 //\r
738 // Source is Video.\r
739 //\r
740 if (Args->SourceY + Args->Height > Private->height) {\r
741 return EFI_INVALID_PARAMETER;\r
742 }\r
743\r
744 if (Args->SourceX + Args->Width > Private->width) {\r
745 return EFI_INVALID_PARAMETER;\r
746 }\r
747 }\r
748\r
749 if (BltOperation == EfiUgaBltBufferToVideo\r
750 || BltOperation == EfiUgaVideoToVideo\r
751 || BltOperation == EfiUgaVideoFill) {\r
752 //\r
753 // Destination is Video\r
754 //\r
755 if (Args->DestinationY + Args->Height > Private->height) {\r
756 return EFI_INVALID_PARAMETER;\r
757 }\r
758\r
759 if (Args->DestinationX + Args->Width > Private->width) {\r
760 return EFI_INVALID_PARAMETER;\r
761 }\r
762 }\r
763\r
764 switch (BltOperation) {\r
765 case EfiUgaVideoToBltBuffer:\r
766 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->DestinationY * Args->Delta) + Args->DestinationX * sizeof (EFI_UGA_PIXEL));\r
767 Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL);\r
768 for (SrcY = Args->SourceY; SrcY < (Args->Height + Args->SourceY); SrcY++) {\r
769 for (SrcX = Args->SourceX; SrcX < (Args->Width + Args->SourceX); SrcX++) {\r
770 *Blt++ = X11ColorToPixel (Private, XGetPixel (Private->image, SrcX, SrcY));\r
771 }\r
772 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta);\r
773 }\r
774 break;\r
775 case EfiUgaBltBufferToVideo:\r
776 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->SourceY * Args->Delta) + Args->SourceX * sizeof (EFI_UGA_PIXEL));\r
777 Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL);\r
778 for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) {\r
779 for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) {\r
780 XPutPixel(Private->image, DstX, DstY, X11PixelToColor(Private, *Blt));\r
781 Blt++;\r
782 }\r
783 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta);\r
784 }\r
785 break;\r
786 case EfiUgaVideoToVideo:\r
787 Dst = Private->image_data + (Args->DestinationX << Private->pixel_shift)\r
788 + Args->DestinationY * Private->line_bytes;\r
789 Src = Private->image_data + (Args->SourceX << Private->pixel_shift)\r
790 + Args->SourceY * Private->line_bytes;\r
791 Nbr = Args->Width << Private->pixel_shift;\r
792 if (Args->DestinationY < Args->SourceY) {\r
793 for (Index = 0; Index < Args->Height; Index++) {\r
794 memcpy (Dst, Src, Nbr);\r
795 Dst += Private->line_bytes;\r
796 Src += Private->line_bytes;\r
797 }\r
798 } else {\r
799 Dst += (Args->Height - 1) * Private->line_bytes;\r
800 Src += (Args->Height - 1) * Private->line_bytes;\r
801 for (Index = 0; Index < Args->Height; Index++) {\r
802 //\r
803 // Source and Destination Y may be equal, therefore Dst and Src may\r
804 // overlap.\r
805 //\r
806 memmove (Dst, Src, Nbr);\r
807 Dst -= Private->line_bytes;\r
808 Src -= Private->line_bytes;\r
809 }\r
810 }\r
811 break;\r
812 case EfiUgaVideoFill:\r
813 Color = X11PixelToColor(Private, *BltBuffer);\r
814 for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) {\r
815 for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) {\r
816 XPutPixel(Private->image, DstX, DstY, Color);\r
817 }\r
818 }\r
819 break;\r
820 default:\r
821 return EFI_INVALID_PARAMETER;\r
822 }\r
823\r
824 //\r
825 // Refresh screen.\r
826 //\r
827 switch (BltOperation) {\r
828 case EfiUgaVideoToVideo:\r
829 XCopyArea(\r
830 Private->display, Private->win, Private->win, Private->gc,\r
831 Args->SourceX, Args->SourceY, Args->Width, Args->Height,\r
832 Args->DestinationX, Args->DestinationY\r
833 );\r
834\r
835 while (1) {\r
836 XNextEvent (Private->display, &ev);\r
837 HandleEvent (Private, &ev);\r
838 if (ev.type == NoExpose || ev.type == GraphicsExpose) {\r
839 break;\r
840 }\r
841 }\r
842 break;\r
843 case EfiUgaVideoFill:\r
844 Color = X11PixelToColor (Private, *BltBuffer);\r
845 XSetForeground (Private->display, Private->gc, Color);\r
846 XFillRectangle (\r
847 Private->display, Private->win, Private->gc,\r
848 Args->DestinationX, Args->DestinationY, Args->Width, Args->Height\r
849 );\r
850 XFlush (Private->display);\r
851 break;\r
852 case EfiUgaBltBufferToVideo:\r
853 Redraw (Private, Args->DestinationX, Args->DestinationY, Args->Width, Args->Height);\r
854 break;\r
855 default:\r
856 break;\r
857 }\r
858 return EFI_SUCCESS;\r
859}\r
860\r
861\r
862EFI_STATUS\r
863X11CheckPointer (\r
864 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo\r
865 )\r
866{\r
867 GRAPHICS_IO_PRIVATE *Drv;\r
868\r
869 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;\r
870\r
871 HandleEvents (Drv);\r
872 if (Drv->pointer_state_changed != 0) {\r
873 return EFI_SUCCESS;\r
874 }\r
875\r
876 return EFI_NOT_READY;\r
877}\r
878\r
879\r
880EFI_STATUS\r
881X11GetPointerState (\r
882 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,\r
883 IN EFI_SIMPLE_POINTER_STATE *State\r
884 )\r
885{\r
886 EFI_STATUS EfiStatus;\r
887 GRAPHICS_IO_PRIVATE *Drv;\r
888\r
889 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;\r
890\r
891 EfiStatus = X11CheckPointer (GraphicsIo);\r
892 if (EfiStatus != EFI_SUCCESS) {\r
893 return EfiStatus;\r
894 }\r
895\r
896 memcpy (State, &Drv->pointer_state, sizeof (EFI_SIMPLE_POINTER_STATE));\r
897\r
898 Drv->pointer_state.RelativeMovementX = 0;\r
899 Drv->pointer_state.RelativeMovementY = 0;\r
900 Drv->pointer_state.RelativeMovementZ = 0;\r
901 Drv->pointer_state_changed = 0;\r
902 return EFI_SUCCESS;\r
903}\r
904\r
905\r
906\r
907EFI_STATUS\r
908X11GraphicsWindowOpen (\r
909 IN EMU_IO_THUNK_PROTOCOL *This\r
910 )\r
911{\r
912 GRAPHICS_IO_PRIVATE *Drv;\r
913 unsigned int border_width = 0;\r
914 char *display_name = NULL;\r
915\r
916 Drv = (GRAPHICS_IO_PRIVATE *)calloc (1, sizeof (GRAPHICS_IO_PRIVATE));\r
917 if (Drv == NULL) {\r
918 return EFI_OUT_OF_RESOURCES;\r
919 }\r
920\r
921 Drv->GraphicsIo.Size = GasketX11Size;\r
922 Drv->GraphicsIo.CheckKey = GasketX11CheckKey;\r
923 Drv->GraphicsIo.GetKey = GasketX11GetKey;\r
924 Drv->GraphicsIo.KeySetState = GasketX11KeySetState;\r
925 Drv->GraphicsIo.RegisterKeyNotify = GasketX11RegisterKeyNotify;\r
926 Drv->GraphicsIo.Blt = GasketX11Blt;\r
927 Drv->GraphicsIo.CheckPointer = GasketX11CheckPointer;\r
928 Drv->GraphicsIo.GetPointerState = GasketX11GetPointerState;\r
929\r
930\r
931 Drv->key_count = 0;\r
932 Drv->key_rd = 0;\r
933 Drv->key_wr = 0;\r
934 Drv->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;\r
935 Drv->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
936 Drv->MakeRegisterdKeyCallback = NULL;\r
937 Drv->BreakRegisterdKeyCallback = NULL;\r
938 Drv->RegisterdKeyCallbackContext = NULL;\r
939\r
940\r
941 Drv->display = XOpenDisplay (display_name);\r
942 if (Drv->display == NULL) {\r
943 fprintf (stderr, "uga: cannot connect to X server %s\n", XDisplayName (display_name));\r
944 free (Drv);\r
945 return EFI_DEVICE_ERROR;\r
946 }\r
947 Drv->screen = DefaultScreen (Drv->display);\r
948 Drv->visual = DefaultVisual (Drv->display, Drv->screen);\r
949 Drv->win = XCreateSimpleWindow (\r
950 Drv->display, RootWindow (Drv->display, Drv->screen),\r
951 0, 0, 4, 4, border_width,\r
952 WhitePixel (Drv->display, Drv->screen),\r
953 BlackPixel (Drv->display, Drv->screen)\r
954 );\r
955\r
956 Drv->depth = DefaultDepth (Drv->display, Drv->screen);\r
957 XDefineCursor (Drv->display, Drv->win, XCreateFontCursor (Drv->display, XC_pirate));\r
958\r
959 Drv->Title = malloc (StrSize (This->ConfigString));\r
960 UnicodeStrToAsciiStr (This->ConfigString, Drv->Title);\r
961 XStoreName (Drv->display, Drv->win, Drv->Title);\r
962\r
963// XAutoRepeatOff (Drv->display);\r
964 XSelectInput (\r
965 Drv->display, Drv->win,\r
966 ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask\r
967 );\r
968 Drv->gc = DefaultGC (Drv->display, Drv->screen);\r
969\r
970 This->Private = (VOID *)Drv;\r
971 This->Interface = (VOID *)Drv;\r
972 return EFI_SUCCESS;\r
973}\r
974\r
975\r
976EFI_STATUS\r
977X11GraphicsWindowClose (\r
978 IN EMU_IO_THUNK_PROTOCOL *This\r
979 )\r
980{\r
981 GRAPHICS_IO_PRIVATE *Drv;\r
982\r
983 Drv = (GRAPHICS_IO_PRIVATE *)This->Private;\r
984\r
985 if (Drv == NULL) {\r
986 return EFI_SUCCESS;\r
987 }\r
988\r
989 if (Drv->image != NULL) {\r
990 XDestroyImage(Drv->image);\r
991\r
992 if (Drv->use_shm) {\r
993 shmdt (Drv->image_data);\r
994 }\r
995\r
996 Drv->image_data = NULL;\r
997 Drv->image = NULL;\r
998 }\r
999 XDestroyWindow (Drv->display, Drv->win);\r
1000 XCloseDisplay (Drv->display);\r
1001\r
1002#ifdef __APPLE__\r
1003 // Free up the shared memory\r
1004 shmctl (Drv->xshm_info.shmid, IPC_RMID, NULL);\r
1005#endif\r
1006\r
1007 free (Drv);\r
1008 return EFI_SUCCESS;\r
1009}\r
1010\r
1011\r
1012EMU_IO_THUNK_PROTOCOL gX11ThunkIo = {\r
1013 &gEmuGraphicsWindowProtocolGuid,\r
1014 NULL,\r
1015 NULL,\r
1016 0,\r
1017 GasketX11GraphicsWindowOpen,\r
1018 GasketX11GraphicsWindowClose,\r
1019 NULL\r
1020};\r
1021\r
1022\r