1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_VIDEO_DRIVER_DIRECTFB
24 
25 #include "SDL_DirectFB_video.h"
26 #include "SDL_DirectFB_modes.h"
27 #include "SDL_DirectFB_window.h"
28 #include "SDL_DirectFB_shape.h"
29 
30 #if SDL_DIRECTFB_OPENGL
31 #include "SDL_DirectFB_opengl.h"
32 #endif
33 
34 #include "SDL_syswm.h"
35 
36 #include "../SDL_pixels_c.h"
37 
38 int
DirectFB_CreateWindow(_THIS,SDL_Window * window)39 DirectFB_CreateWindow(_THIS, SDL_Window * window)
40 {
41     SDL_DFB_DEVICEDATA(_this);
42     SDL_DFB_DISPLAYDATA(window);
43     DFB_WindowData *windata = NULL;
44     DFBWindowOptions wopts;
45     DFBWindowDescription desc;
46     int x, y;
47     int bshaped = 0;
48 
49     SDL_DFB_ALLOC_CLEAR(window->driverdata, sizeof(DFB_WindowData));
50     SDL_memset(&desc, 0, sizeof(DFBWindowDescription));
51     windata = (DFB_WindowData *) window->driverdata;
52 
53     windata->is_managed = devdata->has_own_wm;
54 #if 1
55     SDL_DFB_CHECKERR(devdata->dfb->SetCooperativeLevel(devdata->dfb,
56                                                        DFSCL_NORMAL));
57     SDL_DFB_CHECKERR(dispdata->layer->SetCooperativeLevel(dispdata->layer,
58                                                           DLSCL_ADMINISTRATIVE));
59 #endif
60     /* FIXME ... ughh, ugly */
61     if (window->x == -1000 && window->y == -1000)
62         bshaped = 1;
63 
64     /* Fill the window description. */
65     x = window->x;
66     y = window->y;
67 
68     DirectFB_WM_AdjustWindowLayout(window, window->flags, window->w, window->h);
69 
70     /* Create Window */
71     desc.caps = 0;
72     desc.flags =
73         DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_POSX | DWDESC_POSY | DWDESC_SURFACE_CAPS;
74 
75     if (bshaped) {
76         desc.flags |= DWDESC_CAPS;
77         desc.caps |= DWCAPS_ALPHACHANNEL;
78     }
79     else
80     {
81         desc.flags |= DWDESC_PIXELFORMAT;
82     }
83 
84     if (!(window->flags & SDL_WINDOW_BORDERLESS))
85         desc.caps |= DWCAPS_NODECORATION;
86 
87     desc.posx = x;
88     desc.posy = y;
89     desc.width = windata->size.w;
90     desc.height = windata->size.h;
91     desc.pixelformat = dispdata->pixelformat;
92     desc.surface_caps = DSCAPS_PREMULTIPLIED;
93 #if DIRECTFB_MAJOR_VERSION == 1 && DIRECTFB_MINOR_VERSION >= 6
94     if (window->flags & SDL_WINDOW_OPENGL) {
95         desc.surface_caps |= DSCAPS_GL;
96     }
97 #endif
98 
99     /* Create the window. */
100     SDL_DFB_CHECKERR(dispdata->layer->CreateWindow(dispdata->layer, &desc,
101                                                    &windata->dfbwin));
102 
103     /* Set Options */
104     SDL_DFB_CHECK(windata->dfbwin->GetOptions(windata->dfbwin, &wopts));
105 
106     /* explicit rescaling of surface */
107     wopts |= DWOP_SCALE;
108     if (window->flags & SDL_WINDOW_RESIZABLE) {
109         wopts &= ~DWOP_KEEP_SIZE;
110     }
111     else {
112         wopts |= DWOP_KEEP_SIZE;
113     }
114 
115     if (window->flags & SDL_WINDOW_FULLSCREEN) {
116         wopts |= DWOP_KEEP_POSITION | DWOP_KEEP_STACKING | DWOP_KEEP_SIZE;
117         SDL_DFB_CHECK(windata->dfbwin->SetStackingClass(windata->dfbwin, DWSC_UPPER));
118     }
119 
120     if (bshaped) {
121         wopts |= DWOP_SHAPED | DWOP_ALPHACHANNEL;
122         wopts &= ~DWOP_OPAQUE_REGION;
123     }
124 
125     SDL_DFB_CHECK(windata->dfbwin->SetOptions(windata->dfbwin, wopts));
126 
127     /* See what we got */
128     SDL_DFB_CHECK(DirectFB_WM_GetClientSize
129                      (_this, window, &window->w, &window->h));
130 
131     /* Get the window's surface. */
132     SDL_DFB_CHECKERR(windata->dfbwin->GetSurface(windata->dfbwin,
133                                                  &windata->window_surface));
134 
135     /* And get a subsurface for rendering */
136     SDL_DFB_CHECKERR(windata->window_surface->
137                      GetSubSurface(windata->window_surface, &windata->client,
138                                    &windata->surface));
139 
140     SDL_DFB_CHECK(windata->dfbwin->SetOpacity(windata->dfbwin, 0xFF));
141 
142     /* Create Eventbuffer */
143 
144     SDL_DFB_CHECKERR(windata->dfbwin->CreateEventBuffer(windata->dfbwin,
145                                                         &windata->
146                                                         eventbuffer));
147     SDL_DFB_CHECKERR(windata->dfbwin->
148                      EnableEvents(windata->dfbwin, DWET_ALL));
149 
150     /* Create a font */
151     /* FIXME: once during Video_Init */
152     windata->font = NULL;
153 
154     /* Make it the top most window. */
155     SDL_DFB_CHECK(windata->dfbwin->RaiseToTop(windata->dfbwin));
156 
157     /* remember parent */
158     /* windata->sdlwin = window; */
159 
160     /* Add to list ... */
161 
162     windata->next = devdata->firstwin;
163     windata->opacity = 0xFF;
164     devdata->firstwin = window;
165 
166     /* Draw Frame */
167     DirectFB_WM_RedrawLayout(_this, window);
168 
169     return 0;
170   error:
171     SDL_DFB_RELEASE(windata->surface);
172     SDL_DFB_RELEASE(windata->dfbwin);
173     return -1;
174 }
175 
176 int
DirectFB_CreateWindowFrom(_THIS,SDL_Window * window,const void * data)177 DirectFB_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
178 {
179     return SDL_Unsupported();
180 }
181 
182 void
DirectFB_SetWindowTitle(_THIS,SDL_Window * window)183 DirectFB_SetWindowTitle(_THIS, SDL_Window * window)
184 {
185     SDL_DFB_WINDOWDATA(window);
186 
187     if (windata->is_managed) {
188         windata->wm_needs_redraw = 1;
189         DirectFB_WM_RedrawLayout(_this, window);
190     } else {
191         SDL_Unsupported();
192     }
193 }
194 
195 void
DirectFB_SetWindowIcon(_THIS,SDL_Window * window,SDL_Surface * icon)196 DirectFB_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
197 {
198     SDL_DFB_DEVICEDATA(_this);
199     SDL_DFB_WINDOWDATA(window);
200     SDL_Surface *surface = NULL;
201 
202     if (icon) {
203         SDL_PixelFormat format;
204         DFBSurfaceDescription dsc;
205         Uint32 *dest;
206         Uint32 *p;
207         int pitch, i;
208 
209         /* Convert the icon to ARGB for modern window managers */
210         SDL_InitFormat(&format, SDL_PIXELFORMAT_ARGB8888);
211         surface = SDL_ConvertSurface(icon, &format, 0);
212         if (!surface) {
213             return;
214         }
215         dsc.flags =
216             DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_CAPS;
217         dsc.caps = DSCAPS_VIDEOONLY;
218         dsc.width = surface->w;
219         dsc.height = surface->h;
220         dsc.pixelformat = DSPF_ARGB;
221 
222         SDL_DFB_CHECKERR(devdata->dfb->CreateSurface(devdata->dfb, &dsc,
223                                                      &windata->icon));
224 
225         SDL_DFB_CHECKERR(windata->icon->Lock(windata->icon, DSLF_WRITE,
226                                              (void *) &dest, &pitch));
227 
228         p = surface->pixels;
229         for (i = 0; i < surface->h; i++)
230             memcpy((char *) dest + i * pitch,
231                    (char *) p + i * surface->pitch, 4 * surface->w);
232 
233         SDL_DFB_CHECK(windata->icon->Unlock(windata->icon));
234         SDL_FreeSurface(surface);
235     } else {
236         SDL_DFB_RELEASE(windata->icon);
237     }
238     return;
239   error:
240     SDL_FreeSurface(surface);
241     SDL_DFB_RELEASE(windata->icon);
242     return;
243 }
244 
245 void
DirectFB_SetWindowPosition(_THIS,SDL_Window * window)246 DirectFB_SetWindowPosition(_THIS, SDL_Window * window)
247 {
248     SDL_DFB_WINDOWDATA(window);
249     int x, y;
250 
251     x = window->x;
252     y = window->y;
253 
254     DirectFB_WM_AdjustWindowLayout(window, window->flags, window->w, window->h);
255     SDL_DFB_CHECK(windata->dfbwin->MoveTo(windata->dfbwin, x, y));
256 }
257 
258 void
DirectFB_SetWindowSize(_THIS,SDL_Window * window)259 DirectFB_SetWindowSize(_THIS, SDL_Window * window)
260 {
261     SDL_DFB_WINDOWDATA(window);
262 
263     if(SDL_IsShapedWindow(window))
264         DirectFB_ResizeWindowShape(window);
265 
266     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
267         int cw;
268         int ch;
269 
270         /* Make sure all events are disabled for this operation ! */
271         SDL_DFB_CHECKERR(windata->dfbwin->DisableEvents(windata->dfbwin,
272                                                         DWET_ALL));
273         SDL_DFB_CHECKERR(DirectFB_WM_GetClientSize(_this, window, &cw, &ch));
274 
275         if (cw != window->w || ch != window->h) {
276 
277             DirectFB_WM_AdjustWindowLayout(window, window->flags, window->w, window->h);
278             SDL_DFB_CHECKERR(windata->dfbwin->Resize(windata->dfbwin,
279                                                      windata->size.w,
280                                                      windata->size.h));
281         }
282 
283         SDL_DFB_CHECKERR(DirectFB_WM_GetClientSize
284                      (_this, window, &window->w, &window->h));
285         DirectFB_AdjustWindowSurface(window);
286 
287         SDL_DFB_CHECKERR(windata->dfbwin->EnableEvents(windata->dfbwin,
288                                                        DWET_ALL));
289 
290     }
291     return;
292   error:
293     SDL_DFB_CHECK(windata->dfbwin->EnableEvents(windata->dfbwin, DWET_ALL));
294     return;
295 }
296 
297 void
DirectFB_ShowWindow(_THIS,SDL_Window * window)298 DirectFB_ShowWindow(_THIS, SDL_Window * window)
299 {
300     SDL_DFB_WINDOWDATA(window);
301 
302     SDL_DFB_CHECK(windata->dfbwin->SetOpacity(windata->dfbwin, windata->opacity));
303 
304 }
305 
306 void
DirectFB_HideWindow(_THIS,SDL_Window * window)307 DirectFB_HideWindow(_THIS, SDL_Window * window)
308 {
309     SDL_DFB_WINDOWDATA(window);
310 
311     SDL_DFB_CHECK(windata->dfbwin->GetOpacity(windata->dfbwin, &windata->opacity));
312     SDL_DFB_CHECK(windata->dfbwin->SetOpacity(windata->dfbwin, 0));
313 }
314 
315 void
DirectFB_RaiseWindow(_THIS,SDL_Window * window)316 DirectFB_RaiseWindow(_THIS, SDL_Window * window)
317 {
318     SDL_DFB_WINDOWDATA(window);
319 
320     SDL_DFB_CHECK(windata->dfbwin->RaiseToTop(windata->dfbwin));
321     SDL_DFB_CHECK(windata->dfbwin->RequestFocus(windata->dfbwin));
322 }
323 
324 void
DirectFB_MaximizeWindow(_THIS,SDL_Window * window)325 DirectFB_MaximizeWindow(_THIS, SDL_Window * window)
326 {
327     SDL_DFB_WINDOWDATA(window);
328     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
329     DFBWindowOptions wopts;
330 
331     SDL_DFB_CHECK(windata->dfbwin->GetPosition(windata->dfbwin,
332                                  &windata->restore.x, &windata->restore.y));
333     SDL_DFB_CHECK(windata->dfbwin->GetSize(windata->dfbwin, &windata->restore.w,
334                              &windata->restore.h));
335 
336     DirectFB_WM_AdjustWindowLayout(window, window->flags | SDL_WINDOW_MAXIMIZED, display->current_mode.w, display->current_mode.h) ;
337 
338     SDL_DFB_CHECK(windata->dfbwin->MoveTo(windata->dfbwin, 0, 0));
339     SDL_DFB_CHECK(windata->dfbwin->Resize(windata->dfbwin,
340                             display->current_mode.w, display->current_mode.h));
341 
342     /* Set Options */
343     SDL_DFB_CHECK(windata->dfbwin->GetOptions(windata->dfbwin, &wopts));
344     wopts |= DWOP_KEEP_SIZE | DWOP_KEEP_POSITION;
345     SDL_DFB_CHECK(windata->dfbwin->SetOptions(windata->dfbwin, wopts));
346 }
347 
348 void
DirectFB_MinimizeWindow(_THIS,SDL_Window * window)349 DirectFB_MinimizeWindow(_THIS, SDL_Window * window)
350 {
351     /* FIXME: Size to 32x32 ? */
352 
353     SDL_Unsupported();
354 }
355 
356 void
DirectFB_RestoreWindow(_THIS,SDL_Window * window)357 DirectFB_RestoreWindow(_THIS, SDL_Window * window)
358 {
359     SDL_DFB_WINDOWDATA(window);
360     DFBWindowOptions wopts;
361 
362     /* Set Options */
363     SDL_DFB_CHECK(windata->dfbwin->GetOptions(windata->dfbwin, &wopts));
364     wopts &= ~(DWOP_KEEP_SIZE | DWOP_KEEP_POSITION);
365     SDL_DFB_CHECK(windata->dfbwin->SetOptions(windata->dfbwin, wopts));
366 
367     /* Window layout */
368     DirectFB_WM_AdjustWindowLayout(window, window->flags & ~(SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED),
369         windata->restore.w, windata->restore.h);
370     SDL_DFB_CHECK(windata->dfbwin->Resize(windata->dfbwin, windata->restore.w,
371                             windata->restore.h));
372     SDL_DFB_CHECK(windata->dfbwin->MoveTo(windata->dfbwin, windata->restore.x,
373                             windata->restore.y));
374 
375     if (!(window->flags & SDL_WINDOW_RESIZABLE))
376         wopts |= DWOP_KEEP_SIZE;
377 
378     if (window->flags & SDL_WINDOW_FULLSCREEN)
379         wopts |= DWOP_KEEP_POSITION | DWOP_KEEP_SIZE;
380     SDL_DFB_CHECK(windata->dfbwin->SetOptions(windata->dfbwin, wopts));
381 
382 
383 }
384 
385 void
DirectFB_SetWindowGrab(_THIS,SDL_Window * window,SDL_bool grabbed)386 DirectFB_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
387 {
388     SDL_DFB_DEVICEDATA(_this);
389     SDL_DFB_WINDOWDATA(window);
390     DFB_WindowData *gwindata = ((devdata->grabbed_window) ? (DFB_WindowData *) ((devdata->grabbed_window)->driverdata) : NULL);
391 
392     if ((window->flags & SDL_WINDOW_INPUT_GRABBED)) {
393         if (gwindata != NULL)
394         {
395             SDL_DFB_CHECK(gwindata->dfbwin->UngrabPointer(gwindata->dfbwin));
396             SDL_DFB_CHECK(gwindata->dfbwin->UngrabKeyboard(gwindata->dfbwin));
397         }
398         SDL_DFB_CHECK(windata->dfbwin->GrabPointer(windata->dfbwin));
399         SDL_DFB_CHECK(windata->dfbwin->GrabKeyboard(windata->dfbwin));
400         devdata->grabbed_window = window;
401     } else {
402         SDL_DFB_CHECK(windata->dfbwin->UngrabPointer(windata->dfbwin));
403         SDL_DFB_CHECK(windata->dfbwin->UngrabKeyboard(windata->dfbwin));
404         devdata->grabbed_window = NULL;
405     }
406 }
407 
408 void
DirectFB_DestroyWindow(_THIS,SDL_Window * window)409 DirectFB_DestroyWindow(_THIS, SDL_Window * window)
410 {
411     SDL_DFB_DEVICEDATA(_this);
412     SDL_DFB_WINDOWDATA(window);
413     DFB_WindowData *p;
414 
415     /* Some cleanups */
416     SDL_DFB_CHECK(windata->dfbwin->UngrabPointer(windata->dfbwin));
417     SDL_DFB_CHECK(windata->dfbwin->UngrabKeyboard(windata->dfbwin));
418 
419 #if SDL_DIRECTFB_OPENGL
420     DirectFB_GL_DestroyWindowContexts(_this, window);
421 #endif
422 
423     if (window->shaper)
424     {
425         SDL_ShapeData *data = window->shaper->driverdata;
426         SDL_DFB_CHECK(data->surface->ReleaseSource(data->surface));
427         SDL_DFB_RELEASE(data->surface);
428         SDL_DFB_FREE(data);
429         SDL_DFB_FREE(window->shaper);
430     }
431 
432     SDL_DFB_CHECK(windata->window_surface->SetFont(windata->window_surface, NULL));
433     SDL_DFB_CHECK(windata->surface->ReleaseSource(windata->surface));
434     SDL_DFB_CHECK(windata->window_surface->ReleaseSource(windata->window_surface));
435     SDL_DFB_RELEASE(windata->icon);
436     SDL_DFB_RELEASE(windata->font);
437     SDL_DFB_RELEASE(windata->eventbuffer);
438     SDL_DFB_RELEASE(windata->surface);
439     SDL_DFB_RELEASE(windata->window_surface);
440 
441     SDL_DFB_RELEASE(windata->dfbwin);
442 
443     /* Remove from list ... */
444 
445     p = devdata->firstwin->driverdata;
446 
447     while (p && p->next != window)
448         p = (p->next ? p->next->driverdata : NULL);
449     if (p)
450         p->next = windata->next;
451     else
452         devdata->firstwin = windata->next;
453     SDL_free(windata);
454     return;
455 }
456 
457 SDL_bool
DirectFB_GetWindowWMInfo(_THIS,SDL_Window * window,struct SDL_SysWMinfo * info)458 DirectFB_GetWindowWMInfo(_THIS, SDL_Window * window,
459                          struct SDL_SysWMinfo * info)
460 {
461     const Uint32 version = ((((Uint32) info->version.major) * 1000000) +
462                             (((Uint32) info->version.minor) * 10000) +
463                             (((Uint32) info->version.patch)));
464 
465     SDL_DFB_DEVICEDATA(_this);
466     SDL_DFB_WINDOWDATA(window);
467 
468     /* Before 2.0.6, it was possible to build an SDL with DirectFB support
469        (SDL_SysWMinfo will be large enough to hold DirectFB info), but build
470        your app against SDL headers that didn't have DirectFB support
471        (SDL_SysWMinfo could be smaller than DirectFB needs. This would lead
472        to an app properly using SDL_GetWindowWMInfo() but we'd accidentally
473        overflow memory on the stack or heap. To protect against this, we've
474        padded out the struct unconditionally in the headers and DirectFB will
475        just return an error for older apps using this function. Those apps
476        will need to be recompiled against newer headers or not use DirectFB,
477        maybe by forcing SDL_VIDEODRIVER=x11. */
478     if (version < 2000006) {
479         info->subsystem = SDL_SYSWM_UNKNOWN;
480         SDL_SetError("Version must be 2.0.6 or newer");
481         return SDL_FALSE;
482     }
483 
484     if (info->version.major == SDL_MAJOR_VERSION &&
485         info->version.minor == SDL_MINOR_VERSION) {
486         info->subsystem = SDL_SYSWM_DIRECTFB;
487         info->info.dfb.dfb = devdata->dfb;
488         info->info.dfb.window = windata->dfbwin;
489         info->info.dfb.surface = windata->surface;
490         return SDL_TRUE;
491     } else {
492         SDL_SetError("Application not compiled with SDL %d.%d",
493                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
494         return SDL_FALSE;
495     }
496 }
497 
498 void
DirectFB_AdjustWindowSurface(SDL_Window * window)499 DirectFB_AdjustWindowSurface(SDL_Window * window)
500 {
501     SDL_DFB_WINDOWDATA(window);
502     int adjust = windata->wm_needs_redraw;
503     int cw, ch;
504 
505     DirectFB_WM_AdjustWindowLayout(window, window->flags, window->w, window->h);
506 
507     SDL_DFB_CHECKERR(windata->
508                      window_surface->GetSize(windata->window_surface, &cw,
509                                              &ch));
510     if (cw != windata->size.w || ch != windata->size.h) {
511         adjust = 1;
512     }
513 
514     if (adjust) {
515 #if SDL_DIRECTFB_OPENGL
516         DirectFB_GL_FreeWindowContexts(SDL_GetVideoDevice(), window);
517 #endif
518 
519 #if (DFB_VERSION_ATLEAST(1,2,1))
520         SDL_DFB_CHECKERR(windata->dfbwin->ResizeSurface(windata->dfbwin,
521                                                         windata->size.w,
522                                                         windata->size.h));
523         SDL_DFB_CHECKERR(windata->surface->MakeSubSurface(windata->surface,
524                                                           windata->
525                                                           window_surface,
526                                                           &windata->client));
527 #else
528         DFBWindowOptions opts;
529 
530         SDL_DFB_CHECKERR(windata->dfbwin->GetOptions(windata->dfbwin, &opts));
531         /* recreate subsurface */
532         SDL_DFB_RELEASE(windata->surface);
533 
534         if (opts & DWOP_SCALE)
535             SDL_DFB_CHECKERR(windata->dfbwin->ResizeSurface(windata->dfbwin,
536                                                             windata->size.w,
537                                                             windata->size.h));
538         SDL_DFB_CHECKERR(windata->window_surface->
539                          GetSubSurface(windata->window_surface,
540                                        &windata->client, &windata->surface));
541 #endif
542         DirectFB_WM_RedrawLayout(SDL_GetVideoDevice(), window);
543 
544 #if SDL_DIRECTFB_OPENGL
545         DirectFB_GL_ReAllocWindowContexts(SDL_GetVideoDevice(), window);
546 #endif
547    }
548   error:
549     return;
550 }
551 
552 int
DirectFB_SetWindowOpacity(_THIS,SDL_Window * window,float opacity)553 DirectFB_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
554 {
555     const Uint8 alpha = (Uint8) ((unsigned int) (opacity * 255.0f));
556     SDL_DFB_WINDOWDATA(window);
557     SDL_DFB_CHECKERR(windata->dfbwin->SetOpacity(windata->dfbwin, alpha));
558     windata->opacity = alpha;
559     return 0;
560 
561 error:
562     return -1;
563 }
564 
565 #endif /* SDL_VIDEO_DRIVER_DIRECTFB */
566