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