/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- AZPopUp.m for the Azalea window manager Copyright (c) 2006 Yen-Ju Chen popup.c for the Openbox window manager Copyright (c) 2004 Mikael Magnusson Copyright (c) 2003 Ben Jansens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. See the COPYING file for a copy of the GNU General Public License. */ #import "AZPopUp.h" #import "AZClient.h" #import "AZScreen.h" #import "AZStacking.h" #import "openbox.h" @implementation AZPopUp - (void) positionWithGravity: (int) _gravity x: (int) _x y: (int) _y { gravity = _gravity; x = _x; y = _y; } - (void) sizeWithWidth: (int) _w height: (int) _h { w = _w; h = _h; } - (void) sizeToString: (NSString *) _text { int textw, texth; int iconw; [a_text texture][0].data.text.string = _text; [a_text minimalSizeWithWidth: &textw height: &texth]; /*XXX textw += ob_rr_theme->bevel * 2;*/ texth += ob_rr_theme->padding * 2; h = texth + ob_rr_theme->padding * 2; iconw = (hasicon ? texth : 0); w = textw + iconw + ob_rr_theme->padding * (hasicon ? 3 : 2); } - (void) setTextAlign: (RrJustify) align { [a_text texture][0].data.text.justify = align; } - (void) showText: (NSString *) _text { int l, t, r, b; int _x, _y, _w, _h; int textw, texth; int iconw; Rect *area; /* won't go outside this */ area = [[AZScreen defaultScreen] physicalArea]; /* XXX this should work quite good, someone with xinerama, and different resolutions on screens? */ [a_bg marginsWithLeft: &l top: &t right: &r bottom: &b]; XSetWindowBorderWidth(ob_display, bg, ob_rr_theme->bwidth); XSetWindowBorder(ob_display, bg, ob_rr_theme->b_color->pixel); /* set up the textures */ [a_text texture][0].data.text.string = _text; /* measure the shit out */ [a_text minimalSizeWithWidth: &textw height: &texth]; /*XXX textw += ob_rr_theme->padding * 2;*/ texth += ob_rr_theme->padding * 2; /* set the sizes up and reget the text sizes from the calculated outer sizes */ if (h) { _h = h; texth = _h - (t+b + ob_rr_theme->padding * 2); } else _h = t+b + texth + ob_rr_theme->padding * 2; iconw = (hasicon ? texth : 0); if (w) { _w = w; textw = _w - (l+r + iconw + ob_rr_theme->padding * (hasicon ? 3 : 2)); } else _w = l+r + textw + iconw + ob_rr_theme->padding * (hasicon ? 3 : 2); /* sanity checks to avoid crashes! */ if (_w < 1) _w = 1; if (_h < 1) _h = 1; if (textw < 1) textw = 1; if (texth < 1) texth = 1; /* set up the x coord */ _x = x; switch (gravity) { case NorthGravity: case CenterGravity: case SouthGravity: _x -= _w / 2; break; case NorthEastGravity: case EastGravity: case SouthEastGravity: _x -= _w; break; } /* set up the y coord */ _y = y; switch (gravity) { case WestGravity: case CenterGravity: case EastGravity: _y -= _h / 2; break; case SouthWestGravity: case SouthGravity: case SouthEastGravity: _y -= _h; break; } _x=MAX(MIN(_x, area->width-_w),0); _y=MAX(MIN(_y, area->height-_h),0); /* set the windows/appearances up */ XMoveResizeWindow(ob_display, bg, _x, _y, _w, _h); [a_text surfacePointer]->parent = a_bg; [a_text surfacePointer]->parentx = l + iconw + ob_rr_theme->padding * (hasicon ? 2 : 1); [a_text surfacePointer]->parenty = t + ob_rr_theme->padding; XMoveResizeWindow(ob_display, text, l + iconw + ob_rr_theme->padding * (hasicon ? 2 : 1), t + ob_rr_theme->padding, textw, texth); [a_bg paint: bg width: _w height: _h]; [a_text paint: text width: textw height: texth]; if (hasicon) { if (iconw < 1) iconw = 1; /* sanity check for crashes */ /* draw icon */ [self drawIconAtX: l + ob_rr_theme->padding y: t + ob_rr_theme->padding width: iconw height: texth]; } if (!mapped) { XMapWindow(ob_display, bg); [[AZStacking stacking] raiseWindow: self group: NO]; mapped = YES; } } - (void) hide { if (mapped) { XUnmapWindow(ob_display, bg); mapped = NO; } } - (id) initWithIcon: (BOOL) hasIcon; { self = [super init]; XSetWindowAttributes attrib; hasicon = hasIcon; gravity = NorthWestGravity; x = y = w = h = 0; a_bg = [ob_rr_theme->app_hilite_bg copy]; a_text = [ob_rr_theme->app_hilite_label copy]; attrib.override_redirect = True; bg = XCreateWindow(ob_display, RootWindow(ob_display, ob_screen), 0, 0, 1, 1, 0, [ob_rr_inst depth], InputOutput, [ob_rr_inst visual], CWOverrideRedirect, &attrib); text = XCreateWindow(ob_display, bg, 0, 0, 1, 1, 0, [ob_rr_inst depth], InputOutput, [ob_rr_inst visual], 0, NULL); XMapWindow(ob_display, text); [[AZStacking stacking] addWindow: self]; return self; } - (void) dealloc { XDestroyWindow(ob_display, bg); XDestroyWindow(ob_display, text); DESTROY(a_bg); DESTROY(a_text); [[AZStacking stacking] removeWindow: self]; [super dealloc]; } - (void) drawIconAtX: (int) x y: (int) y width: (int) w height: (int) h { // subclass responsibility } /* AZWindow protocol */ - (Window_InternalType) windowType { return Window_Internal; } - (int) windowLayer { return OB_STACKING_LAYER_INTERNAL; } - (Window) windowTop { return bg; } @end @implementation AZIconPopUp - (void) drawIconAtX: (int) px y: (int) py width: (int) pw height: (int) ph { [a_icon surfacePointer]->parent = a_bg; [a_icon surfacePointer]->parentx = px; [a_icon surfacePointer]->parenty = py; XMoveResizeWindow(ob_display, icon, px, py, pw, ph); [a_icon paint: icon width: pw height: ph]; } - (void) showText: (NSString *) _text icon: (AZClientIcon *) _icon { if (_icon) { [a_icon texture][0].type = RR_TEXTURE_RGBA; [a_icon texture][0].data.rgba.width = [_icon width]; [a_icon texture][0].data.rgba.height = [_icon height]; [a_icon texture][0].data.rgba.data = [_icon data]; } else { [a_icon texture][0].type = RR_TEXTURE_NONE; } [super showText: _text]; } - (id) initWithIcon: (BOOL) hasIcon; { self = [super initWithIcon: hasIcon]; a_icon = [ob_rr_theme->a_clear_tex copy]; icon = XCreateWindow(ob_display, bg, 0, 0, 1, 1, 0, [ob_rr_inst depth], InputOutput, [ob_rr_inst visual], 0, NULL); XMapWindow(ob_display, icon); return self; } - (void) dealloc { XDestroyWindow(ob_display, icon); DESTROY(a_icon); [super dealloc]; } @end @implementation AZPagerPopUp - (void) drawIconAtX: (int) px y: (int) py width: (int) pw height: (int) ph { int _x, _y; unsigned int rown, n; unsigned int horz_inc; unsigned int vert_inc; unsigned int r, c; int eachw, eachh; AZScreen *screen = [AZScreen defaultScreen]; DesktopLayout desktop_layout = [screen desktopLayout]; eachw = (pw - ob_rr_theme->bwidth - (desktop_layout.columns * ob_rr_theme->bwidth)) / desktop_layout.columns; eachh = (ph - ob_rr_theme->bwidth - (desktop_layout.rows * ob_rr_theme->bwidth)) / desktop_layout.rows; /* make them squares */ eachw = eachh = MIN(eachw, eachh); /* center */ px += (pw - (desktop_layout.columns * (eachw + ob_rr_theme->bwidth) + ob_rr_theme->bwidth)) / 2; py += (ph - (desktop_layout.rows * (eachh + ob_rr_theme->bwidth) + ob_rr_theme->bwidth)) / 2; if (eachw <= 0 || eachh <= 0) return; switch (desktop_layout.orientation) { case OB_ORIENTATION_HORZ: switch (desktop_layout.start_corner) { case OB_CORNER_TOPLEFT: n = 0; horz_inc = 1; vert_inc = desktop_layout.columns; break; case OB_CORNER_TOPRIGHT: n = desktop_layout.columns - 1; horz_inc = -1; vert_inc = desktop_layout.columns; break; case OB_CORNER_BOTTOMRIGHT: n = desktop_layout.rows * desktop_layout.columns - 1; horz_inc = -1; vert_inc = -desktop_layout.columns; break; case OB_CORNER_BOTTOMLEFT: n = (desktop_layout.rows - 1) * desktop_layout.columns; horz_inc = 1; vert_inc = -desktop_layout.columns; break; default: NSAssert(0, @"Should not reach here"); } break; case OB_ORIENTATION_VERT: switch (desktop_layout.start_corner) { case OB_CORNER_TOPLEFT: n = 0; horz_inc = desktop_layout.rows; vert_inc = 1; break; case OB_CORNER_TOPRIGHT: n = desktop_layout.rows * (desktop_layout.columns - 1); horz_inc = -desktop_layout.rows; vert_inc = 1; break; case OB_CORNER_BOTTOMRIGHT: n = desktop_layout.rows * desktop_layout.columns - 1; horz_inc = -desktop_layout.rows; vert_inc = -1; break; case OB_CORNER_BOTTOMLEFT: n = desktop_layout.rows - 1; horz_inc = desktop_layout.rows; vert_inc = -1; break; default: NSAssert(0, @"Should not reach here"); } break; default: NSAssert(0, @"Should not reach here"); } rown = n; for (r = 0, _y = 0; r < desktop_layout.rows; ++r, _y += eachh + ob_rr_theme->bwidth) { for (c = 0, _x = 0; c < desktop_layout.columns; ++c, _x += eachw + ob_rr_theme->bwidth) { AZAppearance *a; if (n < desks) { a = (n == curdesk ? hilight : unhilight); [a surfacePointer]->parent = a_bg; [a surfacePointer]->parentx = _x + px; [a surfacePointer]->parenty = _y + py; XMoveResizeWindow(ob_display, [[wins objectAtIndex: n] intValue], _x + px, _y + py, eachw, eachh); [a paint: [[wins objectAtIndex: n] intValue] width: eachw height: eachh]; } n += horz_inc; } n = rown += vert_inc; } } - (void) showText: (NSString *) _text desktop: (unsigned int) desk { unsigned int i; unsigned int num_desktops = [[AZScreen defaultScreen] numberOfDesktops]; if (num_desktops < desks) { for (i = desks-1; i >= num_desktops; i--) { XDestroyWindow(ob_display, [[wins objectAtIndex: i] intValue]); [wins removeObjectAtIndex: i]; } } if (num_desktops > desks) for (i = desks; i < num_desktops; ++i) { XSetWindowAttributes attr; attr.border_pixel = RrColorPixel(ob_rr_theme->b_color); [wins addObject: [NSNumber numberWithInt:XCreateWindow(ob_display, bg, 0, 0, 1, 1, ob_rr_theme->bwidth, [ob_rr_inst depth], InputOutput, [ob_rr_inst visual], CWBorderPixel, &attr)]]; XMapWindow(ob_display, [[wins objectAtIndex: i] intValue]); } desks = num_desktops; curdesk = desk; [super showText: _text]; } - (id) initWithIcon: (BOOL) hasIcon; { self = [super initWithIcon: hasIcon]; desks = 0; wins = [[NSMutableArray alloc] init]; hilight = [ob_rr_theme->app_hilite_fg copy]; unhilight = [ob_rr_theme->app_unhilite_fg copy]; return self; } - (void) dealloc { unsigned int i; for (i = 0; i < desks; ++i) XDestroyWindow(ob_display, [[wins objectAtIndex: i] intValue]); DESTROY(wins); DESTROY(hilight); DESTROY(unhilight); [super dealloc]; } @end