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