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