]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Unix/Host/X11GraphicsWindow.c
EmulatorPkg: Remove all trailing whitespace
[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;
d18d8a1d 43 int screen; // values for window_size in main
bfa084fa 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;
d18d8a1d 68
949f388f 69 EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeRegisterdKeyCallback;
70 EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakRegisterdKeyCallback;
71 VOID *RegisterdKeyCallbackContext;
d18d8a1d 72
949f388f 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 (
d18d8a1d 86 IN struct uga_drv_shift_mask *sm,
bfa084fa 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 }
d18d8a1d 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 }
d18d8a1d 144
145#ifndef __APPLE__
949f388f 146 //
147 // This closes shared memory in real time on OS X. Only closes after folks quit using
d18d8a1d 148 // it on Linux.
949f388f 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 (
d18d8a1d 167 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
168 IN UINT32 Width,
949f388f 169 IN UINT32 Height
170 )
171{
bfa084fa 172 GRAPHICS_IO_PRIVATE *Drv;
173 XSizeHints size_hints;
949f388f 174
d18d8a1d 175 // Destroy current buffer if created.
bfa084fa 176 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
177 if (Drv->image != NULL) {
d18d8a1d 178 // Before destroy buffer, need to make sure the buffer available for access.
bfa084fa 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
d18d8a1d 193 // Allocate image.
bfa084fa 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 }
d18d8a1d 205
bfa084fa 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 }
d18d8a1d 214
bfa084fa 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
d18d8a1d 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 (
d18d8a1d 234 IN GRAPHICS_IO_PRIVATE *Drv,
235 IN XEvent *ev,
bfa084fa 236 IN BOOLEAN Make
237 )
949f388f 238{
239 KeySym *KeySym;
240 EFI_KEY_DATA KeyData;
241 int KeySymArraySize;
d18d8a1d 242
949f388f 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
d18d8a1d 255 // could be mapped to a crazy Unicode character so the old scheme of returning a string.
949f388f 256 //
bfa084fa 257 KeySym = XGetKeyboardMapping (Drv->display, ev->xkey.keycode, 1, &KeySymArraySize);
d18d8a1d 258
949f388f 259 KeyData.Key.ScanCode = 0;
260 KeyData.Key.UnicodeChar = 0;
261 KeyData.KeyState.KeyShiftState = 0;
262
263 //
d18d8a1d 264 // Skipping EFI_SCROLL_LOCK_ACTIVE & EFI_NUM_LOCK_ACTIVE since they are not on Macs
949f388f 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 }
d18d8a1d 273
949f388f 274 // Skipping EFI_MENU_KEY_PRESSED and EFI_SYS_REQ_PRESSED
d18d8a1d 275
949f388f 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:
d18d8a1d 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;
d18d8a1d 306
949f388f 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;
d18d8a1d 329
949f388f 330 case XK_KP_Home:
331 case XK_Home: KeyData.Key.ScanCode = SCAN_HOME; break;
d18d8a1d 332
949f388f 333 case XK_KP_End:
334 case XK_End: KeyData.Key.ScanCode = SCAN_END; break;
d18d8a1d 335
336 case XK_KP_Left:
949f388f 337 case XK_Left: KeyData.Key.ScanCode = SCAN_LEFT; break;
d18d8a1d 338
949f388f 339 case XK_KP_Right:
340 case XK_Right: KeyData.Key.ScanCode = SCAN_RIGHT; break;
d18d8a1d 341
949f388f 342 case XK_KP_Up:
343 case XK_Up: KeyData.Key.ScanCode = SCAN_UP; break;
d18d8a1d 344
949f388f 345 case XK_KP_Down:
346 case XK_Down: KeyData.Key.ScanCode = SCAN_DOWN; break;
d18d8a1d 347
949f388f 348 case XK_KP_Delete:
349 case XK_Delete: KeyData.Key.ScanCode = SCAN_DELETE; break;
d18d8a1d 350
351 case XK_KP_Insert:
949f388f 352 case XK_Insert: KeyData.Key.ScanCode = SCAN_INSERT; break;
d18d8a1d 353
949f388f 354 case XK_KP_Page_Up:
355 case XK_Page_Up: KeyData.Key.ScanCode = SCAN_PAGE_UP; break;
d18d8a1d 356
949f388f 357 case XK_KP_Page_Down:
358 case XK_Page_Down: KeyData.Key.ScanCode = SCAN_PAGE_DOWN; break;
d18d8a1d 359
949f388f 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;
d18d8a1d 366
949f388f 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;
d18d8a1d 379
949f388f 380 // Don't map into X11 by default on a Mac
d18d8a1d 381 // System Preferences->Keyboard->Keyboard Shortcuts can be configured
949f388f 382 // to not use higher function keys as shortcuts and the will show up
d18d8a1d 383 // in X11.
949f388f 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;
d18d8a1d 387
949f388f 388 case XK_F11: KeyData.Key.ScanCode = SCAN_F11; break;
389 case XK_F12: KeyData.Key.ScanCode = SCAN_F12; break;
d18d8a1d 390
949f388f 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
d18d8a1d 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;
949f388f 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;
d18d8a1d 422
949f388f 423 case XK_KP_Enter:
424 case XK_Return: KeyData.Key.UnicodeChar = 0x000d; break;
425
d18d8a1d 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;
949f388f 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) ) {
d18d8a1d 456
949f388f 457 KeyData.Key.UnicodeChar = (CHAR16)KeySym[KEYSYM_UPPER];
458
d18d8a1d 459 // Per UEFI spec since we converted the Unicode clear the shift bits we pass up
949f388f 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 {
d18d8a1d 465 // XK_BackSpace is the start of XK_MISCELLANY. These are the XK_? keys we process in this file
466 ;
949f388f 467 }
d18d8a1d 468
949f388f 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;
d18d8a1d 472 Drv->key_count++;
bfa084fa 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(
d18d8a1d 486 IN GRAPHICS_IO_PRIVATE *Drv,
bfa084fa 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 (
d18d8a1d 507 IN GRAPHICS_IO_PRIVATE *Drv,
508 IN XEvent *ev,
bfa084fa 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 (
d18d8a1d 524 IN GRAPHICS_IO_PRIVATE *Drv,
525 IN UINTN X,
526 IN UINTN Y,
527 IN UINTN Width,
bfa084fa 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 (
d18d8a1d 600 IN GRAPHICS_IO_PRIVATE *Drv,
bfa084fa 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 (
d18d8a1d 611 IN GRAPHICS_IO_PRIVATE *Drv,
bfa084fa 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));
d18d8a1d 618
bfa084fa 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;
d18d8a1d 634
bfa084fa 635 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
d18d8a1d 636
57c7d70f 637 HandleEvents (Drv);
d18d8a1d 638
57c7d70f 639 if (Drv->key_count != 0) {
640 return EFI_SUCCESS;
641 }
d18d8a1d 642
57c7d70f 643 return EFI_NOT_READY;
949f388f 644}
645
646EFI_STATUS
949f388f 647X11GetKey (
d18d8a1d 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;
d18d8a1d 654
bfa084fa 655 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
949f388f 656
57c7d70f 657 EfiStatus = X11CheckKey (GraphicsIo);
bfa084fa 658 if (EFI_ERROR (EfiStatus)) {
659 return EfiStatus;
660 }
d18d8a1d 661
bfa084fa 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--;
d18d8a1d 665
949f388f 666 return EFI_SUCCESS;
667}
668
669
670EFI_STATUS
949f388f 671X11KeySetState (
d18d8a1d 672 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
bfa084fa 673 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
949f388f 674 )
675{
bfa084fa 676 GRAPHICS_IO_PRIVATE *Drv;
d18d8a1d 677
678 Drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo;
679
949f388f 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 }
d18d8a1d 688
bfa084fa 689 Drv->KeyState.KeyToggleState = *KeyToggleState;
949f388f 690 return EFI_SUCCESS;
691}
692
693
694EFI_STATUS
949f388f 695X11RegisterKeyNotify (
d18d8a1d 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
d18d8a1d 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,
d18d8a1d 837 Args->SourceX, Args->SourceY, Args->Width, Args->Height,
bfa084fa 838 Args->DestinationX, Args->DestinationY
839 );
d18d8a1d 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 }
d18d8a1d 881
57c7d70f 882 return EFI_NOT_READY;
949f388f 883}
884
57c7d70f 885
949f388f 886EFI_STATUS
57c7d70f 887X11GetPointerState (
d18d8a1d 888 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
57c7d70f 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 }
d18d8a1d 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;
d18d8a1d 935
949f388f 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;
d18d8a1d 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);
d18d8a1d 963 XDefineCursor (Drv->display, Drv->win, XCreateFontCursor (Drv->display, XC_pirate));
bfa084fa 964
d18d8a1d 965 Drv->Title = malloc (StrSize (This->ConfigString));
bfa084fa 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,
d18d8a1d 972 ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask
bfa084fa 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 }
d18d8a1d 994
bfa084fa 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);
d18d8a1d 1007
949f388f 1008#ifdef __APPLE__
1009 // Free up the shared memory
bfa084fa 1010 shmctl (Drv->xshm_info.shmid, IPC_RMID, NULL);
949f388f 1011#endif
d18d8a1d 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