sbGStreamerPlatformGDK.cpp
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2008 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25 */
26 
27 #include "sbGStreamerPlatformGDK.h"
28 #include "sbGStreamerMediacore.h"
29 
30 #include <gdk/gdkx.h>
31 #include <X11/Xlib.h>
32 
33 #include <prlog.h>
34 #include <nsDebug.h>
35 
42 #ifdef PR_LOGGING
43 
44 static PRLogModuleInfo* gGStreamerPlatformGDK =
45  PR_NewLogModule("sbGStreamerPlatformGDK");
46 
47 #define LOG(args) \
48  if (gGStreamerPlatformGDK) \
49  PR_LOG(gGStreamerPlatformGDK, PR_LOG_WARNING, args)
50 
51 #define TRACE(args) \
52  if (gGStreamerPlatformGDK) \
53  PR_LOG(gGStreamerPlatformGDK, PR_LOG_DEBUG, args)
54 
55 #else /* PR_LOGGING */
56 
57 #define LOG(args) /* nothing */
58 #define TRACE(args) /* nothing */
59 
60 #endif /* PR_LOGGING */
61 
62 // TODO: This is a temporary bit of "UI" to get out of fullscreen mode.
63 // We'll do this properly at some point in the future.
64 /* static */ GdkFilterReturn
65 GDKPlatformInterface::gdk_event_filter(GdkXEvent *gdk_xevent,
66  GdkEvent *event, gpointer data)
67 {
68  GDKPlatformInterface *platform = (GDKPlatformInterface *)data;
69  XEvent *xevent = (XEvent *)gdk_xevent;
70 
71  switch (xevent->type) {
72  case ButtonPress:
73  case ButtonRelease:
74  {
75  platform->SetFullscreen(false);
76  platform->ResizeToWindow();
77  }
78  break;
79  default:
80  break;
81  }
82 
83  return GDK_FILTER_CONTINUE;
84 }
85 
87  BasePlatformInterface(aCore),
88  mWindow(NULL),
89  mParentWindow(NULL),
90  mFullscreenWindow(NULL)
91 {
92 }
93 
94 void
96 {
97  NS_ASSERTION (mFullscreenWindow == NULL, "Fullscreen window is non-null");
98 
99  GdkScreen *screen = NULL;
100  gint screenWidth, screenHeight;
101  GdkWindowAttr attributes;
102  XWindowAttributes xattrs;
103 
104  attributes.window_type = GDK_WINDOW_TOPLEVEL;
105  attributes.x = 0;
106  attributes.y = 0;
107  attributes.width = 0;
108  attributes.height = 0;
109  attributes.wclass = GDK_INPUT_OUTPUT;
110  attributes.event_mask = 0;
111 
112  // Create a new, full-screen, window.
113  // Reparent our video window to this full-screen window
114  mFullscreenWindow = gdk_window_new(NULL, &attributes, GDK_WA_X | GDK_WA_Y);
115  gdk_window_show(mFullscreenWindow);
116  gdk_window_reparent(mWindow, mFullscreenWindow, 0, 0);
117  gdk_window_fullscreen(mFullscreenWindow);
118 
119  // Start listening to button press events on this window and the fullscreen
120  // window and register a gdk event filter to process them.
121  XGetWindowAttributes(GDK_DISPLAY (), GDK_WINDOW_XWINDOW (mWindow), &xattrs);
122  XSelectInput(GDK_DISPLAY (), GDK_WINDOW_XWINDOW (mWindow),
123  xattrs.your_event_mask | ButtonPressMask);
124  gdk_window_add_filter(mWindow, gdk_event_filter, this);
125 
126  XGetWindowAttributes(GDK_DISPLAY (), GDK_WINDOW_XWINDOW (mFullscreenWindow),
127  &xattrs);
128  XSelectInput(GDK_DISPLAY (), GDK_WINDOW_XWINDOW (mFullscreenWindow),
129  xattrs.your_event_mask | ButtonPressMask);
130  gdk_window_add_filter(mFullscreenWindow, gdk_event_filter, this);
131 
132  // Get the default screen. This can be wrong, but GDK doesn't seem to properly
133  // support multiple screens (?)
134  screen = gdk_screen_get_default();
135 
136  screenWidth = gdk_screen_get_width(screen);
137  screenHeight = gdk_screen_get_height(screen);
138 
139  SetDisplayArea(0, 0, screenWidth, screenHeight);
140  ResizeVideo();
141 
142  /* Set the cursor invisible in full screen mode initially. */
143  SetInvisibleCursor();
144 
145  // TODO: if the user moves the cursor, it should become visible.
146 }
147 
148 void
150 {
151  NS_ASSERTION (mFullscreenWindow, "Fullscreen window is null");
152 
153  gdk_window_remove_filter(mWindow, gdk_event_filter, this);
154  gdk_window_remove_filter(mFullscreenWindow, gdk_event_filter, this);
155 
156  gdk_window_unfullscreen(mWindow);
157  gdk_window_reparent(mWindow, mParentWindow, 0, 0);
158  gdk_window_destroy(mFullscreenWindow);
159  mFullscreenWindow = NULL;
160 
161  SetDefaultCursor();
162 }
163 
164 void
165 GDKPlatformInterface::SetInvisibleCursor()
166 {
167  guint32 data = 0;
168  GdkPixmap* pixmap = gdk_bitmap_create_from_data(NULL, (gchar*)&data, 1, 1);
169 
170  GdkColor color = { 0, 0, 0, 0 };
171  GdkCursor* cursor = gdk_cursor_new_from_pixmap(pixmap,
172  pixmap, &color, &color, 0, 0);
173 
174  gdk_pixmap_unref(pixmap);
175 
176  gdk_window_set_cursor(mWindow, cursor);
177  if (mFullscreenWindow)
178  gdk_window_set_cursor(mFullscreenWindow, cursor);
179 
180  gdk_cursor_unref(cursor);
181 
182 }
183 
184 void
185 GDKPlatformInterface::SetDefaultCursor()
186 {
187  gdk_window_set_cursor(mWindow, NULL);
188  if (mFullscreenWindow)
189  gdk_window_set_cursor(mFullscreenWindow, NULL);
190 }
191 
192 void
194 {
195  if (mWindow) {
196  LOG(("Moving video window to %d,%d, size %d,%d", x, y, width, height));
197  gdk_window_move_resize(mWindow, x, y, width, height);
198  }
199 }
200 
201 GstElement *
202 GDKPlatformInterface::SetVideoSink(GstElement *aVideoSink)
203 {
204  if (mVideoSink) {
205  gst_object_unref(mVideoSink);
206  mVideoSink = NULL;
207  }
208 
209  // Use the provided sink, if any.
210  mVideoSink = aVideoSink;
211 
212  if (!mVideoSink)
213  mVideoSink = gst_element_factory_make("gconfvideosink", "video-sink");
214  if (!mVideoSink) {
215  // Then hopefully autovideosink will pick something appropriate...
216  mVideoSink = gst_element_factory_make("autovideosink", "video-sink");
217  }
218 
219  // Keep a reference to it.
220  if (mVideoSink)
221  gst_object_ref(mVideoSink);
222 
223  return mVideoSink;
224 }
225 
226 GstElement *
227 GDKPlatformInterface::SetAudioSink(GstElement *aAudioSink)
228 {
229  if (mAudioSink) {
230  gst_object_unref(mAudioSink);
231  mAudioSink = NULL;
232  }
233 
234  // Use the audio sink provided, if any.
235  mAudioSink = aAudioSink;
236 
237  if (!mAudioSink) {
238  mAudioSink = gst_element_factory_make("gconfaudiosink", "audio-sink");
239  if (mAudioSink) {
240  // Set the profile for gconfaudiosink to use to 'Music and Movies',
241  // this is profile 1 (we can't use the enum directly, as the header
242  // is not installed).
243  g_object_set (G_OBJECT (mAudioSink), "profile", 1, NULL);
244  }
245  }
246 
247  if (!mAudioSink) {
248  // Then hopefully autoaudiosink will pick something appropriate...
249  mAudioSink = gst_element_factory_make("autoaudiosink", "audio-sink");
250  }
251 
252  // Keep a reference to it.
253  if (mAudioSink)
254  gst_object_ref(mAudioSink);
255 
256  return mAudioSink;
257 }
258 
259 nsresult
260 GDKPlatformInterface::SetVideoBox (nsIBoxObject *aBoxObject, nsIWidget *aWidget)
261 {
262  // First let the superclass do its thing.
263  nsresult rv = BasePlatformInterface::SetVideoBox (aBoxObject, aWidget);
264  NS_ENSURE_SUCCESS(rv, rv);
265 
266  if (aWidget) {
267  mParentWindow = GDK_WINDOW(aWidget->GetNativeData(NS_NATIVE_WIDGET));
268  NS_ENSURE_TRUE(mParentWindow != NULL, NS_ERROR_FAILURE);
269 
270  // Create the video window, initially with zero size.
271  GdkWindowAttr attributes;
272 
273  attributes.window_type = GDK_WINDOW_CHILD;
274  attributes.x = 0;
275  attributes.y = 0;
276  attributes.width = 0;
277  attributes.height = 0;
278  attributes.wclass = GDK_INPUT_OUTPUT;
279  attributes.event_mask = GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK |
280  GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK;
281 
282  mWindow = gdk_window_new(mParentWindow, &attributes, GDK_WA_X | GDK_WA_Y);
283  NS_ENSURE_TRUE(mParentWindow != NULL, NS_ERROR_FAILURE);
284 
285  gdk_window_show(mWindow);
286 
287  // If we're running on GTK+ 2.17.X or later, the GdkWindow here may not
288  // correspond to a real X window.
289  // To ensure that it is, we need to call gdk_x11_drawable_get_xid() here
290  // (we're called from the main thread here, so this is safe).
291  mWindowXID = gdk_x11_drawable_get_xid (mWindow);
292  }
293  else {
294  // hide, unparent, and then destroy our private window
295  gdk_window_hide(mWindow);
296  gdk_window_reparent(mWindow, NULL, 0, 0);
297  gdk_window_destroy(mWindow);
298 
299  mWindow = nsnull;
300  mWindowXID = 0;
301  mParentWindow = nsnull;
302  }
303 
304  return NS_OK;
305 }
306 
307 void GDKPlatformInterface::SetXOverlayWindowID(GstXOverlay *aXOverlay)
308 {
309  nsresult rv;
310 
311  if (!mWindow) {
312  // If we haven't already had a window explicitly set on us, then request
313  // one from the mediacore manager. This needs to be main-thread, as it does
314  // DOM stuff internally.
315  nsCOMPtr<nsIThread> mainThread;
316  rv = NS_GetMainThread(getter_AddRefs(mainThread));
317  NS_ENSURE_SUCCESS(rv, /* void */);
318 
319  nsCOMPtr<nsIRunnable> runnable =
320  NS_NEW_RUNNABLE_METHOD (sbGStreamerMediacore,
321  mCore,
322  RequestVideoWindow);
323 
324  rv = mainThread->Dispatch(runnable, NS_DISPATCH_SYNC);
325  NS_ENSURE_SUCCESS(rv, /* void */);
326  }
327 
328  if (mWindowXID) {
329  gst_x_overlay_set_xwindow_id(aXOverlay, mWindowXID);
330 
331  LOG(("Set xoverlay %d to windowid %x\n", aXOverlay, mWindowXID));
332  }
333 }
334 
sbGStreamerMediacore * mCore
return NS_OK
tabData attributes[name]
GstElement * SetAudioSink(GstElement *aAudioSink)
GDKPlatformInterface(sbGStreamerMediacore *aCore)
var event
#define LOG(args)
function width(ele) rect(ele).width
virtual nsresult SetVideoBox(nsIBoxObject *aVideoBox, nsIWidget *aWidget)
void SetFullscreen(bool aFullscreen)
void SetDisplayArea(int x, int y, int width, int height)
_updateDatepicker height
observe data
Definition: FeedWriter.js:1329
void SetXOverlayWindowID(GstXOverlay *aXOverlay)
nsresult SetVideoBox(nsIBoxObject *aBoxObject, nsIWidget *aWidget)
GstElement * SetVideoSink(GstElement *aVideoSink)
void MoveVideoWindow(int x, int y, int width, int height)