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-2007 Dana 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.
29 #include "render/render.h"
30 #include "render/theme.h"
32 static gboolean
popup_show_timeout(gpointer data
)
36 XMapWindow(ob_display
, self
->bg
);
37 stacking_raise(INTERNAL_AS_WINDOW(self
));
39 self
->delay_mapped
= FALSE
;
41 return FALSE
; /* don't repeat */
44 ObPopup
*popup_new(gboolean hasicon
)
46 XSetWindowAttributes attrib
;
47 ObPopup
*self
= g_new0(ObPopup
, 1);
49 self
->obwin
.type
= Window_Internal
;
50 self
->hasicon
= hasicon
;
51 self
->gravity
= NorthWestGravity
;
52 self
->x
= self
->y
= self
->w
= self
->h
= 0;
53 self
->a_bg
= RrAppearanceCopy(ob_rr_theme
->osd_hilite_bg
);
54 self
->a_text
= RrAppearanceCopy(ob_rr_theme
->osd_hilite_label
);
56 attrib
.override_redirect
= True
;
57 self
->bg
= XCreateWindow(ob_display
, RootWindow(ob_display
, ob_screen
),
58 0, 0, 1, 1, 0, RrDepth(ob_rr_inst
),
59 InputOutput
, RrVisual(ob_rr_inst
),
60 CWOverrideRedirect
, &attrib
);
62 self
->text
= XCreateWindow(ob_display
, self
->bg
,
63 0, 0, 1, 1, 0, RrDepth(ob_rr_inst
),
64 InputOutput
, RrVisual(ob_rr_inst
), 0, NULL
);
66 XMapWindow(ob_display
, self
->text
);
68 stacking_add(INTERNAL_AS_WINDOW(self
));
72 void popup_free(ObPopup
*self
)
75 XDestroyWindow(ob_display
, self
->bg
);
76 XDestroyWindow(ob_display
, self
->text
);
77 RrAppearanceFree(self
->a_bg
);
78 RrAppearanceFree(self
->a_text
);
79 stacking_remove(self
);
84 void popup_position(ObPopup
*self
, gint gravity
, gint x
, gint y
)
86 self
->gravity
= gravity
;
91 void popup_width(ObPopup
*self
, gint w
)
97 void popup_height(ObPopup
*self
, gint h
)
101 /* don't let the height be smaller than the text */
102 texth
= RrMinHeight(self
->a_text
) + ob_rr_theme
->paddingy
* 2;
103 self
->h
= MAX(h
, texth
);
106 void popup_width_to_string(ObPopup
*self
, gchar
*text
, gint max
)
108 self
->a_text
->texture
[0].data
.text
.string
= text
;
109 self
->w
= RrMinWidth(self
->a_text
);
113 void popup_height_to_string(ObPopup
*self
, gchar
*text
)
115 self
->h
= RrMinHeight(self
->a_text
) + ob_rr_theme
->paddingy
* 2;
118 void popup_width_to_strings(ObPopup
*self
, gchar
**strings
, gint num
, gint max
)
123 for (i
= 0; i
< num
; ++i
) {
124 popup_width_to_string(self
, strings
[i
], max
);
125 maxw
= MAX(maxw
, self
->w
);
130 void popup_set_text_align(ObPopup
*self
, RrJustify align
)
132 self
->a_text
->texture
[0].data
.text
.justify
= align
;
135 void popup_delay_show(ObPopup
*self
, gulong usec
, gchar
*text
)
141 Rect
*area
; /* won't go outside this */
143 area
= screen_physical_area(); /* XXX this should work quite
144 good, someone with xinerama,
145 and different resolutions on
148 RrMargins(self
->a_bg
, &l
, &t
, &r
, &b
);
150 XSetWindowBorderWidth(ob_display
, self
->bg
, ob_rr_theme
->fbwidth
);
151 XSetWindowBorder(ob_display
, self
->bg
, ob_rr_theme
->frame_b_color
->pixel
);
153 /* set up the textures */
154 self
->a_text
->texture
[0].data
.text
.string
= text
;
156 /* measure the text out */
157 RrMinSize(self
->a_text
, &textw
, &texth
);
158 texth
+= ob_rr_theme
->paddingy
* 2;
160 /* set the sizes up and reget the text sizes from the calculated
164 texth
= h
- (t
+b
+ ob_rr_theme
->paddingy
* 2);
166 h
= t
+b
+ texth
+ ob_rr_theme
->paddingy
* 2;
167 iconw
= (self
->hasicon
? texth
: 0);
170 w
= l
+r
+ textw
+ iconw
+ ob_rr_theme
->paddingx
*
171 (self
->hasicon
? 3 : 2);
172 /* cap it at "maxw" */
174 w
= MIN(w
, self
->maxw
);
176 /* sanity checks to avoid crashes! */
179 if (textw
< 1) textw
= 1;
180 if (texth
< 1) texth
= 1;
182 /* set up the x coord */
184 switch (self
->gravity
) {
190 case NorthEastGravity
:
192 case SouthEastGravity
:
197 /* set up the y coord */
199 switch (self
->gravity
) {
205 case SouthWestGravity
:
207 case SouthEastGravity
:
212 x
=MAX(MIN(x
, area
->width
-w
),0);
213 y
=MAX(MIN(y
, area
->height
-h
),0);
215 /* set the windows/appearances up */
216 XMoveResizeWindow(ob_display
, self
->bg
, x
, y
, w
, h
);
218 self
->a_text
->surface
.parent
= self
->a_bg
;
219 self
->a_text
->surface
.parentx
= l
+ iconw
+
220 ob_rr_theme
->paddingx
* (self
->hasicon
? 2 : 1);
221 self
->a_text
->surface
.parenty
= t
+ ob_rr_theme
->paddingy
;
222 XMoveResizeWindow(ob_display
, self
->text
,
223 l
+ iconw
+ ob_rr_theme
->paddingx
*
224 (self
->hasicon
? 2 : 1),
225 t
+ ob_rr_theme
->paddingy
, textw
, texth
);
227 RrPaint(self
->a_bg
, self
->bg
, w
, h
);
228 RrPaint(self
->a_text
, self
->text
, textw
, texth
);
231 if (iconw
< 1) iconw
= 1; /* sanity check for crashes */
233 self
->draw_icon(l
+ ob_rr_theme
->paddingx
,
234 t
+ ob_rr_theme
->paddingy
,
235 iconw
, texth
, self
->draw_icon_data
);
238 /* do the actual showing */
241 /* don't kill previous show timers */
242 if (!self
->delay_mapped
) {
243 ob_main_loop_timeout_add(ob_main_loop
, usec
,
244 popup_show_timeout
, self
,
245 g_direct_equal
, NULL
);
246 self
->delay_mapped
= TRUE
;
249 popup_show_timeout(self
);
254 void popup_hide(ObPopup
*self
)
257 XUnmapWindow(ob_display
, self
->bg
);
258 self
->mapped
= FALSE
;
260 /* kill enter events cause by this unmapping */
261 event_ignore_queued_enters();
262 } else if (self
->delay_mapped
) {
263 ob_main_loop_timeout_remove(ob_main_loop
, popup_show_timeout
);
264 self
->delay_mapped
= FALSE
;
268 static void icon_popup_draw_icon(gint x
, gint y
, gint w
, gint h
, gpointer data
)
270 ObIconPopup
*self
= data
;
272 self
->a_icon
->surface
.parent
= self
->popup
->a_bg
;
273 self
->a_icon
->surface
.parentx
= x
;
274 self
->a_icon
->surface
.parenty
= y
;
275 XMoveResizeWindow(ob_display
, self
->icon
, x
, y
, w
, h
);
276 RrPaint(self
->a_icon
, self
->icon
, w
, h
);
279 ObIconPopup
*icon_popup_new()
283 self
= g_new0(ObIconPopup
, 1);
284 self
->popup
= popup_new(TRUE
);
285 self
->a_icon
= RrAppearanceCopy(ob_rr_theme
->a_clear_tex
);
286 self
->icon
= XCreateWindow(ob_display
, self
->popup
->bg
,
288 RrDepth(ob_rr_inst
), InputOutput
,
289 RrVisual(ob_rr_inst
), 0, NULL
);
290 XMapWindow(ob_display
, self
->icon
);
292 self
->popup
->draw_icon
= icon_popup_draw_icon
;
293 self
->popup
->draw_icon_data
= self
;
298 void icon_popup_free(ObIconPopup
*self
)
301 XDestroyWindow(ob_display
, self
->icon
);
302 RrAppearanceFree(self
->a_icon
);
303 popup_free(self
->popup
);
308 void icon_popup_delay_show(ObIconPopup
*self
, gulong usec
,
309 gchar
*text
, const ObClientIcon
*icon
)
312 self
->a_icon
->texture
[0].type
= RR_TEXTURE_RGBA
;
313 self
->a_icon
->texture
[0].data
.rgba
.width
= icon
->width
;
314 self
->a_icon
->texture
[0].data
.rgba
.height
= icon
->height
;
315 self
->a_icon
->texture
[0].data
.rgba
.data
= icon
->data
;
317 self
->a_icon
->texture
[0].type
= RR_TEXTURE_NONE
;
319 popup_delay_show(self
->popup
, usec
, text
);
322 static void pager_popup_draw_icon(gint px
, gint py
, gint w
, gint h
,
325 ObPagerPopup
*self
= data
;
333 eachw
= (w
- ob_rr_theme
->fbwidth
-
334 (screen_desktop_layout
.columns
* ob_rr_theme
->fbwidth
))
335 / screen_desktop_layout
.columns
;
336 eachh
= (h
- ob_rr_theme
->fbwidth
-
337 (screen_desktop_layout
.rows
* ob_rr_theme
->fbwidth
))
338 / screen_desktop_layout
.rows
;
339 /* make them squares */
340 eachw
= eachh
= MIN(eachw
, eachh
);
343 px
+= (w
- (screen_desktop_layout
.columns
* (eachw
+ ob_rr_theme
->fbwidth
) +
344 ob_rr_theme
->fbwidth
)) / 2;
345 py
+= (h
- (screen_desktop_layout
.rows
* (eachh
+ ob_rr_theme
->fbwidth
) +
346 ob_rr_theme
->fbwidth
)) / 2;
348 if (eachw
<= 0 || eachh
<= 0)
351 switch (screen_desktop_layout
.orientation
) {
352 case OB_ORIENTATION_HORZ
:
353 switch (screen_desktop_layout
.start_corner
) {
354 case OB_CORNER_TOPLEFT
:
357 vert_inc
= screen_desktop_layout
.columns
;
359 case OB_CORNER_TOPRIGHT
:
360 n
= screen_desktop_layout
.columns
- 1;
362 vert_inc
= screen_desktop_layout
.columns
;
364 case OB_CORNER_BOTTOMRIGHT
:
365 n
= screen_desktop_layout
.rows
* screen_desktop_layout
.columns
- 1;
367 vert_inc
= -screen_desktop_layout
.columns
;
369 case OB_CORNER_BOTTOMLEFT
:
370 n
= (screen_desktop_layout
.rows
- 1)
371 * screen_desktop_layout
.columns
;
373 vert_inc
= -screen_desktop_layout
.columns
;
376 g_assert_not_reached();
379 case OB_ORIENTATION_VERT
:
380 switch (screen_desktop_layout
.start_corner
) {
381 case OB_CORNER_TOPLEFT
:
383 horz_inc
= screen_desktop_layout
.rows
;
386 case OB_CORNER_TOPRIGHT
:
387 n
= screen_desktop_layout
.rows
388 * (screen_desktop_layout
.columns
- 1);
389 horz_inc
= -screen_desktop_layout
.rows
;
392 case OB_CORNER_BOTTOMRIGHT
:
393 n
= screen_desktop_layout
.rows
* screen_desktop_layout
.columns
- 1;
394 horz_inc
= -screen_desktop_layout
.rows
;
397 case OB_CORNER_BOTTOMLEFT
:
398 n
= screen_desktop_layout
.rows
- 1;
399 horz_inc
= screen_desktop_layout
.rows
;
403 g_assert_not_reached();
407 g_assert_not_reached();
411 for (r
= 0, y
= 0; r
< screen_desktop_layout
.rows
;
412 ++r
, y
+= eachh
+ ob_rr_theme
->fbwidth
)
414 for (c
= 0, x
= 0; c
< screen_desktop_layout
.columns
;
415 ++c
, x
+= eachw
+ ob_rr_theme
->fbwidth
)
419 if (n
< self
->desks
) {
420 a
= (n
== self
->curdesk
? self
->hilight
: self
->unhilight
);
422 a
->surface
.parent
= self
->popup
->a_bg
;
423 a
->surface
.parentx
= x
+ px
;
424 a
->surface
.parenty
= y
+ py
;
425 XMoveResizeWindow(ob_display
, self
->wins
[n
],
426 x
+ px
, y
+ py
, eachw
, eachh
);
427 RrPaint(a
, self
->wins
[n
], eachw
, eachh
);
431 n
= rown
+= vert_inc
;
435 ObPagerPopup
*pager_popup_new()
439 self
= g_new(ObPagerPopup
, 1);
440 self
->popup
= popup_new(TRUE
);
443 self
->wins
= g_new(Window
, self
->desks
);
444 self
->hilight
= RrAppearanceCopy(ob_rr_theme
->osd_hilite_fg
);
445 self
->unhilight
= RrAppearanceCopy(ob_rr_theme
->osd_unhilite_fg
);
447 self
->popup
->hasicon
= TRUE
;
448 self
->popup
->draw_icon
= pager_popup_draw_icon
;
449 self
->popup
->draw_icon_data
= self
;
454 void pager_popup_free(ObPagerPopup
*self
)
459 for (i
= 0; i
< self
->desks
; ++i
)
460 XDestroyWindow(ob_display
, self
->wins
[i
]);
462 RrAppearanceFree(self
->hilight
);
463 RrAppearanceFree(self
->unhilight
);
464 popup_free(self
->popup
);
469 void pager_popup_delay_show(ObPagerPopup
*self
, gulong usec
,
470 gchar
*text
, guint desk
)
474 if (screen_num_desktops
< self
->desks
)
475 for (i
= screen_num_desktops
; i
< self
->desks
; ++i
)
476 XDestroyWindow(ob_display
, self
->wins
[i
]);
478 if (screen_num_desktops
!= self
->desks
)
479 self
->wins
= g_renew(Window
, self
->wins
, screen_num_desktops
);
481 if (screen_num_desktops
> self
->desks
)
482 for (i
= self
->desks
; i
< screen_num_desktops
; ++i
) {
483 XSetWindowAttributes attr
;
485 attr
.border_pixel
= RrColorPixel(ob_rr_theme
->frame_b_color
);
486 self
->wins
[i
] = XCreateWindow(ob_display
, self
->popup
->bg
,
487 0, 0, 1, 1, ob_rr_theme
->fbwidth
,
488 RrDepth(ob_rr_inst
), InputOutput
,
489 RrVisual(ob_rr_inst
), CWBorderPixel
,
491 XMapWindow(ob_display
, self
->wins
[i
]);
494 self
->desks
= screen_num_desktops
;
495 self
->curdesk
= desk
;
497 popup_delay_show(self
->popup
, usec
, text
);