OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This file defines utility functions for X11 (Linux only). This code has been | 5 // This file defines utility functions for X11 (Linux only). This code has been |
6 // ported from XCB since we can't use XCB on Ubuntu while its 32-bit support | 6 // ported from XCB since we can't use XCB on Ubuntu while its 32-bit support |
7 // remains woefully incomplete. | 7 // remains woefully incomplete. |
8 | 8 |
9 #include "app/x11_util.h" | 9 #include "app/x11_util.h" |
10 | 10 |
11 #include <gdk/gdk.h> | 11 #include <gdk/gdk.h> |
12 #include <gdk/gdkx.h> | 12 #include <gdk/gdkx.h> |
13 #include <gtk/gtk.h> | 13 #include <gtk/gtk.h> |
14 | 14 |
15 #include <sys/ipc.h> | 15 #include <sys/ipc.h> |
16 #include <sys/shm.h> | 16 #include <sys/shm.h> |
17 | 17 |
18 #include <list> | 18 #include <list> |
19 #include <set> | 19 #include <set> |
20 | 20 |
21 #include "base/command_line.h" | 21 #include "base/command_line.h" |
22 #include "base/logging.h" | 22 #include "base/logging.h" |
| 23 #include "base/stringprintf.h" |
23 #include "base/thread.h" | 24 #include "base/thread.h" |
24 #include "app/x11_util_internal.h" | 25 #include "app/x11_util_internal.h" |
25 #include "gfx/rect.h" | 26 #include "gfx/rect.h" |
26 #include "gfx/size.h" | 27 #include "gfx/size.h" |
27 | 28 |
28 namespace x11_util { | 29 namespace x11_util { |
29 | 30 |
30 namespace { | 31 namespace { |
31 | 32 |
32 // Used to cache the XRenderPictFormat for a visual/display pair. | 33 // Used to cache the XRenderPictFormat for a visual/display pair. |
(...skipping 13 matching lines...) Expand all Loading... |
46 CachedPictFormats* get_cached_pict_formats() { | 47 CachedPictFormats* get_cached_pict_formats() { |
47 static CachedPictFormats* formats = NULL; | 48 static CachedPictFormats* formats = NULL; |
48 if (!formats) | 49 if (!formats) |
49 formats = new CachedPictFormats(); | 50 formats = new CachedPictFormats(); |
50 return formats; | 51 return formats; |
51 } | 52 } |
52 | 53 |
53 // Maximum number of CachedPictFormats we keep around. | 54 // Maximum number of CachedPictFormats we keep around. |
54 const size_t kMaxCacheSize = 5; | 55 const size_t kMaxCacheSize = 5; |
55 | 56 |
56 int X11ErrorHandler(Display* d, XErrorEvent* e) { | 57 int DefaultX11ErrorHandler(Display* d, XErrorEvent* e) { |
57 LOG(FATAL) << "X Error detected: serial " << e->serial | 58 LOG(FATAL) << GetErrorEventDescription(e); |
58 << " error_code " << static_cast<unsigned int>(e->error_code) | |
59 << " request_code " << static_cast<unsigned int>(e->request_code) | |
60 << " minor_code " << static_cast<unsigned int>(e->minor_code); | |
61 return 0; | 59 return 0; |
62 } | 60 } |
63 | 61 |
64 int X11IOErrorHandler(Display* d) { | 62 int DefaultX11IOErrorHandler(Display* d) { |
| 63 // If there's an IO error it likely means the X server has gone away |
65 LOG(FATAL) << "X IO Error detected"; | 64 LOG(FATAL) << "X IO Error detected"; |
66 return 0; | 65 return 0; |
67 } | 66 } |
68 | 67 |
69 } // namespace | 68 } // namespace |
70 | 69 |
71 void SetX11ErrorHandlers() { | |
72 XSetErrorHandler(X11ErrorHandler); | |
73 XSetIOErrorHandler(X11IOErrorHandler); | |
74 } | |
75 | |
76 bool XDisplayExists() { | 70 bool XDisplayExists() { |
77 return (gdk_display_get_default() != NULL); | 71 return (gdk_display_get_default() != NULL); |
78 } | 72 } |
79 | 73 |
80 Display* GetXDisplay() { | 74 Display* GetXDisplay() { |
81 static Display* display = NULL; | 75 static Display* display = NULL; |
82 | 76 |
83 if (!display) | 77 if (!display) |
84 display = gdk_x11_get_default_xdisplay(); | 78 display = gdk_x11_get_default_xdisplay(); |
85 | 79 |
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 return result; | 448 return result; |
455 } | 449 } |
456 | 450 |
457 void RestackWindow(XID window, XID sibling, bool above) { | 451 void RestackWindow(XID window, XID sibling, bool above) { |
458 XWindowChanges changes; | 452 XWindowChanges changes; |
459 changes.sibling = sibling; | 453 changes.sibling = sibling; |
460 changes.stack_mode = above ? Above : Below; | 454 changes.stack_mode = above ? Above : Below; |
461 XConfigureWindow(GetXDisplay(), window, CWSibling | CWStackMode, &changes); | 455 XConfigureWindow(GetXDisplay(), window, CWSibling | CWStackMode, &changes); |
462 } | 456 } |
463 | 457 |
464 XRenderPictFormat* GetRenderVisualFormat(Display* dpy, Visual* visual) { | |
465 DCHECK(QueryRenderSupport(dpy)); | |
466 | |
467 CachedPictFormats* formats = get_cached_pict_formats(); | |
468 | |
469 for (CachedPictFormats::const_iterator i = formats->begin(); | |
470 i != formats->end(); ++i) { | |
471 if (i->equals(dpy, visual)) | |
472 return i->format; | |
473 } | |
474 | |
475 // Not cached, look up the value. | |
476 XRenderPictFormat* pictformat = XRenderFindVisualFormat(dpy, visual); | |
477 CHECK(pictformat) << "XRENDER does not support default visual"; | |
478 | |
479 // And store it in the cache. | |
480 CachedPictFormat cached_value; | |
481 cached_value.visual = visual; | |
482 cached_value.display = dpy; | |
483 cached_value.format = pictformat; | |
484 formats->push_front(cached_value); | |
485 | |
486 if (formats->size() == kMaxCacheSize) { | |
487 formats->pop_back(); | |
488 // We should really only have at most 2 display/visual combinations: | |
489 // one for normal browser windows, and possibly another for an argb window | |
490 // created to display a menu. | |
491 // | |
492 // If we get here it's not fatal, we just need to make sure we aren't | |
493 // always blowing away the cache. If we are, then we should figure out why | |
494 // and make it bigger. | |
495 NOTREACHED(); | |
496 } | |
497 | |
498 return pictformat; | |
499 } | |
500 | |
501 XRenderPictFormat* GetRenderARGB32Format(Display* dpy) { | |
502 static XRenderPictFormat* pictformat = NULL; | |
503 if (pictformat) | |
504 return pictformat; | |
505 | |
506 // First look for a 32-bit format which ignores the alpha value | |
507 XRenderPictFormat templ; | |
508 templ.depth = 32; | |
509 templ.type = PictTypeDirect; | |
510 templ.direct.red = 16; | |
511 templ.direct.green = 8; | |
512 templ.direct.blue = 0; | |
513 templ.direct.redMask = 0xff; | |
514 templ.direct.greenMask = 0xff; | |
515 templ.direct.blueMask = 0xff; | |
516 templ.direct.alphaMask = 0; | |
517 | |
518 static const unsigned long kMask = | |
519 PictFormatType | PictFormatDepth | | |
520 PictFormatRed | PictFormatRedMask | | |
521 PictFormatGreen | PictFormatGreenMask | | |
522 PictFormatBlue | PictFormatBlueMask | | |
523 PictFormatAlphaMask; | |
524 | |
525 pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */); | |
526 | |
527 if (!pictformat) { | |
528 // Not all X servers support xRGB32 formats. However, the XRENDER spec says | |
529 // that they must support an ARGB32 format, so we can always return that. | |
530 pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32); | |
531 CHECK(pictformat) << "XRENDER ARGB32 not supported."; | |
532 } | |
533 | |
534 return pictformat; | |
535 } | |
536 | |
537 XSharedMemoryId AttachSharedMemory(Display* display, int shared_memory_key) { | 458 XSharedMemoryId AttachSharedMemory(Display* display, int shared_memory_key) { |
538 DCHECK(QuerySharedMemorySupport(display)); | 459 DCHECK(QuerySharedMemorySupport(display)); |
539 | 460 |
540 XShmSegmentInfo shminfo; | 461 XShmSegmentInfo shminfo; |
541 memset(&shminfo, 0, sizeof(shminfo)); | 462 memset(&shminfo, 0, sizeof(shminfo)); |
542 shminfo.shmid = shared_memory_key; | 463 shminfo.shmid = shared_memory_key; |
543 | 464 |
544 // This function is only called if QuerySharedMemorySupport returned true. In | 465 // This function is only called if QuerySharedMemorySupport returned true. In |
545 // which case we've already succeeded in having the X server attach to one of | 466 // which case we've already succeeded in having the X server attach to one of |
546 // our shared memory segments. | 467 // our shared memory segments. |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
819 gdk_display_get_default(), "_NET_WM_DESKTOP"); | 740 gdk_display_get_default(), "_NET_WM_DESKTOP"); |
820 event.xclient.format = 32; | 741 event.xclient.format = 32; |
821 event.xclient.data.l[0] = desktop; | 742 event.xclient.data.l[0] = desktop; |
822 event.xclient.data.l[1] = 1; // source indication | 743 event.xclient.data.l[1] = 1; // source indication |
823 | 744 |
824 int result = XSendEvent(GetXDisplay(), GetX11RootWindow(), False, | 745 int result = XSendEvent(GetXDisplay(), GetX11RootWindow(), False, |
825 SubstructureNotifyMask, &event); | 746 SubstructureNotifyMask, &event); |
826 return result == Success; | 747 return result == Success; |
827 } | 748 } |
828 | 749 |
| 750 void SetDefaultX11ErrorHandlers() { |
| 751 SetX11ErrorHandlers(NULL, NULL); |
| 752 } |
| 753 |
| 754 // ---------------------------------------------------------------------------- |
| 755 // These functions are declared in x11_util_internal.h because they require |
| 756 // XLib.h to be included, and it conflicts with many other headers. |
| 757 XRenderPictFormat* GetRenderARGB32Format(Display* dpy) { |
| 758 static XRenderPictFormat* pictformat = NULL; |
| 759 if (pictformat) |
| 760 return pictformat; |
| 761 |
| 762 // First look for a 32-bit format which ignores the alpha value |
| 763 XRenderPictFormat templ; |
| 764 templ.depth = 32; |
| 765 templ.type = PictTypeDirect; |
| 766 templ.direct.red = 16; |
| 767 templ.direct.green = 8; |
| 768 templ.direct.blue = 0; |
| 769 templ.direct.redMask = 0xff; |
| 770 templ.direct.greenMask = 0xff; |
| 771 templ.direct.blueMask = 0xff; |
| 772 templ.direct.alphaMask = 0; |
| 773 |
| 774 static const unsigned long kMask = |
| 775 PictFormatType | PictFormatDepth | |
| 776 PictFormatRed | PictFormatRedMask | |
| 777 PictFormatGreen | PictFormatGreenMask | |
| 778 PictFormatBlue | PictFormatBlueMask | |
| 779 PictFormatAlphaMask; |
| 780 |
| 781 pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */); |
| 782 |
| 783 if (!pictformat) { |
| 784 // Not all X servers support xRGB32 formats. However, the XRENDER spec says |
| 785 // that they must support an ARGB32 format, so we can always return that. |
| 786 pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32); |
| 787 CHECK(pictformat) << "XRENDER ARGB32 not supported."; |
| 788 } |
| 789 |
| 790 return pictformat; |
| 791 } |
| 792 |
| 793 XRenderPictFormat* GetRenderVisualFormat(Display* dpy, Visual* visual) { |
| 794 DCHECK(QueryRenderSupport(dpy)); |
| 795 |
| 796 CachedPictFormats* formats = get_cached_pict_formats(); |
| 797 |
| 798 for (CachedPictFormats::const_iterator i = formats->begin(); |
| 799 i != formats->end(); ++i) { |
| 800 if (i->equals(dpy, visual)) |
| 801 return i->format; |
| 802 } |
| 803 |
| 804 // Not cached, look up the value. |
| 805 XRenderPictFormat* pictformat = XRenderFindVisualFormat(dpy, visual); |
| 806 CHECK(pictformat) << "XRENDER does not support default visual"; |
| 807 |
| 808 // And store it in the cache. |
| 809 CachedPictFormat cached_value; |
| 810 cached_value.visual = visual; |
| 811 cached_value.display = dpy; |
| 812 cached_value.format = pictformat; |
| 813 formats->push_front(cached_value); |
| 814 |
| 815 if (formats->size() == kMaxCacheSize) { |
| 816 formats->pop_back(); |
| 817 // We should really only have at most 2 display/visual combinations: |
| 818 // one for normal browser windows, and possibly another for an argb window |
| 819 // created to display a menu. |
| 820 // |
| 821 // If we get here it's not fatal, we just need to make sure we aren't |
| 822 // always blowing away the cache. If we are, then we should figure out why |
| 823 // and make it bigger. |
| 824 NOTREACHED(); |
| 825 } |
| 826 |
| 827 return pictformat; |
| 828 } |
| 829 |
| 830 void SetX11ErrorHandlers(XErrorHandler error_handler, |
| 831 XIOErrorHandler io_error_handler) { |
| 832 XSetErrorHandler(error_handler ? error_handler : DefaultX11ErrorHandler); |
| 833 XSetIOErrorHandler( |
| 834 io_error_handler ? io_error_handler : DefaultX11IOErrorHandler); |
| 835 } |
| 836 |
| 837 std::string GetErrorEventDescription(XErrorEvent* error_event) { |
| 838 return base::StringPrintf( |
| 839 "X Error detected: %lu error_code %u request_code %u minor_code %u", |
| 840 error_event->serial, |
| 841 error_event->error_code, |
| 842 error_event->request_code, |
| 843 error_event->minor_code); |
| 844 } |
| 845 // ---------------------------------------------------------------------------- |
| 846 // End of x11_util_internal.h |
| 847 |
| 848 |
829 } // namespace x11_util | 849 } // namespace x11_util |
OLD | NEW |