nsSystemTrayIconGTK.cpp
Go to the documentation of this file.
1 /* vim: set fileencoding=utf-8 shiftwidth=2 : */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is toolkit/components/systray
16  *
17  * The Initial Developer of the Original Code is
18  * Mook <mook.moz+cvs.mozilla.org@gmail.com>.
19  * Portions created by the Initial Developer are Copyright (C) 2007
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  * Brad Peterson <b_peterson@yahoo.com>
24  * Daniel Glazman <daniel.glazman@disruptive-innovations.com>
25  * Matthew Gertner <matthew@allpeers.com>
26  *
27  * Alternatively, the contents of this file may be used under the terms of
28  * either the GNU General Public License Version 2 or later (the "GPL"), or
29  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30  * in which case the provisions of the GPL or the LGPL are applicable instead
31  * of those above. If you wish to allow use of your version of this file only
32  * under the terms of either the GPL or the LGPL, and not to allow others to
33  * use your version of this file under the terms of the MPL, indicate your
34  * decision by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL or the LGPL. If you do not delete
36  * the provisions above, a recipient may use your version of this file under
37  * the terms of any one of the MPL, the GPL or the LGPL.
38  *
39  * ***** END LICENSE BLOCK ***** */
40 
41 #include "nsSystemTrayIconGTK.h"
42 // headers for SetImageFromURI
43 #include "nsServiceManagerUtils.h"
44 #include "nsIInterfaceRequestorUtils.h"
45 #include "imgILoader.h"
46 #include "imgIRequest.h"
47 #include "nsNetError.h" // for NS_BINDING_ABORTED
48 #include "nsIImageToPixbuf.h"
49 // needed for event dispatching
50 #include "nsIDOMNode.h"
51 #include "nsIDOMDocumentEvent.h"
52 #include "nsIDOMDocument.h"
53 #include "nsStringGlue.h"
54 #include "nsIDOMDocumentView.h"
55 #include "nsIDOMMouseEvent.h"
56 #include "nsIDOMAbstractView.h"
57 
58 // debugging
59 #include <cstdio>
60 
62  imgIDecoderObserver,
63  imgIContainerObserver)
64 
66  :mSigPopup(G_MAXULONG),
67  mSigActivate(G_MAXULONG)
68 {
69  // make the new icon (have a default image in case things break later)
70  mIcon = gtk_status_icon_new_from_stock(GTK_STOCK_MISSING_IMAGE);
71 }
72 
74 {
75  if (mIcon) {
76  g_object_unref(mIcon);
77  mIcon = nsnull;
78  }
79  if (mRequest) {
81  }
82 }
83 
85 {
86  nsresult rv;
87 
88  nsCOMPtr<imgILoader> imgloader =
89  do_GetService("@mozilla.org/image/loader;1", &rv);
90  NS_ENSURE_SUCCESS(rv, rv);
91 
92  if (mRequest) {
94  }
95  rv = imgloader->LoadImage(aURI, aURI, aURI, nsnull, this, nsnull,
96  nsIRequest::LOAD_BACKGROUND, nsnull, nsnull,
97  getter_AddRefs(mRequest));
98  NS_ENSURE_SUCCESS(rv, rv);
99 
100  return NS_OK;
101 }
102 
103 nsresult nsSystemTrayIconGTK::SetEventTarget(nsIDOMEventTarget *aEventTarget)
104 {
105  if (!mIcon) {
106  return NS_ERROR_NOT_INITIALIZED;
107  }
108 
109  mEventTarget = aEventTarget;
110 
111  if (G_MAXULONG == mSigPopup) {
112  // popup signal not connected yet, do so now
113  mSigPopup = g_signal_connect(G_OBJECT(mIcon), "popup-menu",
114  G_CALLBACK(OnPopupMenu), this);
115  }
116 
117  if (G_MAXULONG == mSigActivate) {
118  // connect the activate signal
119  mSigActivate = g_signal_connect(G_OBJECT(mIcon), "activate",
120  G_CALLBACK(OnActivate), this);
121  }
122 
123  return NS_OK;
124 }
125 
126 void nsSystemTrayIconGTK::OnPopupMenu(GtkStatusIcon *status_icon,
127  guint button,
128  guint activate_time,
129  gpointer user_data)
130 {
131  // we got a "popup menu" signal, tell Gecko to dispatch a context menu event
132  printf("dispatching context menu event\n");
133  nsSystemTrayIconGTK *self =
134  reinterpret_cast<nsSystemTrayIconGTK*>(user_data);
135  self->DispatchEvent(NS_LITERAL_STRING("mousedown"), 2 /* right button */);
136  self->DispatchEvent(NS_LITERAL_STRING("mouseup"), 2 /* right button */);
137  self->DispatchEvent(NS_LITERAL_STRING("click"), 2 /* right button */);
138  self->DispatchEvent(NS_LITERAL_STRING("contextmenu"), 2 /* right button */);
139 }
140 
141 void nsSystemTrayIconGTK::OnActivate(GtkStatusIcon *status_icon,
142  gpointer user_data)
143 {
144  nsSystemTrayIconGTK *self =
145  reinterpret_cast<nsSystemTrayIconGTK*>(user_data);
146  self->DispatchEvent(NS_LITERAL_STRING("mousedown"), 0 /* left button */);
147  self->DispatchEvent(NS_LITERAL_STRING("mouseup"), 0 /* left button */);
148  self->DispatchEvent(NS_LITERAL_STRING("click"), 0 /* left button */);
149 }
150 
151 void nsSystemTrayIconGTK::DispatchEvent(const nsAString& aType, PRUint16 aButton)
152 {
153  nsresult rv;
154 
155  // first, create an event...
156  nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mEventTarget, &rv));
157  if (NS_FAILED(rv)) return;
158 
159  nsCOMPtr<nsIDOMDocument> doc;
160  rv = node->GetOwnerDocument(getter_AddRefs(doc));
161  if (NS_FAILED(rv)) return;
162 
163  nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(doc, &rv));
164  if (NS_FAILED(rv)) return;
165 
166  nsCOMPtr<nsIDOMEvent> event;
167  rv = docEvent->CreateEvent(NS_LITERAL_STRING("mouseevent"),
168  getter_AddRefs(event));
169  if (NS_FAILED(rv)) return;
170 
171  nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(event, &rv));
172  if (NS_FAILED(rv)) return;
173 
174  // get the view the event occurred on
175  nsCOMPtr<nsIDOMDocumentView> documentView(do_QueryInterface(doc, &rv));
176  if (NS_FAILED(rv)) return;
177 
178  nsCOMPtr<nsIDOMAbstractView> view;
179  rv = documentView->GetDefaultView(getter_AddRefs(view));
180  if (NS_FAILED(rv)) return;
181 
182  // figure out where to position the popup
183  GdkRectangle rect;
184  gboolean hasRect;
185  hasRect = gtk_status_icon_get_geometry(mIcon, NULL, &rect, NULL);
186  if (!hasRect) {
187  rect.x = rect.y = 0;
188  }
189 
190  // initialize the event
191  // TODO: give useful arguments here
192  rv = mouseEvent->InitMouseEvent(aType,
193  PR_FALSE, PR_TRUE, view, 1 /*single click*/,
194  rect.x, rect.y, rect.x, rect.y,
195  0, 0, 0, 0, aButton, nsnull);
196  if (NS_FAILED(rv)) return;
197 
198  // and dispatch it. (yes, return value is ignored; we can't do anything)
199  PRBool result;
200  mEventTarget->DispatchEvent(event, &result);
201 }
202 
204 /* void onStartRequest (in imgIRequest aRequest); */
205 NS_IMETHODIMP nsSystemTrayIconGTK::OnStartRequest(imgIRequest *aRequest)
206 {
207  return NS_OK;
208 }
209 
210 /* void onStartDecode (in imgIRequest aRequest); */
211 NS_IMETHODIMP nsSystemTrayIconGTK::OnStartDecode(imgIRequest *aRequest)
212 {
213  return NS_OK;
214 }
215 
216 /* void onStartContainer (in imgIRequest aRequest, in imgIContainer aContainer); */
217 NS_IMETHODIMP nsSystemTrayIconGTK::OnStartContainer(imgIRequest *aRequest, imgIContainer *aContainer)
218 {
219  return NS_OK;
220 }
221 
222 /* void onStartFrame (in imgIRequest aRequest, in unsigned long aFrame); */
223 NS_IMETHODIMP
224 nsSystemTrayIconGTK::OnStartFrame(imgIRequest *aRequest,
225  PRUint32 aFrame)
226 {
227  return NS_OK;
228 }
229 
230 /* [noscript] void onDataAvailable (in imgIRequest aRequest,
231  in boolean aCurrentFrame, [const] in nsIntRect aRect); */
232 NS_IMETHODIMP
233 nsSystemTrayIconGTK::OnDataAvailable(imgIRequest *aRequest,
234  PRBool aCurrentFrame,
235  const nsIntRect * aRect)
236 {
237  return NS_OK;
238 }
239 
240 /* void onStopFrame (in imgIRequest aRequest, in unsigned long aFrame); */
241 NS_IMETHODIMP
242 nsSystemTrayIconGTK::OnStopFrame(imgIRequest *aRequest,
243  PRUint32 aFrame)
244 {
245  // the frame is done; put it in the tray
246  nsresult rv;
247 
248  if (!mIcon) {
249  // ... our icon went away somewhere, oops
250  return NS_ERROR_UNEXPECTED;
251  }
252 
253  nsCOMPtr<imgIContainer> image;
254  rv = aRequest->GetImage(getter_AddRefs(image));
255  NS_ENSURE_SUCCESS(rv, rv);
256 
257  nsCOMPtr<nsIImageToPixbuf> imgToPixbuf =
258  do_GetService("@mozilla.org/widget/image-to-gdk-pixbuf;1", &rv);
259  NS_ENSURE_SUCCESS(rv, rv);
260 
261  GdkPixbuf* pixbuf = imgToPixbuf->ConvertImageToPixbuf(image);
262  if (!pixbuf) {
263  return NS_ERROR_FAILURE;
264  }
265 
266  gtk_status_icon_set_from_pixbuf(mIcon, pixbuf);
267  return NS_OK;
268 }
269 
270 /* void onStopContainer (in imgIRequest aRequest, in imgIContainer aContainer); */
271 NS_IMETHODIMP nsSystemTrayIconGTK::OnStopContainer(imgIRequest *aRequest, imgIContainer *aContainer)
272 {
273  return NS_OK;
274 }
275 
276 /* void onStopDecode (in imgIRequest aRequest, in nsresult status, in wstring statusArg); */
277 NS_IMETHODIMP nsSystemTrayIconGTK::OnStopDecode(imgIRequest *aRequest, nsresult status, const PRUnichar *statusArg)
278 {
279  return NS_OK;
280 }
281 
282 /* void onStopRequest (in imgIRequest aRequest, in boolean aIsLastPart); */
283 NS_IMETHODIMP nsSystemTrayIconGTK::OnStopRequest(imgIRequest *aRequest, PRBool aIsLastPart)
284 {
285  return NS_OK;
286 }
287 
289 /* [noscript] void frameChanged (in imgIContainer aContainer,
290  in nsIntRect aDirtyRect); */
291 NS_IMETHODIMP
292 nsSystemTrayIconGTK::FrameChanged(imgIContainer *aContainer,
293  nsIntRect * aDirtyRect)
294 {
295  return NS_OK;
296 }
return NS_OK
nsresult SetEventTarget(nsIDOMEventTarget *aEventTarget)
nsresult SetImageFromURI(nsIURI *aURI)
static void OnActivate(GtkStatusIcon *status_icon, gpointer user_data)
function doc() browser.contentDocument
var event
void DispatchEvent(const nsAString &aType, PRUint16 aButton)
nsCOMPtr< imgIRequest > mRequest
NS_IMPL_ISUPPORTS2(nsSystemTrayIconGTK, imgIDecoderObserver, imgIContainerObserver) nsSystemTrayIconGTK
nsCOMPtr< nsIDOMEventTarget > mEventTarget
function rect(ele) ele.getBoundingClientRect()
let node
static void OnPopupMenu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data)
const NS_BINDING_ABORTED