Imported Upstream version 2.0.14
[platform/upstream/SDL.git] / src / video / directfb / SDL_DirectFB_WM.c
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_window.h"
27
28 #include "../../events/SDL_windowevents_c.h"
29
30 #define COLOR_EXPAND(col) col.r, col.g, col.b, col.a
31
32 static DFB_Theme theme_std = {
33     4, 4, 8, 8,
34     {255, 200, 200, 200},
35     24,
36     {255, 0, 0, 255},
37     16,
38     {255, 255, 255, 255},
39     "/usr/share/fonts/truetype/freefont/FreeSans.ttf",
40     {255, 255, 0, 0},
41     {255, 255, 255, 0},
42 };
43
44 static DFB_Theme theme_none = {
45     0, 0, 0, 0,
46     {0, 0, 0, 0},
47     0,
48     {0, 0, 0, 0},
49     0,
50     {0, 0, 0, 0},
51     NULL
52 };
53
54 static void
55 DrawTriangle(IDirectFBSurface * s, int down, int x, int y, int w)
56 {
57     int x1, x2, x3;
58     int y1, y2, y3;
59
60     if (down) {
61         x1 = x + w / 2;
62         x2 = x;
63         x3 = x + w;
64         y1 = y + w;
65         y2 = y;
66         y3 = y;
67     } else {
68         x1 = x + w / 2;
69         x2 = x;
70         x3 = x + w;
71         y1 = y;
72         y2 = y + w;
73         y3 = y + w;
74     }
75     s->FillTriangle(s, x1, y1, x2, y2, x3, y3);
76 }
77
78 static void
79 LoadFont(_THIS, SDL_Window * window)
80 {
81     SDL_DFB_DEVICEDATA(_this);
82     SDL_DFB_WINDOWDATA(window);
83
84     if (windata->font != NULL) {
85         SDL_DFB_RELEASE(windata->font);
86         windata->font = NULL;
87         SDL_DFB_CHECK(windata->window_surface->SetFont(windata->window_surface, windata->font));
88     }
89
90     if (windata->theme.font != NULL)
91     {
92         DFBFontDescription fdesc;
93
94         SDL_zero(fdesc);
95         fdesc.flags = DFDESC_HEIGHT;
96         fdesc.height = windata->theme.font_size;
97         SDL_DFB_CHECK(devdata->
98                       dfb->CreateFont(devdata->dfb, windata->theme.font,
99                                       &fdesc, &windata->font));
100         SDL_DFB_CHECK(windata->window_surface->SetFont(windata->window_surface, windata->font));
101     }
102 }
103
104 static void
105 DrawCraption(_THIS, IDirectFBSurface * s, int x, int y, char *text)
106 {
107     DFBSurfaceTextFlags flags;
108
109     flags = DSTF_CENTER | DSTF_TOP;
110
111     s->DrawString(s, text, -1, x, y, flags);
112 }
113
114 void
115 DirectFB_WM_RedrawLayout(_THIS, SDL_Window * window)
116 {
117     SDL_DFB_WINDOWDATA(window);
118     IDirectFBSurface *s = windata->window_surface;
119     DFB_Theme *t = &windata->theme;
120     int i;
121     int d = (t->caption_size - t->font_size) / 2;
122     int x, y, w;
123
124
125     if (!windata->is_managed || (window->flags & SDL_WINDOW_FULLSCREEN))
126         return;
127
128     SDL_DFB_CHECK(s->SetSrcBlendFunction(s, DSBF_ONE));
129     SDL_DFB_CHECK(s->SetDstBlendFunction(s, DSBF_ZERO));
130     SDL_DFB_CHECK(s->SetDrawingFlags(s, DSDRAW_NOFX));
131     SDL_DFB_CHECK(s->SetBlittingFlags(s, DSBLIT_NOFX));
132
133     LoadFont(_this, window);
134     /* s->SetDrawingFlags(s, DSDRAW_BLEND); */
135     s->SetColor(s, COLOR_EXPAND(t->frame_color));
136     /* top */
137     for (i = 0; i < t->top_size; i++)
138         s->DrawLine(s, 0, i, windata->size.w, i);
139     /* bottom */
140     for (i = windata->size.h - t->bottom_size; i < windata->size.h; i++)
141         s->DrawLine(s, 0, i, windata->size.w, i);
142     /* left */
143     for (i = 0; i < t->left_size; i++)
144         s->DrawLine(s, i, 0, i, windata->size.h);
145     /* right */
146     for (i = windata->size.w - t->right_size; i < windata->size.w; i++)
147         s->DrawLine(s, i, 0, i, windata->size.h);
148     /* Caption */
149     s->SetColor(s, COLOR_EXPAND(t->caption_color));
150     s->FillRectangle(s, t->left_size, t->top_size, windata->client.w,
151                      t->caption_size);
152     /* Close Button */
153     w = t->caption_size;
154     x = windata->size.w - t->right_size - w + d;
155     y = t->top_size + d;
156     s->SetColor(s, COLOR_EXPAND(t->close_color));
157     DrawTriangle(s, 1, x, y, w - 2 * d);
158     /* Max Button */
159     s->SetColor(s, COLOR_EXPAND(t->max_color));
160     DrawTriangle(s, window->flags & SDL_WINDOW_MAXIMIZED ? 1 : 0, x - w,
161                y, w - 2 * d);
162
163     /* Caption */
164     if (*window->title) {
165         s->SetColor(s, COLOR_EXPAND(t->font_color));
166         DrawCraption(_this, s, (x - w) / 2, t->top_size + d, window->title);
167     }
168     /* Icon */
169     if (windata->icon) {
170         DFBRectangle dr;
171
172         dr.x = t->left_size + d;
173         dr.y = t->top_size + d;
174         dr.w = w - 2 * d;
175         dr.h = w - 2 * d;
176         s->SetBlittingFlags(s, DSBLIT_BLEND_ALPHACHANNEL);
177
178         s->StretchBlit(s, windata->icon, NULL, &dr);
179     }
180     windata->wm_needs_redraw = 0;
181 }
182
183 DFBResult
184 DirectFB_WM_GetClientSize(_THIS, SDL_Window * window, int *cw, int *ch)
185 {
186     SDL_DFB_WINDOWDATA(window);
187     IDirectFBWindow *dfbwin = windata->dfbwin;
188
189     SDL_DFB_CHECK(dfbwin->GetSize(dfbwin, cw, ch));
190     dfbwin->GetSize(dfbwin, cw, ch);
191     *cw -= windata->theme.left_size + windata->theme.right_size;
192     *ch -=
193         windata->theme.top_size + windata->theme.caption_size +
194         windata->theme.bottom_size;
195     return DFB_OK;
196 }
197
198 void
199 DirectFB_WM_AdjustWindowLayout(SDL_Window * window, int flags, int w, int h)
200 {
201     SDL_DFB_WINDOWDATA(window);
202
203     if (!windata->is_managed)
204         windata->theme = theme_none;
205     else if (flags & SDL_WINDOW_BORDERLESS)
206         /* desc.caps |= DWCAPS_NODECORATION;) */
207         windata->theme = theme_none;
208     else if (flags & SDL_WINDOW_FULLSCREEN) {
209         windata->theme = theme_none;
210     } else if (flags & SDL_WINDOW_MAXIMIZED) {
211         windata->theme = theme_std;
212         windata->theme.left_size = 0;
213         windata->theme.right_size = 0;
214         windata->theme.top_size = 0;
215         windata->theme.bottom_size = 0;
216     } else {
217         windata->theme = theme_std;
218     }
219
220     windata->client.x = windata->theme.left_size;
221     windata->client.y = windata->theme.top_size + windata->theme.caption_size;
222     windata->client.w = w;
223     windata->client.h = h;
224     windata->size.w =
225         w + windata->theme.left_size + windata->theme.right_size;
226     windata->size.h =
227         h + windata->theme.top_size +
228         windata->theme.caption_size + windata->theme.bottom_size;
229 }
230
231
232 enum
233 {
234     WM_POS_NONE = 0x00,
235     WM_POS_CAPTION = 0x01,
236     WM_POS_CLOSE = 0x02,
237     WM_POS_MAX = 0x04,
238     WM_POS_LEFT = 0x08,
239     WM_POS_RIGHT = 0x10,
240     WM_POS_TOP = 0x20,
241     WM_POS_BOTTOM = 0x40,
242 };
243
244 static int
245 WMIsClient(DFB_WindowData * p, int x, int y)
246 {
247     x -= p->client.x;
248     y -= p->client.y;
249     if (x < 0 || y < 0)
250         return 0;
251     if (x >= p->client.w || y >= p->client.h)
252         return 0;
253     return 1;
254 }
255
256 static int
257 WMPos(DFB_WindowData * p, int x, int y)
258 {
259     int pos = WM_POS_NONE;
260
261     if (!WMIsClient(p, x, y)) {
262         if (y < p->theme.top_size) {
263             pos |= WM_POS_TOP;
264         } else if (y < p->client.y) {
265             if (x <
266                 p->size.w - p->theme.right_size - 2 * p->theme.caption_size) {
267                 pos |= WM_POS_CAPTION;
268             } else if (x <
269                        p->size.w - p->theme.right_size -
270                        p->theme.caption_size) {
271                 pos |= WM_POS_MAX;
272             } else {
273                 pos |= WM_POS_CLOSE;
274             }
275         } else if (y >= p->size.h - p->theme.bottom_size) {
276             pos |= WM_POS_BOTTOM;
277         }
278         if (x < p->theme.left_size) {
279             pos |= WM_POS_LEFT;
280         } else if (x >= p->size.w - p->theme.right_size) {
281             pos |= WM_POS_RIGHT;
282         }
283     }
284     return pos;
285 }
286
287 int
288 DirectFB_WM_ProcessEvent(_THIS, SDL_Window * window, DFBWindowEvent * evt)
289 {
290     SDL_DFB_DEVICEDATA(_this);
291     SDL_DFB_WINDOWDATA(window);
292     DFB_WindowData *gwindata = ((devdata->grabbed_window) ? (DFB_WindowData *) ((devdata->grabbed_window)->driverdata) : NULL);
293     IDirectFBWindow *dfbwin = windata->dfbwin;
294     DFBWindowOptions wopts;
295
296     if (!windata->is_managed)
297         return 0;
298
299     SDL_DFB_CHECK(dfbwin->GetOptions(dfbwin, &wopts));
300
301     switch (evt->type) {
302     case DWET_BUTTONDOWN:
303         if (evt->buttons & DIBM_LEFT) {
304             int pos = WMPos(windata, evt->x, evt->y);
305             switch (pos) {
306             case WM_POS_NONE:
307                 return 0;
308             case WM_POS_CLOSE:
309                 windata->wm_grab = WM_POS_NONE;
310                 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_CLOSE, 0,
311                                     0);
312                 return 1;
313             case WM_POS_MAX:
314                 windata->wm_grab = WM_POS_NONE;
315                 if (window->flags & SDL_WINDOW_MAXIMIZED) {
316                     SDL_RestoreWindow(window);
317                 } else {
318                     SDL_MaximizeWindow(window);
319                 }
320                 return 1;
321             case WM_POS_CAPTION:
322                 if (!(wopts & DWOP_KEEP_STACKING)) {
323                     DirectFB_RaiseWindow(_this, window);
324                 }
325                 if (window->flags & SDL_WINDOW_MAXIMIZED)
326                     return 1;
327                 /* fall through */
328             default:
329                 windata->wm_grab = pos;
330                 if (gwindata != NULL)
331                     SDL_DFB_CHECK(gwindata->dfbwin->UngrabPointer(gwindata->dfbwin));
332                 SDL_DFB_CHECK(dfbwin->GrabPointer(dfbwin));
333                 windata->wm_lastx = evt->cx;
334                 windata->wm_lasty = evt->cy;
335             }
336         }
337         return 1;
338     case DWET_BUTTONUP:
339         if (!windata->wm_grab)
340             return 0;
341         if (!(evt->buttons & DIBM_LEFT)) {
342             if (windata->wm_grab & (WM_POS_RIGHT | WM_POS_BOTTOM)) {
343                 int dx = evt->cx - windata->wm_lastx;
344                 int dy = evt->cy - windata->wm_lasty;
345
346                 if (!(wopts & DWOP_KEEP_SIZE)) {
347                     int cw, ch;
348                     if ((windata->wm_grab & (WM_POS_BOTTOM | WM_POS_RIGHT)) == WM_POS_BOTTOM)
349                         dx = 0;
350                     else if ((windata->wm_grab & (WM_POS_BOTTOM | WM_POS_RIGHT)) == WM_POS_RIGHT)
351                         dy = 0;
352                     SDL_DFB_CHECK(dfbwin->GetSize(dfbwin, &cw, &ch));
353
354                     /* necessary to trigger an event - ugly */
355                     SDL_DFB_CHECK(dfbwin->DisableEvents(dfbwin, DWET_ALL));
356                     SDL_DFB_CHECK(dfbwin->Resize(dfbwin, cw + dx + 1, ch + dy));
357                     SDL_DFB_CHECK(dfbwin->EnableEvents(dfbwin, DWET_ALL));
358
359                     SDL_DFB_CHECK(dfbwin->Resize(dfbwin, cw + dx, ch + dy));
360                 }
361             }
362             SDL_DFB_CHECK(dfbwin->UngrabPointer(dfbwin));
363             if (gwindata != NULL)
364                 SDL_DFB_CHECK(gwindata->dfbwin->GrabPointer(gwindata->dfbwin));
365             windata->wm_grab = WM_POS_NONE;
366             return 1;
367         }
368         break;
369     case DWET_MOTION:
370         if (!windata->wm_grab)
371             return 0;
372         if (evt->buttons & DIBM_LEFT) {
373             int dx = evt->cx - windata->wm_lastx;
374             int dy = evt->cy - windata->wm_lasty;
375
376             if (windata->wm_grab & WM_POS_CAPTION) {
377                 if (!(wopts & DWOP_KEEP_POSITION))
378                     SDL_DFB_CHECK(dfbwin->Move(dfbwin, dx, dy));
379             }
380             if (windata->wm_grab & (WM_POS_RIGHT | WM_POS_BOTTOM)) {
381                 if (!(wopts & DWOP_KEEP_SIZE)) {
382                     int cw, ch;
383
384                     /* Make sure all events are disabled for this operation ! */
385                     SDL_DFB_CHECK(dfbwin->DisableEvents(dfbwin, DWET_ALL));
386
387                     if ((windata->wm_grab & (WM_POS_BOTTOM | WM_POS_RIGHT)) == WM_POS_BOTTOM)
388                         dx = 0;
389                     else if ((windata->wm_grab & (WM_POS_BOTTOM | WM_POS_RIGHT)) == WM_POS_RIGHT)
390                         dy = 0;
391
392                     SDL_DFB_CHECK(dfbwin->GetSize(dfbwin, &cw, &ch));
393                     SDL_DFB_CHECK(dfbwin->Resize(dfbwin, cw + dx, ch + dy));
394
395                     SDL_DFB_CHECK(dfbwin->EnableEvents(dfbwin, DWET_ALL));
396                 }
397             }
398             windata->wm_lastx = evt->cx;
399             windata->wm_lasty = evt->cy;
400             return 1;
401         }
402         break;
403     case DWET_KEYDOWN:
404         break;
405     case DWET_KEYUP:
406         break;
407     default:
408         ;
409     }
410     return 0;
411 }
412
413 #endif /* SDL_VIDEO_DRIVER_DIRECTFB */