sbGtkWindowMoveService.cpp
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2009 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
25 #include "sbGtkWindowMoveService.h"
26 #include "../NativeWindowFromNode.h"
27 
28 #include <nsIWidget.h>
29 #include <nsComponentManagerUtils.h>
30 
31 #define SB_WIN_MOVE_TIMEOUT 100
32 
33 
34 //==============================================================================
35 // GTK signal callbacks.
36 //==============================================================================
37 
38 void frame_callback(GtkWindow *aWindow, GdkEvent *aEvent, gpointer data)
39 {
40  sbGtkWindowMoveService *winService =
41  (sbGtkWindowMoveService *)data;
42  NS_ENSURE_TRUE(winService, /* void */);
43 
44  winService->OnWindowFrameCallback(aWindow, aEvent);
45 }
46 
47 void window_destroyed(GtkWindow *aWindow, gpointer data)
48 {
49  sbGtkWindowMoveService *winService =
50  (sbGtkWindowMoveService *)data;
51  NS_ENSURE_TRUE(winService, /* void */);
52 
53  winService->OnWindowDestroyed(aWindow);
54 }
55 
56 
57 //==============================================================================
58 // sbGtkWindowContext
59 //==============================================================================
60 
62 
64  PRInt32 aPreviousX,
65  PRInt32 aPreviousY,
66  PRInt32 aConfigureHandlerID,
67  PRInt32 aDestroyHandlerID)
68  : mListener(aListener)
69  , mIsTimerSet(PR_FALSE)
70  , mShouldReArmTimer(PR_FALSE)
71  , mPreviousX(aPreviousX)
72  , mPreviousY(aPreviousY)
73  , mConfigureHandlerID(aConfigureHandlerID)
74  , mDestroyHandlerID(aDestroyHandlerID)
75 {
76  nsresult rv;
77  mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
78  NS_ENSURE_SUCCESS(rv, /* void */);
79 }
80 
82 {
83 }
84 
85 nsresult
87 {
88  NS_ENSURE_ARG_POINTER(aEvent);
89 
90  nsresult rv;
91 
92  // Only process this event if the (x,y) coords have moved.
93  if (aEvent->configure.x != mPreviousX ||
94  aEvent->configure.y != mPreviousY)
95  {
96  // Stash the new (x,y) coords.
97  mPreviousX = aEvent->configure.x;
98  mPreviousY = aEvent->configure.y;
99 
100  if (mIsTimerSet) {
101  // Since the window has moved, and the move stop timer is still set
102  // the flag to re-arm the timer when the timer eventually fires.
103  mShouldReArmTimer = PR_TRUE;
104  }
105  else {
106  rv = mListener->OnMoveStarted();
107  NS_ENSURE_SUCCESS(rv, rv);
108 
109  // Notify the listener that a move occured and then arm the timer.
110  rv = mTimer->InitWithCallback(this,
112  nsITimer::TYPE_ONE_SHOT);
113  NS_ENSURE_SUCCESS(rv, rv);
114 
115  mIsTimerSet = PR_TRUE;
116  mShouldReArmTimer = PR_FALSE;
117  }
118  }
119 
120  return NS_OK;
121 }
122 
123 nsresult
125 {
126  // The window is closing, kill the move timer.
127  if (mIsTimerSet) {
128  nsresult rv = mTimer->Cancel();
129  NS_ENSURE_SUCCESS(rv, rv);
130 
131  mIsTimerSet = PR_FALSE;
132  mShouldReArmTimer = PR_FALSE;
133  }
134  return NS_OK;
135 }
136 
137 nsresult
138 sbGtkWindowContext::GetSignalHandlerIDs(PRInt32 *aOutConfigureHandlerID,
139  PRInt32 *aOutDestroyHandlerID)
140 {
141  NS_ENSURE_ARG_POINTER(aOutConfigureHandlerID);
142  NS_ENSURE_ARG_POINTER(aOutDestroyHandlerID);
143 
144  *aOutConfigureHandlerID = mConfigureHandlerID;
145  *aOutDestroyHandlerID = mDestroyHandlerID;
146 
147  return NS_OK;
148 }
149 
150 //------------------------------------------------------------------------------
151 // nsITimerCallback
152 
153 NS_IMETHODIMP
154 sbGtkWindowContext::Notify(nsITimer *aTimer)
155 {
156  NS_ENSURE_ARG_POINTER(aTimer);
157 
158  nsresult rv;
159  if (mShouldReArmTimer) {
160  // The window was moved during the timer wait, re-set the timer.
161  rv = mTimer->InitWithCallback(this,
163  nsITimer::TYPE_ONE_SHOT);
164  NS_ENSURE_SUCCESS(rv, rv);
165 
166  mShouldReArmTimer = PR_FALSE;
167  }
168  else {
169  // The window has now stopped moving by our records, invoke the listener.
170  mIsTimerSet = PR_FALSE;
171  mShouldReArmTimer = PR_FALSE;
172 
173  rv = mListener->OnMoveStopped();
174  NS_ENSURE_SUCCESS(rv, rv);
175  }
176 
177  return NS_OK;
178 }
179 
180 
181 //==============================================================================
182 // sbGtkWindowMoveService
183 //==============================================================================
184 
186 
188 {
189 }
190 
192 {
193 }
194 
195 nsresult
197  GdkEvent *aEvent)
198 {
199  NS_ENSURE_ARG_POINTER(aWindow);
200  NS_ENSURE_ARG_POINTER(aEvent);
201 
202  // First, find the context reference for this window to see if the (x,y)
203  // coords have been modified.
204  sbGtkWindowMoveServiceIter foundIter =
205  mWindowContextMap.find(aWindow);
206  NS_ENSURE_TRUE(foundIter != mWindowContextMap.end(), NS_ERROR_FAILURE);
207 
208  nsRefPtr<sbGtkWindowContext> winContext((*foundIter).second);
209  NS_ENSURE_TRUE(winContext, NS_ERROR_FAILURE);
210 
211  nsresult rv = winContext->OnFrameEvent(aEvent);
212  NS_ENSURE_SUCCESS(rv, rv);
213 
214  return NS_OK;
215 }
216 
217 nsresult
219 {
220  NS_ENSURE_ARG_POINTER(aWindow);
221 
222  sbGtkWindowMoveServiceIter foundIter =
223  mWindowContextMap.find(aWindow);
224  NS_ENSURE_TRUE(foundIter != mWindowContextMap.end(), NS_ERROR_FAILURE);
225 
226  nsRefPtr<sbGtkWindowContext> winContext((*foundIter).second);
227  NS_ENSURE_TRUE(winContext, NS_ERROR_FAILURE);
228 
229  nsresult rv = winContext->OnWindowDestroyed();
230  NS_ENSURE_SUCCESS(rv, rv);
231 
232  // Now remove this item from the map.
233  mWindowContextMap.erase(foundIter);
234 
235  return NS_OK;
236 }
237 
238 //------------------------------------------------------------------------------
239 // sbIWindowMoveService
240 
241 NS_IMETHODIMP
242 sbGtkWindowMoveService::StartWatchingWindow(nsISupports *aWindow,
243  sbIWindowMoveListener *aListener)
244 {
245  NS_ENSURE_ARG_POINTER(aWindow);
246  NS_ENSURE_ARG_POINTER(aListener);
247 
248  nsIWidget *widget = NativeWindowFromNode::getWidget(aWindow);
249  NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
250 
251  GtkWidget *window =
252  reinterpret_cast<GtkWidget *>(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
253  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
254 
255  // Listen for frame events for move notifications.
256  gtk_widget_add_events(GTK_WIDGET(window), GDK_CONFIGURE);
257  PRInt32 configureHandlerID = g_signal_connect(G_OBJECT(window),
258  "configure-event",
259  G_CALLBACK(frame_callback),
260  this);
261 
262  // Listen for window close events to cleanup the context that will be
263  // created for this window.
264  PRInt32 destroyHandlerID = g_signal_connect(G_OBJECT(window),
265  "destroy",
266  G_CALLBACK(window_destroyed),
267  this);
268 
269  // Stash this widget as a |GtkWindow| object.
270  GtkWindow *widgetWindow = GTK_WINDOW(window);
271 
272  // Get the current (x,y) coords.
273  PRInt32 curX, curY;
274  gtk_window_get_position(widgetWindow, &curX, &curY);
275 
276  // Stash the window with some context in the listener map.
277  nsRefPtr<sbGtkWindowContext> context = new sbGtkWindowContext(
278  aListener, curX, curY, configureHandlerID, destroyHandlerID);
279  NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
280 
281  mWindowContextMap.insert(sbGtkWindowContextMapPair(widgetWindow, context));
282  return NS_OK;
283 }
284 
285 NS_IMETHODIMP
286 sbGtkWindowMoveService::StopWatchingWindow(nsISupports *aWindow,
287  sbIWindowMoveListener *aListener)
288 {
289  NS_ENSURE_ARG_POINTER(aWindow);
290  NS_ENSURE_ARG_POINTER(aListener);
291 
292  // Clear out the matching window context for the closing window.
293  nsIWidget *widget = NativeWindowFromNode::getWidget(aWindow);
294  NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
295 
296  GtkWidget *window =
297  reinterpret_cast<GtkWidget *>(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
298 
299  GtkWindow *widgetWindow = GTK_WINDOW(window);
300 
301  sbGtkWindowMoveServiceIter foundIter =
302  mWindowContextMap.find(widgetWindow);
303  if (foundIter != mWindowContextMap.end()) {
304  // Before removing the context from the map, remove the handler ID signal
305  // handlers first.
306  nsRefPtr<sbGtkWindowContext> winContext((*foundIter).second);
307  NS_ENSURE_TRUE(winContext, NS_ERROR_FAILURE);
308 
309  PRInt32 configureHandlerID, destroyHandlerID;
310  nsresult rv = winContext->GetSignalHandlerIDs(&configureHandlerID,
311  &destroyHandlerID);
312  NS_ENSURE_SUCCESS(rv, rv);
313 
314  g_signal_handler_disconnect(window, configureHandlerID);
315  g_signal_handler_disconnect(window, destroyHandlerID);
316 
317  mWindowContextMap.erase(foundIter);
318  }
319 
320  return NS_OK;
321 }
322 
return NS_OK
#define SB_WIN_MOVE_TIMEOUT
sbGtkWindowContextMap::iterator sbGtkWindowMoveServiceIter
NS_IMPL_ISUPPORTS1(sbDeviceCapabilitiesUtils, sbIDeviceCapabilitiesUtils) sbDeviceCapabilitiesUtils
static nsIWidget * getWidget(nsISupports *window)
nsresult OnFrameEvent(GdkEvent *aEvent)
nsresult GetSignalHandlerIDs(PRInt32 *aOutConfigureHandlerID, PRInt32 *aOutDestroyHandlerID)
let window
void window_destroyed(GtkWindow *aWindow, gpointer data)
void frame_callback(GtkWindow *aWindow, GdkEvent *aEvent, gpointer data)
nsresult OnWindowDestroyed(GtkWindow *aWindow)
sbGtkWindowContextMap::value_type sbGtkWindowContextMapPair
observe data
Definition: FeedWriter.js:1329
nsITimerCallback
NS_DECL_ISUPPORTS NS_DECL_SBIWINDOWMOVESERVICE nsresult OnWindowFrameCallback(GtkWindow *aWindow, GdkEvent *aEvent)