]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/X11GraphicsWindow.c
InOsEmuPkg: Make XIP work properly
[mirror_edk2.git] / InOsEmuPkg / Unix / Sec / X11GraphicsWindow.c
CommitLineData
949f388f 1/*++ @file
2
e332b442 3Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
949f388f 4Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
e332b442 5
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution. The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
949f388f 13
14**/
15
16#include "SecMain.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/* XQueryPointer */
32
33struct uga_drv_shift_mask {
34 unsigned char shift;
35 unsigned char size;
36 unsigned char csize;
37};
38
39#define NBR_KEYS 32
40typedef struct {
41 EMU_GRAPHICS_WINDOW_PROTOCOL GraphicsIo;
42
43 Display *display;
44 int screen; /* values for window_size in main */
45 Window win;
46 GC gc;
47 Visual *visual;
48
49 int depth;
50 unsigned int width;
51 unsigned int height;
52 unsigned int line_bytes;
53 unsigned int pixel_shift;
54 unsigned char *image_data;
55
56 struct uga_drv_shift_mask r, g, b;
57
58 int use_shm;
59 XShmSegmentInfo xshm_info;
60 XImage *image;
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
79void
80HandleEvents(GRAPHICS_IO_PRIVATE *drv);
81
82void
83fill_shift_mask (struct uga_drv_shift_mask *sm, unsigned long mask)
84{
85 sm->shift = 0;
86 sm->size = 0;
87 while ((mask & 1) == 0)
88 {
89 mask >>= 1;
90 sm->shift++;
91 }
92 while (mask & 1)
93 {
94 sm->size++;
95 mask >>= 1;
96 }
97 sm->csize = 8 - sm->size;
98}
99
100int
101TryCreateShmImage (
102 IN GRAPHICS_IO_PRIVATE *drv
103 )
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
159EFI_STATUS
160X11Size(
161 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
162 IN UINT32 Width,
163 IN UINT32 Height
164 )
165{
166 GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
167 XSizeHints size_hints;
168
169 /* Destroy current buffer if created. */
170 if (drv->image != NULL)
171 {
172 /* Before destroy buffer, need to make sure the buffer available for access. */
173 XDestroyImage(drv->image);
174
175 if (drv->use_shm)
176 shmdt (drv->image_data);
177
178 drv->image_data = NULL;
179 drv->image = NULL;
180 }
181
182 drv->width = Width;
183 drv->height = Height;
184 XResizeWindow (drv->display, drv->win, Width, Height);
185
186 /* Allocate image. */
187 if (XShmQueryExtension(drv->display) && TryCreateShmImage(drv)) {
188 drv->use_shm = 1;
189 } else {
190 drv->use_shm = 0;
191 if (drv->depth > 16)
192 drv->pixel_shift = 2;
193 else if (drv->depth > 8)
194 drv->pixel_shift = 1;
195 else
196 drv->pixel_shift = 0;
197
198 drv->image_data = malloc((drv->width * drv->height) << drv->pixel_shift);
199 drv->image = XCreateImage (drv->display, drv->visual, drv->depth,
200 ZPixmap, 0, (char *)drv->image_data,
201 drv->width, drv->height,
202 8 << drv->pixel_shift, 0);
203 }
204 drv->line_bytes = drv->image->bytes_per_line;
205 fill_shift_mask (&drv->r, drv->image->red_mask);
206 fill_shift_mask (&drv->g, drv->image->green_mask);
207 fill_shift_mask (&drv->b, drv->image->blue_mask);
208
209 /* Set WM hints. */
210 size_hints.flags = PSize | PMinSize | PMaxSize;
211 size_hints.min_width = size_hints.max_width = size_hints.base_width = Width;
212 size_hints.min_height = size_hints.max_height = size_hints.base_height = Height;
213 XSetWMNormalHints (drv->display, drv->win, &size_hints);
214
215 XMapWindow (drv->display, drv->win);
216 HandleEvents(drv);
217 return EFI_SUCCESS;
218}
219
220void
221handleKeyEvent(GRAPHICS_IO_PRIVATE *drv, XEvent *ev, BOOLEAN Make)
222{
223 KeySym *KeySym;
224 EFI_KEY_DATA KeyData;
225 int KeySymArraySize;
226
227 if (Make) {
228 if (drv->key_count == NBR_KEYS) {
229 return;
230 }
231 }
232
233 // keycode is a physical key on the keyboard
234 // KeySym is a mapping of a physical key
235 // KeyboardMapping is the array of KeySym for a given keycode. key, shifted key, option key, command key, ...
236 //
237 // Returns an array of KeySymArraySize of KeySym for the keycode. [0] is lower case, [1] is upper case,
238 // [2] and [3] are based on option and command modifiers. The problem we have is command V
239 // could be mapped to a crazy Unicode character so the old scheme of returning a string.
240 //
241 KeySym = XGetKeyboardMapping (drv->display, ev->xkey.keycode, 1, &KeySymArraySize);
242
243 KeyData.Key.ScanCode = 0;
244 KeyData.Key.UnicodeChar = 0;
245 KeyData.KeyState.KeyShiftState = 0;
246
247 //
248 // Skipping EFI_SCROLL_LOCK_ACTIVE & EFI_NUM_LOCK_ACTIVE since they are not on Macs
249 //
250 if ((ev->xkey.state & LockMask) == 0) {
251 drv->KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;
252 } else {
253 if (Make) {
254 drv->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
255 }
256 }
257
258 // Skipping EFI_MENU_KEY_PRESSED and EFI_SYS_REQ_PRESSED
259
260 switch (*KeySym) {
261 case XK_Control_R:
262 if (Make) {
263 drv->KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
264 } else {
265 drv->KeyState.KeyShiftState &= ~EFI_RIGHT_CONTROL_PRESSED;
266 }
267 break;
268 case XK_Control_L:
269 if (Make) {
270 drv->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
271 } else {
272 drv->KeyState.KeyShiftState &= ~EFI_LEFT_CONTROL_PRESSED;
273 }
274 break;
275
276 case XK_Shift_R:
277 if (Make) {
278 drv->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
279 } else {
280 drv->KeyState.KeyShiftState &= ~EFI_RIGHT_SHIFT_PRESSED;
281 }
282 break;
283 case XK_Shift_L:
284 if (Make) {
285 drv->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
286 } else {
287 drv->KeyState.KeyShiftState &= ~EFI_LEFT_SHIFT_PRESSED;
288 }
289 break;
290
291 case XK_Mode_switch:
292 if (Make) {
293 drv->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;
294 } else {
295 drv->KeyState.KeyShiftState &= ~EFI_LEFT_ALT_PRESSED;
296 }
297 break;
298
299 case XK_Meta_R:
300 if (Make) {
301 drv->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
302 } else {
303 drv->KeyState.KeyShiftState &= ~EFI_RIGHT_LOGO_PRESSED;
304 }
305 break;
306 case XK_Meta_L:
307 if (Make) {
308 drv->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
309 } else {
310 drv->KeyState.KeyShiftState &= ~EFI_LEFT_LOGO_PRESSED;
311 }
312 break;
313
314 case XK_KP_Home:
315 case XK_Home: KeyData.Key.ScanCode = SCAN_HOME; break;
316
317 case XK_KP_End:
318 case XK_End: KeyData.Key.ScanCode = SCAN_END; break;
319
320 case XK_KP_Left:
321 case XK_Left: KeyData.Key.ScanCode = SCAN_LEFT; break;
322
323 case XK_KP_Right:
324 case XK_Right: KeyData.Key.ScanCode = SCAN_RIGHT; break;
325
326 case XK_KP_Up:
327 case XK_Up: KeyData.Key.ScanCode = SCAN_UP; break;
328
329 case XK_KP_Down:
330 case XK_Down: KeyData.Key.ScanCode = SCAN_DOWN; break;
331
332 case XK_KP_Delete:
333 case XK_Delete: KeyData.Key.ScanCode = SCAN_DELETE; break;
334
335 case XK_KP_Insert:
336 case XK_Insert: KeyData.Key.ScanCode = SCAN_INSERT; break;
337
338 case XK_KP_Page_Up:
339 case XK_Page_Up: KeyData.Key.ScanCode = SCAN_PAGE_UP; break;
340
341 case XK_KP_Page_Down:
342 case XK_Page_Down: KeyData.Key.ScanCode = SCAN_PAGE_DOWN; break;
343
344 case XK_Escape: KeyData.Key.ScanCode = SCAN_ESC; break;
345
e332b442 346 case XK_Pause: KeyData.Key.ScanCode = SCAN_PAUSE; break;
347
949f388f 348 case XK_KP_F1:
349 case XK_F1: KeyData.Key.ScanCode = SCAN_F1; break;
350
351 case XK_KP_F2:
352 case XK_F2: KeyData.Key.ScanCode = SCAN_F2; break;
353
354 case XK_KP_F3:
355 case XK_F3: KeyData.Key.ScanCode = SCAN_F3; break;
356
357 case XK_KP_F4:
358 case XK_F4: KeyData.Key.ScanCode = SCAN_F4; break;
359
360 case XK_F5: KeyData.Key.ScanCode = SCAN_F5; break;
361 case XK_F6: KeyData.Key.ScanCode = SCAN_F6; break;
362 case XK_F7: KeyData.Key.ScanCode = SCAN_F7; break;
363
364 // Don't map into X11 by default on a Mac
365 // System Preferences->Keyboard->Keyboard Shortcuts can be configured
366 // to not use higher function keys as shortcuts and the will show up
367 // in X11.
368 case XK_F8: KeyData.Key.ScanCode = SCAN_F8; break;
369 case XK_F9: KeyData.Key.ScanCode = SCAN_F9; break;
370 case XK_F10: KeyData.Key.ScanCode = SCAN_F10; break;
371
372 case XK_F11: KeyData.Key.ScanCode = SCAN_F11; break;
373 case XK_F12: KeyData.Key.ScanCode = SCAN_F12; break;
374
375 case XK_F13: KeyData.Key.ScanCode = SCAN_F13; break;
376 case XK_F14: KeyData.Key.ScanCode = SCAN_F14; break;
377 case XK_F15: KeyData.Key.ScanCode = SCAN_F15; break;
378 case XK_F16: KeyData.Key.ScanCode = SCAN_F16; break;
379 case XK_F17: KeyData.Key.ScanCode = SCAN_F17; break;
380 case XK_F18: KeyData.Key.ScanCode = SCAN_F18; break;
381 case XK_F19: KeyData.Key.ScanCode = SCAN_F19; break;
382 case XK_F20: KeyData.Key.ScanCode = SCAN_F20; break;
383 case XK_F21: KeyData.Key.ScanCode = SCAN_F21; break;
384 case XK_F22: KeyData.Key.ScanCode = SCAN_F22; break;
385 case XK_F23: KeyData.Key.ScanCode = SCAN_F23; break;
386 case XK_F24: KeyData.Key.ScanCode = SCAN_F24; break;
387
388 // No mapping in X11
389 //case XK_: KeyData.Key.ScanCode = SCAN_MUTE; break;
390 //case XK_: KeyData.Key.ScanCode = SCAN_VOLUME_UP; break;
391 //case XK_: KeyData.Key.ScanCode = SCAN_VOLUME_DOWN; break;
392 //case XK_: KeyData.Key.ScanCode = SCAN_BRIGHTNESS_UP; break;
393 //case XK_: KeyData.Key.ScanCode = SCAN_BRIGHTNESS_DOWN; break;
394 //case XK_: KeyData.Key.ScanCode = SCAN_SUSPEND; break;
395 //case XK_: KeyData.Key.ScanCode = SCAN_HIBERNATE; break;
396 //case XK_: KeyData.Key.ScanCode = SCAN_TOGGLE_DISPLAY; break;
397 //case XK_: KeyData.Key.ScanCode = SCAN_RECOVERY; break;
398 //case XK_: KeyData.Key.ScanCode = SCAN_EJECT; break;
399
400 case XK_BackSpace: KeyData.Key.UnicodeChar = 0x0008; break;
401
402 case XK_KP_Tab:
403 case XK_Tab: KeyData.Key.UnicodeChar = 0x0009; break;
404
405 case XK_Linefeed: KeyData.Key.UnicodeChar = 0x000a; break;
406
407 case XK_KP_Enter:
408 case XK_Return: KeyData.Key.UnicodeChar = 0x000d; break;
409
410 case XK_KP_Equal : KeyData.Key.UnicodeChar = L'='; break;
411 case XK_KP_Multiply : KeyData.Key.UnicodeChar = L'*'; break;
412 case XK_KP_Add : KeyData.Key.UnicodeChar = L'+'; break;
413 case XK_KP_Separator : KeyData.Key.UnicodeChar = L'~'; break;
414 case XK_KP_Subtract : KeyData.Key.UnicodeChar = L'-'; break;
415 case XK_KP_Decimal : KeyData.Key.UnicodeChar = L'.'; break;
416 case XK_KP_Divide : KeyData.Key.UnicodeChar = L'/'; break;
417
418 case XK_KP_0 : KeyData.Key.UnicodeChar = L'0'; break;
419 case XK_KP_1 : KeyData.Key.UnicodeChar = L'1'; break;
420 case XK_KP_2 : KeyData.Key.UnicodeChar = L'2'; break;
421 case XK_KP_3 : KeyData.Key.UnicodeChar = L'3'; break;
422 case XK_KP_4 : KeyData.Key.UnicodeChar = L'4'; break;
423 case XK_KP_5 : KeyData.Key.UnicodeChar = L'5'; break;
424 case XK_KP_6 : KeyData.Key.UnicodeChar = L'6'; break;
425 case XK_KP_7 : KeyData.Key.UnicodeChar = L'7'; break;
426 case XK_KP_8 : KeyData.Key.UnicodeChar = L'8'; break;
427 case XK_KP_9 : KeyData.Key.UnicodeChar = L'9'; break;
428
429 default:
430 ;
431 }
432
433 // The global state is our state
434 KeyData.KeyState.KeyShiftState = drv->KeyState.KeyShiftState;
435 KeyData.KeyState.KeyToggleState = drv->KeyState.KeyToggleState;
436
437 if (*KeySym < XK_BackSpace) {
438 if (((drv->KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) ||
439 ((drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0) ) {
440
441 KeyData.Key.UnicodeChar = (CHAR16)KeySym[KEYSYM_UPPER];
442
443 // Per UEFI spec since we converted the Unicode clear the shift bits we pass up
444 KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
445 } else {
446 KeyData.Key.UnicodeChar = (CHAR16)KeySym[KEYSYM_LOWER];
447 }
448 } else {
449 // XK_BackSpace is the start of XK_MISCELLANY. These are the XK_? keys we process in this file
450 ;
451 }
452
453 if (Make) {
454 memcpy (&drv->keys[drv->key_wr], &KeyData, sizeof (EFI_KEY_DATA));
455 drv->key_wr = (drv->key_wr + 1) % NBR_KEYS;
456 drv->key_count++;
457 if (drv->MakeRegisterdKeyCallback != NULL) {
458 ReverseGasketUint64Uint64 (drv->MakeRegisterdKeyCallback ,drv->RegisterdKeyCallbackContext, &KeyData);
459 }
460 } else {
461 if (drv->BreakRegisterdKeyCallback != NULL) {
462 ReverseGasketUint64Uint64 (drv->BreakRegisterdKeyCallback ,drv->RegisterdKeyCallbackContext, &KeyData);
463 }
464 }
465}
466
467
468void
469handleMouseMoved(GRAPHICS_IO_PRIVATE *drv, XEvent *ev)
470{
471 if ( ev->xmotion.x != drv->previous_x )
472 {
473 drv->pointer_state.RelativeMovementX += ( ev->xmotion.x - drv->previous_x );
474 drv->previous_x = ev->xmotion.x;
475 drv->pointer_state_changed = 1;
476 }
477
478 if ( ev->xmotion.y != drv->previous_y )
479 {
480 drv->pointer_state.RelativeMovementY += ( ev->xmotion.y - drv->previous_y );
481 drv->previous_y = ev->xmotion.y;
482 drv->pointer_state_changed = 1;
483 }
484
485 drv->pointer_state.RelativeMovementZ = 0;
486}
487
488void
489handleMouseDown(GRAPHICS_IO_PRIVATE *drv, XEvent *ev, BOOLEAN Pressed)
490{
491 if ( ev->xbutton.button == Button1 )
492 {
493 drv->pointer_state_changed = ( drv->pointer_state.LeftButton != Pressed );
494 drv->pointer_state.LeftButton = Pressed;
495 }
496 if ( ev->xbutton.button == Button2 )
497 {
498 drv->pointer_state_changed = ( drv->pointer_state.RightButton != Pressed );
499 drv->pointer_state.RightButton = Pressed;
500 }
501}
502
503void
504Redraw(GRAPHICS_IO_PRIVATE *drv, UINTN X, UINTN Y, UINTN Width, UINTN Height)
505{
506 if (drv->use_shm)
507 XShmPutImage (drv->display, drv->win, drv->gc, drv->image,
508 X, Y, X, Y, Width, Height, False);
509 else
510 XPutImage (drv->display, drv->win, drv->gc, drv->image,
511 X, Y, X, Y, Width, Height);
512 XFlush(drv->display);
513}
514
515void
516HandleEvent(GRAPHICS_IO_PRIVATE *drv, XEvent *ev)
517{
518 switch (ev->type)
519 {
520 case Expose:
521 Redraw(drv, ev->xexpose.x, ev->xexpose.y,
522 ev->xexpose.width, ev->xexpose.height);
523 break;
524 case GraphicsExpose:
525 Redraw(drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
526 ev->xgraphicsexpose.width, ev->xgraphicsexpose.height);
527 break;
528 case KeyPress:
529 handleKeyEvent(drv, ev, TRUE);
530 break;
531 case KeyRelease:
532 handleKeyEvent(drv, ev, FALSE);
533 break;
534 case MappingNotify:
535 XRefreshKeyboardMapping(&ev->xmapping);
536 break;
537 case MotionNotify:
538 handleMouseMoved(drv, ev);
539 break;
540 case ButtonPress:
541 handleMouseDown(drv, ev, TRUE);
542 break;
543 case ButtonRelease:
544 handleMouseDown(drv, ev, FALSE);
545 break;
546#if 0
547 case DestroyNotify:
548 XCloseDisplay (drv->display);
549 exit (1);
550 break;
551#endif
552 case NoExpose:
553 default:
554 break;
555 }
556}
557
558void
559HandleEvents(GRAPHICS_IO_PRIVATE *drv)
560{
561 while (XPending(drv->display) != 0)
562 {
563 XEvent ev;
564
565 XNextEvent (drv->display, &ev);
566 HandleEvent(drv, &ev);
567 }
568}
569
570unsigned long
571X11PixelToColor (GRAPHICS_IO_PRIVATE *drv, EFI_UGA_PIXEL pixel)
572{
573 return ((pixel.Red >> drv->r.csize) << drv->r.shift)
574 | ((pixel.Green >> drv->g.csize) << drv->g.shift)
575 | ((pixel.Blue >> drv->b.csize) << drv->b.shift);
576}
577
578EFI_UGA_PIXEL
579X11ColorToPixel (GRAPHICS_IO_PRIVATE *drv, unsigned long val)
580{
581 EFI_UGA_PIXEL res;
582
583 memset (&res, 0, sizeof (EFI_UGA_PIXEL));
584 /* FIXME: should round instead of truncate. */
585 res.Red = (val >> drv->r.shift) << drv->r.csize;
586 res.Green = (val >> drv->g.shift) << drv->g.csize;
587 res.Blue = (val >> drv->b.shift) << drv->b.csize;
588
589 return res;
590}
591
592STATIC EFI_STATUS
593CheckKeyInternal( GRAPHICS_IO_PRIVATE *drv, BOOLEAN delay )
594{
595 HandleEvents(drv);
596 if (drv->key_count != 0)
597 return EFI_SUCCESS;
598 if ( delay )
599 /* EFI is polling. Be CPU-friendly. */
600 SecSleep (20);
601 return EFI_NOT_READY;
602 }
603
604EFI_STATUS
605X11CheckKey(EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo)
606{
607 GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
608 return CheckKeyInternal(drv, TRUE);
609}
610
611EFI_STATUS
612EFIAPI
613X11GetKey (
614 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
615 IN EFI_KEY_DATA *KeyData
616 )
617{
618 GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
619 EFI_STATUS status;
620
621 status = CheckKeyInternal(drv, FALSE);
622 if (status != EFI_SUCCESS)
623 return status;
624
625 CopyMem (KeyData, &drv->keys[drv->key_rd], sizeof (EFI_KEY_DATA));
626 drv->key_rd = (drv->key_rd + 1) % NBR_KEYS;
627 drv->key_count--;
628 return EFI_SUCCESS;
629}
630
631
632EFI_STATUS
633EFIAPI
634X11KeySetState (
635 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
636 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
637 )
638{
639 GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
640// XKeyEvent event;
641
642 if (*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) {
643 if ((drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == 0) {
644 //
645 // We could create an XKeyEvent and send a XK_Caps_Lock to
646 // the UGA/GOP Window
647 //
648 }
649 }
650
651 drv->KeyState.KeyToggleState = *KeyToggleState;
652 return EFI_SUCCESS;
653}
654
655
656EFI_STATUS
657EFIAPI
658X11RegisterKeyNotify (
659 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
660 IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeCallBack,
661 IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakCallBack,
662 IN VOID *Context
663 )
664{
665 GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
666
667 drv->MakeRegisterdKeyCallback = MakeCallBack;
668 drv->BreakRegisterdKeyCallback = BreakCallBack;
669 drv->RegisterdKeyCallbackContext = Context;
670
671 return EFI_SUCCESS;
672}
673
674
675EFI_STATUS
676X11Blt (
677 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
678 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
679 IN EFI_UGA_BLT_OPERATION BltOperation,
680 IN EMU_GRAPHICS_WINDOWS__BLT_ARGS *Args
681 )
682{
683 GRAPHICS_IO_PRIVATE *Private = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
684 UINTN DstY;
685 UINTN SrcY;
686 UINTN DstX;
687 UINTN SrcX;
688 UINTN Index;
689 EFI_UGA_PIXEL *Blt;
690 UINT8 *Dst;
691 UINT8 *Src;
692 UINTN Nbr;
693 unsigned long Color;
694
695 //
696 // Check bounds
697 //
698 if (BltOperation == EfiUgaVideoToBltBuffer
699 || BltOperation == EfiUgaVideoToVideo) {
700 //
701 // Source is Video.
702 //
703 if (Args->SourceY + Args->Height > Private->height) {
704 return EFI_INVALID_PARAMETER;
705 }
706
707 if (Args->SourceX + Args->Width > Private->width) {
708 return EFI_INVALID_PARAMETER;
709 }
710 }
711
712 if (BltOperation == EfiUgaBltBufferToVideo
713 || BltOperation == EfiUgaVideoToVideo
714 || BltOperation == EfiUgaVideoFill) {
715 //
716 // Destination is Video
717 //
718 if (Args->DestinationY + Args->Height > Private->height) {
719 return EFI_INVALID_PARAMETER;
720 }
721
722 if (Args->DestinationX + Args->Width > Private->width) {
723 return EFI_INVALID_PARAMETER;
724 }
725 }
726
727 switch (BltOperation) {
728 case EfiUgaVideoToBltBuffer:
729 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->DestinationY * Args->Delta) + Args->DestinationX * sizeof (EFI_UGA_PIXEL));
730 Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL);
731 for (SrcY = Args->SourceY; SrcY < (Args->Height + Args->SourceY); SrcY++) {
732 for (SrcX = Args->SourceX; SrcX < (Args->Width + Args->SourceX); SrcX++) {
733 *Blt++ = X11ColorToPixel(Private,
734 XGetPixel(Private->image, SrcX, SrcY));
735 }
736 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta);
737 }
738 break;
739 case EfiUgaBltBufferToVideo:
740 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->SourceY * Args->Delta) + Args->SourceX * sizeof (EFI_UGA_PIXEL));
741 Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL);
742 for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) {
743 for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) {
744 XPutPixel(Private->image, DstX, DstY, X11PixelToColor(Private, *Blt));
745 Blt++;
746 }
747 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta);
748 }
749 break;
750 case EfiUgaVideoToVideo:
751 Dst = Private->image_data + (Args->DestinationX << Private->pixel_shift)
752 + Args->DestinationY * Private->line_bytes;
753 Src = Private->image_data + (Args->SourceX << Private->pixel_shift)
754 + Args->SourceY * Private->line_bytes;
755 Nbr = Args->Width << Private->pixel_shift;
756 if (Args->DestinationY < Args->SourceY) {
757 for (Index = 0; Index < Args->Height; Index++) {
758 memcpy (Dst, Src, Nbr);
759 Dst += Private->line_bytes;
760 Src += Private->line_bytes;
761 }
762 }
763 else {
764 Dst += (Args->Height - 1) * Private->line_bytes;
765 Src += (Args->Height - 1) * Private->line_bytes;
766 for (Index = 0; Index < Args->Height; Index++) {
767 //
768 // Source and Destination Y may be equal, therefore Dst and Src may
769 // overlap.
770 //
771 memmove (Dst, Src, Nbr);
772 Dst -= Private->line_bytes;
773 Src -= Private->line_bytes;
774 }
775 }
776 break;
777 case EfiUgaVideoFill:
778 Color = X11PixelToColor(Private, *BltBuffer);
779 for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) {
780 for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) {
781 XPutPixel(Private->image, DstX, DstY, Color);
782 }
783 }
784 break;
785 default:
786 return EFI_INVALID_PARAMETER;
787 }
788
789 //
790 // Refresh screen.
791 //
792 switch (BltOperation) {
793 case EfiUgaVideoToVideo:
794 XCopyArea(Private->display, Private->win, Private->win, Private->gc,
795 Args->SourceX, Args->SourceY, Args->Width, Args->Height, Args->DestinationX, Args->DestinationY);
796 while (1) {
797 XEvent ev;
798
799 XNextEvent (Private->display, &ev);
800 HandleEvent(Private, &ev);
801 if (ev.type == NoExpose || ev.type == GraphicsExpose)
802 break;
803 }
804 break;
805 case EfiUgaVideoFill:
806 Color = X11PixelToColor(Private, *BltBuffer);
807 XSetForeground(Private->display, Private->gc, Color);
808 XFillRectangle(Private->display, Private->win, Private->gc,
809 Args->DestinationX, Args->DestinationY, Args->Width, Args->Height);
810 XFlush(Private->display);
811 break;
812 case EfiUgaBltBufferToVideo:
813 Redraw(Private, Args->DestinationX, Args->DestinationY, Args->Width, Args->Height);
814 break;
815 default:
816 break;
817 }
818 return EFI_SUCCESS;
819}
820
821STATIC EFI_STATUS
822CheckPointerInternal( GRAPHICS_IO_PRIVATE *drv, BOOLEAN delay )
823{
824 HandleEvents(drv);
825 if (drv->pointer_state_changed != 0)
826 return EFI_SUCCESS;
827 if ( delay )
828 /* EFI is polling. Be CPU-friendly. */
829 SecSleep (20);
830 return EFI_NOT_READY;
831}
832
833EFI_STATUS
834X11CheckPointer(EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo)
835{
836 GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
837 return( CheckPointerInternal( drv, TRUE ) );
838}
839
840EFI_STATUS
841X11GetPointerState (EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, EFI_SIMPLE_POINTER_STATE *state)
842{
843 GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
844 EFI_STATUS status;
845
846 status = CheckPointerInternal( drv, FALSE );
847 if (status != EFI_SUCCESS)
848 return status;
849
850 memcpy( state, &drv->pointer_state, sizeof( EFI_SIMPLE_POINTER_STATE ) );
851
852 drv->pointer_state.RelativeMovementX = 0;
853 drv->pointer_state.RelativeMovementY = 0;
854 drv->pointer_state.RelativeMovementZ = 0;
855 drv->pointer_state_changed = 0;
856 return EFI_SUCCESS;
857}
858
859
860
861EFI_STATUS
862X11GraphicsWindowOpen (
863 IN EMU_IO_THUNK_PROTOCOL *This
864 )
865{
866 GRAPHICS_IO_PRIVATE *drv;
867 unsigned int border_width = 0;
868 char *display_name = NULL;
869 int title_len;
870
871 drv = (GRAPHICS_IO_PRIVATE *)calloc (1, sizeof (GRAPHICS_IO_PRIVATE));
872 if (drv == NULL)
873 return EFI_OUT_OF_RESOURCES;
874
875 drv->GraphicsIo.Size = GasketX11Size;
876 drv->GraphicsIo.CheckKey = GasketX11CheckKey;
877 drv->GraphicsIo.GetKey = GasketX11GetKey;
878 drv->GraphicsIo.KeySetState = GasketX11KeySetState;
879 drv->GraphicsIo.RegisterKeyNotify = GasketX11RegisterKeyNotify;
880 drv->GraphicsIo.Blt = GasketX11Blt;
881 drv->GraphicsIo.CheckPointer = GasketX11CheckPointer;
882 drv->GraphicsIo.GetPointerState = GasketX11GetPointerState;
883
884
885 drv->key_count = 0;
886 drv->key_rd = 0;
887 drv->key_wr = 0;
888 drv->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
889 drv->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
890 drv->MakeRegisterdKeyCallback = NULL;
891 drv->BreakRegisterdKeyCallback = NULL;
892 drv->RegisterdKeyCallbackContext = NULL;
893
894
895 drv->display = XOpenDisplay (display_name);
896 if (drv->display == NULL) {
897 fprintf (stderr, "uga: cannot connect to X server %s\n", XDisplayName (display_name));
898 free (drv);
899 return EFI_DEVICE_ERROR;
900 }
901 drv->screen = DefaultScreen (drv->display);
902 drv->visual = DefaultVisual (drv->display, drv->screen);
903 drv->win = XCreateSimpleWindow
904 (drv->display, RootWindow (drv->display, drv->screen),
905 0, 0, 4, 4, border_width,
906 WhitePixel (drv->display, drv->screen),
907 BlackPixel (drv->display, drv->screen));
908
909 drv->depth = DefaultDepth (drv->display, drv->screen);
910 XDefineCursor (drv->display, drv->win, XCreateFontCursor (drv->display, XC_pirate));
911
912 /* Compute title len and convert to Ascii. */
913 for (title_len = 0; This->ConfigString[title_len] != 0; title_len++)
914 ;
915 {
916 char title[title_len + 1];
917 int i;
918 for (i = 0; i < title_len; i++)
919 title[i] = This->ConfigString[i];
920 title[i] = 0;
921
922 XStoreName (drv->display, drv->win, title);
923 }
924
925// XAutoRepeatOff (drv->display);
926 XSelectInput (drv->display, drv->win,
927 ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask );
928 drv->gc = DefaultGC (drv->display, drv->screen);
929
930 This->Private = (VOID *)drv;
931 This->Interface = (VOID *)drv;
932 return EFI_SUCCESS;
933}
934
935
936EFI_STATUS
937X11GraphicsWindowClose (
938 IN EMU_IO_THUNK_PROTOCOL *This
939 )
940{
941 GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)This->Private;
942
943 if (drv == NULL)
944 return EFI_SUCCESS;
945 if (drv->image != NULL)
946 {
947 XDestroyImage(drv->image);
948
949 if (drv->use_shm)
950 shmdt (drv->image_data);
951
952 drv->image_data = NULL;
953 drv->image = NULL;
954 }
955 XDestroyWindow(drv->display, drv->win);
956 XCloseDisplay(drv->display);
957
958#ifdef __APPLE__
959 // Free up the shared memory
960 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
961#endif
962
963 free(drv);
964 return EFI_SUCCESS;
965}
966
967
968EMU_IO_THUNK_PROTOCOL gX11ThunkIo = {
969 &gEmuGraphicsWindowProtocolGuid,
970 NULL,
971 NULL,
972 0,
973 GasketX11GraphicsWindowOpen,
974 GasketX11GraphicsWindowClose,
975 NULL
976};
977
978