]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/Sec/UgaX11.c
Added support for Xcode on Snow Leopard. Upaded with bug fixes for Snow Leopard.
[mirror_edk2.git] / UnixPkg / Sec / UgaX11.c
1 /*++
2
3 Copyright (c) 2004 - 2009, Intel Corporation
4 Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 --*/
14
15 #include <sys/ipc.h>
16 #include <sys/shm.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19
20 #include "PiPei.h"
21 #include "Protocol/UnixThunk.h"
22 #include "Protocol/SimpleTextIn.h"
23 #include "Protocol/UgaDraw.h"
24 #include "Protocol/UnixUgaIo.h"
25 #include <X11/Xlib.h>
26 #include <X11/Xutil.h>
27 #include <X11/Xos.h>
28 #include <X11/extensions/XShm.h>
29 #include <X11/keysym.h>
30
31 #include <Ppi/StatusCode.h>
32
33 #include <Library/PeCoffLib.h>
34 #include <Library/BaseLib.h>
35 #include <Library/BaseMemoryLib.h>
36 #include <Library/PrintLib.h>
37 #include <Library/PcdLib.h>
38 #include <Library/DebugLib.h>
39
40 extern void msSleep (unsigned long Milliseconds);
41
42 /* XQueryPointer */
43
44 struct uga_drv_shift_mask
45 {
46 unsigned char shift;
47 unsigned char size;
48 unsigned char csize;
49 };
50
51 #define NBR_KEYS 32
52 typedef struct
53 {
54 EFI_UNIX_UGA_IO_PROTOCOL UgaIo;
55
56 Display *display;
57 int screen; /* values for window_size in main */
58 Window win;
59 GC gc;
60 Visual *visual;
61
62 int depth;
63 unsigned int width;
64 unsigned int height;
65 unsigned int line_bytes;
66 unsigned int pixel_shift;
67 unsigned char *image_data;
68
69 struct uga_drv_shift_mask r, g, b;
70
71 int use_shm;
72 XShmSegmentInfo xshm_info;
73 XImage *image;
74
75 unsigned int key_rd;
76 unsigned int key_wr;
77 unsigned int key_count;
78 EFI_INPUT_KEY keys[NBR_KEYS];
79 } UGA_IO_PRIVATE;
80
81 void
82 HandleEvents(UGA_IO_PRIVATE *drv);
83
84 void
85 fill_shift_mask (struct uga_drv_shift_mask *sm, unsigned long mask)
86 {
87 sm->shift = 0;
88 sm->size = 0;
89 while ((mask & 1) == 0)
90 {
91 mask >>= 1;
92 sm->shift++;
93 }
94 while (mask & 1)
95 {
96 sm->size++;
97 mask >>= 1;
98 }
99 sm->csize = 8 - sm->size;
100 }
101
102 int
103 TryCreateShmImage(UGA_IO_PRIVATE *drv)
104 {
105 drv->image = XShmCreateImage (drv->display, drv->visual,
106 drv->depth, ZPixmap, NULL, &drv->xshm_info,
107 drv->width, drv->height);
108 if (drv->image == NULL)
109 return 0;
110
111 switch (drv->image->bitmap_unit) {
112 case 32:
113 drv->pixel_shift = 2;
114 break;
115 case 16:
116 drv->pixel_shift = 1;
117 break;
118 case 8:
119 drv->pixel_shift = 0;
120 break;
121 }
122
123 drv->xshm_info.shmid = shmget
124 (IPC_PRIVATE, drv->image->bytes_per_line * drv->image->height,
125 IPC_CREAT | 0777);
126 if (drv->xshm_info.shmid < 0) {
127 XDestroyImage(drv->image);
128 return 0;
129 }
130
131 drv->image_data = shmat (drv->xshm_info.shmid, NULL, 0);
132 if(!drv->image_data) {
133 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
134 XDestroyImage(drv->image);
135 return 0;
136 }
137
138 #ifndef __APPLE__
139 //
140 // This closes shared memory in real time on OS X. Only closes after folks quit using
141 // it on Linux.
142 //
143 /* Can this fail ? */
144 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
145 #endif
146
147 drv->xshm_info.shmaddr = (char*)drv->image_data;
148 drv->image->data = (char*)drv->image_data;
149
150 if (!XShmAttach (drv->display, &drv->xshm_info)) {
151 shmdt (drv->image_data);
152 XDestroyImage(drv->image);
153 return 0;
154 }
155 return 1;
156 }
157
158 EFI_STATUS
159 UgaClose (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
160 {
161 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
162
163 if (drv == NULL)
164 return EFI_SUCCESS;
165 if (drv->image != NULL)
166 {
167 XDestroyImage(drv->image);
168
169 if (drv->use_shm)
170 shmdt (drv->image_data);
171
172 drv->image_data = NULL;
173 drv->image = NULL;
174 }
175 XDestroyWindow(drv->display, drv->win);
176 XCloseDisplay(drv->display);
177
178 #ifdef __APPLE__
179 // Free up the shared memory
180 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
181 #endif
182
183 free(drv);
184 return EFI_SUCCESS;
185 }
186
187 EFI_STATUS
188 UgaSize(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, UINT32 Width, UINT32 Height)
189 {
190 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
191 XSizeHints size_hints;
192
193 /* Destroy current buffer if created. */
194 if (drv->image != NULL)
195 {
196 /* Before destroy buffer, need to make sure the buffer available for access. */
197 XDestroyImage(drv->image);
198
199 if (drv->use_shm)
200 shmdt (drv->image_data);
201
202 drv->image_data = NULL;
203 drv->image = NULL;
204 }
205
206 drv->width = Width;
207 drv->height = Height;
208 XResizeWindow (drv->display, drv->win, Width, Height);
209
210 /* Allocate image. */
211 if (XShmQueryExtension(drv->display) && TryCreateShmImage(drv)) {
212 drv->use_shm = 1;
213 } else {
214 drv->use_shm = 0;
215 if (drv->depth > 16)
216 drv->pixel_shift = 2;
217 else if (drv->depth > 8)
218 drv->pixel_shift = 1;
219 else
220 drv->pixel_shift = 0;
221
222 drv->image_data = malloc((drv->width * drv->height) << drv->pixel_shift);
223 drv->image = XCreateImage (drv->display, drv->visual, drv->depth,
224 ZPixmap, 0, (char *)drv->image_data,
225 drv->width, drv->height,
226 8 << drv->pixel_shift, 0);
227 }
228 drv->line_bytes = drv->image->bytes_per_line;
229 fill_shift_mask (&drv->r, drv->image->red_mask);
230 fill_shift_mask (&drv->g, drv->image->green_mask);
231 fill_shift_mask (&drv->b, drv->image->blue_mask);
232
233 /* Set WM hints. */
234 size_hints.flags = PSize | PMinSize | PMaxSize;
235 size_hints.min_width = size_hints.max_width = size_hints.base_width = Width;
236 size_hints.min_height = size_hints.max_height = size_hints.base_height = Height;
237 XSetWMNormalHints (drv->display, drv->win, &size_hints);
238
239 XMapWindow (drv->display, drv->win);
240 HandleEvents(drv);
241 return EFI_SUCCESS;
242 }
243
244 void
245 handleKeyEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
246 {
247 KeySym keysym;
248 char str[4];
249 EFI_INPUT_KEY Key;
250 int res;
251
252 if (drv->key_count == NBR_KEYS)
253 return;
254
255 res = XLookupString(&ev->xkey, str, sizeof(str), &keysym, NULL);
256 Key.ScanCode = 0;
257 Key.UnicodeChar = 0;
258 switch (keysym) {
259 case XK_Home: Key.ScanCode = SCAN_HOME; break;
260 case XK_End: Key.ScanCode = SCAN_END; break;
261 case XK_Left: Key.ScanCode = SCAN_LEFT; break;
262 case XK_Right: Key.ScanCode = SCAN_RIGHT; break;
263 case XK_Up: Key.ScanCode = SCAN_UP; break;
264 case XK_Down: Key.ScanCode = SCAN_DOWN; break;
265 case XK_Delete: Key.ScanCode = SCAN_DELETE; break;
266 case XK_Insert: Key.ScanCode = SCAN_INSERT; break;
267 case XK_Page_Up: Key.ScanCode = SCAN_PAGE_UP; break;
268 case XK_Page_Down: Key.ScanCode = SCAN_PAGE_DOWN; break;
269 case XK_Escape: Key.ScanCode = SCAN_ESC; break;
270
271 case XK_F1: Key.ScanCode = SCAN_F1; break;
272 case XK_F2: Key.ScanCode = SCAN_F2; break;
273 case XK_F3: Key.ScanCode = SCAN_F3; break;
274 case XK_F4: Key.ScanCode = SCAN_F4; break;
275 case XK_F5: Key.ScanCode = SCAN_F5; break;
276 case XK_F6: Key.ScanCode = SCAN_F6; break;
277 case XK_F7: Key.ScanCode = SCAN_F7; break;
278 case XK_F8: Key.ScanCode = SCAN_F8; break;
279 case XK_F9: Key.ScanCode = SCAN_F9; break;
280
281 default:
282 if (res == 1) {
283 Key.UnicodeChar = str[0];
284 } else {
285 return;
286 }
287 }
288
289 drv->keys[drv->key_wr] = Key;
290 drv->key_wr = (drv->key_wr + 1) % NBR_KEYS;
291 drv->key_count++;
292 }
293
294 void
295 Redraw(UGA_IO_PRIVATE *drv, UINTN X, UINTN Y, UINTN Width, UINTN Height)
296 {
297 if (drv->use_shm)
298 XShmPutImage (drv->display, drv->win, drv->gc, drv->image,
299 X, Y, X, Y, Width, Height, False);
300 else
301 XPutImage (drv->display, drv->win, drv->gc, drv->image,
302 X, Y, X, Y, Width, Height);
303 XFlush(drv->display);
304 }
305
306 void
307 HandleEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
308 {
309 switch (ev->type)
310 {
311 case Expose:
312 Redraw(drv, ev->xexpose.x, ev->xexpose.y,
313 ev->xexpose.width, ev->xexpose.height);
314 break;
315 case GraphicsExpose:
316 Redraw(drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
317 ev->xgraphicsexpose.width, ev->xgraphicsexpose.height);
318 break;
319 case KeyPress:
320 handleKeyEvent(drv, ev);
321 break;
322 case MappingNotify:
323 XRefreshKeyboardMapping(&ev->xmapping);
324 break;
325 #if 0
326 case DestroyNotify:
327 XCloseDisplay (drv->display);
328 exit (1);
329 break;
330 #endif
331 case NoExpose:
332 default:
333 break;
334 }
335 }
336
337 void
338 HandleEvents(UGA_IO_PRIVATE *drv)
339 {
340 while (XPending(drv->display) != 0)
341 {
342 XEvent ev;
343
344 XNextEvent (drv->display, &ev);
345 HandleEvent(drv, &ev);
346 }
347 }
348
349 unsigned long
350 UgaPixelToColor (UGA_IO_PRIVATE *drv, EFI_UGA_PIXEL pixel)
351 {
352 return ((pixel.Red >> drv->r.csize) << drv->r.shift)
353 | ((pixel.Green >> drv->g.csize) << drv->g.shift)
354 | ((pixel.Blue >> drv->b.csize) << drv->b.shift);
355 }
356
357 EFI_UGA_PIXEL
358 UgaColorToPixel (UGA_IO_PRIVATE *drv, unsigned long val)
359 {
360 EFI_UGA_PIXEL res;
361
362 memset (&res, 0, sizeof (EFI_UGA_PIXEL));
363 /* FIXME: should round instead of truncate. */
364 res.Red = (val >> drv->r.shift) << drv->r.csize;
365 res.Green = (val >> drv->g.shift) << drv->g.csize;
366 res.Blue = (val >> drv->b.shift) << drv->b.csize;
367
368 return res;
369 }
370
371 EFI_STATUS
372 UgaCheckKey(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
373 {
374 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
375 HandleEvents(drv);
376 if (drv->key_count != 0)
377 return EFI_SUCCESS;
378 else {
379 /* EFI is certainly polling. Be CPU-friendly. */
380 msSleep (20);
381 return EFI_NOT_READY;
382 }
383 }
384
385 EFI_STATUS
386 UgaGetKey (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, EFI_INPUT_KEY *key)
387 {
388 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
389 EFI_STATUS status;
390
391 status = UgaCheckKey(UgaIo);
392 if (status != EFI_SUCCESS)
393 return status;
394
395 *key = drv->keys[drv->key_rd];
396 drv->key_rd = (drv->key_rd + 1) % NBR_KEYS;
397 drv->key_count--;
398 return EFI_SUCCESS;
399 }
400
401 EFI_STATUS
402 UgaBlt(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
403 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
404 IN EFI_UGA_BLT_OPERATION BltOperation,
405 IN UINTN SourceX,
406 IN UINTN SourceY,
407 IN UINTN DestinationX,
408 IN UINTN DestinationY,
409 IN UINTN Width,
410 IN UINTN Height,
411 IN UINTN Delta OPTIONAL
412 )
413 {
414 UGA_IO_PRIVATE *Private = (UGA_IO_PRIVATE *)UgaIo;
415 UINTN DstY;
416 UINTN SrcY;
417 UINTN DstX;
418 UINTN SrcX;
419 UINTN Index;
420 EFI_UGA_PIXEL *Blt;
421 UINT8 *Dst;
422 UINT8 *Src;
423 UINTN Nbr;
424 unsigned long Color;
425
426 //
427 // Check bounds
428 //
429 if (BltOperation == EfiUgaVideoToBltBuffer
430 || BltOperation == EfiUgaVideoToVideo) {
431 //
432 // Source is Video.
433 //
434 if (SourceY + Height > Private->height) {
435 return EFI_INVALID_PARAMETER;
436 }
437
438 if (SourceX + Width > Private->width) {
439 return EFI_INVALID_PARAMETER;
440 }
441 }
442
443 if (BltOperation == EfiUgaBltBufferToVideo
444 || BltOperation == EfiUgaVideoToVideo
445 || BltOperation == EfiUgaVideoFill) {
446 //
447 // Destination is Video
448 //
449 if (DestinationY + Height > Private->height) {
450 return EFI_INVALID_PARAMETER;
451 }
452
453 if (DestinationX + Width > Private->width) {
454 return EFI_INVALID_PARAMETER;
455 }
456 }
457
458 switch (BltOperation) {
459 case EfiUgaVideoToBltBuffer:
460 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (DestinationY * Delta) + DestinationX * sizeof (EFI_UGA_PIXEL));
461 Delta -= Width * sizeof (EFI_UGA_PIXEL);
462 for (SrcY = SourceY; SrcY < (Height + SourceY); SrcY++) {
463 for (SrcX = SourceX; SrcX < (Width + SourceX); SrcX++) {
464 *Blt++ = UgaColorToPixel(Private,
465 XGetPixel(Private->image, SrcX, SrcY));
466 }
467 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
468 }
469 break;
470 case EfiUgaBltBufferToVideo:
471 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (SourceY * Delta) + SourceX * sizeof (EFI_UGA_PIXEL));
472 Delta -= Width * sizeof (EFI_UGA_PIXEL);
473 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
474 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
475 XPutPixel(Private->image, DstX, DstY, UgaPixelToColor(Private, *Blt));
476 Blt++;
477 }
478 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
479 }
480 break;
481 case EfiUgaVideoToVideo:
482 Dst = Private->image_data + (DestinationX << Private->pixel_shift)
483 + DestinationY * Private->line_bytes;
484 Src = Private->image_data + (SourceX << Private->pixel_shift)
485 + SourceY * Private->line_bytes;
486 Nbr = Width << Private->pixel_shift;
487 if (DestinationY < SourceY) {
488 for (Index = 0; Index < Height; Index++) {
489 memcpy (Dst, Src, Nbr);
490 Dst += Private->line_bytes;
491 Src += Private->line_bytes;
492 }
493 }
494 else {
495 Dst += (Height - 1) * Private->line_bytes;
496 Src += (Height - 1) * Private->line_bytes;
497 for (Index = 0; Index < Height; Index++) {
498 //
499 // Source and Destination Y may be equal, therefore Dst and Src may
500 // overlap.
501 //
502 memmove (Dst, Src, Nbr);
503 Dst -= Private->line_bytes;
504 Src -= Private->line_bytes;
505 }
506 }
507 break;
508 case EfiUgaVideoFill:
509 Color = UgaPixelToColor(Private, *BltBuffer);
510 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
511 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
512 XPutPixel(Private->image, DstX, DstY, Color);
513 }
514 }
515 break;
516 default:
517 return EFI_INVALID_PARAMETER;
518 }
519
520 //
521 // Refresh screen.
522 //
523 switch (BltOperation) {
524 case EfiUgaVideoToVideo:
525 XCopyArea(Private->display, Private->win, Private->win, Private->gc,
526 SourceX, SourceY, Width, Height, DestinationX, DestinationY);
527 while (1) {
528 XEvent ev;
529
530 XNextEvent (Private->display, &ev);
531 HandleEvent(Private, &ev);
532 if (ev.type == NoExpose || ev.type == GraphicsExpose)
533 break;
534 }
535 break;
536 case EfiUgaVideoFill:
537 Color = UgaPixelToColor(Private, *BltBuffer);
538 XSetForeground(Private->display, Private->gc, Color);
539 XFillRectangle(Private->display, Private->win, Private->gc,
540 DestinationX, DestinationY, Width, Height);
541 XFlush(Private->display);
542 break;
543 case EfiUgaBltBufferToVideo:
544 Redraw(Private, DestinationX, DestinationY, Width, Height);
545 break;
546 default:
547 break;
548 }
549 return EFI_SUCCESS;
550 }
551
552 EFI_STATUS
553 UgaCreate (EFI_UNIX_UGA_IO_PROTOCOL **Uga, CONST CHAR16 *Title)
554 {
555 UGA_IO_PRIVATE *drv;
556 unsigned int border_width = 0;
557 char *display_name = NULL;
558 int title_len;
559
560 drv = (UGA_IO_PRIVATE *)calloc (1, sizeof (UGA_IO_PRIVATE));
561 if (drv == NULL)
562 return EFI_OUT_OF_RESOURCES;
563
564 #ifdef __APPLE__
565 //
566 //
567 //
568 EFI_STATUS EFIAPI GasketUgaClose (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo);
569 EFI_STATUS EFIAPI GasketUgaSize (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, UINT32 Width, UINT32 Height);
570 EFI_STATUS EFIAPI GasketUgaCheckKey (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo);
571 EFI_STATUS EFIAPI GasketUgaGetKey (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, EFI_INPUT_KEY *key);
572 EFI_STATUS EFIAPI GasketUgaBlt (
573 EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
574 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
575 IN EFI_UGA_BLT_OPERATION BltOperation,
576 IN UINTN SourceX,
577 IN UINTN SourceY,
578 IN UINTN DestinationX,
579 IN UINTN DestinationY,
580 IN UINTN Width,
581 IN UINTN Height,
582 IN UINTN Delta OPTIONAL
583 );
584
585 drv->UgaIo.UgaClose = GasketUgaClose;
586 drv->UgaIo.UgaSize = GasketUgaSize;
587 drv->UgaIo.UgaCheckKey = GasketUgaCheckKey;
588 drv->UgaIo.UgaGetKey = GasketUgaGetKey;
589 drv->UgaIo.UgaBlt = GasketUgaBlt;
590 #else
591 drv->UgaIo.UgaClose = UgaClose;
592 drv->UgaIo.UgaSize = UgaSize;
593 drv->UgaIo.UgaCheckKey = UgaCheckKey;
594 drv->UgaIo.UgaGetKey = UgaGetKey;
595 drv->UgaIo.UgaBlt = UgaBlt;
596 #endif
597
598
599
600 drv->key_count = 0;
601 drv->key_rd = 0;
602 drv->key_wr = 0;
603 drv->display = XOpenDisplay (display_name);
604 if (drv->display == NULL)
605 {
606 fprintf (stderr, "uga: cannot connect to X server %s\n",
607 XDisplayName (display_name));
608 free (drv);
609 return EFI_DEVICE_ERROR;
610 }
611 drv->screen = DefaultScreen (drv->display);
612 drv->visual = DefaultVisual (drv->display, drv->screen);
613 drv->win = XCreateSimpleWindow
614 (drv->display, RootWindow (drv->display, drv->screen),
615 0, 0, 4, 4, border_width,
616 WhitePixel (drv->display, drv->screen),
617 BlackPixel (drv->display, drv->screen));
618
619 drv->depth = DefaultDepth (drv->display, drv->screen);
620
621 /* Compute title len and convert to Ascii. */
622 for (title_len = 0; Title[title_len] != 0; title_len++)
623 ;
624 {
625 char title[title_len + 1];
626 int i;
627 for (i = 0; i < title_len; i++)
628 title[i] = Title[i];
629 title[i] = 0;
630
631 XStoreName (drv->display, drv->win, title);
632 }
633
634 XSelectInput (drv->display, drv->win,
635 ExposureMask | KeyPressMask);
636 drv->gc = DefaultGC (drv->display, drv->screen);
637
638 *Uga = (EFI_UNIX_UGA_IO_PROTOCOL *)drv;
639 return EFI_SUCCESS;
640 }