]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/Sec/UgaX11.c
2nd wave of r11105 checkin.2nd wave of r11105 checkin.
[mirror_edk2.git] / UnixPkg / Sec / UgaX11.c
CommitLineData
ccd55824 1/*++
2
f9b8ab56 3Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
2ff79f2e 4Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
f9b8ab56 5This program and the accompanying materials
ccd55824 6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13--*/
d0c3acd4 14#include <Common/UnixInclude.h>
ccd55824 15
804405e7 16#include <sys/ipc.h>
17#include <sys/shm.h>
804405e7 18
2ff79f2e 19#include <PiPei.h>
20#include <Protocol/SimplePointer.h>
21#include <Protocol/SimpleTextIn.h>
22#include <Protocol/SimpleTextInEx.h>
23#include <Protocol/UgaDraw.h>
804405e7 24#include <X11/Xlib.h>
25#include <X11/Xutil.h>
26#include <X11/Xos.h>
27#include <X11/extensions/XShm.h>
28#include <X11/keysym.h>
2ff79f2e 29#include <X11/cursorfont.h>
30
31#include <Protocol/UnixThunk.h>
32#include <Protocol/UnixUgaIo.h>
804405e7 33
804405e7 34#include <Ppi/StatusCode.h>
35
36#include <Library/PeCoffLib.h>
37#include <Library/BaseLib.h>
38#include <Library/BaseMemoryLib.h>
39#include <Library/PrintLib.h>
40#include <Library/PcdLib.h>
41#include <Library/DebugLib.h>
42
2ff79f2e 43#include "Gasket.h"
44#include "SecMain.h"
45
46
804405e7 47extern void msSleep (unsigned long Milliseconds);
48
49/* XQueryPointer */
50
2ff79f2e 51struct uga_drv_shift_mask {
804405e7 52 unsigned char shift;
53 unsigned char size;
54 unsigned char csize;
55};
56
57#define NBR_KEYS 32
2ff79f2e 58typedef struct {
804405e7 59 EFI_UNIX_UGA_IO_PROTOCOL UgaIo;
60
61 Display *display;
62 int screen; /* values for window_size in main */
63 Window win;
64 GC gc;
65 Visual *visual;
66
67 int depth;
68 unsigned int width;
69 unsigned int height;
70 unsigned int line_bytes;
71 unsigned int pixel_shift;
72 unsigned char *image_data;
73
74 struct uga_drv_shift_mask r, g, b;
75
76 int use_shm;
77 XShmSegmentInfo xshm_info;
78 XImage *image;
79
80 unsigned int key_rd;
81 unsigned int key_wr;
82 unsigned int key_count;
2ff79f2e 83 EFI_KEY_DATA keys[NBR_KEYS];
84
85 EFI_KEY_STATE KeyState;
86
87 UGA_REGISTER_KEY_NOTIFY_CALLBACK RegisterdKeyCallback;
88 VOID *RegisterdKeyCallbackContext;
89
90 int previous_x;
91 int previous_y;
92 EFI_SIMPLE_POINTER_STATE pointer_state;
93 int pointer_state_changed;
804405e7 94} UGA_IO_PRIVATE;
95
7492c63d 96void
804405e7 97HandleEvents(UGA_IO_PRIVATE *drv);
98
7492c63d 99void
804405e7 100fill_shift_mask (struct uga_drv_shift_mask *sm, unsigned long mask)
101{
102 sm->shift = 0;
103 sm->size = 0;
104 while ((mask & 1) == 0)
105 {
106 mask >>= 1;
107 sm->shift++;
108 }
109 while (mask & 1)
110 {
111 sm->size++;
112 mask >>= 1;
113 }
114 sm->csize = 8 - sm->size;
115}
116
7492c63d 117int
804405e7 118TryCreateShmImage(UGA_IO_PRIVATE *drv)
119{
120 drv->image = XShmCreateImage (drv->display, drv->visual,
288a3c98 121 drv->depth, ZPixmap, NULL, &drv->xshm_info,
122 drv->width, drv->height);
804405e7 123 if (drv->image == NULL)
124 return 0;
125
126 switch (drv->image->bitmap_unit) {
127 case 32:
128 drv->pixel_shift = 2;
129 break;
130 case 16:
131 drv->pixel_shift = 1;
132 break;
133 case 8:
134 drv->pixel_shift = 0;
135 break;
136 }
137
138 drv->xshm_info.shmid = shmget
288a3c98 139 (IPC_PRIVATE, drv->image->bytes_per_line * drv->image->height,
140 IPC_CREAT | 0777);
7ee3b613
A
141 if (drv->xshm_info.shmid < 0) {
142 XDestroyImage(drv->image);
143 return 0;
144 }
804405e7 145
146 drv->image_data = shmat (drv->xshm_info.shmid, NULL, 0);
7ee3b613
A
147 if(!drv->image_data) {
148 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
149 XDestroyImage(drv->image);
150 return 0;
151 }
ccd55824 152
153#ifndef __APPLE__
154 //
155 // This closes shared memory in real time on OS X. Only closes after folks quit using
156 // it on Linux.
157 //
804405e7 158 /* Can this fail ? */
159 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
ccd55824 160#endif
804405e7 161
162 drv->xshm_info.shmaddr = (char*)drv->image_data;
163 drv->image->data = (char*)drv->image_data;
288a3c98 164
7ee3b613
A
165 if (!XShmAttach (drv->display, &drv->xshm_info)) {
166 shmdt (drv->image_data);
167 XDestroyImage(drv->image);
168 return 0;
169 }
804405e7 170 return 1;
171}
172
804405e7 173EFI_STATUS
174UgaClose (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
175{
176 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
177
178 if (drv == NULL)
179 return EFI_SUCCESS;
180 if (drv->image != NULL)
181 {
182 XDestroyImage(drv->image);
183
184 if (drv->use_shm)
288a3c98 185 shmdt (drv->image_data);
804405e7 186
187 drv->image_data = NULL;
188 drv->image = NULL;
189 }
190 XDestroyWindow(drv->display, drv->win);
191 XCloseDisplay(drv->display);
ccd55824 192
193#ifdef __APPLE__
194 // Free up the shared memory
195 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
196#endif
197
804405e7 198 free(drv);
199 return EFI_SUCCESS;
200}
201
804405e7 202EFI_STATUS
203UgaSize(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, UINT32 Width, UINT32 Height)
204{
205 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
206 XSizeHints size_hints;
207
208 /* Destroy current buffer if created. */
209 if (drv->image != NULL)
210 {
7d28e82d 211 /* Before destroy buffer, need to make sure the buffer available for access. */
804405e7 212 XDestroyImage(drv->image);
213
214 if (drv->use_shm)
288a3c98 215 shmdt (drv->image_data);
804405e7 216
217 drv->image_data = NULL;
218 drv->image = NULL;
219 }
220
221 drv->width = Width;
222 drv->height = Height;
223 XResizeWindow (drv->display, drv->win, Width, Height);
224
225 /* Allocate image. */
288a3c98 226 if (XShmQueryExtension(drv->display) && TryCreateShmImage(drv)) {
227 drv->use_shm = 1;
228 } else {
229 drv->use_shm = 0;
230 if (drv->depth > 16)
231 drv->pixel_shift = 2;
232 else if (drv->depth > 8)
233 drv->pixel_shift = 1;
234 else
235 drv->pixel_shift = 0;
804405e7 236
237 drv->image_data = malloc((drv->width * drv->height) << drv->pixel_shift);
238 drv->image = XCreateImage (drv->display, drv->visual, drv->depth,
288a3c98 239 ZPixmap, 0, (char *)drv->image_data,
240 drv->width, drv->height,
241 8 << drv->pixel_shift, 0);
804405e7 242 }
243 drv->line_bytes = drv->image->bytes_per_line;
244 fill_shift_mask (&drv->r, drv->image->red_mask);
245 fill_shift_mask (&drv->g, drv->image->green_mask);
246 fill_shift_mask (&drv->b, drv->image->blue_mask);
247
248 /* Set WM hints. */
249 size_hints.flags = PSize | PMinSize | PMaxSize;
250 size_hints.min_width = size_hints.max_width = size_hints.base_width = Width;
251 size_hints.min_height = size_hints.max_height = size_hints.base_height = Height;
252 XSetWMNormalHints (drv->display, drv->win, &size_hints);
253
254 XMapWindow (drv->display, drv->win);
255 HandleEvents(drv);
256 return EFI_SUCCESS;
257}
258
7492c63d 259void
804405e7 260handleKeyEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
261{
262 KeySym keysym;
263 char str[4];
2ff79f2e 264 EFI_KEY_DATA KeyData;
804405e7 265 int res;
266
267 if (drv->key_count == NBR_KEYS)
268 return;
269
270 res = XLookupString(&ev->xkey, str, sizeof(str), &keysym, NULL);
2ff79f2e 271 KeyData.Key.ScanCode = 0;
272 KeyData.Key.UnicodeChar = 0;
273 KeyData.KeyState.KeyShiftState = 0;
274
275 //
276 // KeyRelease is not supported (on Mac) so we can not easily implement Ex functions.
277 // If a modifier key is hit by its self we get a keysym. If a modfifier and key is hit
278 // we get the state bit set and keysym is the modified key.
279 //
280 // We use lack of state bits being set to clear ToggleState and KeyShiftState. We can
281 // also use the stat bits to set ToggleState and KeyShiftState.
282 // Skipping EFI_SCROLL_LOCK_ACTIVE & EFI_NUM_LOCK_ACTIVE since they are not on Macs
283 //
284 if ((ev->xkey.state & LockMask) == 0) {
285 drv->KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;
286 } else {
287 drv->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
288 }
289
290 if ((ev->xkey.state & ControlMask) == 0) {
291 drv->KeyState.KeyShiftState &= ~(EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED);
292 } else if ((drv->KeyState.KeyShiftState & EFI_RIGHT_CONTROL_PRESSED) == 0) {
293 drv->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
294 }
295
296 if ((ev->xkey.state & ShiftMask) == 0) {
297 drv->KeyState.KeyShiftState &= ~(EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED);
298 } else if ((drv->KeyState.KeyShiftState & EFI_RIGHT_SHIFT_PRESSED) == 0) {
299 drv->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
300 }
301
302 if ((ev->xkey.state & Mod2Mask) == 0) {
303 drv->KeyState.KeyShiftState &= ~(EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED);
304 } else if ((drv->KeyState.KeyShiftState & EFI_RIGHT_LOGO_PRESSED) == 0) {
305 drv->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
306 }
307
308 if ((ev->xkey.state & 0x2000) == 0) {
309 drv->KeyState.KeyShiftState &= ~(EFI_LEFT_ALT_PRESSED);
310 } else {
311 drv->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;
312 }
313
314
288a3c98 315 switch (keysym) {
2ff79f2e 316 case XK_Control_R:
317 drv->KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
318 break;
319 case XK_Control_L:
320 drv->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
321 break;
322
323 case XK_Shift_R:
324 drv->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
325 break;
326 case XK_Shift_L:
327 drv->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
328 break;
329
330 case XK_Mode_switch:
331 drv->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;
332 break;
333
334 case XK_Meta_R:
335 drv->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
336 break;
337 case XK_Meta_L:
338 drv->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
339 break;
340
341 case XK_Home: KeyData.Key.ScanCode = SCAN_HOME; break;
342 case XK_End: KeyData.Key.ScanCode = SCAN_END; break;
343 case XK_Left: KeyData.Key.ScanCode = SCAN_LEFT; break;
344 case XK_Right: KeyData.Key.ScanCode = SCAN_RIGHT; break;
345 case XK_Up: KeyData.Key.ScanCode = SCAN_UP; break;
346 case XK_Down: KeyData.Key.ScanCode = SCAN_DOWN; break;
347 case XK_Delete: KeyData.Key.ScanCode = SCAN_DELETE; break;
348 case XK_Insert: KeyData.Key.ScanCode = SCAN_INSERT; break;
349 case XK_Page_Up: KeyData.Key.ScanCode = SCAN_PAGE_UP; break;
350 case XK_Page_Down: KeyData.Key.ScanCode = SCAN_PAGE_DOWN; break;
351 case XK_Escape: KeyData.Key.ScanCode = SCAN_ESC; break;
352
353 case XK_F1: KeyData.Key.ScanCode = SCAN_F1; break;
354 case XK_F2: KeyData.Key.ScanCode = SCAN_F2; break;
355 case XK_F3: KeyData.Key.ScanCode = SCAN_F3; break;
356 case XK_F4: KeyData.Key.ScanCode = SCAN_F4; break;
357 case XK_F5: KeyData.Key.ScanCode = SCAN_F5; break;
358 case XK_F6: KeyData.Key.ScanCode = SCAN_F6; break;
359 case XK_F7: KeyData.Key.ScanCode = SCAN_F7; break;
360 case XK_F8: KeyData.Key.ScanCode = SCAN_F8; break;
361 case XK_F9: KeyData.Key.ScanCode = SCAN_F9; break;
804405e7 362
363 default:
364 if (res == 1) {
2ff79f2e 365 KeyData.Key.UnicodeChar = str[0];
804405e7 366 } else {
367 return;
368 }
288a3c98 369 }
370
2ff79f2e 371 // The global state is our state
372 KeyData.KeyState.KeyShiftState = drv->KeyState.KeyShiftState;
373 KeyData.KeyState.KeyToggleState = drv->KeyState.KeyToggleState;
374
375 CopyMem (&drv->keys[drv->key_wr], &KeyData, sizeof (EFI_KEY_DATA));
804405e7 376 drv->key_wr = (drv->key_wr + 1) % NBR_KEYS;
377 drv->key_count++;
2ff79f2e 378
379
380#if defined(__APPLE__) || defined(MDE_CPU_X64)
381 ReverseGasketUint64Uint64 (drv->RegisterdKeyCallback ,drv->RegisterdKeyCallbackContext, &KeyData);
382#else
383 drv->RegisterdKeyCallback (drv->RegisterdKeyCallbackContext, &KeyData);
384#endif
385
386
387}
388
389
390void
391handleMouseMoved(UGA_IO_PRIVATE *drv, XEvent *ev)
392{
393 if ( ev->xmotion.x != drv->previous_x )
394 {
395 drv->pointer_state.RelativeMovementX += ( ev->xmotion.x - drv->previous_x );
396 drv->previous_x = ev->xmotion.x;
397 drv->pointer_state_changed = 1;
398 }
399
400 if ( ev->xmotion.y != drv->previous_y )
401 {
402 drv->pointer_state.RelativeMovementY += ( ev->xmotion.y - drv->previous_y );
403 drv->previous_y = ev->xmotion.y;
404 drv->pointer_state_changed = 1;
405 }
406
407 drv->pointer_state.RelativeMovementZ = 0;
408}
409
410void
411handleMouseDown(UGA_IO_PRIVATE *drv, XEvent *ev, BOOLEAN Pressed)
412{
413 if ( ev->xbutton.button == Button1 )
414 {
415 drv->pointer_state_changed = ( drv->pointer_state.LeftButton != Pressed );
416 drv->pointer_state.LeftButton = Pressed;
417 }
418 if ( ev->xbutton.button == Button2 )
419 {
420 drv->pointer_state_changed = ( drv->pointer_state.RightButton != Pressed );
421 drv->pointer_state.RightButton = Pressed;
422 }
804405e7 423}
424
7492c63d 425void
804405e7 426Redraw(UGA_IO_PRIVATE *drv, UINTN X, UINTN Y, UINTN Width, UINTN Height)
427{
428 if (drv->use_shm)
429 XShmPutImage (drv->display, drv->win, drv->gc, drv->image,
288a3c98 430 X, Y, X, Y, Width, Height, False);
804405e7 431 else
432 XPutImage (drv->display, drv->win, drv->gc, drv->image,
288a3c98 433 X, Y, X, Y, Width, Height);
434 XFlush(drv->display);
804405e7 435}
436
7492c63d 437void
804405e7 438HandleEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
439{
440 switch (ev->type)
441 {
442 case Expose:
443 Redraw(drv, ev->xexpose.x, ev->xexpose.y,
288a3c98 444 ev->xexpose.width, ev->xexpose.height);
804405e7 445 break;
446 case GraphicsExpose:
447 Redraw(drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
288a3c98 448 ev->xgraphicsexpose.width, ev->xgraphicsexpose.height);
804405e7 449 break;
450 case KeyPress:
451 handleKeyEvent(drv, ev);
452 break;
2ff79f2e 453 case KeyRelease:
454 break;
804405e7 455 case MappingNotify:
456 XRefreshKeyboardMapping(&ev->xmapping);
457 break;
2ff79f2e 458 case MotionNotify:
459 handleMouseMoved(drv, ev);
460 break;
461 case ButtonPress:
462 handleMouseDown(drv, ev, TRUE);
463 break;
464 case ButtonRelease:
465 handleMouseDown(drv, ev, FALSE);
466 break;
804405e7 467#if 0
468 case DestroyNotify:
469 XCloseDisplay (drv->display);
470 exit (1);
471 break;
472#endif
473 case NoExpose:
474 default:
475 break;
476 }
477}
478
7492c63d 479void
804405e7 480HandleEvents(UGA_IO_PRIVATE *drv)
481{
482 while (XPending(drv->display) != 0)
483 {
484 XEvent ev;
288a3c98 485
804405e7 486 XNextEvent (drv->display, &ev);
487 HandleEvent(drv, &ev);
488 }
489}
490
804405e7 491unsigned long
492UgaPixelToColor (UGA_IO_PRIVATE *drv, EFI_UGA_PIXEL pixel)
493{
494 return ((pixel.Red >> drv->r.csize) << drv->r.shift)
495 | ((pixel.Green >> drv->g.csize) << drv->g.shift)
496 | ((pixel.Blue >> drv->b.csize) << drv->b.shift);
497}
498
804405e7 499EFI_UGA_PIXEL
500UgaColorToPixel (UGA_IO_PRIVATE *drv, unsigned long val)
501{
502 EFI_UGA_PIXEL res;
503
504 memset (&res, 0, sizeof (EFI_UGA_PIXEL));
505 /* FIXME: should round instead of truncate. */
506 res.Red = (val >> drv->r.shift) << drv->r.csize;
507 res.Green = (val >> drv->g.shift) << drv->g.csize;
508 res.Blue = (val >> drv->b.shift) << drv->b.csize;
509
510 return res;
511}
512
2ff79f2e 513STATIC EFI_STATUS
514CheckKeyInternal( UGA_IO_PRIVATE *drv, BOOLEAN delay )
804405e7 515{
804405e7 516 HandleEvents(drv);
2ff79f2e 517 if (drv->key_count != 0)
804405e7 518 return EFI_SUCCESS;
2ff79f2e 519 if ( delay )
520 /* EFI is polling. Be CPU-friendly. */
804405e7 521 msSleep (20);
522 return EFI_NOT_READY;
523 }
2ff79f2e 524
525EFI_STATUS
526UgaCheckKey(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
527{
528 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
529 return( CheckKeyInternal( drv, TRUE ) );
804405e7 530}
531
804405e7 532EFI_STATUS
2ff79f2e 533EFIAPI
534UgaGetKey (
535 IN EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
536 IN EFI_KEY_DATA *KeyData
537 )
804405e7 538{
539 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
540 EFI_STATUS status;
541
2ff79f2e 542 status = CheckKeyInternal(drv, FALSE);
804405e7 543 if (status != EFI_SUCCESS)
544 return status;
545
2ff79f2e 546 CopyMem (KeyData, &drv->keys[drv->key_rd], sizeof (EFI_KEY_DATA));
804405e7 547 drv->key_rd = (drv->key_rd + 1) % NBR_KEYS;
548 drv->key_count--;
549 return EFI_SUCCESS;
550}
551
2ff79f2e 552
553EFI_STATUS
554EFIAPI
555UgaKeySetState (
556 IN EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
557 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
558 )
559{
560 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
561// XKeyEvent event;
562
563 if (*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) {
564 if ((drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == 0) {
565 //
566 // We could create an XKeyEvent and send a XK_Caps_Lock to
567 // the UGA/GOP Window
568 //
569 }
570 }
571
572 drv->KeyState.KeyToggleState = *KeyToggleState;
573 return EFI_SUCCESS;
574}
575
576
577EFI_STATUS
578EFIAPI
579UgaRegisterKeyNotify (
580 IN EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
581 IN UGA_REGISTER_KEY_NOTIFY_CALLBACK CallBack,
582 IN VOID *Context
583 )
584{
585 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
586
587 drv->RegisterdKeyCallback = CallBack;
588 drv->RegisterdKeyCallbackContext = Context;
589
590 return EFI_SUCCESS;
591}
592
593
288a3c98 594EFI_STATUS
a4902ccc 595UgaBlt(
596 IN EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
597 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
598 IN EFI_UGA_BLT_OPERATION BltOperation,
599 IN UGA_BLT_ARGS *Args
288a3c98 600 )
804405e7 601{
602 UGA_IO_PRIVATE *Private = (UGA_IO_PRIVATE *)UgaIo;
288a3c98 603 UINTN DstY;
604 UINTN SrcY;
804405e7 605 UINTN DstX;
606 UINTN SrcX;
607 UINTN Index;
288a3c98 608 EFI_UGA_PIXEL *Blt;
804405e7 609 UINT8 *Dst;
610 UINT8 *Src;
611 UINTN Nbr;
612 unsigned long Color;
613
614 //
615 // Check bounds
616 //
617 if (BltOperation == EfiUgaVideoToBltBuffer
288a3c98 618 || BltOperation == EfiUgaVideoToVideo) {
619 //
804405e7 620 // Source is Video.
288a3c98 621 //
a4902ccc 622 if (Args->SourceY + Args->Height > Private->height) {
288a3c98 623 return EFI_INVALID_PARAMETER;
624 }
625
a4902ccc 626 if (Args->SourceX + Args->Width > Private->width) {
288a3c98 627 return EFI_INVALID_PARAMETER;
628 }
804405e7 629 }
630
631 if (BltOperation == EfiUgaBltBufferToVideo
632 || BltOperation == EfiUgaVideoToVideo
288a3c98 633 || BltOperation == EfiUgaVideoFill) {
634 //
635 // Destination is Video
636 //
a4902ccc 637 if (Args->DestinationY + Args->Height > Private->height) {
288a3c98 638 return EFI_INVALID_PARAMETER;
639 }
640
a4902ccc 641 if (Args->DestinationX + Args->Width > Private->width) {
288a3c98 642 return EFI_INVALID_PARAMETER;
643 }
804405e7 644 }
645
288a3c98 646 switch (BltOperation) {
804405e7 647 case EfiUgaVideoToBltBuffer:
a4902ccc 648 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->DestinationY * Args->Delta) + Args->DestinationX * sizeof (EFI_UGA_PIXEL));
649 Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL);
650 for (SrcY = Args->SourceY; SrcY < (Args->Height + Args->SourceY); SrcY++) {
651 for (SrcX = Args->SourceX; SrcX < (Args->Width + Args->SourceX); SrcX++) {
288a3c98 652 *Blt++ = UgaColorToPixel(Private,
653 XGetPixel(Private->image, SrcX, SrcY));
804405e7 654 }
a4902ccc 655 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta);
288a3c98 656 }
804405e7 657 break;
288a3c98 658 case EfiUgaBltBufferToVideo:
a4902ccc 659 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->SourceY * Args->Delta) + Args->SourceX * sizeof (EFI_UGA_PIXEL));
660 Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL);
661 for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) {
662 for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) {
288a3c98 663 XPutPixel(Private->image, DstX, DstY, UgaPixelToColor(Private, *Blt));
664 Blt++;
804405e7 665 }
a4902ccc 666 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta);
804405e7 667 }
668 break;
288a3c98 669 case EfiUgaVideoToVideo:
a4902ccc 670 Dst = Private->image_data + (Args->DestinationX << Private->pixel_shift)
671 + Args->DestinationY * Private->line_bytes;
672 Src = Private->image_data + (Args->SourceX << Private->pixel_shift)
673 + Args->SourceY * Private->line_bytes;
674 Nbr = Args->Width << Private->pixel_shift;
675 if (Args->DestinationY < Args->SourceY) {
676 for (Index = 0; Index < Args->Height; Index++) {
288a3c98 677 memcpy (Dst, Src, Nbr);
678 Dst += Private->line_bytes;
679 Src += Private->line_bytes;
804405e7 680 }
681 }
682 else {
a4902ccc 683 Dst += (Args->Height - 1) * Private->line_bytes;
684 Src += (Args->Height - 1) * Private->line_bytes;
685 for (Index = 0; Index < Args->Height; Index++) {
288a3c98 686 //
687 // Source and Destination Y may be equal, therefore Dst and Src may
688 // overlap.
689 //
690 memmove (Dst, Src, Nbr);
691 Dst -= Private->line_bytes;
692 Src -= Private->line_bytes;
804405e7 693 }
694 }
695 break;
696 case EfiUgaVideoFill:
697 Color = UgaPixelToColor(Private, *BltBuffer);
a4902ccc 698 for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) {
699 for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) {
288a3c98 700 XPutPixel(Private->image, DstX, DstY, Color);
804405e7 701 }
288a3c98 702 }
804405e7 703 break;
704 default:
288a3c98 705 return EFI_INVALID_PARAMETER;
804405e7 706 }
707
708 //
709 // Refresh screen.
710 //
288a3c98 711 switch (BltOperation) {
712 case EfiUgaVideoToVideo:
804405e7 713 XCopyArea(Private->display, Private->win, Private->win, Private->gc,
a4902ccc 714 Args->SourceX, Args->SourceY, Args->Width, Args->Height, Args->DestinationX, Args->DestinationY);
804405e7 715 while (1) {
716 XEvent ev;
288a3c98 717
804405e7 718 XNextEvent (Private->display, &ev);
719 HandleEvent(Private, &ev);
720 if (ev.type == NoExpose || ev.type == GraphicsExpose)
288a3c98 721 break;
804405e7 722 }
723 break;
724 case EfiUgaVideoFill:
725 Color = UgaPixelToColor(Private, *BltBuffer);
726 XSetForeground(Private->display, Private->gc, Color);
727 XFillRectangle(Private->display, Private->win, Private->gc,
a4902ccc 728 Args->DestinationX, Args->DestinationY, Args->Width, Args->Height);
288a3c98 729 XFlush(Private->display);
804405e7 730 break;
288a3c98 731 case EfiUgaBltBufferToVideo:
a4902ccc 732 Redraw(Private, Args->DestinationX, Args->DestinationY, Args->Width, Args->Height);
804405e7 733 break;
734 default:
735 break;
736 }
737 return EFI_SUCCESS;
738}
739
2ff79f2e 740STATIC EFI_STATUS
741CheckPointerInternal( UGA_IO_PRIVATE *drv, BOOLEAN delay )
742{
743 HandleEvents(drv);
744 if (drv->pointer_state_changed != 0)
745 return EFI_SUCCESS;
746 if ( delay )
747 /* EFI is polling. Be CPU-friendly. */
748 msSleep (20);
749 return EFI_NOT_READY;
750}
751
752EFI_STATUS
753UgaCheckPointer(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
754{
755 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
756 return( CheckPointerInternal( drv, TRUE ) );
757}
758
759EFI_STATUS
760UgaGetPointerState (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, EFI_SIMPLE_POINTER_STATE *state)
761{
762 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
763 EFI_STATUS status;
764
765 status = CheckPointerInternal( drv, FALSE );
766 if (status != EFI_SUCCESS)
767 return status;
768
769 memcpy( state, &drv->pointer_state, sizeof( EFI_SIMPLE_POINTER_STATE ) );
770
771 drv->pointer_state.RelativeMovementX = 0;
772 drv->pointer_state.RelativeMovementY = 0;
773 drv->pointer_state.RelativeMovementZ = 0;
774 drv->pointer_state_changed = 0;
775 return EFI_SUCCESS;
776}
777
804405e7 778EFI_STATUS
779UgaCreate (EFI_UNIX_UGA_IO_PROTOCOL **Uga, CONST CHAR16 *Title)
780{
781 UGA_IO_PRIVATE *drv;
782 unsigned int border_width = 0;
783 char *display_name = NULL;
784 int title_len;
785
ccd55824 786 drv = (UGA_IO_PRIVATE *)calloc (1, sizeof (UGA_IO_PRIVATE));
804405e7 787 if (drv == NULL)
788 return EFI_OUT_OF_RESOURCES;
789
2ff79f2e 790#if defined(__APPLE__) || defined(MDE_CPU_X64)
ccd55824 791//
792//
793//
ccd55824 794 drv->UgaIo.UgaClose = GasketUgaClose;
795 drv->UgaIo.UgaSize = GasketUgaSize;
796 drv->UgaIo.UgaCheckKey = GasketUgaCheckKey;
797 drv->UgaIo.UgaGetKey = GasketUgaGetKey;
2ff79f2e 798 drv->UgaIo.UgaKeySetState = GasketUgaKeySetState;
799 drv->UgaIo.UgaRegisterKeyNotify = GasketUgaRegisterKeyNotify;
ccd55824 800 drv->UgaIo.UgaBlt = GasketUgaBlt;
2ff79f2e 801 drv->UgaIo.UgaCheckPointer = GasketUgaCheckPointer;
802 drv->UgaIo.UgaGetPointerState = GasketUgaGetPointerState;
ccd55824 803#else
804405e7 804 drv->UgaIo.UgaClose = UgaClose;
805 drv->UgaIo.UgaSize = UgaSize;
806 drv->UgaIo.UgaCheckKey = UgaCheckKey;
807 drv->UgaIo.UgaGetKey = UgaGetKey;
2ff79f2e 808 drv->UgaIo.UgaKeySetState = UgaKeySetState;
809 drv->UgaIo.UgaRegisterKeyNotify = UgaRegisterKeyNotify;
804405e7 810 drv->UgaIo.UgaBlt = UgaBlt;
2ff79f2e 811 drv->UgaIo.UgaCheckPointer = UgaCheckPointer;
812 drv->UgaIo.UgaGetPointerState = UgaGetPointerState;
ccd55824 813#endif
814
815
804405e7 816
817 drv->key_count = 0;
818 drv->key_rd = 0;
819 drv->key_wr = 0;
2ff79f2e 820 drv->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
821 drv->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
822 drv->RegisterdKeyCallback = NULL;
823 drv->RegisterdKeyCallbackContext = NULL;
824
825
804405e7 826 drv->display = XOpenDisplay (display_name);
827 if (drv->display == NULL)
828 {
829 fprintf (stderr, "uga: cannot connect to X server %s\n",
288a3c98 830 XDisplayName (display_name));
804405e7 831 free (drv);
832 return EFI_DEVICE_ERROR;
833 }
834 drv->screen = DefaultScreen (drv->display);
835 drv->visual = DefaultVisual (drv->display, drv->screen);
836 drv->win = XCreateSimpleWindow
288a3c98 837 (drv->display, RootWindow (drv->display, drv->screen),
838 0, 0, 4, 4, border_width,
839 WhitePixel (drv->display, drv->screen),
840 BlackPixel (drv->display, drv->screen));
804405e7 841
842 drv->depth = DefaultDepth (drv->display, drv->screen);
2ff79f2e 843 XDefineCursor (drv->display, drv->win, XCreateFontCursor (drv->display, XC_pirate));
804405e7 844
845 /* Compute title len and convert to Ascii. */
846 for (title_len = 0; Title[title_len] != 0; title_len++)
847 ;
848 {
849 char title[title_len + 1];
850 int i;
851 for (i = 0; i < title_len; i++)
852 title[i] = Title[i];
853 title[i] = 0;
854
855 XStoreName (drv->display, drv->win, title);
856 }
857
2ff79f2e 858 XSelectInput (drv->display, drv->win,
859 ExposureMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask );
804405e7 860 drv->gc = DefaultGC (drv->display, drv->screen);
861
862 *Uga = (EFI_UNIX_UGA_IO_PROTOCOL *)drv;
863 return EFI_SUCCESS;
864}