1 /*
2 (c) Copyright 2000-2002 convergence integrated media GmbH.
3 All rights reserved.
4
5 Written by Denis Oliver Kropp <dok@directfb.org>,
6 Andreas Hundt <andi@fischlustig.de>,
7 Sven Neumann <neo@directfb.org> and
8 Julien Moutte <julien@moutte.net>.
9
10 This file is subject to the terms and conditions of the MIT License:
11
12 Permission is hereby granted, free of charge, to any person
13 obtaining a copy of this software and associated documentation
14 files (the "Software"), to deal in the Software without restriction,
15 including without limitation the rights to use, copy, modify, merge,
16 publish, distribute, sublicense, and/or sell copies of the Software,
17 and to permit persons to whom the Software is furnished to do so,
18 subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be
21 included in all copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
27 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <math.h>
36 #include <time.h>
37
38 #include <directfb.h>
39 #include <gst/gst.h>
40 #include <string.h>
41
42 /* macro for a safe call to DirectFB functions */
43 #define DFBCHECK(x...) \
44 { \
45 err = x; \
46 if (err != DFB_OK) { \
47 fprintf( stderr, "%s <%d>:\n\t", __FILE__, __LINE__ ); \
48 DirectFBErrorFatal( #x, err ); \
49 } \
50 }
51
52 typedef struct
53 {
54 const gchar *padname;
55 GstPad *target;
56 GstElement *bin;
57 } dyn_link;
58
59 static inline long
myclock(void)60 myclock (void)
61 {
62 struct timeval tv;
63
64 gettimeofday (&tv, NULL);
65 return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
66 }
67
68 static void
dynamic_link(GstPadTemplate * templ,GstPad * newpad,gpointer data)69 dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
70 {
71 dyn_link *connect = (dyn_link *) data;
72
73 if (connect->padname == NULL ||
74 !strcmp (gst_pad_get_name (newpad), connect->padname)) {
75 gst_pad_link (newpad, connect->target);
76 }
77 }
78
79 static void
size_changed(GObject * obj,GParamSpec * pspec,IDirectFBWindow * window)80 size_changed (GObject * obj, GParamSpec * pspec, IDirectFBWindow * window)
81 {
82 GstPad *pad = GST_PAD (obj);
83 GstStructure *s;
84 GstCaps *caps;
85
86 if (!(caps = gst_pad_get_current_caps (pad)))
87 return;
88
89 s = gst_caps_get_structure (caps, 0);
90 if (s) {
91 gint width, height;
92
93 if (!(gst_structure_get_int (s, "width", &width) &&
94 gst_structure_get_int (s, "height", &height))) {
95 gst_caps_unref (caps);
96 return;
97 }
98
99 window->Resize (window, width, height);
100 }
101 gst_caps_unref (caps);
102 }
103
104 static void
setup_dynamic_link(GstElement * element,const gchar * padname,GstPad * target,GstElement * bin)105 setup_dynamic_link (GstElement * element, const gchar * padname,
106 GstPad * target, GstElement * bin)
107 {
108 dyn_link *connect;
109
110 connect = g_new0 (dyn_link, 1);
111 connect->padname = g_strdup (padname);
112 connect->target = target;
113 connect->bin = bin;
114
115 g_signal_connect (G_OBJECT (element), "pad-added", G_CALLBACK (dynamic_link),
116 connect);
117 }
118
119 int
main(int argc,char * argv[])120 main (int argc, char *argv[])
121 {
122 IDirectFB *dfb;
123 IDirectFBDisplayLayer *layer;
124
125 IDirectFBImageProvider *provider;
126 IDirectFBVideoProvider *video_provider;
127
128 IDirectFBSurface *bgsurface;
129
130 IDirectFBWindow *window1;
131 IDirectFBWindow *window2;
132 IDirectFBWindow *window3;
133 IDirectFBSurface *window_surface1;
134 IDirectFBSurface *window_surface2;
135 IDirectFBSurface *window_surface3;
136
137 GstElement *pipeline;
138
139 IDirectFBEventBuffer *buffer;
140
141 IDirectFBFont *font;
142
143 DFBDisplayLayerConfig layer_config;
144 DFBGraphicsDeviceDescription gdesc;
145 DFBWindowID id1;
146 DFBWindowID id2;
147 DFBWindowID id3;
148
149 int fontheight;
150 int err;
151 int quit = 0;
152
153
154 DFBCHECK (DirectFBInit (&argc, &argv));
155 gst_init (&argc, &argv);
156 DFBCHECK (DirectFBCreate (&dfb));
157
158 dfb->GetDeviceDescription (dfb, &gdesc);
159
160 DFBCHECK (dfb->GetDisplayLayer (dfb, DLID_PRIMARY, &layer));
161
162 layer->SetCooperativeLevel (layer, DLSCL_ADMINISTRATIVE);
163
164 if (!((gdesc.blitting_flags & DSBLIT_BLEND_ALPHACHANNEL) &&
165 (gdesc.blitting_flags & DSBLIT_BLEND_COLORALPHA))) {
166 layer_config.flags = DLCONF_BUFFERMODE;
167 layer_config.buffermode = DLBM_BACKSYSTEM;
168
169 layer->SetConfiguration (layer, &layer_config);
170 }
171
172 layer->GetConfiguration (layer, &layer_config);
173 layer->EnableCursor (layer, 1);
174
175 {
176 DFBFontDescription desc;
177
178 desc.flags = DFDESC_HEIGHT;
179 desc.height = layer_config.width / 50;
180
181 DFBCHECK (dfb->CreateFont (dfb, "decker.ttf", &desc, &font));
182 font->GetHeight (font, &fontheight);
183 }
184
185 if (argc < 2 ||
186 dfb->CreateVideoProvider (dfb, argv[1], &video_provider) != DFB_OK) {
187 video_provider = NULL;
188 }
189
190 {
191 DFBSurfaceDescription desc;
192
193 desc.flags = DSDESC_WIDTH | DSDESC_HEIGHT;
194 desc.width = layer_config.width;
195 desc.height = layer_config.height;
196
197 DFBCHECK (dfb->CreateSurface (dfb, &desc, &bgsurface));
198
199 DFBCHECK (bgsurface->SetFont (bgsurface, font));
200
201 bgsurface->SetColor (bgsurface, 0xCF, 0xCF, 0xFF, 0xFF);
202 bgsurface->DrawString (bgsurface,
203 "Move the mouse over a window to activate it.",
204 -1, 0, 0, DSTF_LEFT | DSTF_TOP);
205
206 bgsurface->SetColor (bgsurface, 0xCF, 0xDF, 0xCF, 0xFF);
207 bgsurface->DrawString (bgsurface,
208 "Press left mouse button and drag to move the window.",
209 -1, 0, fontheight, DSTF_LEFT | DSTF_TOP);
210
211 bgsurface->SetColor (bgsurface, 0xCF, 0xEF, 0x9F, 0xFF);
212 bgsurface->DrawString (bgsurface,
213 "Press middle mouse button to raise/lower the window.",
214 -1, 0, fontheight * 2, DSTF_LEFT | DSTF_TOP);
215
216 bgsurface->SetColor (bgsurface, 0xCF, 0xFF, 0x6F, 0xFF);
217 bgsurface->DrawString (bgsurface,
218 "Press right mouse button when you are done.", -1,
219 0, fontheight * 3, DSTF_LEFT | DSTF_TOP);
220
221 layer->SetBackgroundImage (layer, bgsurface);
222 layer->SetBackgroundMode (layer, DLBM_IMAGE);
223 }
224
225 {
226 DFBSurfaceDescription sdsc;
227 DFBWindowDescription desc;
228
229 desc.flags = (DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT);
230
231 if (!video_provider) {
232 desc.caps = DWCAPS_ALPHACHANNEL;
233 desc.flags |= DWDESC_CAPS;
234
235 sdsc.width = 300;
236 sdsc.height = 200;
237 } else {
238 video_provider->GetSurfaceDescription (video_provider, &sdsc);
239
240 if (sdsc.flags & DSDESC_CAPS) {
241 desc.flags |= DWDESC_SURFACE_CAPS;
242 desc.surface_caps = sdsc.caps;
243 }
244 }
245
246 desc.posx = 20;
247 desc.posy = 120;
248 desc.width = sdsc.width;
249 desc.height = sdsc.height;
250
251 DFBCHECK (layer->CreateWindow (layer, &desc, &window2));
252 window2->GetSurface (window2, &window_surface2);
253
254 window2->SetOpacity (window2, 0xFF);
255
256 window2->GetID (window2, &id2);
257
258 window2->CreateEventBuffer (window2, &buffer);
259
260 if (video_provider) {
261 video_provider->PlayTo (video_provider, window_surface2,
262 NULL, NULL, NULL);
263 } else {
264 window_surface2->SetColor (window_surface2, 0x00, 0x30, 0x10, 0xc0);
265 window_surface2->DrawRectangle (window_surface2,
266 0, 0, desc.width, desc.height);
267 window_surface2->SetColor (window_surface2, 0x80, 0xa0, 0x00, 0x90);
268 window_surface2->FillRectangle (window_surface2,
269 1, 1, desc.width - 2, desc.height - 2);
270 }
271
272 window_surface2->Flip (window_surface2, NULL, 0);
273 }
274
275 {
276 DFBWindowDescription desc;
277
278 desc.flags = (DWDESC_POSX | DWDESC_POSY |
279 DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS);
280 desc.posx = 200;
281 desc.posy = 200;
282 desc.width = 512;
283 desc.height = 145;
284 desc.caps = DWCAPS_ALPHACHANNEL;
285
286 DFBCHECK (layer->CreateWindow (layer, &desc, &window1));
287 window1->GetSurface (window1, &window_surface1);
288
289 DFBCHECK (dfb->CreateImageProvider (dfb, "dfblogo.png", &provider));
290 provider->RenderTo (provider, window_surface1, NULL);
291
292 window_surface1->SetColor (window_surface1, 0xFF, 0x20, 0x20, 0x90);
293 window_surface1->DrawRectangle (window_surface1,
294 0, 0, desc.width, desc.height);
295
296 window_surface1->Flip (window_surface1, NULL, 0);
297
298 provider->Release (provider);
299
300 window1->AttachEventBuffer (window1, buffer);
301
302 window1->SetOpacity (window1, 0xFF);
303
304 window1->GetID (window1, &id1);
305 }
306
307 {
308 DFBWindowDescription desc;
309 GstElement *src, *decode;
310 GstElement *v_queue, *v_scale, *cs, *v_sink;
311 GstElement *a_queue, *conv, *a_sink;
312 GstPad *v_pad, *a_pad;
313
314 desc.flags = (DWDESC_POSX | DWDESC_POSY |
315 DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS);
316 desc.posx = 10;
317 desc.posy = 10;
318 desc.width = 100;
319 desc.height = 100;
320 desc.caps = DWCAPS_ALPHACHANNEL;
321
322 DFBCHECK (layer->CreateWindow (layer, &desc, &window3));
323 window3->GetSurface (window3, &window_surface3);
324
325 window3->AttachEventBuffer (window3, buffer);
326
327 window3->SetOpacity (window3, 0xFF);
328
329 window3->GetID (window3, &id3);
330
331 pipeline = gst_pipeline_new ("pipeline");
332
333 src = gst_element_factory_make ("gnomevfssrc", "src");
334 g_object_set (src, "location", argv[1], NULL);
335 decode = gst_element_factory_make ("decodebin", "decode");
336
337 v_queue = gst_element_factory_make ("queue", "v_queue");
338 v_scale = gst_element_factory_make ("videoscale", "v_scale");
339 cs = gst_element_factory_make ("videoconvert", "cs");
340 v_sink = gst_element_factory_make ("dfbvideosink", "v_sink");
341 g_object_set (v_sink, "surface", window_surface3, NULL);
342
343 a_queue = gst_element_factory_make ("queue", "a_queue");
344 conv = gst_element_factory_make ("audioconvert", "conv");
345 a_sink = gst_element_factory_make ("alsasink", "a_sink");
346
347 gst_bin_add_many (GST_BIN (pipeline), src, decode, NULL);
348 gst_bin_add_many (GST_BIN (pipeline), v_queue, v_scale, cs, v_sink, NULL);
349 gst_bin_add_many (GST_BIN (pipeline), a_queue, conv, a_sink, NULL);
350
351 gst_element_link (src, decode);
352 gst_element_link_many (v_queue, v_scale, cs, v_sink, NULL);
353 gst_element_link_many (a_queue, conv, a_sink, NULL);
354
355 v_pad = gst_element_get_static_pad (v_queue, "sink");
356 a_pad = gst_element_get_static_pad (a_queue, "sink");
357
358 setup_dynamic_link (decode, NULL, v_pad, NULL);
359 setup_dynamic_link (decode, NULL, a_pad, NULL);
360
361 /* We want to know when the size is defined */
362 g_signal_connect (v_pad, "notify::caps", G_CALLBACK (size_changed),
363 window3);
364
365 gst_object_unref (a_pad);
366 gst_object_unref (v_pad);
367
368 gst_element_set_state (pipeline, GST_STATE_PLAYING);
369 }
370
371 window1->RequestFocus (window1);
372 window1->RaiseToTop (window1);
373
374 while (!quit) {
375 static IDirectFBWindow *active = NULL;
376 static int grabbed = 0;
377 static int startx = 0;
378 static int starty = 0;
379 static int endx = 0;
380 static int endy = 0;
381 DFBWindowEvent evt;
382
383 buffer->WaitForEventWithTimeout (buffer, 0, 10);
384
385 while (buffer->GetEvent (buffer, DFB_EVENT (&evt)) == DFB_OK) {
386 IDirectFBWindow *window;
387
388 if (evt.window_id == id1)
389 window = window1;
390 else if (evt.window_id == id3)
391 window = window3;
392 else
393 window = window2;
394
395 if (evt.type == DWET_GOTFOCUS) {
396 active = window;
397 } else if (active) {
398 switch (evt.type) {
399
400 case DWET_BUTTONDOWN:
401 if (!grabbed && evt.button == DIBI_LEFT) {
402 grabbed = 1;
403 startx = evt.cx;
404 starty = evt.cy;
405 window->GrabPointer (window);
406 }
407 break;
408
409 case DWET_BUTTONUP:
410 switch (evt.button) {
411 case DIBI_LEFT:
412 if (grabbed) {
413 window->UngrabPointer (window);
414 grabbed = 0;
415 }
416 break;
417 case DIBI_MIDDLE:
418 active->RaiseToTop (active);
419 break;
420 case DIBI_RIGHT:
421 quit = DIKS_DOWN;
422 break;
423 default:
424 break;
425 }
426 break;
427
428 case DWET_KEYDOWN:
429 if (grabbed)
430 break;
431 switch (evt.key_id) {
432 case DIKI_RIGHT:
433 active->Move (active, 1, 0);
434 break;
435 case DIKI_LEFT:
436 active->Move (active, -1, 0);
437 break;
438 case DIKI_UP:
439 active->Move (active, 0, -1);
440 break;
441 case DIKI_DOWN:
442 active->Move (active, 0, 1);
443 break;
444 default:
445 break;
446 }
447 break;
448
449 case DWET_LOSTFOCUS:
450 if (!grabbed && active == window)
451 active = NULL;
452 break;
453
454 default:
455 break;
456
457 }
458 }
459
460 switch (evt.type) {
461
462 case DWET_MOTION:
463 endx = evt.cx;
464 endy = evt.cy;
465 break;
466
467 case DWET_KEYDOWN:
468 switch (evt.key_symbol) {
469 case DIKS_ESCAPE:
470 case DIKS_SMALL_Q:
471 case DIKS_CAPITAL_Q:
472 case DIKS_BACK:
473 case DIKS_STOP:
474 quit = 1;
475 break;
476 default:
477 break;
478 }
479 break;
480
481 default:
482 break;
483 }
484 }
485
486 if (video_provider)
487 window_surface2->Flip (window_surface2, NULL, 0);
488
489 if (active) {
490 if (grabbed) {
491 active->Move (active, endx - startx, endy - starty);
492 startx = endx;
493 starty = endy;
494 }
495 active->SetOpacity (active, (sin (myclock () / 300.0) * 85) + 170);
496 }
497 }
498
499 if (video_provider)
500 video_provider->Release (video_provider);
501
502 gst_element_set_state (pipeline, GST_STATE_NULL);
503
504 buffer->Release (buffer);
505 font->Release (font);
506 window_surface2->Release (window_surface2);
507 window_surface1->Release (window_surface1);
508 window_surface3->Release (window_surface3);
509 window2->Release (window2);
510 window1->Release (window1);
511 window3->Release (window3);
512 layer->Release (layer);
513 bgsurface->Release (bgsurface);
514 dfb->Release (dfb);
515
516 return 42;
517 }
518