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 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 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 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 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 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 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 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 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 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