1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 popup.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003 Ben Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
27 #include "render/render.h"
28 #include "render/theme.h"
30 ObPopup
*popup_new(gboolean hasicon
)
32 XSetWindowAttributes attrib
;
33 ObPopup
*self
= g_new0(ObPopup
, 1);
35 self
->obwin
.type
= Window_Internal
;
36 self
->hasicon
= hasicon
;
37 self
->gravity
= NorthWestGravity
;
38 self
->x
= self
->y
= self
->w
= self
->h
= 0;
39 self
->a_bg
= RrAppearanceCopy(ob_rr_theme
->osd_hilite_bg
);
40 self
->a_text
= RrAppearanceCopy(ob_rr_theme
->osd_hilite_label
);
42 attrib
.override_redirect
= True
;
43 self
->bg
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
44 0, 0, 1, 1, 0, RrDepth(ob_rr_inst
),
45 InputOutput
, RrVisual(ob_rr_inst
),
46 CWOverrideRedirect
, &attrib
);
48 self
->text
= XCreateWindow(ob_display
, self
->bg
,
49 0, 0, 1, 1, 0, RrDepth(ob_rr_inst
),
50 InputOutput
, RrVisual(ob_rr_inst
), 0, NULL
);
52 XMapWindow(ob_display
, self
->text
);
54 stacking_add(INTERNAL_AS_WINDOW(self
));
58 void popup_free(ObPopup
*self
)
61 XDestroyWindow(ob_display
, self
->bg
);
62 XDestroyWindow(ob_display
, self
->text
);
63 RrAppearanceFree(self
->a_bg
);
64 RrAppearanceFree(self
->a_text
);
65 stacking_remove(self
);
70 void popup_position(ObPopup
*self
, gint gravity
, gint x
, gint y
)
72 self
->gravity
= gravity
;
77 void popup_size(ObPopup
*self
, gint w
, gint h
)
83 void popup_size_to_string(ObPopup
*self
, gchar
*text
)
88 self
->a_text
->texture
[0].data
.text
.string
= text
;
89 RrMinsize(self
->a_text
, &textw
, &texth
);
90 /*XXX textw += ob_rr_theme->bevel * 2;*/
91 texth
+= ob_rr_theme
->paddingy
* 2;
93 self
->h
= texth
+ ob_rr_theme
->paddingy
* 2;
94 iconw
= (self
->hasicon
? texth
: 0);
95 self
->w
= textw
+ iconw
+ ob_rr_theme
->paddingx
* (self
->hasicon
? 3 : 2);
98 void popup_set_text_align(ObPopup
*self
, RrJustify align
)
100 self
->a_text
->texture
[0].data
.text
.justify
= align
;
103 void popup_show(ObPopup
*self
, gchar
*text
)
109 Rect
*area
; /* won't go outside this */
111 area
= screen_physical_area(); /* XXX this should work quite
112 good, someone with xinerama,
113 and different resolutions on
116 RrMargins(self
->a_bg
, &l
, &t
, &r
, &b
);
118 XSetWindowBorderWidth(ob_display
, self
->bg
, ob_rr_theme
->fbwidth
);
119 XSetWindowBorder(ob_display
, self
->bg
, ob_rr_theme
->frame_b_color
->pixel
);
121 /* set up the textures */
122 self
->a_text
->texture
[0].data
.text
.string
= text
;
124 /* measure the shit out */
125 RrMinsize(self
->a_text
, &textw
, &texth
);
126 /*XXX textw += ob_rr_theme->padding * 2;*/
127 texth
+= ob_rr_theme
->paddingy
* 2;
129 /* set the sizes up and reget the text sizes from the calculated
133 texth
= h
- (t
+b
+ ob_rr_theme
->paddingy
* 2);
135 h
= t
+b
+ texth
+ ob_rr_theme
->paddingy
* 2;
136 iconw
= (self
->hasicon
? texth
: 0);
139 textw
= w
- (l
+r
+ iconw
+ ob_rr_theme
->paddingx
*
140 (self
->hasicon
? 3 : 2));
142 w
= l
+r
+ textw
+ iconw
+ ob_rr_theme
->paddingx
*
143 (self
->hasicon
? 3 : 2);
144 /* sanity checks to avoid crashes! */
147 if (textw
< 1) textw
= 1;
148 if (texth
< 1) texth
= 1;
150 /* set up the x coord */
152 switch (self
->gravity
) {
158 case NorthEastGravity
:
160 case SouthEastGravity
:
165 /* set up the y coord */
167 switch (self
->gravity
) {
173 case SouthWestGravity
:
175 case SouthEastGravity
:
180 x
=MAX(MIN(x
, area
->width
-w
),0);
181 y
=MAX(MIN(y
, area
->height
-h
),0);
183 /* set the windows/appearances up */
184 XMoveResizeWindow(ob_display
, self
->bg
, x
, y
, w
, h
);
186 self
->a_text
->surface
.parent
= self
->a_bg
;
187 self
->a_text
->surface
.parentx
= l
+ iconw
+
188 ob_rr_theme
->paddingx
* (self
->hasicon
? 2 : 1);
189 self
->a_text
->surface
.parenty
= t
+ ob_rr_theme
->paddingy
;
190 XMoveResizeWindow(ob_display
, self
->text
,
191 l
+ iconw
+ ob_rr_theme
->paddingx
*
192 (self
->hasicon
? 2 : 1),
193 t
+ ob_rr_theme
->paddingy
, textw
, texth
);
195 RrPaint(self
->a_bg
, self
->bg
, w
, h
);
196 RrPaint(self
->a_text
, self
->text
, textw
, texth
);
199 if (iconw
< 1) iconw
= 1; /* sanity check for crashes */
201 self
->draw_icon(l
+ ob_rr_theme
->paddingx
,
202 t
+ ob_rr_theme
->paddingy
,
203 iconw
, texth
, self
->draw_icon_data
);
207 XMapWindow(ob_display
, self
->bg
);
208 stacking_raise(INTERNAL_AS_WINDOW(self
));
213 void popup_hide(ObPopup
*self
)
218 XUnmapWindow(ob_display
, self
->bg
);
219 self
->mapped
= FALSE
;
221 /* kill enter events cause by this unmapping */
222 XSync(ob_display
, FALSE
);
223 while (XCheckTypedEvent(ob_display
, EnterNotify
, &e
));
227 static void icon_popup_draw_icon(gint x
, gint y
, gint w
, gint h
, gpointer data
)
229 ObIconPopup
*self
= data
;
231 self
->a_icon
->surface
.parent
= self
->popup
->a_bg
;
232 self
->a_icon
->surface
.parentx
= x
;
233 self
->a_icon
->surface
.parenty
= y
;
234 XMoveResizeWindow(ob_display
, self
->icon
, x
, y
, w
, h
);
235 RrPaint(self
->a_icon
, self
->icon
, w
, h
);
238 ObIconPopup
*icon_popup_new()
242 self
= g_new0(ObIconPopup
, 1);
243 self
->popup
= popup_new(TRUE
);
244 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_clear_tex
);
245 self
->icon
= XCreateWindow(ob_display
, self
->popup
->bg
,
247 RrDepth(ob_rr_inst
), InputOutput
,
248 RrVisual(ob_rr_inst
), 0, NULL
);
249 XMapWindow(ob_display
, self
->icon
);
251 self
->popup
->draw_icon
= icon_popup_draw_icon
;
252 self
->popup
->draw_icon_data
= self
;
257 void icon_popup_free(ObIconPopup
*self
)
260 XDestroyWindow(ob_display
, self
->icon
);
261 RrAppearanceFree(self
->a_icon
);
262 popup_free(self
->popup
);
267 void icon_popup_show(ObIconPopup
*self
,
268 gchar
*text
, const ObClientIcon
*icon
)
271 self
->a_icon
->texture
[0].type
= RR_TEXTURE_RGBA
;
272 self
->a_icon
->texture
[0].data
.rgba
.width
= icon
->width
;
273 self
->a_icon
->texture
[0].data
.rgba
.height
= icon
->height
;
274 self
->a_icon
->texture
[0].data
.rgba
.data
= icon
->data
;
276 self
->a_icon
->texture
[0].type
= RR_TEXTURE_NONE
;
278 popup_show(self
->popup
, text
);
281 static void pager_popup_draw_icon(gint px
, gint py
, gint w
, gint h
,
284 ObPagerPopup
*self
= data
;
292 eachw
= (w
- ob_rr_theme
->fbwidth
-
293 (screen_desktop_layout
.columns
* ob_rr_theme
->fbwidth
))
294 / screen_desktop_layout
.columns
;
295 eachh
= (h
- ob_rr_theme
->fbwidth
-
296 (screen_desktop_layout
.rows
* ob_rr_theme
->fbwidth
))
297 / screen_desktop_layout
.rows
;
298 /* make them squares */
299 eachw
= eachh
= MIN(eachw
, eachh
);
302 px
+= (w
- (screen_desktop_layout
.columns
* (eachw
+ ob_rr_theme
->fbwidth
) +
303 ob_rr_theme
->fbwidth
)) / 2;
304 py
+= (h
- (screen_desktop_layout
.rows
* (eachh
+ ob_rr_theme
->fbwidth
) +
305 ob_rr_theme
->fbwidth
)) / 2;
307 if (eachw
<= 0 || eachh
<= 0)
310 switch (screen_desktop_layout
.orientation
) {
311 case OB_ORIENTATION_HORZ
:
312 switch (screen_desktop_layout
.start_corner
) {
313 case OB_CORNER_TOPLEFT
:
316 vert_inc
= screen_desktop_layout
.columns
;
318 case OB_CORNER_TOPRIGHT
:
319 n
= screen_desktop_layout
.columns
- 1;
321 vert_inc
= screen_desktop_layout
.columns
;
323 case OB_CORNER_BOTTOMRIGHT
:
324 n
= screen_desktop_layout
.rows
* screen_desktop_layout
.columns
- 1;
326 vert_inc
= -screen_desktop_layout
.columns
;
328 case OB_CORNER_BOTTOMLEFT
:
329 n
= (screen_desktop_layout
.rows
- 1)
330 * screen_desktop_layout
.columns
;
332 vert_inc
= -screen_desktop_layout
.columns
;
335 g_assert_not_reached();
338 case OB_ORIENTATION_VERT
:
339 switch (screen_desktop_layout
.start_corner
) {
340 case OB_CORNER_TOPLEFT
:
342 horz_inc
= screen_desktop_layout
.rows
;
345 case OB_CORNER_TOPRIGHT
:
346 n
= screen_desktop_layout
.rows
347 * (screen_desktop_layout
.columns
- 1);
348 horz_inc
= -screen_desktop_layout
.rows
;
351 case OB_CORNER_BOTTOMRIGHT
:
352 n
= screen_desktop_layout
.rows
* screen_desktop_layout
.columns
- 1;
353 horz_inc
= -screen_desktop_layout
.rows
;
356 case OB_CORNER_BOTTOMLEFT
:
357 n
= screen_desktop_layout
.rows
- 1;
358 horz_inc
= screen_desktop_layout
.rows
;
362 g_assert_not_reached();
366 g_assert_not_reached();
370 for (r
= 0, y
= 0; r
< screen_desktop_layout
.rows
;
371 ++r
, y
+= eachh
+ ob_rr_theme
->fbwidth
)
373 for (c
= 0, x
= 0; c
< screen_desktop_layout
.columns
;
374 ++c
, x
+= eachw
+ ob_rr_theme
->fbwidth
)
378 if (n
< self
->desks
) {
379 a
= (n
== self
->curdesk
? self
->hilight
: self
->unhilight
);
381 a
->surface
.parent
= self
->popup
->a_bg
;
382 a
->surface
.parentx
= x
+ px
;
383 a
->surface
.parenty
= y
+ py
;
384 XMoveResizeWindow(ob_display
, self
->wins
[n
],
385 x
+ px
, y
+ py
, eachw
, eachh
);
386 RrPaint(a
, self
->wins
[n
], eachw
, eachh
);
390 n
= rown
+= vert_inc
;
394 ObPagerPopup
*pager_popup_new()
398 self
= g_new(ObPagerPopup
, 1);
399 self
->popup
= popup_new(TRUE
);
402 self
->wins
= g_new(Window
, self
->desks
);
403 self
->hilight
= RrAppearanceCopy(ob_rr_theme
->osd_hilite_fg
);
404 self
->unhilight
= RrAppearanceCopy(ob_rr_theme
->osd_unhilite_fg
);
406 self
->popup
->draw_icon
= pager_popup_draw_icon
;
407 self
->popup
->draw_icon_data
= self
;
412 void pager_popup_free(ObPagerPopup
*self
)
417 for (i
= 0; i
< self
->desks
; ++i
)
418 XDestroyWindow(ob_display
, self
->wins
[i
]);
420 RrAppearanceFree(self
->hilight
);
421 RrAppearanceFree(self
->unhilight
);
422 popup_free(self
->popup
);
427 void pager_popup_show(ObPagerPopup
*self
, gchar
*text
, guint desk
)
431 if (screen_num_desktops
< self
->desks
)
432 for (i
= screen_num_desktops
; i
< self
->desks
; ++i
)
433 XDestroyWindow(ob_display
, self
->wins
[i
]);
435 if (screen_num_desktops
!= self
->desks
)
436 self
->wins
= g_renew(Window
, self
->wins
, screen_num_desktops
);
438 if (screen_num_desktops
> self
->desks
)
439 for (i
= self
->desks
; i
< screen_num_desktops
; ++i
) {
440 XSetWindowAttributes attr
;
442 attr
.border_pixel
= RrColorPixel(ob_rr_theme
->frame_b_color
);
443 self
->wins
[i
] = XCreateWindow(ob_display
, self
->popup
->bg
,
444 0, 0, 1, 1, ob_rr_theme
->fbwidth
,
445 RrDepth(ob_rr_inst
), InputOutput
,
446 RrVisual(ob_rr_inst
), CWBorderPixel
,
448 XMapWindow(ob_display
, self
->wins
[i
]);
451 self
->desks
= screen_num_desktops
;
452 self
->curdesk
= desk
;
454 popup_show(self
->popup
, text
);