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