|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim:expandtab:shiftwidth=4:tabstop=4: |
|
3 */ |
|
4 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #include <sys/types.h> |
|
9 #include <unistd.h> |
|
10 #include <fcntl.h> |
|
11 #include <errno.h> |
|
12 #include <gdk/gdk.h> |
|
13 #include "nsAppShell.h" |
|
14 #include "nsWindow.h" |
|
15 #include "prlog.h" |
|
16 #include "prenv.h" |
|
17 #include "mozilla/HangMonitor.h" |
|
18 #include "mozilla/unused.h" |
|
19 #include "GeckoProfiler.h" |
|
20 |
|
21 using mozilla::unused; |
|
22 |
|
23 #define NOTIFY_TOKEN 0xFA |
|
24 |
|
25 #ifdef PR_LOGGING |
|
26 PRLogModuleInfo *gWidgetLog = nullptr; |
|
27 PRLogModuleInfo *gWidgetFocusLog = nullptr; |
|
28 PRLogModuleInfo *gWidgetDragLog = nullptr; |
|
29 PRLogModuleInfo *gWidgetDrawLog = nullptr; |
|
30 #endif |
|
31 |
|
32 static GPollFunc sPollFunc; |
|
33 |
|
34 // Wrapper function to disable hang monitoring while waiting in poll(). |
|
35 static gint |
|
36 PollWrapper(GPollFD *ufds, guint nfsd, gint timeout_) |
|
37 { |
|
38 mozilla::HangMonitor::Suspend(); |
|
39 profiler_sleep_start(); |
|
40 gint result = (*sPollFunc)(ufds, nfsd, timeout_); |
|
41 profiler_sleep_end(); |
|
42 mozilla::HangMonitor::NotifyActivity(); |
|
43 return result; |
|
44 } |
|
45 |
|
46 /*static*/ gboolean |
|
47 nsAppShell::EventProcessorCallback(GIOChannel *source, |
|
48 GIOCondition condition, |
|
49 gpointer data) |
|
50 { |
|
51 nsAppShell *self = static_cast<nsAppShell *>(data); |
|
52 |
|
53 unsigned char c; |
|
54 unused << read(self->mPipeFDs[0], &c, 1); |
|
55 NS_ASSERTION(c == (unsigned char) NOTIFY_TOKEN, "wrong token"); |
|
56 |
|
57 self->NativeEventCallback(); |
|
58 return TRUE; |
|
59 } |
|
60 |
|
61 nsAppShell::~nsAppShell() |
|
62 { |
|
63 if (mTag) |
|
64 g_source_remove(mTag); |
|
65 if (mPipeFDs[0]) |
|
66 close(mPipeFDs[0]); |
|
67 if (mPipeFDs[1]) |
|
68 close(mPipeFDs[1]); |
|
69 } |
|
70 |
|
71 nsresult |
|
72 nsAppShell::Init() |
|
73 { |
|
74 #ifdef PR_LOGGING |
|
75 if (!gWidgetLog) |
|
76 gWidgetLog = PR_NewLogModule("Widget"); |
|
77 if (!gWidgetFocusLog) |
|
78 gWidgetFocusLog = PR_NewLogModule("WidgetFocus"); |
|
79 if (!gWidgetDragLog) |
|
80 gWidgetDragLog = PR_NewLogModule("WidgetDrag"); |
|
81 if (!gWidgetDrawLog) |
|
82 gWidgetDrawLog = PR_NewLogModule("WidgetDraw"); |
|
83 #endif |
|
84 |
|
85 if (!sPollFunc) { |
|
86 sPollFunc = g_main_context_get_poll_func(nullptr); |
|
87 g_main_context_set_poll_func(nullptr, &PollWrapper); |
|
88 } |
|
89 |
|
90 if (PR_GetEnv("MOZ_DEBUG_PAINTS")) |
|
91 gdk_window_set_debug_updates(TRUE); |
|
92 |
|
93 int err = pipe(mPipeFDs); |
|
94 if (err) |
|
95 return NS_ERROR_OUT_OF_MEMORY; |
|
96 |
|
97 GIOChannel *ioc; |
|
98 GSource *source; |
|
99 |
|
100 // make the pipe nonblocking |
|
101 |
|
102 int flags = fcntl(mPipeFDs[0], F_GETFL, 0); |
|
103 if (flags == -1) |
|
104 goto failed; |
|
105 err = fcntl(mPipeFDs[0], F_SETFL, flags | O_NONBLOCK); |
|
106 if (err == -1) |
|
107 goto failed; |
|
108 flags = fcntl(mPipeFDs[1], F_GETFL, 0); |
|
109 if (flags == -1) |
|
110 goto failed; |
|
111 err = fcntl(mPipeFDs[1], F_SETFL, flags | O_NONBLOCK); |
|
112 if (err == -1) |
|
113 goto failed; |
|
114 |
|
115 ioc = g_io_channel_unix_new(mPipeFDs[0]); |
|
116 source = g_io_create_watch(ioc, G_IO_IN); |
|
117 g_io_channel_unref(ioc); |
|
118 g_source_set_callback(source, (GSourceFunc)EventProcessorCallback, this, nullptr); |
|
119 g_source_set_can_recurse(source, TRUE); |
|
120 mTag = g_source_attach(source, nullptr); |
|
121 g_source_unref(source); |
|
122 |
|
123 return nsBaseAppShell::Init(); |
|
124 failed: |
|
125 close(mPipeFDs[0]); |
|
126 close(mPipeFDs[1]); |
|
127 mPipeFDs[0] = mPipeFDs[1] = 0; |
|
128 return NS_ERROR_FAILURE; |
|
129 } |
|
130 |
|
131 void |
|
132 nsAppShell::ScheduleNativeEventCallback() |
|
133 { |
|
134 unsigned char buf[] = { NOTIFY_TOKEN }; |
|
135 unused << write(mPipeFDs[1], buf, 1); |
|
136 } |
|
137 |
|
138 bool |
|
139 nsAppShell::ProcessNextNativeEvent(bool mayWait) |
|
140 { |
|
141 return g_main_context_iteration(nullptr, mayWait); |
|
142 } |