1 /* Public domain */
2
3 #ifndef _AGAR_GUI_WINDOW_H_
4 #define _AGAR_GUI_WINDOW_H_
5
6 #include <agar/gui/widget.h>
7
8 #include <agar/gui/begin.h>
9
10 #define AG_WINDOW_CAPTION_MAX 512
11
12 struct ag_titlebar;
13 struct ag_font;
14 struct ag_icon;
15 struct ag_widget;
16 struct ag_cursor;
17
18 #define AG_WINDOW_UPPER_LEFT AG_WINDOW_TL
19 #define AG_WINDOW_UPPER_CENTER AG_WINDOW_TC
20 #define AG_WINDOW_UPPER_RIGHT AG_WINDOW_TR
21 #define AG_WINDOW_MIDDLE_LEFT AG_WINDOW_ML
22 #define AG_WINDOW_CENTER AG_WINDOW_MC
23 #define AG_WINDOW_MIDDLE_RIGHT AG_WINDOW_MR
24 #define AG_WINDOW_LOWER_LEFT AG_WINDOW_BL
25 #define AG_WINDOW_LOWER_CENTER AG_WINDOW_BC
26 #define AG_WINDOW_LOWER_RIGHT AG_WINDOW_BR
27
28 /* For AG_WindowSetCloseAction() */
29 enum ag_window_close_action {
30 AG_WINDOW_HIDE,
31 AG_WINDOW_DETACH,
32 AG_WINDOW_IGNORE
33 };
34
35 /*
36 * Window function (used by the underlying window manager to set decoration,
37 * stacking position and other window behavior settings). Maps to EWMH types.
38 * SYNC: agWindowWmTypeNames[].
39 */
40 enum ag_window_wm_type {
41 AG_WINDOW_WM_NORMAL, /* Normal, top-level window */
42 AG_WINDOW_WM_DESKTOP, /* Desktop feature (e.g., fullscreen) */
43 AG_WINDOW_WM_DOCK, /* Dock or panel feature */
44 AG_WINDOW_WM_TOOLBAR, /* Toolbar "torn off" from main window */
45 AG_WINDOW_WM_MENU, /* Pinnable menu window */
46 AG_WINDOW_WM_UTILITY, /* Persistent utility window (e.g.,
47 a palette or a toolbox). */
48 AG_WINDOW_WM_SPLASH, /* Introductory splash screen */
49 AG_WINDOW_WM_DIALOG, /* Dialog window */
50 AG_WINDOW_WM_DROPDOWN_MENU, /* Menubar-triggered drop-down menu */
51 AG_WINDOW_WM_POPUP_MENU, /* Contextual popup menu */
52 AG_WINDOW_WM_TOOLTIP, /* Mouse hover triggered tooltip */
53 AG_WINDOW_WM_NOTIFICATION, /* Notification bubble */
54 AG_WINDOW_WM_COMBO, /* Combo-box triggered window */
55 AG_WINDOW_WM_DND /* Draggable object */
56 };
57
58 typedef AG_TAILQ_HEAD(ag_cursor_areaq, ag_cursor_area) AG_CursorAreaQ;
59
60 /* Window instance */
61 typedef struct ag_window {
62 struct ag_widget wid;
63
64 Uint flags;
65 #define AG_WINDOW_MODAL 0x00000001 /* Application-modal window */
66 #define AG_WINDOW_MAXIMIZED 0x00000002 /* Window is maximized (read-only) */
67 #define AG_WINDOW_MINIMIZED 0x00000004 /* Window is minimized (read-only) */
68 #define AG_WINDOW_KEEPABOVE 0x00000008 /* Keep window above others */
69 #define AG_WINDOW_KEEPBELOW 0x00000010 /* Keep window below others */
70 #define AG_WINDOW_DENYFOCUS 0x00000020 /* Prevent focus gain if possible */
71 #define AG_WINDOW_NOTITLE 0x00000040 /* Disable titlebar */
72 #define AG_WINDOW_NOBORDERS 0x00000080 /* Disable window borders */
73 #define AG_WINDOW_NOHRESIZE 0x00000100 /* Disable horizontal resize ctrl */
74 #define AG_WINDOW_NOVRESIZE 0x00000200 /* Disable vertical resize ctrl */
75 #define AG_WINDOW_NOCLOSE 0x00000400 /* Disable close button */
76 #define AG_WINDOW_NOMINIMIZE 0x00000800 /* Disable minimize button */
77 #define AG_WINDOW_NOMAXIMIZE 0x00001000 /* Disable maximize button */
78 #define AG_WINDOW_TILING 0x00002000 /* Subject to WM tiling */
79 #define AG_WINDOW_MINSIZEPCT 0x00004000 /* Min size is in % (read-only) */
80 #define AG_WINDOW_NOBACKGROUND 0x00008000 /* Don't fill the background */
81 #define AG_WINDOW_MAIN 0x00010000 /* Break from AG_EventLoop() on close */
82 #define AG_WINDOW_FOCUSONATTACH 0x00020000 /* Focus on attach (read-only) */
83 #define AG_WINDOW_HMAXIMIZE 0x00040000 /* Keep maximized horizontally */
84 #define AG_WINDOW_VMAXIMIZE 0x00080000 /* Keep maximized vertically */
85 #define AG_WINDOW_NOMOVE 0x00100000 /* Disallow movement of window */
86 #define AG_WINDOW_NOCLIPPING 0x00200000 /* Don't set a clipping rectangle over the window area */
87 #define AG_WINDOW_MODKEYEVENTS 0x00400000 /* Generate key{up,down} events for
88 keypresses on modifier keys */
89 #define AG_WINDOW_DETACHING 0x00800000 /* Being detached (read-only) */
90 #define AG_WINDOW_NOCURSORCHG 0x04000000 /* Inhibit any cursor change */
91 #define AG_WINDOW_FADEIN 0x08000000 /* Fade-in (compositing WMs) */
92 #define AG_WINDOW_FADEOUT 0x10000000 /* Fade-out (compositing WMs) */
93
94 #define AG_WINDOW_NORESIZE (AG_WINDOW_NOHRESIZE|AG_WINDOW_NOVRESIZE)
95 #define AG_WINDOW_NOBUTTONS (AG_WINDOW_NOCLOSE|AG_WINDOW_NOMINIMIZE|\
96 AG_WINDOW_NOMAXIMIZE)
97 #define AG_WINDOW_PLAIN (AG_WINDOW_NOTITLE|AG_WINDOW_NOBORDERS)
98
99 char caption[AG_WINDOW_CAPTION_MAX]; /* Window caption */
100 int visible; /* Window is visible */
101 int dirty; /* Window needs redraw */
102
103 struct ag_titlebar *tbar; /* Titlebar (if any) */
104 enum ag_window_alignment alignment; /* Initial position */
105 int spacing; /* Default spacing (px) */
106 int tPad, bPad, lPad, rPad; /* Window padding (px) */
107 int wReq, hReq; /* Requested geometry (px) */
108 int wMin, hMin; /* Minimum geometry (px) */
109 int wBorderBot; /* Bottom border size (px) */
110 int wBorderSide; /* Side border size (px) */
111 int wResizeCtrl; /* Resize controls size (px) */
112 AG_Rect rSaved; /* Saved geometry */
113 int minPct; /* For MINSIZEPCT */
114
115 struct ag_window *parent; /* Logical parent window */
116 struct ag_window *transientFor; /* Transient parent window */
117 struct ag_window *pinnedTo; /* Pinned to parent window */
118
119 AG_TAILQ_HEAD_(ag_window) subwins; /* For AG_WindowAttach() */
120 AG_TAILQ_ENTRY(ag_window) swins; /* In parent's subwins */
121 AG_TAILQ_ENTRY(ag_window) detach; /* In agWindowDetachQ */
122
123 struct ag_icon *icon; /* Window icon (for internal WM) */
124 AG_Rect r; /* View area */
125 int nFocused; /* Widgets in focus chain */
126 AG_Widget *widExclMotion; /* Widget exclusively receiving mousemotion */
127 AG_CursorAreaQ cursorAreas; /* Cursor-change areas */
128 AG_CursorArea *caResize[5]; /* Window-resize areas */
129
130 AG_Timer fadeTo; /* Fade timer */
131 float fadeInTime, fadeOutTime; /* Fade time (s) */
132 float fadeInIncr, fadeOutIncr; /* Fade increment */
133 float fadeOpacity; /* Fade opacity */
134 enum ag_window_wm_type wmType; /* Window function */
135 int zoom; /* Effective zoom level */
136 AG_TAILQ_ENTRY(ag_window) visibility; /* In agWindow{Show,Hide}Q */
137 AG_TAILQ_ENTRY(ag_window) user; /* In user list */
138 } AG_Window;
139
140 typedef AG_TAILQ_HEAD(ag_windowq, ag_window) AG_WindowQ;
141
142 __BEGIN_DECLS
143 extern const char *agWindowWmTypeNames[];
144 extern AG_WidgetClass agWindowClass;
145
146 /* Protected by agDrivers VFS lock */
147 extern AG_WindowQ agWindowDetachQ; /* AG_ObjectDetach() queue */
148 extern AG_WindowQ agWindowShowQ; /* AG_WindowShow() queue */
149 extern AG_WindowQ agWindowHideQ; /* AG_WindowHide() queue */
150 extern AG_Window *agWindowToFocus; /* Window to focus next */
151 extern AG_Window *agWindowFocused; /* Window holding focus */
152
153 void AG_InitWindowSystem(void);
154 void AG_DestroyWindowSystem(void);
155 AG_Window *AG_WindowNew(Uint);
156 AG_Window *AG_WindowNewSw(void *, Uint);
157 AG_Window *AG_WindowNewNamedS(Uint, const char *);
158 AG_Window *AG_WindowNewNamed(Uint, const char *, ...)
159 FORMAT_ATTRIBUTE(printf,2,3);
160
161 void AG_WindowSetCaptionS(AG_Window *, const char *);
162 void AG_WindowSetCaption(AG_Window *, const char *, ...)
163 FORMAT_ATTRIBUTE(printf,2,3)
164 NONNULL_ATTRIBUTE(2);
165
166 void AG_WindowUpdateCaption(AG_Window *);
167 #define AG_WindowSetIcon(win,su) AG_IconSetSurface((win)->icon,(su))
168 #define AG_WindowSetIconNODUP(win,su) AG_IconSetSurfaceNODUP((win)->icon,(su))
169
170 void AG_WindowSetSpacing(AG_Window *, int);
171 void AG_WindowSetPadding(AG_Window *, int, int, int, int);
172 #define AG_WindowSetPaddingLeft(w,p) AG_WindowSetPadding((w),(p),-1,-1,-1)
173 #define AG_WindowSetPaddingRight(w,p) AG_WindowSetPadding((w),-1,(p),-1,-1)
174 #define AG_WindowSetPaddingTop(w,p) AG_WindowSetPadding((w),-1,-1,(p),-1)
175 #define AG_WindowSetPaddingBottom(w,p) AG_WindowSetPadding((w),-1,-1,-1,(p))
176 void AG_WindowSetSideBorders(AG_Window *, int);
177 void AG_WindowSetBottomBorder(AG_Window *, int);
178
179 void AG_WindowSetPosition(AG_Window *, enum ag_window_alignment, int);
180 void AG_WindowSetCloseAction(AG_Window *, enum ag_window_close_action);
181
182 void AG_WindowSetMinSize(AG_Window *, int, int);
183 void AG_WindowSetMinSizePct(AG_Window *, int);
184 int AG_WindowSetGeometryRect(AG_Window *, AG_Rect, int);
185 int AG_WindowSetGeometryAligned(AG_Window *, enum ag_window_alignment,
186 int, int);
187 int AG_WindowSetGeometryAlignedPct(AG_Window *, enum ag_window_alignment,
188 int, int);
189 #define AG_WindowSetGeometry(win,x,y,w,h) \
190 AG_WindowSetGeometryRect((win),AG_RECT((x),(y),(w),(h)),0)
191 #define AG_WindowSetGeometryBounded(win,x,y,w,h) \
192 AG_WindowSetGeometryRect((win),AG_RECT((x),(y),(w),(h)),1)
193 void AG_WindowComputeAlignment(AG_Window *, AG_SizeAlloc *);
194
195 int AG_WindowSetOpacity(AG_Window *, float);
196 void AG_WindowSetFadeIn(AG_Window *, float, float);
197 void AG_WindowSetFadeOut(AG_Window *, float, float);
198 void AG_WindowSetZoom(AG_Window *, int);
199
200 void AG_WindowSaveGeometry(AG_Window *);
201 int AG_WindowRestoreGeometry(AG_Window *);
202 void AG_WindowMaximize(AG_Window *);
203 void AG_WindowUnmaximize(AG_Window *);
204 void AG_WindowMinimize(AG_Window *);
205 void AG_WindowUnminimize(AG_Window *);
206
207 void AG_WindowAttach(AG_Window *, AG_Window *);
208 void AG_WindowDetach(AG_Window *, AG_Window *);
209 void AG_WindowMakeTransient(AG_Window *, AG_Window *);
210 void AG_WindowPin(AG_Window *, AG_Window *);
211 void AG_WindowUnpin(AG_Window *);
212 void AG_WindowMovePinned(AG_Window *, int, int);
213 void AG_WindowShow(AG_Window *);
214 void AG_WindowHide(AG_Window *);
215 void AG_WindowDrawQueued(void);
216 void AG_WindowResize(AG_Window *);
217
218 void AG_WindowFocus(AG_Window *);
219 int AG_WindowFocusAtPos(AG_DriverSw *, int, int);
220 int AG_WindowFocusNamed(const char *);
221 void AG_WindowCycleFocus(AG_Window *, int);
222 #define AG_WindowFindFocused() agWindowFocused
223 #define AG_WindowIsFocused(win) (agWindowFocused == win)
224 void AG_WindowDetachGenEv(AG_Event *);
225 void AG_WindowHideGenEv(AG_Event *);
226 void AG_WindowCloseGenEv(AG_Event *);
227
228 void AG_CloseFocusedWindow(void);
229
230 void AG_WindowProcessFocusChange(void);
231 void AG_WindowProcessShowQueue(void);
232 void AG_WindowProcessHideQueue(void);
233 void AG_WindowProcessDetachQueue(void);
234
235 AG_CursorArea *AG_MapCursor(void *, AG_Rect, struct ag_cursor *);
236 AG_CursorArea *AG_MapStockCursor(void *, AG_Rect, int);
237 void AG_UnmapCursor(void *, AG_CursorArea *);
238 void AG_UnmapAllCursors(AG_Window *, void *);
239
240 #define AGWINDOW(win) ((AG_Window *)(win))
241 #define AGWINDETACH(win) AG_WindowDetachGenEv, "%p", (win)
242 #define AGWINHIDE(win) AG_WindowHideGenEv, "%p", (win)
243 #define AGWINCLOSE(win) AG_WindowCloseGenEv, "%p", (win)
244
245 /* Window iterators. */
246 #define AG_FOREACH_WINDOW(var, ob) \
247 AGOBJECT_FOREACH_CHILD(var, ob, ag_window)
248 #define AG_FOREACH_WINDOW_REVERSE(var, ob) \
249 AGOBJECT_FOREACH_CHILD_REVERSE(var, ob, ag_window)
250
251 /*
252 * Render a window to the display (must be enclosed between calls to
253 * AG_BeginRendering() and AG_EndRendering()).
254 * The agDrivers VFS and Window object must be locked.
255 */
256 static __inline__ void
AG_WindowDraw(AG_Window * win)257 AG_WindowDraw(AG_Window *win)
258 {
259 AG_Driver *drv = AGWIDGET(win)->drv;
260
261 if (!win->visible) {
262 return;
263 }
264 AGDRIVER_CLASS(drv)->renderWindow(win);
265 win->dirty = 0;
266 }
267
268 /*
269 * Return the effective focus state of a widget.
270 * The Widget and agDrivers VFS must be locked.
271 */
272 static __inline__ int
AG_WidgetIsFocused(void * p)273 AG_WidgetIsFocused(void *p)
274 {
275 AG_Widget *wid = (AG_Widget *)p;
276
277 return ((AGWIDGET(p)->flags & AG_WIDGET_FOCUSED) &&
278 (wid->window == NULL || AG_WindowIsFocused(wid->window)));
279 }
280
281 /*
282 * Recompute the coordinates and geometries of all widgets attached to the
283 * window. This is used following AG_ObjectAttach() and AG_ObjectDetach()
284 * calls made in event context, or direct modifications to the x,y,w,h
285 * fields of the Widget structure.
286 *
287 * The agDrivers VFS and Window must be locked.
288 */
289 static __inline__ void
AG_WindowUpdate(AG_Window * win)290 AG_WindowUpdate(AG_Window *win)
291 {
292 AG_SizeAlloc a;
293
294 if (win == NULL) {
295 return;
296 }
297 if (AGWIDGET(win)->x != -1 && AGWIDGET(win)->y != -1) {
298 a.x = AGWIDGET(win)->x;
299 a.y = AGWIDGET(win)->y;
300 a.w = AGWIDGET(win)->w;
301 a.h = AGWIDGET(win)->h;
302 AG_WidgetSizeAlloc(win, &a);
303 }
304 AG_WidgetUpdateCoords(win, AGWIDGET(win)->x, AGWIDGET(win)->y);
305 }
306
307 /*
308 * Return visibility status of window.
309 * The agDrivers VFS and Window object must be locked.
310 */
311 static __inline__ int
AG_WindowIsVisible(AG_Window * win)312 AG_WindowIsVisible(AG_Window *win)
313 {
314 return (win->visible);
315 }
316
317 /*
318 * Test whether a window is currently selected for a given WM operation.
319 * The agDrivers VFS must be locked.
320 */
321 static __inline__ int
AG_WindowSelectedWM(AG_Window * win,enum ag_wm_operation op)322 AG_WindowSelectedWM(AG_Window *win, enum ag_wm_operation op)
323 {
324 AG_Driver *drv = AGWIDGET(win)->drv;
325
326 return (AGDRIVER_SINGLE(drv) &&
327 AGDRIVER_SW(drv)->winSelected == win &&
328 AGDRIVER_SW(drv)->winop == op);
329 }
330
331 /*
332 * Return a pointer to a widget's parent window.
333 * The agDrivers VFS must be locked.
334 */
335 static __inline__ AG_Window *
AG_ParentWindow(void * obj)336 AG_ParentWindow(void *obj)
337 {
338 return (AGWIDGET(obj)->window);
339 }
340
341 /* Set an explicit widget position in pixels. */
342 static __inline__ void
AG_WidgetSetPosition(void * wid,int x,int y)343 AG_WidgetSetPosition(void *wid, int x, int y)
344 {
345 AG_ObjectLock(wid);
346 AGWIDGET(wid)->x = x;
347 AGWIDGET(wid)->y = y;
348 AG_WidgetUpdate(wid);
349 AG_ObjectUnlock(wid);
350 }
351
352 /* Set an explicit widget geometry in pixels. */
353 static __inline__ void
AG_WidgetSetSize(void * wid,int w,int h)354 AG_WidgetSetSize(void *wid, int w, int h)
355 {
356 AG_ObjectLock(wid);
357 AGWIDGET(wid)->w = w;
358 AGWIDGET(wid)->h = h;
359 AG_WidgetUpdate(wid);
360 AG_ObjectUnlock(wid);
361 }
362
363 /* Set an explicit widget geometry from an AG_Rect argument. */
364 static __inline__ void
AG_WidgetSetGeometry(void * wid,AG_Rect r)365 AG_WidgetSetGeometry(void *wid, AG_Rect r)
366 {
367 AG_ObjectLock(wid);
368 AGWIDGET(wid)->x = r.x;
369 AGWIDGET(wid)->y = r.y;
370 AGWIDGET(wid)->w = r.w;
371 AGWIDGET(wid)->h = r.h;
372 AG_WidgetUpdate(wid);
373 AG_ObjectUnlock(wid);
374 }
375
376 /* Set the largest allowable window size. */
377 static __inline__ void
AG_WindowSetGeometryMax(AG_Window * win)378 AG_WindowSetGeometryMax(AG_Window *win)
379 {
380 Uint wMax, hMax;
381
382 AG_GetDisplaySize((void *)AGWIDGET(win)->drv, &wMax, &hMax);
383 AG_WindowSetGeometry(win, 0, 0, wMax, hMax);
384 }
385
386 /* Request widget redraw. */
387 static __inline__ void
AG_Redraw(void * obj)388 AG_Redraw(void *obj)
389 {
390 if (AGWIDGET(obj)->window != NULL)
391 AGWIDGET(obj)->window->dirty = 1;
392 }
393
394 /*
395 * Alternate interface to AG_MapCursor(). Create a new mapping or
396 * update the rectangle of an existing one.
397 */
398 static __inline__ void
AG_SetCursor(void * obj,AG_CursorArea ** ca,AG_Rect r,struct ag_cursor * c)399 AG_SetCursor(void *obj, AG_CursorArea **ca, AG_Rect r, struct ag_cursor *c)
400 {
401 if (*ca == NULL) {
402 *ca = AG_MapCursor(obj, r, c);
403 } else {
404 (*ca)->r = r;
405 }
406 }
407 static __inline__ void
AG_SetStockCursor(void * obj,AG_CursorArea ** ca,AG_Rect r,int cName)408 AG_SetStockCursor(void *obj, AG_CursorArea **ca, AG_Rect r, int cName)
409 {
410 if (*ca == NULL) {
411 *ca = AG_MapStockCursor(obj, r, cName);
412 } else {
413 (*ca)->r = r;
414 }
415 }
416
417 /*
418 * Process synchronous window operations. This includes focus changes,
419 * visibility changes and the detach operation. Called from custom event
420 * loops or driver code, after all queued events have been processed.
421 */
422 static __inline__ void
AG_WindowProcessQueued(void)423 AG_WindowProcessQueued(void)
424 {
425 AG_LockVFS(&agDrivers);
426 if (agWindowToFocus != NULL) { AG_WindowProcessFocusChange(); }
427 if (!AG_TAILQ_EMPTY(&agWindowShowQ)) { AG_WindowProcessShowQueue(); }
428 if (!AG_TAILQ_EMPTY(&agWindowHideQ)) { AG_WindowProcessHideQueue(); }
429 if (!AG_TAILQ_EMPTY(&agWindowDetachQ)) { AG_WindowProcessDetachQueue(); }
430 AG_UnlockVFS(&agDrivers);
431 }
432
433 #ifdef AG_LEGACY
434 #define AG_WINDOW_POPUP 0x01000000
435 #define AG_WINDOW_DIALOG 0x02000000
436 #define AG_WINDOW_CASCADE AG_WINDOW_TILING
437 AG_Window *AG_FindWindow(const char *) DEPRECATED_ATTRIBUTE;
438 void AG_ViewAttach(AG_Window *) DEPRECATED_ATTRIBUTE;
439 void AG_ViewDetach(AG_Window *) DEPRECATED_ATTRIBUTE;
440 void AG_WindowSetVisibility(AG_Window *, int) DEPRECATED_ATTRIBUTE;
441 int AG_WindowIntersect(AG_DriverSw *, int, int) DEPRECATED_ATTRIBUTE;
442 #endif /* AG_LEGACY */
443 __END_DECLS
444
445 #include <agar/gui/close.h>
446 #endif /* _AGAR_GUI_WINDOW_H_ */
447