OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "ui/base/x/x11_util.h" | 9 #include "ui/base/x/x11_util.h" |
10 | 10 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 static CachedPictFormats* formats = NULL; | 58 static CachedPictFormats* formats = NULL; |
59 if (!formats) | 59 if (!formats) |
60 formats = new CachedPictFormats(); | 60 formats = new CachedPictFormats(); |
61 return formats; | 61 return formats; |
62 } | 62 } |
63 | 63 |
64 // Maximum number of CachedPictFormats we keep around. | 64 // Maximum number of CachedPictFormats we keep around. |
65 const size_t kMaxCacheSize = 5; | 65 const size_t kMaxCacheSize = 5; |
66 | 66 |
67 int DefaultX11ErrorHandler(Display* d, XErrorEvent* e) { | 67 int DefaultX11ErrorHandler(Display* d, XErrorEvent* e) { |
| 68 DCHECK(!MessageLoop::current() || |
| 69 MessageLoop::current()->type() == MessageLoop::TYPE_UI); |
68 MessageLoop::current()->PostTask( | 70 MessageLoop::current()->PostTask( |
69 FROM_HERE, NewRunnableFunction(LogErrorEventDescription, d, *e)); | 71 FROM_HERE, NewRunnableFunction(LogErrorEventDescription, d, *e)); |
70 return 0; | 72 return 0; |
71 } | 73 } |
72 | 74 |
73 int DefaultX11IOErrorHandler(Display* d) { | 75 int DefaultX11IOErrorHandler(Display* d) { |
74 // If there's an IO error it likely means the X server has gone away | 76 // If there's an IO error it likely means the X server has gone away |
75 LOG(ERROR) << "X IO Error detected"; | 77 LOG(ERROR) << "X IO Error detected"; |
76 _exit(1); | 78 _exit(1); |
77 } | 79 } |
78 | 80 |
| 81 XErrorHandler current_error_handler = DefaultX11ErrorHandler; |
| 82 XErrorEvent last_error_event = {0, NULL, 0, 0, 0, 0, 0 }; |
| 83 |
| 84 int BaseX11ErrorHandler(Display* d, XErrorEvent* e) { |
| 85 last_error_event = *e; |
| 86 return current_error_handler(d, e); |
| 87 } |
| 88 |
79 Atom GetAtom(const char* name) { | 89 Atom GetAtom(const char* name) { |
80 #if defined(TOOLKIT_USES_GTK) | 90 #if defined(TOOLKIT_USES_GTK) |
81 return gdk_x11_get_xatom_by_name_for_display( | 91 return gdk_x11_get_xatom_by_name_for_display( |
82 gdk_display_get_default(), name); | 92 gdk_display_get_default(), name); |
83 #else | 93 #else |
84 return XInternAtom(GetXDisplay(), name, false); | 94 return XInternAtom(GetXDisplay(), name, false); |
85 #endif | 95 #endif |
86 } | 96 } |
87 | 97 |
88 // Note: The caller should free the resulting value data. | 98 // Note: The caller should free the resulting value data. |
89 bool GetProperty(XID window, const std::string& property_name, long max_length, | 99 bool GetProperty(XID window, const std::string& property_name, long max_length, |
90 Atom* type, int* format, unsigned long* num_items, | 100 Atom* type, int* format, unsigned long* num_items, |
91 unsigned char** property) { | 101 unsigned char** property) { |
92 Atom property_atom = GetAtom(property_name.c_str()); | 102 Atom property_atom = GetAtom(property_name.c_str()); |
93 unsigned long remaining_bytes = 0; | 103 unsigned long remaining_bytes = 0; |
94 return XGetWindowProperty(GetXDisplay(), | 104 return XGetWindowProperty(GetXDisplay(), |
95 window, | 105 window, |
96 property_atom, | 106 property_atom, |
97 0, // offset into property data to read | 107 0, // offset into property data to read |
98 max_length, // max length to get | 108 max_length, // max length to get |
99 False, // deleted | 109 False, // deleted |
100 AnyPropertyType, | 110 AnyPropertyType, |
101 type, | 111 type, |
102 format, | 112 format, |
103 num_items, | 113 num_items, |
104 &remaining_bytes, | 114 &remaining_bytes, |
105 property); | 115 property); |
106 } | 116 } |
107 | 117 |
| 118 std::string BuildX11ErrorString(const XErrorEvent& error_event) { |
| 119 char error_str[256]; |
| 120 char request_str[256]; |
| 121 |
| 122 XGetErrorText(error_event.display, error_event.error_code, error_str, |
| 123 sizeof(error_str)); |
| 124 |
| 125 strncpy(request_str, "Unknown", sizeof(request_str)); |
| 126 if (error_event.request_code < 128) { |
| 127 std::string num = base::UintToString(error_event.request_code); |
| 128 XGetErrorDatabaseText(error_event.display, "XRequest", num.c_str(), |
| 129 "Unknown", request_str, sizeof(request_str)); |
| 130 } else { |
| 131 int num_ext; |
| 132 char** ext_list = XListExtensions(error_event.display, &num_ext); |
| 133 |
| 134 for (int i = 0; i < num_ext; i++) { |
| 135 int ext_code, first_event, first_error; |
| 136 XQueryExtension(error_event.display, ext_list[i], &ext_code, &first_event, |
| 137 &first_error); |
| 138 if (error_event.request_code == ext_code) { |
| 139 std::string msg = StringPrintf( |
| 140 "%s.%d", ext_list[i], error_event.minor_code); |
| 141 XGetErrorDatabaseText(error_event.display, "XRequest", msg.c_str(), |
| 142 "Unknown", request_str, sizeof(request_str)); |
| 143 break; |
| 144 } |
| 145 } |
| 146 XFreeExtensionList(ext_list); |
| 147 } |
| 148 |
| 149 std::ostringstream error_ss; |
| 150 error_ss << "X Error detected: " |
| 151 << "serial " << error_event.serial << ", " |
| 152 << "error_code " << static_cast<int>(error_event.error_code) |
| 153 << " (" << error_str << "), " |
| 154 << "request_code " << static_cast<int>(error_event.request_code) |
| 155 << ", " |
| 156 << "minor_code " << static_cast<int>(error_event.minor_code) |
| 157 << " (" << request_str << ")"; |
| 158 return error_ss.str(); |
| 159 } |
| 160 |
108 } // namespace | 161 } // namespace |
109 | 162 |
110 bool XDisplayExists() { | 163 bool XDisplayExists() { |
111 return (GetXDisplay() != NULL); | 164 return (GetXDisplay() != NULL); |
112 } | 165 } |
113 | 166 |
114 Display* GetXDisplay() { | 167 Display* GetXDisplay() { |
115 return base::MessagePumpForUI::GetDefaultXDisplay(); | 168 return base::MessagePumpForUI::GetDefaultXDisplay(); |
116 } | 169 } |
117 | 170 |
(...skipping 570 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
688 event.xclient.format = 32; | 741 event.xclient.format = 32; |
689 event.xclient.data.l[0] = desktop; | 742 event.xclient.data.l[0] = desktop; |
690 event.xclient.data.l[1] = 1; // source indication | 743 event.xclient.data.l[1] = 1; // source indication |
691 | 744 |
692 int result = XSendEvent(GetXDisplay(), GetX11RootWindow(), False, | 745 int result = XSendEvent(GetXDisplay(), GetX11RootWindow(), False, |
693 SubstructureNotifyMask, &event); | 746 SubstructureNotifyMask, &event); |
694 return result == Success; | 747 return result == Success; |
695 } | 748 } |
696 | 749 |
697 void SetDefaultX11ErrorHandlers() { | 750 void SetDefaultX11ErrorHandlers() { |
| 751 XSetErrorHandler(BaseX11ErrorHandler); |
698 SetX11ErrorHandlers(NULL, NULL); | 752 SetX11ErrorHandlers(NULL, NULL); |
699 } | 753 } |
700 | 754 |
701 bool IsX11WindowFullScreen(XID window) { | 755 bool IsX11WindowFullScreen(XID window) { |
702 // First check if _NET_WM_STATE property contains _NET_WM_STATE_FULLSCREEN. | 756 // First check if _NET_WM_STATE property contains _NET_WM_STATE_FULLSCREEN. |
703 static Atom atom = GetAtom("_NET_WM_STATE_FULLSCREEN"); | 757 static Atom atom = GetAtom("_NET_WM_STATE_FULLSCREEN"); |
704 | 758 |
705 std::vector<Atom> atom_properties; | 759 std::vector<Atom> atom_properties; |
706 if (GetAtomArrayProperty(window, | 760 if (GetAtomArrayProperty(window, |
707 "_NET_WM_STATE", | 761 "_NET_WM_STATE", |
(...skipping 15 matching lines...) Expand all Loading... |
723 return monitor_rect.x == window_rect.x() && | 777 return monitor_rect.x == window_rect.x() && |
724 monitor_rect.y == window_rect.y() && | 778 monitor_rect.y == window_rect.y() && |
725 monitor_rect.width == window_rect.width() && | 779 monitor_rect.width == window_rect.width() && |
726 monitor_rect.height == window_rect.height(); | 780 monitor_rect.height == window_rect.height(); |
727 #else | 781 #else |
728 NOTIMPLEMENTED(); | 782 NOTIMPLEMENTED(); |
729 return false; | 783 return false; |
730 #endif | 784 #endif |
731 } | 785 } |
732 | 786 |
| 787 void CheckForReportedX11Error() { |
| 788 DCHECK(!MessageLoop::current() || |
| 789 MessageLoop::current()->type() == MessageLoop::TYPE_UI); |
| 790 if (!last_error_event.display) |
| 791 return; |
| 792 XSync(last_error_event.display, False); |
| 793 LOG(FATAL) << BuildX11ErrorString(last_error_event); |
| 794 } |
| 795 |
733 // ---------------------------------------------------------------------------- | 796 // ---------------------------------------------------------------------------- |
734 // These functions are declared in x11_util_internal.h because they require | 797 // These functions are declared in x11_util_internal.h because they require |
735 // XLib.h to be included, and it conflicts with many other headers. | 798 // XLib.h to be included, and it conflicts with many other headers. |
736 XRenderPictFormat* GetRenderARGB32Format(Display* dpy) { | 799 XRenderPictFormat* GetRenderARGB32Format(Display* dpy) { |
737 static XRenderPictFormat* pictformat = NULL; | 800 static XRenderPictFormat* pictformat = NULL; |
738 if (pictformat) | 801 if (pictformat) |
739 return pictformat; | 802 return pictformat; |
740 | 803 |
741 // First look for a 32-bit format which ignores the alpha value | 804 // First look for a 32-bit format which ignores the alpha value |
742 XRenderPictFormat templ; | 805 XRenderPictFormat templ; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
801 // always blowing away the cache. If we are, then we should figure out why | 864 // always blowing away the cache. If we are, then we should figure out why |
802 // and make it bigger. | 865 // and make it bigger. |
803 NOTREACHED(); | 866 NOTREACHED(); |
804 } | 867 } |
805 | 868 |
806 return pictformat; | 869 return pictformat; |
807 } | 870 } |
808 | 871 |
809 void SetX11ErrorHandlers(XErrorHandler error_handler, | 872 void SetX11ErrorHandlers(XErrorHandler error_handler, |
810 XIOErrorHandler io_error_handler) { | 873 XIOErrorHandler io_error_handler) { |
811 XSetErrorHandler(error_handler ? error_handler : DefaultX11ErrorHandler); | 874 DCHECK(!MessageLoop::current() || |
812 XSetIOErrorHandler( | 875 MessageLoop::current()->type() == MessageLoop::TYPE_UI); |
813 io_error_handler ? io_error_handler : DefaultX11IOErrorHandler); | 876 current_error_handler = error_handler ? |
| 877 error_handler : DefaultX11ErrorHandler; |
| 878 XSetIOErrorHandler(io_error_handler ? |
| 879 io_error_handler : DefaultX11IOErrorHandler); |
814 } | 880 } |
815 | 881 |
816 void LogErrorEventDescription(Display* dpy, | 882 void LogErrorEventDescription(Display* dpy, |
817 const XErrorEvent& error_event) { | 883 const XErrorEvent& error_event) { |
818 char error_str[256]; | 884 DCHECK(!MessageLoop::current() || |
819 char request_str[256]; | 885 MessageLoop::current()->type() == MessageLoop::TYPE_UI); |
820 | 886 DCHECK_EQ(dpy, error_event.display) |
821 XGetErrorText(dpy, error_event.error_code, error_str, sizeof(error_str)); | 887 << "Attempt to log error for mismatching X11 display."; |
822 | 888 LOG(ERROR) << BuildX11ErrorString(error_event); |
823 strncpy(request_str, "Unknown", sizeof(request_str)); | |
824 if (error_event.request_code < 128) { | |
825 std::string num = base::UintToString(error_event.request_code); | |
826 XGetErrorDatabaseText( | |
827 dpy, "XRequest", num.c_str(), "Unknown", request_str, | |
828 sizeof(request_str)); | |
829 } else { | |
830 int num_ext; | |
831 char** ext_list = XListExtensions(dpy, &num_ext); | |
832 | |
833 for (int i = 0; i < num_ext; i++) { | |
834 int ext_code, first_event, first_error; | |
835 XQueryExtension(dpy, ext_list[i], &ext_code, &first_event, &first_error); | |
836 if (error_event.request_code == ext_code) { | |
837 std::string msg = StringPrintf( | |
838 "%s.%d", ext_list[i], error_event.minor_code); | |
839 XGetErrorDatabaseText( | |
840 dpy, "XRequest", msg.c_str(), "Unknown", request_str, | |
841 sizeof(request_str)); | |
842 break; | |
843 } | |
844 } | |
845 XFreeExtensionList(ext_list); | |
846 } | |
847 | |
848 LOG(ERROR) | |
849 << "X Error detected: " | |
850 << "serial " << error_event.serial << ", " | |
851 << "error_code " << static_cast<int>(error_event.error_code) | |
852 << " (" << error_str << "), " | |
853 << "request_code " << static_cast<int>(error_event.request_code) << ", " | |
854 << "minor_code " << static_cast<int>(error_event.minor_code) | |
855 << " (" << request_str << ")"; | |
856 } | 889 } |
857 | 890 |
858 // ---------------------------------------------------------------------------- | 891 // ---------------------------------------------------------------------------- |
859 // End of x11_util_internal.h | 892 // End of x11_util_internal.h |
860 | 893 |
861 | 894 |
862 } // namespace ui | 895 } // namespace ui |
OLD | NEW |