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