TianoCore EDK2 master
Loading...
Searching...
No Matches
X11GraphicsWindow.c
1/*++ @file
2
3Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
4Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
5
6SPDX-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
26 unsigned char shift;
27 unsigned char size;
28 unsigned char csize;
29};
30
31#define NBR_KEYS 32
32typedef struct {
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;
71
72void
73HandleEvents (
75 );
76
77void
78fill_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
98int
99TryCreateShmImage (
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
167X11Size (
169 IN UINT32 Width,
170 IN UINT32 Height
171 )
172{
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
239void
240handleKeyEvent (
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
553void
554handleMouseMoved (
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
574void
575handleMouseDown (
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
592void
593Redraw (
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
633void
634HandleEvent (
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
688void
689HandleEvents (
691 )
692{
693 XEvent ev;
694
695 while (XPending (Drv->display) != 0) {
696 XNextEvent (Drv->display, &ev);
697 HandleEvent (Drv, &ev);
698 }
699}
700
701unsigned long
702X11PixelToColor (
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
713X11ColorToPixel (
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
731X11CheckKey (
733 )
734{
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
749X11GetKey (
751 IN EFI_KEY_DATA *KeyData
752 )
753{
754 EFI_STATUS EfiStatus;
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
772X11KeySetState (
774 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
775 )
776{
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
795X11RegisterKeyNotify (
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{
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
814X11Blt (
816 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
817 IN EFI_UGA_BLT_OPERATION BltOperation,
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) {
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;
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;
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) {
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;
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
988X11CheckPointer (
990 )
991{
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
1005X11GetPointerState (
1006 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
1008 )
1009{
1010 EFI_STATUS EfiStatus;
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
1030X11GraphicsWindowOpen (
1032 )
1033{
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
1103X11GraphicsWindowClose (
1105 )
1106{
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
1138EMU_IO_THUNK_PROTOCOL gX11ThunkIo = {
1139 &gEmuGraphicsWindowProtocolGuid,
1140 NULL,
1141 NULL,
1142 0,
1143 GasketX11GraphicsWindowOpen,
1144 GasketX11GraphicsWindowClose,
1145 NULL
1146};
UINT64 UINTN
UINTN EFIAPI StrSize(IN CONST CHAR16 *String)
Definition: String.c:72
RETURN_STATUS EFIAPI UnicodeStrToAsciiStrS(IN CONST CHAR16 *Source, OUT CHAR8 *Destination, IN UINTN DestMax)
Definition: SafeString.c:2650
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
UINT8 EFI_KEY_TOGGLE_STATE
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_UGA_BLT_OPERATION
Definition: UgaDraw.h:83
@ EfiUgaVideoToVideo
Definition: UgaDraw.h:103
@ EfiUgaVideoToBltBuffer
Definition: UgaDraw.h:89
@ EfiUgaBltBufferToVideo
Definition: UgaDraw.h:96
@ EfiUgaVideoFill
Definition: UgaDraw.h:84
EFI_KEY_TOGGLE_STATE KeyToggleState
UINT32 KeyShiftState
EFI_INPUT_KEY Key
EFI_KEY_STATE KeyState