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