/*++ @file Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.
Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Host.h" #include #include #include #include #include #include #include #include #define KEYSYM_LOWER 0 #define KEYSYM_UPPER 1 struct uga_drv_shift_mask { unsigned char shift; unsigned char size; unsigned char csize; }; #define NBR_KEYS 32 typedef struct { EMU_GRAPHICS_WINDOW_PROTOCOL GraphicsIo; Display *display; int screen; // values for window_size in main Window win; GC gc; Visual *visual; int depth; unsigned int width; unsigned int height; unsigned int line_bytes; unsigned int pixel_shift; unsigned char *image_data; struct uga_drv_shift_mask r, g, b; int use_shm; XShmSegmentInfo xshm_info; XImage *image; char *Title; unsigned int key_rd; unsigned int key_wr; unsigned int key_count; EFI_KEY_DATA keys[NBR_KEYS]; EFI_KEY_STATE KeyState; EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeRegisterdKeyCallback; EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakRegisterdKeyCallback; VOID *RegisterdKeyCallbackContext; int previous_x; int previous_y; EFI_SIMPLE_POINTER_STATE pointer_state; int pointer_state_changed; } GRAPHICS_IO_PRIVATE; void HandleEvents ( IN GRAPHICS_IO_PRIVATE *Drv ); void fill_shift_mask ( IN struct uga_drv_shift_mask *sm, IN unsigned long mask ) { sm->shift = 0; sm->size = 0; while ((mask & 1) == 0) { mask >>= 1; sm->shift++; } while (mask & 1) { sm->size++; mask >>= 1; } sm->csize = 8 - sm->size; } int TryCreateShmImage ( IN GRAPHICS_IO_PRIVATE *Drv ) { Drv->image = XShmCreateImage ( Drv->display, Drv->visual, Drv->depth, ZPixmap, NULL, &Drv->xshm_info, Drv->width, Drv->height ); if (Drv->image == NULL) { return 0; } switch (Drv->image->bitmap_unit) { case 32: Drv->pixel_shift = 2; break; case 16: Drv->pixel_shift = 1; break; case 8: Drv->pixel_shift = 0; break; } Drv->xshm_info.shmid = shmget ( IPC_PRIVATE, Drv->image->bytes_per_line * Drv->image->height, IPC_CREAT | 0777 ); if (Drv->xshm_info.shmid < 0) { XDestroyImage (Drv->image); return 0; } Drv->image_data = shmat (Drv->xshm_info.shmid, NULL, 0); if (!Drv->image_data) { shmctl (Drv->xshm_info.shmid, IPC_RMID, NULL); XDestroyImage (Drv->image); return 0; } #ifndef __APPLE__ // // This closes shared memory in real time on OS X. Only closes after folks quit using // it on Linux. // shmctl (Drv->xshm_info.shmid, IPC_RMID, NULL); #endif Drv->xshm_info.shmaddr = (char *)Drv->image_data; Drv->image->data = (char *)Drv->image_data; if (!XShmAttach (Drv->display, &Drv->xshm_info)) { shmdt (Drv->image_data); XDestroyImage (Drv->image); return 0; } return 1; } EFI_STATUS X11Size ( IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, IN UINT32 Width, IN UINT32 Height ) { GRAPHICS_IO_PRIVATE *Drv; XSizeHints size_hints; // Destroy current buffer if created. Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; if (Drv->image != NULL) { // Before destroy buffer, need to make sure the buffer available for access. XDestroyImage (Drv->image); if (Drv->use_shm) { shmdt (Drv->image_data); } Drv->image_data = NULL; Drv->image = NULL; } Drv->width = Width; Drv->height = Height; XResizeWindow (Drv->display, Drv->win, Width, Height); // Allocate image. if (XShmQueryExtension (Drv->display) && TryCreateShmImage (Drv)) { Drv->use_shm = 1; } else { Drv->use_shm = 0; if (Drv->depth > 16) { Drv->pixel_shift = 2; } else if (Drv->depth > 8) { Drv->pixel_shift = 1; } else { Drv->pixel_shift = 0; } Drv->image_data = malloc ((Drv->width * Drv->height) << Drv->pixel_shift); Drv->image = XCreateImage ( Drv->display, Drv->visual, Drv->depth, ZPixmap, 0, (char *)Drv->image_data, Drv->width, Drv->height, 8 << Drv->pixel_shift, 0 ); } Drv->line_bytes = Drv->image->bytes_per_line; fill_shift_mask (&Drv->r, Drv->image->red_mask); fill_shift_mask (&Drv->g, Drv->image->green_mask); fill_shift_mask (&Drv->b, Drv->image->blue_mask); // Set WM hints. size_hints.flags = PSize | PMinSize | PMaxSize; size_hints.min_width = size_hints.max_width = size_hints.base_width = Width; size_hints.min_height = size_hints.max_height = size_hints.base_height = Height; XSetWMNormalHints (Drv->display, Drv->win, &size_hints); XMapWindow (Drv->display, Drv->win); HandleEvents (Drv); return EFI_SUCCESS; } void handleKeyEvent ( IN GRAPHICS_IO_PRIVATE *Drv, IN XEvent *ev, IN BOOLEAN Make ) { KeySym *KeySym; EFI_KEY_DATA KeyData; int KeySymArraySize; if (Make) { if (Drv->key_count == NBR_KEYS) { return; } } // keycode is a physical key on the keyboard // KeySym is a mapping of a physical key // KeyboardMapping is the array of KeySym for a given keycode. key, shifted key, option key, command key, ... // // Returns an array of KeySymArraySize of KeySym for the keycode. [0] is lower case, [1] is upper case, // [2] and [3] are based on option and command modifiers. The problem we have is command V // could be mapped to a crazy Unicode character so the old scheme of returning a string. // KeySym = XGetKeyboardMapping (Drv->display, ev->xkey.keycode, 1, &KeySymArraySize); KeyData.Key.ScanCode = 0; KeyData.Key.UnicodeChar = 0; KeyData.KeyState.KeyShiftState = 0; // // Skipping EFI_SCROLL_LOCK_ACTIVE & EFI_NUM_LOCK_ACTIVE since they are not on Macs // if ((ev->xkey.state & LockMask) == 0) { Drv->KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE; } else { if (Make) { Drv->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE; } } // Skipping EFI_MENU_KEY_PRESSED and EFI_SYS_REQ_PRESSED switch (*KeySym) { case XK_Control_R: if (Make) { Drv->KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED; } else { Drv->KeyState.KeyShiftState &= ~EFI_RIGHT_CONTROL_PRESSED; } break; case XK_Control_L: if (Make) { Drv->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED; } else { Drv->KeyState.KeyShiftState &= ~EFI_LEFT_CONTROL_PRESSED; } break; case XK_Shift_R: if (Make) { Drv->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED; } else { Drv->KeyState.KeyShiftState &= ~EFI_RIGHT_SHIFT_PRESSED; } break; case XK_Shift_L: if (Make) { Drv->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED; } else { Drv->KeyState.KeyShiftState &= ~EFI_LEFT_SHIFT_PRESSED; } break; case XK_Mode_switch: if (Make) { Drv->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED; } else { Drv->KeyState.KeyShiftState &= ~EFI_LEFT_ALT_PRESSED; } break; case XK_Meta_R: if (Make) { Drv->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED; } else { Drv->KeyState.KeyShiftState &= ~EFI_RIGHT_LOGO_PRESSED; } break; case XK_Meta_L: if (Make) { Drv->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED; } else { Drv->KeyState.KeyShiftState &= ~EFI_LEFT_LOGO_PRESSED; } break; case XK_KP_Home: case XK_Home: KeyData.Key.ScanCode = SCAN_HOME; break; case XK_KP_End: case XK_End: KeyData.Key.ScanCode = SCAN_END; break; case XK_KP_Left: case XK_Left: KeyData.Key.ScanCode = SCAN_LEFT; break; case XK_KP_Right: case XK_Right: KeyData.Key.ScanCode = SCAN_RIGHT; break; case XK_KP_Up: case XK_Up: KeyData.Key.ScanCode = SCAN_UP; break; case XK_KP_Down: case XK_Down: KeyData.Key.ScanCode = SCAN_DOWN; break; case XK_KP_Delete: case XK_Delete: KeyData.Key.ScanCode = SCAN_DELETE; break; case XK_KP_Insert: case XK_Insert: KeyData.Key.ScanCode = SCAN_INSERT; break; case XK_KP_Page_Up: case XK_Page_Up: KeyData.Key.ScanCode = SCAN_PAGE_UP; break; case XK_KP_Page_Down: case XK_Page_Down: KeyData.Key.ScanCode = SCAN_PAGE_DOWN; break; case XK_Escape: KeyData.Key.ScanCode = SCAN_ESC; break; case XK_Pause: KeyData.Key.ScanCode = SCAN_PAUSE; break; case XK_KP_F1: case XK_F1: KeyData.Key.ScanCode = SCAN_F1; break; case XK_KP_F2: case XK_F2: KeyData.Key.ScanCode = SCAN_F2; break; case XK_KP_F3: case XK_F3: KeyData.Key.ScanCode = SCAN_F3; break; case XK_KP_F4: case XK_F4: KeyData.Key.ScanCode = SCAN_F4; break; case XK_F5: KeyData.Key.ScanCode = SCAN_F5; break; case XK_F6: KeyData.Key.ScanCode = SCAN_F6; break; case XK_F7: KeyData.Key.ScanCode = SCAN_F7; break; // Don't map into X11 by default on a Mac // System Preferences->Keyboard->Keyboard Shortcuts can be configured // to not use higher function keys as shortcuts and the will show up // in X11. case XK_F8: KeyData.Key.ScanCode = SCAN_F8; break; case XK_F9: KeyData.Key.ScanCode = SCAN_F9; break; case XK_F10: KeyData.Key.ScanCode = SCAN_F10; break; case XK_F11: KeyData.Key.ScanCode = SCAN_F11; break; case XK_F12: KeyData.Key.ScanCode = SCAN_F12; break; case XK_F13: KeyData.Key.ScanCode = SCAN_F13; break; case XK_F14: KeyData.Key.ScanCode = SCAN_F14; break; case XK_F15: KeyData.Key.ScanCode = SCAN_F15; break; case XK_F16: KeyData.Key.ScanCode = SCAN_F16; break; case XK_F17: KeyData.Key.ScanCode = SCAN_F17; break; case XK_F18: KeyData.Key.ScanCode = SCAN_F18; break; case XK_F19: KeyData.Key.ScanCode = SCAN_F19; break; case XK_F20: KeyData.Key.ScanCode = SCAN_F20; break; case XK_F21: KeyData.Key.ScanCode = SCAN_F21; break; case XK_F22: KeyData.Key.ScanCode = SCAN_F22; break; case XK_F23: KeyData.Key.ScanCode = SCAN_F23; break; case XK_F24: KeyData.Key.ScanCode = SCAN_F24; break; // No mapping in X11 // case XK_: KeyData.Key.ScanCode = SCAN_MUTE; break; // case XK_: KeyData.Key.ScanCode = SCAN_VOLUME_UP; break; // case XK_: KeyData.Key.ScanCode = SCAN_VOLUME_DOWN; break; // case XK_: KeyData.Key.ScanCode = SCAN_BRIGHTNESS_UP; break; // case XK_: KeyData.Key.ScanCode = SCAN_BRIGHTNESS_DOWN; break; // case XK_: KeyData.Key.ScanCode = SCAN_SUSPEND; break; // case XK_: KeyData.Key.ScanCode = SCAN_HIBERNATE; break; // case XK_: KeyData.Key.ScanCode = SCAN_TOGGLE_DISPLAY; break; // case XK_: KeyData.Key.ScanCode = SCAN_RECOVERY; break; // case XK_: KeyData.Key.ScanCode = SCAN_EJECT; break; case XK_BackSpace: KeyData.Key.UnicodeChar = 0x0008; break; case XK_KP_Tab: case XK_Tab: KeyData.Key.UnicodeChar = 0x0009; break; case XK_Linefeed: KeyData.Key.UnicodeChar = 0x000a; break; case XK_KP_Enter: case XK_Return: KeyData.Key.UnicodeChar = 0x000d; break; case XK_KP_Equal: KeyData.Key.UnicodeChar = L'='; break; case XK_KP_Multiply: KeyData.Key.UnicodeChar = L'*'; break; case XK_KP_Add: KeyData.Key.UnicodeChar = L'+'; break; case XK_KP_Separator: KeyData.Key.UnicodeChar = L'~'; break; case XK_KP_Subtract: KeyData.Key.UnicodeChar = L'-'; break; case XK_KP_Decimal: KeyData.Key.UnicodeChar = L'.'; break; case XK_KP_Divide: KeyData.Key.UnicodeChar = L'/'; break; case XK_KP_0: KeyData.Key.UnicodeChar = L'0'; break; case XK_KP_1: KeyData.Key.UnicodeChar = L'1'; break; case XK_KP_2: KeyData.Key.UnicodeChar = L'2'; break; case XK_KP_3: KeyData.Key.UnicodeChar = L'3'; break; case XK_KP_4: KeyData.Key.UnicodeChar = L'4'; break; case XK_KP_5: KeyData.Key.UnicodeChar = L'5'; break; case XK_KP_6: KeyData.Key.UnicodeChar = L'6'; break; case XK_KP_7: KeyData.Key.UnicodeChar = L'7'; break; case XK_KP_8: KeyData.Key.UnicodeChar = L'8'; break; case XK_KP_9: KeyData.Key.UnicodeChar = L'9'; break; default: ; } // The global state is our state KeyData.KeyState.KeyShiftState = Drv->KeyState.KeyShiftState; KeyData.KeyState.KeyToggleState = Drv->KeyState.KeyToggleState; if (*KeySym < XK_BackSpace) { if (((Drv->KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) || ((Drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0)) { KeyData.Key.UnicodeChar = (CHAR16)KeySym[KEYSYM_UPPER]; // Per UEFI spec since we converted the Unicode clear the shift bits we pass up KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED); } else { KeyData.Key.UnicodeChar = (CHAR16)KeySym[KEYSYM_LOWER]; } } else { // XK_BackSpace is the start of XK_MISCELLANY. These are the XK_? keys we process in this file } if (Make) { memcpy (&Drv->keys[Drv->key_wr], &KeyData, sizeof (EFI_KEY_DATA)); Drv->key_wr = (Drv->key_wr + 1) % NBR_KEYS; Drv->key_count++; if (Drv->MakeRegisterdKeyCallback != NULL) { ReverseGasketUint64Uint64 (Drv->MakeRegisterdKeyCallback, Drv->RegisterdKeyCallbackContext, &KeyData); } } else { if (Drv->BreakRegisterdKeyCallback != NULL) { ReverseGasketUint64Uint64 (Drv->BreakRegisterdKeyCallback, Drv->RegisterdKeyCallbackContext, &KeyData); } } } void handleMouseMoved ( IN GRAPHICS_IO_PRIVATE *Drv, IN XEvent *ev ) { if (ev->xmotion.x != Drv->previous_x) { Drv->pointer_state.RelativeMovementX += (ev->xmotion.x - Drv->previous_x); Drv->previous_x = ev->xmotion.x; Drv->pointer_state_changed = 1; } if (ev->xmotion.y != Drv->previous_y) { Drv->pointer_state.RelativeMovementY += (ev->xmotion.y - Drv->previous_y); Drv->previous_y = ev->xmotion.y; Drv->pointer_state_changed = 1; } Drv->pointer_state.RelativeMovementZ = 0; } void handleMouseDown ( IN GRAPHICS_IO_PRIVATE *Drv, IN XEvent *ev, IN BOOLEAN Pressed ) { if (ev->xbutton.button == Button1) { Drv->pointer_state_changed = (Drv->pointer_state.LeftButton != Pressed); Drv->pointer_state.LeftButton = Pressed; } if ( ev->xbutton.button == Button2 ) { Drv->pointer_state_changed = (Drv->pointer_state.RightButton != Pressed); Drv->pointer_state.RightButton = Pressed; } } void Redraw ( IN GRAPHICS_IO_PRIVATE *Drv, IN UINTN X, IN UINTN Y, IN UINTN Width, IN UINTN Height ) { if (Drv->use_shm) { XShmPutImage ( Drv->display, Drv->win, Drv->gc, Drv->image, X, Y, X, Y, Width, Height, False ); } else { XPutImage ( Drv->display, Drv->win, Drv->gc, Drv->image, X, Y, X, Y, Width, Height ); } XFlush (Drv->display); } void HandleEvent ( GRAPHICS_IO_PRIVATE *Drv, XEvent *ev ) { switch (ev->type) { case Expose: Redraw ( Drv, ev->xexpose.x, ev->xexpose.y, ev->xexpose.width, ev->xexpose.height ); break; case GraphicsExpose: Redraw ( Drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y, ev->xgraphicsexpose.width, ev->xgraphicsexpose.height ); break; case KeyPress: handleKeyEvent (Drv, ev, TRUE); break; case KeyRelease: handleKeyEvent (Drv, ev, FALSE); break; case MappingNotify: XRefreshKeyboardMapping (&ev->xmapping); break; case MotionNotify: handleMouseMoved (Drv, ev); break; case ButtonPress: handleMouseDown (Drv, ev, TRUE); break; case ButtonRelease: handleMouseDown (Drv, ev, FALSE); break; #if 0 case DestroyNotify: XCloseDisplay (Drv->display); exit (1); break; #endif case NoExpose: default: break; } } void HandleEvents ( IN GRAPHICS_IO_PRIVATE *Drv ) { XEvent ev; while (XPending (Drv->display) != 0) { XNextEvent (Drv->display, &ev); HandleEvent (Drv, &ev); } } unsigned long X11PixelToColor ( IN GRAPHICS_IO_PRIVATE *Drv, IN EFI_UGA_PIXEL pixel ) { return ((pixel.Red >> Drv->r.csize) << Drv->r.shift) | ((pixel.Green >> Drv->g.csize) << Drv->g.shift) | ((pixel.Blue >> Drv->b.csize) << Drv->b.shift); } EFI_UGA_PIXEL X11ColorToPixel ( IN GRAPHICS_IO_PRIVATE *Drv, IN unsigned long val ) { EFI_UGA_PIXEL Pixel; memset (&Pixel, 0, sizeof (EFI_UGA_PIXEL)); // Truncation not an issue since X11 and EFI are both using 8 bits per color Pixel.Red = (val >> Drv->r.shift) << Drv->r.csize; Pixel.Green = (val >> Drv->g.shift) << Drv->g.csize; Pixel.Blue = (val >> Drv->b.shift) << Drv->b.csize; return Pixel; } EFI_STATUS X11CheckKey ( IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo ) { GRAPHICS_IO_PRIVATE *Drv; Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; HandleEvents (Drv); if (Drv->key_count != 0) { return EFI_SUCCESS; } return EFI_NOT_READY; } EFI_STATUS X11GetKey ( IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, IN EFI_KEY_DATA *KeyData ) { EFI_STATUS EfiStatus; GRAPHICS_IO_PRIVATE *Drv; Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; EfiStatus = X11CheckKey (GraphicsIo); if (EFI_ERROR (EfiStatus)) { return EfiStatus; } CopyMem (KeyData, &Drv->keys[Drv->key_rd], sizeof (EFI_KEY_DATA)); Drv->key_rd = (Drv->key_rd + 1) % NBR_KEYS; Drv->key_count--; return EFI_SUCCESS; } EFI_STATUS X11KeySetState ( IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, IN EFI_KEY_TOGGLE_STATE *KeyToggleState ) { GRAPHICS_IO_PRIVATE *Drv; Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; if (*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) { if ((Drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == 0) { // // We could create an XKeyEvent and send a XK_Caps_Lock to // the UGA/GOP Window // } } Drv->KeyState.KeyToggleState = *KeyToggleState; return EFI_SUCCESS; } 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 ) { GRAPHICS_IO_PRIVATE *Drv; Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; Drv->MakeRegisterdKeyCallback = MakeCallBack; Drv->BreakRegisterdKeyCallback = BreakCallBack; Drv->RegisterdKeyCallbackContext = Context; return EFI_SUCCESS; } 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 ) { GRAPHICS_IO_PRIVATE *Private; UINTN DstY; UINTN SrcY; UINTN DstX; UINTN SrcX; UINTN Index; EFI_UGA_PIXEL *Blt; UINT8 *Dst; UINT8 *Src; UINTN Nbr; unsigned long Color; XEvent ev; Private = (GRAPHICS_IO_PRIVATE *)GraphicsIo; // // Check bounds // if ( (BltOperation == EfiUgaVideoToBltBuffer) || (BltOperation == EfiUgaVideoToVideo)) { // // Source is Video. // if (Args->SourceY + Args->Height > Private->height) { return EFI_INVALID_PARAMETER; } if (Args->SourceX + Args->Width > Private->width) { return EFI_INVALID_PARAMETER; } } if ( (BltOperation == EfiUgaBltBufferToVideo) || (BltOperation == EfiUgaVideoToVideo) || (BltOperation == EfiUgaVideoFill)) { // // Destination is Video // if (Args->DestinationY + Args->Height > Private->height) { return EFI_INVALID_PARAMETER; } if (Args->DestinationX + Args->Width > Private->width) { return EFI_INVALID_PARAMETER; } } switch (BltOperation) { case EfiUgaVideoToBltBuffer: Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->DestinationY * Args->Delta) + Args->DestinationX * sizeof (EFI_UGA_PIXEL)); Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL); for (SrcY = Args->SourceY; SrcY < (Args->Height + Args->SourceY); SrcY++) { for (SrcX = Args->SourceX; SrcX < (Args->Width + Args->SourceX); SrcX++) { *Blt++ = X11ColorToPixel (Private, XGetPixel (Private->image, SrcX, SrcY)); } Blt = (EFI_UGA_PIXEL *)((UINT8 *)Blt + Args->Delta); } break; case EfiUgaBltBufferToVideo: Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->SourceY * Args->Delta) + Args->SourceX * sizeof (EFI_UGA_PIXEL)); Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL); for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) { for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) { XPutPixel (Private->image, DstX, DstY, X11PixelToColor (Private, *Blt)); Blt++; } Blt = (EFI_UGA_PIXEL *)((UINT8 *)Blt + Args->Delta); } break; case EfiUgaVideoToVideo: Dst = Private->image_data + (Args->DestinationX << Private->pixel_shift) + Args->DestinationY * Private->line_bytes; Src = Private->image_data + (Args->SourceX << Private->pixel_shift) + Args->SourceY * Private->line_bytes; Nbr = Args->Width << Private->pixel_shift; if (Args->DestinationY < Args->SourceY) { for (Index = 0; Index < Args->Height; Index++) { memcpy (Dst, Src, Nbr); Dst += Private->line_bytes; Src += Private->line_bytes; } } else { Dst += (Args->Height - 1) * Private->line_bytes; Src += (Args->Height - 1) * Private->line_bytes; for (Index = 0; Index < Args->Height; Index++) { // // Source and Destination Y may be equal, therefore Dst and Src may // overlap. // memmove (Dst, Src, Nbr); Dst -= Private->line_bytes; Src -= Private->line_bytes; } } break; case EfiUgaVideoFill: Color = X11PixelToColor (Private, *BltBuffer); for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) { for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) { XPutPixel (Private->image, DstX, DstY, Color); } } break; default: return EFI_INVALID_PARAMETER; } // // Refresh screen. // switch (BltOperation) { case EfiUgaVideoToVideo: XCopyArea ( Private->display, Private->win, Private->win, Private->gc, Args->SourceX, Args->SourceY, Args->Width, Args->Height, Args->DestinationX, Args->DestinationY ); while (1) { XNextEvent (Private->display, &ev); HandleEvent (Private, &ev); if ((ev.type == NoExpose) || (ev.type == GraphicsExpose)) { break; } } break; case EfiUgaVideoFill: Color = X11PixelToColor (Private, *BltBuffer); XSetForeground (Private->display, Private->gc, Color); XFillRectangle ( Private->display, Private->win, Private->gc, Args->DestinationX, Args->DestinationY, Args->Width, Args->Height ); XFlush (Private->display); break; case EfiUgaBltBufferToVideo: Redraw (Private, Args->DestinationX, Args->DestinationY, Args->Width, Args->Height); break; default: break; } return EFI_SUCCESS; } EFI_STATUS X11CheckPointer ( IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo ) { GRAPHICS_IO_PRIVATE *Drv; Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; HandleEvents (Drv); if (Drv->pointer_state_changed != 0) { return EFI_SUCCESS; } return EFI_NOT_READY; } EFI_STATUS X11GetPointerState ( IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, IN EFI_SIMPLE_POINTER_STATE *State ) { EFI_STATUS EfiStatus; GRAPHICS_IO_PRIVATE *Drv; Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; EfiStatus = X11CheckPointer (GraphicsIo); if (EfiStatus != EFI_SUCCESS) { return EfiStatus; } memcpy (State, &Drv->pointer_state, sizeof (EFI_SIMPLE_POINTER_STATE)); Drv->pointer_state.RelativeMovementX = 0; Drv->pointer_state.RelativeMovementY = 0; Drv->pointer_state.RelativeMovementZ = 0; Drv->pointer_state_changed = 0; return EFI_SUCCESS; } EFI_STATUS X11GraphicsWindowOpen ( IN EMU_IO_THUNK_PROTOCOL *This ) { GRAPHICS_IO_PRIVATE *Drv; unsigned int border_width = 0; char *display_name = NULL; Drv = (GRAPHICS_IO_PRIVATE *)calloc (1, sizeof (GRAPHICS_IO_PRIVATE)); if (Drv == NULL) { return EFI_OUT_OF_RESOURCES; } Drv->GraphicsIo.Size = GasketX11Size; Drv->GraphicsIo.CheckKey = GasketX11CheckKey; Drv->GraphicsIo.GetKey = GasketX11GetKey; Drv->GraphicsIo.KeySetState = GasketX11KeySetState; Drv->GraphicsIo.RegisterKeyNotify = GasketX11RegisterKeyNotify; Drv->GraphicsIo.Blt = GasketX11Blt; Drv->GraphicsIo.CheckPointer = GasketX11CheckPointer; Drv->GraphicsIo.GetPointerState = GasketX11GetPointerState; Drv->key_count = 0; Drv->key_rd = 0; Drv->key_wr = 0; Drv->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; Drv->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; Drv->MakeRegisterdKeyCallback = NULL; Drv->BreakRegisterdKeyCallback = NULL; Drv->RegisterdKeyCallbackContext = NULL; Drv->display = XOpenDisplay (display_name); if (Drv->display == NULL) { fprintf (stderr, "uga: cannot connect to X server %s\n", XDisplayName (display_name)); free (Drv); return EFI_DEVICE_ERROR; } Drv->screen = DefaultScreen (Drv->display); Drv->visual = DefaultVisual (Drv->display, Drv->screen); Drv->win = XCreateSimpleWindow ( Drv->display, RootWindow (Drv->display, Drv->screen), 0, 0, 4, 4, border_width, WhitePixel (Drv->display, Drv->screen), BlackPixel (Drv->display, Drv->screen) ); Drv->depth = DefaultDepth (Drv->display, Drv->screen); XDefineCursor (Drv->display, Drv->win, XCreateFontCursor (Drv->display, XC_pirate)); Drv->Title = malloc (StrSize (This->ConfigString)); UnicodeStrToAsciiStrS (This->ConfigString, Drv->Title, StrSize (This->ConfigString)); XStoreName (Drv->display, Drv->win, Drv->Title); // XAutoRepeatOff (Drv->display); XSelectInput ( Drv->display, Drv->win, ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask ); Drv->gc = DefaultGC (Drv->display, Drv->screen); This->Private = (VOID *)Drv; This->Interface = (VOID *)Drv; return EFI_SUCCESS; } EFI_STATUS X11GraphicsWindowClose ( IN EMU_IO_THUNK_PROTOCOL *This ) { GRAPHICS_IO_PRIVATE *Drv; Drv = (GRAPHICS_IO_PRIVATE *)This->Private; if (Drv == NULL) { return EFI_SUCCESS; } if (Drv->image != NULL) { XDestroyImage (Drv->image); if (Drv->use_shm) { shmdt (Drv->image_data); } Drv->image_data = NULL; Drv->image = NULL; } XDestroyWindow (Drv->display, Drv->win); XCloseDisplay (Drv->display); #ifdef __APPLE__ // Free up the shared memory shmctl (Drv->xshm_info.shmid, IPC_RMID, NULL); #endif free (Drv); return EFI_SUCCESS; } EMU_IO_THUNK_PROTOCOL gX11ThunkIo = { &gEmuGraphicsWindowProtocolGuid, NULL, NULL, 0, GasketX11GraphicsWindowOpen, GasketX11GraphicsWindowClose, NULL };