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