]> git.proxmox.com Git - mirror_edk2.git/blob - InOsEmuPkg/Unix/Sec/X11GraphicsWindow.c
72c4544ce592db73e83909bcc9d0b32eeb2f38e0
[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 EFI_STATUS
628 CheckKeyInternal (
629 IN GRAPHICS_IO_PRIVATE *Drv,
630 IN BOOLEAN delay
631 )
632 {
633 HandleEvents (Drv);
634
635 if (Drv->key_count != 0) {
636 return EFI_SUCCESS;
637 }
638
639 if (delay) {
640 // EFI is polling. Be CPU-friendly.
641 SecSleep (20);
642 }
643 return EFI_NOT_READY;
644 }
645
646 EFI_STATUS
647 X11CheckKey (
648 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
649 )
650 {
651 GRAPHICS_IO_PRIVATE *Drv;
652
653 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
654
655 return CheckKeyInternal (Drv, TRUE);
656 }
657
658 EFI_STATUS
659 EFIAPI
660 X11GetKey (
661 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
662 IN EFI_KEY_DATA *KeyData
663 )
664 {
665 EFI_STATUS EfiStatus;
666 GRAPHICS_IO_PRIVATE *Drv;
667
668 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
669
670 EfiStatus = CheckKeyInternal (Drv, FALSE);
671 if (EFI_ERROR (EfiStatus)) {
672 return EfiStatus;
673 }
674
675 CopyMem (KeyData, &Drv->keys[Drv->key_rd], sizeof (EFI_KEY_DATA));
676 Drv->key_rd = (Drv->key_rd + 1) % NBR_KEYS;
677 Drv->key_count--;
678
679 return EFI_SUCCESS;
680 }
681
682
683 EFI_STATUS
684 EFIAPI
685 X11KeySetState (
686 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
687 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
688 )
689 {
690 GRAPHICS_IO_PRIVATE *Drv;
691
692 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
693
694 if (*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) {
695 if ((Drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == 0) {
696 //
697 // We could create an XKeyEvent and send a XK_Caps_Lock to
698 // the UGA/GOP Window
699 //
700 }
701 }
702
703 Drv->KeyState.KeyToggleState = *KeyToggleState;
704 return EFI_SUCCESS;
705 }
706
707
708 EFI_STATUS
709 EFIAPI
710 X11RegisterKeyNotify (
711 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
712 IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeCallBack,
713 IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakCallBack,
714 IN VOID *Context
715 )
716 {
717 GRAPHICS_IO_PRIVATE *Drv;
718
719 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
720
721 Drv->MakeRegisterdKeyCallback = MakeCallBack;
722 Drv->BreakRegisterdKeyCallback = BreakCallBack;
723 Drv->RegisterdKeyCallbackContext = Context;
724
725 return EFI_SUCCESS;
726 }
727
728
729 EFI_STATUS
730 X11Blt (
731 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
732 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
733 IN EFI_UGA_BLT_OPERATION BltOperation,
734 IN EMU_GRAPHICS_WINDOWS__BLT_ARGS *Args
735 )
736 {
737 GRAPHICS_IO_PRIVATE *Private;
738 UINTN DstY;
739 UINTN SrcY;
740 UINTN DstX;
741 UINTN SrcX;
742 UINTN Index;
743 EFI_UGA_PIXEL *Blt;
744 UINT8 *Dst;
745 UINT8 *Src;
746 UINTN Nbr;
747 unsigned long Color;
748 XEvent ev;
749
750 Private = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
751
752
753 //
754 // Check bounds
755 //
756 if (BltOperation == EfiUgaVideoToBltBuffer
757 || BltOperation == EfiUgaVideoToVideo) {
758 //
759 // Source is Video.
760 //
761 if (Args->SourceY + Args->Height > Private->height) {
762 return EFI_INVALID_PARAMETER;
763 }
764
765 if (Args->SourceX + Args->Width > Private->width) {
766 return EFI_INVALID_PARAMETER;
767 }
768 }
769
770 if (BltOperation == EfiUgaBltBufferToVideo
771 || BltOperation == EfiUgaVideoToVideo
772 || BltOperation == EfiUgaVideoFill) {
773 //
774 // Destination is Video
775 //
776 if (Args->DestinationY + Args->Height > Private->height) {
777 return EFI_INVALID_PARAMETER;
778 }
779
780 if (Args->DestinationX + Args->Width > Private->width) {
781 return EFI_INVALID_PARAMETER;
782 }
783 }
784
785 switch (BltOperation) {
786 case EfiUgaVideoToBltBuffer:
787 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->DestinationY * Args->Delta) + Args->DestinationX * sizeof (EFI_UGA_PIXEL));
788 Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL);
789 for (SrcY = Args->SourceY; SrcY < (Args->Height + Args->SourceY); SrcY++) {
790 for (SrcX = Args->SourceX; SrcX < (Args->Width + Args->SourceX); SrcX++) {
791 *Blt++ = X11ColorToPixel (Private, XGetPixel (Private->image, SrcX, SrcY));
792 }
793 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta);
794 }
795 break;
796 case EfiUgaBltBufferToVideo:
797 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->SourceY * Args->Delta) + Args->SourceX * sizeof (EFI_UGA_PIXEL));
798 Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL);
799 for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) {
800 for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) {
801 XPutPixel(Private->image, DstX, DstY, X11PixelToColor(Private, *Blt));
802 Blt++;
803 }
804 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta);
805 }
806 break;
807 case EfiUgaVideoToVideo:
808 Dst = Private->image_data + (Args->DestinationX << Private->pixel_shift)
809 + Args->DestinationY * Private->line_bytes;
810 Src = Private->image_data + (Args->SourceX << Private->pixel_shift)
811 + Args->SourceY * Private->line_bytes;
812 Nbr = Args->Width << Private->pixel_shift;
813 if (Args->DestinationY < Args->SourceY) {
814 for (Index = 0; Index < Args->Height; Index++) {
815 memcpy (Dst, Src, Nbr);
816 Dst += Private->line_bytes;
817 Src += Private->line_bytes;
818 }
819 } else {
820 Dst += (Args->Height - 1) * Private->line_bytes;
821 Src += (Args->Height - 1) * Private->line_bytes;
822 for (Index = 0; Index < Args->Height; Index++) {
823 //
824 // Source and Destination Y may be equal, therefore Dst and Src may
825 // overlap.
826 //
827 memmove (Dst, Src, Nbr);
828 Dst -= Private->line_bytes;
829 Src -= Private->line_bytes;
830 }
831 }
832 break;
833 case EfiUgaVideoFill:
834 Color = X11PixelToColor(Private, *BltBuffer);
835 for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) {
836 for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) {
837 XPutPixel(Private->image, DstX, DstY, Color);
838 }
839 }
840 break;
841 default:
842 return EFI_INVALID_PARAMETER;
843 }
844
845 //
846 // Refresh screen.
847 //
848 switch (BltOperation) {
849 case EfiUgaVideoToVideo:
850 XCopyArea(
851 Private->display, Private->win, Private->win, Private->gc,
852 Args->SourceX, Args->SourceY, Args->Width, Args->Height,
853 Args->DestinationX, Args->DestinationY
854 );
855
856 while (1) {
857 XNextEvent (Private->display, &ev);
858 HandleEvent (Private, &ev);
859 if (ev.type == NoExpose || ev.type == GraphicsExpose) {
860 break;
861 }
862 }
863 break;
864 case EfiUgaVideoFill:
865 Color = X11PixelToColor (Private, *BltBuffer);
866 XSetForeground (Private->display, Private->gc, Color);
867 XFillRectangle (
868 Private->display, Private->win, Private->gc,
869 Args->DestinationX, Args->DestinationY, Args->Width, Args->Height
870 );
871 XFlush (Private->display);
872 break;
873 case EfiUgaBltBufferToVideo:
874 Redraw (Private, Args->DestinationX, Args->DestinationY, Args->Width, Args->Height);
875 break;
876 default:
877 break;
878 }
879 return EFI_SUCCESS;
880 }
881
882 EFI_STATUS
883 CheckPointerInternal (
884 IN GRAPHICS_IO_PRIVATE *Drv,
885 IN BOOLEAN delay
886 )
887 {
888 HandleEvents (Drv);
889 if (Drv->pointer_state_changed != 0) {
890 return EFI_SUCCESS;
891 }
892
893 if ( delay ) {
894 // EFI is polling. Be CPU-friendly.
895 SecSleep (20);
896 }
897
898 return EFI_NOT_READY;
899 }
900
901 EFI_STATUS
902 X11CheckPointer (
903 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
904 )
905 {
906 GRAPHICS_IO_PRIVATE *Drv;
907
908 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
909
910 return CheckPointerInternal (Drv, TRUE);
911 }
912
913 EFI_STATUS
914 X11GetPointerState (EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, EFI_SIMPLE_POINTER_STATE *state)
915 {
916 EFI_STATUS EfiStatus;
917 GRAPHICS_IO_PRIVATE *Drv;
918
919 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
920
921 EfiStatus = CheckPointerInternal (Drv, FALSE);
922 if (EfiStatus != EFI_SUCCESS) {
923 return EfiStatus;
924 }
925
926 memcpy (state, &Drv->pointer_state, sizeof (EFI_SIMPLE_POINTER_STATE));
927
928 Drv->pointer_state.RelativeMovementX = 0;
929 Drv->pointer_state.RelativeMovementY = 0;
930 Drv->pointer_state.RelativeMovementZ = 0;
931 Drv->pointer_state_changed = 0;
932 return EFI_SUCCESS;
933 }
934
935
936
937 EFI_STATUS
938 X11GraphicsWindowOpen (
939 IN EMU_IO_THUNK_PROTOCOL *This
940 )
941 {
942 GRAPHICS_IO_PRIVATE *Drv;
943 unsigned int border_width = 0;
944 char *display_name = NULL;
945
946 Drv = (GRAPHICS_IO_PRIVATE *)calloc (1, sizeof (GRAPHICS_IO_PRIVATE));
947 if (Drv == NULL) {
948 return EFI_OUT_OF_RESOURCES;
949 }
950
951 Drv->GraphicsIo.Size = GasketX11Size;
952 Drv->GraphicsIo.CheckKey = GasketX11CheckKey;
953 Drv->GraphicsIo.GetKey = GasketX11GetKey;
954 Drv->GraphicsIo.KeySetState = GasketX11KeySetState;
955 Drv->GraphicsIo.RegisterKeyNotify = GasketX11RegisterKeyNotify;
956 Drv->GraphicsIo.Blt = GasketX11Blt;
957 Drv->GraphicsIo.CheckPointer = GasketX11CheckPointer;
958 Drv->GraphicsIo.GetPointerState = GasketX11GetPointerState;
959
960
961 Drv->key_count = 0;
962 Drv->key_rd = 0;
963 Drv->key_wr = 0;
964 Drv->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
965 Drv->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
966 Drv->MakeRegisterdKeyCallback = NULL;
967 Drv->BreakRegisterdKeyCallback = NULL;
968 Drv->RegisterdKeyCallbackContext = NULL;
969
970
971 Drv->display = XOpenDisplay (display_name);
972 if (Drv->display == NULL) {
973 fprintf (stderr, "uga: cannot connect to X server %s\n", XDisplayName (display_name));
974 free (Drv);
975 return EFI_DEVICE_ERROR;
976 }
977 Drv->screen = DefaultScreen (Drv->display);
978 Drv->visual = DefaultVisual (Drv->display, Drv->screen);
979 Drv->win = XCreateSimpleWindow (
980 Drv->display, RootWindow (Drv->display, Drv->screen),
981 0, 0, 4, 4, border_width,
982 WhitePixel (Drv->display, Drv->screen),
983 BlackPixel (Drv->display, Drv->screen)
984 );
985
986 Drv->depth = DefaultDepth (Drv->display, Drv->screen);
987 XDefineCursor (Drv->display, Drv->win, XCreateFontCursor (Drv->display, XC_pirate));
988
989 Drv->Title = malloc (StrSize (This->ConfigString));
990 UnicodeStrToAsciiStr (This->ConfigString, Drv->Title);
991 XStoreName (Drv->display, Drv->win, Drv->Title);
992
993 // XAutoRepeatOff (Drv->display);
994 XSelectInput (
995 Drv->display, Drv->win,
996 ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask
997 );
998 Drv->gc = DefaultGC (Drv->display, Drv->screen);
999
1000 This->Private = (VOID *)Drv;
1001 This->Interface = (VOID *)Drv;
1002 return EFI_SUCCESS;
1003 }
1004
1005
1006 EFI_STATUS
1007 X11GraphicsWindowClose (
1008 IN EMU_IO_THUNK_PROTOCOL *This
1009 )
1010 {
1011 GRAPHICS_IO_PRIVATE *Drv;
1012
1013 Drv = (GRAPHICS_IO_PRIVATE *)This->Private;
1014
1015 if (Drv == NULL) {
1016 return EFI_SUCCESS;
1017 }
1018
1019 if (Drv->image != NULL) {
1020 XDestroyImage(Drv->image);
1021
1022 if (Drv->use_shm) {
1023 shmdt (Drv->image_data);
1024 }
1025
1026 Drv->image_data = NULL;
1027 Drv->image = NULL;
1028 }
1029 XDestroyWindow (Drv->display, Drv->win);
1030 XCloseDisplay (Drv->display);
1031
1032 #ifdef __APPLE__
1033 // Free up the shared memory
1034 shmctl (Drv->xshm_info.shmid, IPC_RMID, NULL);
1035 #endif
1036
1037 free (Drv);
1038 return EFI_SUCCESS;
1039 }
1040
1041
1042 EMU_IO_THUNK_PROTOCOL gX11ThunkIo = {
1043 &gEmuGraphicsWindowProtocolGuid,
1044 NULL,
1045 NULL,
1046 0,
1047 GasketX11GraphicsWindowOpen,
1048 GasketX11GraphicsWindowClose,
1049 NULL
1050 };
1051
1052