/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT * Copyright 1989 Massachusetts Institute of Technology */ /*********************************************\ * * * BULL WINDOW MANAGER for X11 . * * * * MODULE defining the Bar Wob class. * * * \*********************************************/ /* include */ #include "EXTERN.h" #include "wool.h" #include "wl_atom.h" #include "gwm.h" #include "wl_fsm.h" #include "wl_pixmap.h" #include "wl_cursor.h" #include "wl_bar.h" /* local constants */ /* external */ extern Wob NewWob(); extern Plug NewPlug(); extern WOOL_METHOD WLMenu[]; extern Bar BarOpen(); extern BarEventHandler(), BarClose(), UpdateBarGeometry(), ReconfigureBar(); #ifdef SHAPE /* compile with -I/usr/include/X11 AND -I/usr/include/X11/extensions to work on machines having shapes.h in either place */ #include extern BarIsShaped(), UpdateBarShape(); #define TileIsShaped(tile) \ (tile && (tile)->type == WLPixmap) && ((WOOL_Pixmap) (tile)) -> mask #endif /* SHAPE */ WOB_METHOD BarClass[] = { 0, /* METHODS_ARRAY */ WobEval, WobPrint, WobRelease, WobExecute, WobSet, WobGetCValue, (WOB_METHOD) BarOpen, BarClose, BarEventHandler, (WOB_METHOD) wool_undefined_method_1, WobGetDimensions, (WOB_METHOD) wool_undefined_method_2, (WOB_METHOD) wool_undefined_method_2, ReconfigureBar, (WOB_METHOD) wool_undefined_method_2, (WOB_METHOD) wool_undefined_method_1, (WOB_METHOD) wool_undefined_method_1, (WOB_METHOD) wool_undefined_method_1, (WOB_METHOD) wool_undefined_method_1, (WOB_METHOD) wool_undefined_method_1 }; /* routines */ /* * NewBar * Creates a new bar object from a WOOL_Bar description * Warning: a plug may be NULL to indicate an extensible space */ Bar NewBar(parent, wl_bar, dir) Wob parent; WOOL_Bar wl_bar; short dir; { Bar bar = (Bar) NewWob(sizeof(struct _Bar) + sizeof(Plug) * Max(0, (wl_bar -> plugs_size - 1))); int i; WOOL_OBJECT object; wl_bar = (WOOL_Bar) wool_type_or_evaluate(wl_bar, WLBar); bar -> type = BarClass; bar -> parent = parent; bar -> direction = dir; bar -> elength = 0; bar -> ewidth = (wl_bar -> plugs_size ? 1 : 0); /* set up the box info */ bar -> box.width = bar -> box.height = wl_bar -> min_width; bar -> min_width = wl_bar -> min_width; bar -> max_width = wl_bar -> max_width; bar -> box.borderwidth = wl_bar -> borderwidth; bar -> box.borderpixel = wl_bar -> borderpixel; bar -> box.background = wl_bar -> background; bar -> plug_separator = wl_bar -> plug_separator; increase_reference(bar -> menu = wool_type_or_evaluate(wl_bar -> menu, WLMenu)); increase_reference(bar -> property = (WOOL_OBJECT) wl_bar -> property); increase_reference(bar -> bordertile = wool_type_or_evaluate(wl_bar -> bordertile, WLPixmap)); increase_reference(bar -> fsm = wool_type_or_evaluate(wl_bar -> fsm, WLFsm)); increase_reference(bar -> cursor = wool_type_or_evaluate(wl_bar -> cursor, WLCursor)); increase_reference(bar -> tile = (wl_bar -> tile == TRU ? wl_bar -> tile : wool_type_or_evaluate(wl_bar -> tile, WLPixmap))); /* then recursively sets plug infos */ bar -> nplugs = wl_bar -> plugs_size; for (i = 0; i < wl_bar -> plugs_size; i++) { object = (WOOL_OBJECT) wl_bar -> plugs[i]; if ((object != NIL) && (object -> type != WLBar) && (object -> type != WLPlug)) { object = WOOL_send(WOOL_eval, object, (object)); if (object == UNDEFINED_WOOL_VALUE) wool_error(UNDEFINED_VARIABLE, ""); else if ((object != NIL) && (object -> type != WLBar) && (object -> type != WLPlug)) bad_argument(object, 0, "PLUG or BAR"); } if (object -> type == WLPlug) { bar -> plugs[i] = (Wob) NewPlug(bar, object); bar -> ewidth = 0; } else if (object -> type == WLBar) { bar -> plugs[i] = (Wob) NewBar(bar, object, !dir); if (((Bar) bar -> plugs[i]) -> ewidth) bar -> elength = 1; if (!(((Bar) bar -> plugs[i]) -> elength)) bar -> ewidth = 0; } else { bar -> plugs[i] = (Wob) NULL; bar -> elength = 1; } } return bar; } BarClose(bar) Bar bar; { int i; if(!bar) return; for (i = 0; i < bar -> nplugs; i++) { if (bar -> plugs[i]) if (bar -> plugs[i] -> type == PlugClass) PlugClose(bar -> plugs[i]); else if (bar -> plugs[i] -> type == BarClass) BarClose(bar -> plugs[i]); } WobRelease(bar); } /* * Open a Bar */ Bar BarOpen(bar) Bar bar; { int i; if(!bar) return bar; check_window_size(bar); bar -> hook = XCreateSimpleWindow(dpy, bar -> parent -> hook, bar -> box.x, bar -> box.y, bar -> box.width, bar -> box.height, bar -> box.borderwidth, bar -> box.borderpixel, bar -> box.background); if (bar -> parent -> type == ScreenClass) bar -> status |= TopLevelXWindowStatus; WobRecordHook(bar); if (bar -> cursor != NIL) XDefineCursor(dpy, bar -> hook, ((WOOL_Cursor) bar -> cursor) -> cursor); if (bar -> tile != NIL && bar -> tile != TRU) XSetWindowBackgroundPixmap(dpy, bar -> hook, ((WOOL_Pixmap) bar -> tile) -> pixmap); if (bar -> bordertile != NIL) XSetWindowBorderPixmap(dpy, bar -> hook, ((WOOL_Pixmap) bar -> bordertile) -> pixmap); bar -> curstate = (int) WOOL_send(WOOL_open, bar -> fsm, (bar -> fsm)); for (i = 0; i < bar -> nplugs; i++) { if (bar -> plugs[i]) WOOL_send(WOOL_open, bar -> plugs[i], (bar -> plugs[i])); } bar -> input_mask = WobMask | ((WOOL_Fsm) bar -> fsm) -> mask; XSelectInput(dpy, bar -> hook, bar -> input_mask); #ifdef SHAPE if (BarIsShaped(bar)) { bar -> shaped = 1; UpdateBarShape(bar); } #endif /* SHAPE */ XMapWindow(dpy, bar -> hook); XMapSubwindows(dpy, bar -> hook); return bar; } int CalcNaturalBarWidth(bar) Bar bar; { Plug *plugs; int i, curr_width = 1; plugs = (Plug *) & ((bar -> plugs)[0]); if (bar -> direction == HORIZONTAL) { if (!bar -> nplugs && bar -> tile != NIL && bar -> tile != TRU) curr_width = ((WOOL_Pixmap) bar -> tile) -> height; for (i = 0; i < bar -> nplugs; i++) { if (plugs[i]) if (plugs[i] -> type == PlugClass) { UpdatePlugGeometry(plugs[i]); curr_width = Max(curr_width, plugs[i] -> box.height + 2 * plugs[i] -> box.borderwidth); } else { curr_width = Max(curr_width, CalcNaturalBarLength(plugs[i]) + 2 * plugs[i] -> box.borderwidth); } } curr_width = Min(bar -> max_width, Max(bar -> min_width, curr_width)); return curr_width; } else { if (!bar -> nplugs && bar -> tile != NIL && bar -> tile != TRU) curr_width = ((WOOL_Pixmap) bar -> tile) -> width; for (i = 0; i < bar -> nplugs; i++) { if (plugs[i]) if (plugs[i] -> type == PlugClass) { UpdatePlugGeometry(plugs[i]); curr_width = Max(curr_width, plugs[i] -> box.width + 2 * plugs[i] -> box.borderwidth); } else { curr_width = Max(curr_width, CalcNaturalBarLength(plugs[i]) + 2 * plugs[i] -> box.borderwidth); } } curr_width = Min(bar -> max_width, Max(bar -> min_width, curr_width)); return curr_width; } } int CalcNaturalBarLength(bar) Bar bar; { Plug *plugs; int i, tmp; int current_pos = 0; int space_len = 0, n_spaces = 0; plugs = (Plug *) & ((bar -> plugs)[0]); if (bar -> direction == HORIZONTAL) { for (i = 0; i < bar -> nplugs; i++) if (!plugs[i]) { n_spaces++; current_pos += space_len; } else if (plugs[i] -> type == PlugClass) { UpdatePlugGeometry(plugs[i]); current_pos += plugs[i] -> box.width + bar -> plug_separator + 2 * plugs[i] -> box.borderwidth; } else { tmp = CalcNaturalBarWidth(plugs[i]); if (((Bar) plugs[i]) -> ewidth) if (tmp > space_len) { current_pos += n_spaces * (tmp - space_len); n_spaces++; space_len = tmp; } else { n_spaces++; tmp = space_len; } current_pos += tmp + bar -> plug_separator + 2 * plugs[i] -> box.borderwidth; } if (current_pos) current_pos -= bar -> plug_separator; else if (!bar -> nplugs && bar -> tile != NIL && bar -> tile != TRU) current_pos = ((WOOL_Pixmap) bar -> tile) -> width; else current_pos = 1; } else { for (i = 0; i < bar -> nplugs; i++) if (!plugs[i]) { n_spaces++; current_pos += space_len; } else if (plugs[i] -> type == PlugClass) { UpdatePlugGeometry(plugs[i]); current_pos += plugs[i] -> box.height + bar -> plug_separator + 2 * plugs[i] -> box.borderwidth; } else { tmp = CalcNaturalBarWidth(plugs[i]); if (((Bar) plugs[i]) -> ewidth) if (tmp > space_len) { current_pos += n_spaces * (tmp - space_len); n_spaces++; space_len = tmp; } else { n_spaces++; tmp = space_len; } current_pos += tmp + bar -> plug_separator + 2 * plugs[i] -> box.borderwidth; } if (current_pos) current_pos -= bar -> plug_separator; else if (!bar -> nplugs && bar -> tile != NIL && bar -> tile != TRU) current_pos = ((WOOL_Pixmap) bar -> tile) -> height; else current_pos = 1; } return current_pos; } int CalcMinBarLength(bar) Bar bar; { Plug *plugs; int i, current_pos = 0; plugs = (Plug *) & ((bar -> plugs)[0]); if (bar -> direction == HORIZONTAL) { for (i = 0; i < bar -> nplugs; i++) if (plugs[i]) if (plugs[i] -> type == PlugClass) { UpdatePlugGeometry(plugs[i]); current_pos += plugs[i] -> box.width + bar -> plug_separator + 2 * plugs[i] -> box.borderwidth; } else { current_pos += bar -> plug_separator + 2 * plugs[i] -> box.borderwidth + (((Bar) plugs[i]) -> ewidth ? 1 : CalcNaturalBarWidth(plugs[i])); } if (current_pos) { current_pos -= bar -> plug_separator; } } else { for (i = 0; i < bar -> nplugs; i++) if (plugs[i]) if (plugs[i] -> type == PlugClass) { UpdatePlugGeometry(plugs[i]); current_pos += plugs[i] -> box.height + bar -> plug_separator + 2 * plugs[i] -> box.borderwidth; } else { current_pos += bar -> plug_separator + 2 * plugs[i] -> box.borderwidth + (((Bar) plugs[i]) -> ewidth ? 1 : CalcNaturalBarWidth(plugs[i])); } if (current_pos) { current_pos -= bar -> plug_separator; } } return current_pos; } /* * Called BEFORE adjusting the client * Here we take a bar setup, and suppose that its box data is updated. * Then we ask for the dimension of plugs and proceed to position them. * Adjust the width of the bars */ int UpdateBarWidth(bar) Bar bar; { Plug *plugs; int i; if (!bar) return 0; if (bar -> direction == HORIZONTAL) { bar -> box.height = CalcNaturalBarWidth(bar); } else { bar -> box.width = CalcNaturalBarWidth(bar); } return 2 * bar -> box.borderwidth + (bar -> direction == HORIZONTAL ? bar -> box.height : bar -> box.width); } /* * Called AFTER adjusting the client * Adjust space in the length of the bar. * If we encounter a NULL plug, treat it as an extensible space */ UpdateBarLength(bar) Bar bar; { Plug *plugs; int i, n = 0, current_pos = 0, n_spaces = 0; int total_space, delta = 0, shift = 0; if (!bar) return; plugs = (Plug *) & ((bar -> plugs)[0]); for (i = 0; i < bar -> nplugs; i++) if (!plugs[i]) n_spaces++; else if ((plugs[i] -> type == BarClass) && ((Bar) plugs[i]) -> ewidth) n_spaces++; total_space = (bar -> direction == HORIZONTAL ? bar -> box.width : bar -> box.height) - CalcMinBarLength(bar); if (n_spaces && (total_space > 0)) { shift = total_space / n_spaces; delta = total_space % n_spaces; } if (bar -> direction == HORIZONTAL) { for (i = 0; i < bar -> nplugs; i++) if (plugs[i]) if (plugs[i] -> type == PlugClass) { plugs[i] -> box.x = current_pos; plugs[i] -> box.y = (bar -> box.height - plugs[i]->box.height - 2 * plugs[i] -> box.borderwidth) / 2; current_pos += plugs[i] -> box.width + bar -> plug_separator + 2 * plugs[i] -> box.borderwidth; } else { plugs[i] -> box.x = current_pos; plugs[i] -> box.y = 0; if (((Bar) plugs[i]) -> ewidth) plugs[i] -> box.width = 1 + (++n == n_spaces ? shift+delta : shift); else if (bar -> nplugs == 1) plugs[i] -> box.width = bar -> box.width - 2 * plugs[i] -> box.borderwidth; else plugs[i] -> box.width = CalcNaturalBarWidth(plugs[i]); plugs[i] -> box.height = bar -> box.height - 2 * plugs[i] -> box.borderwidth; UpdateBarLength(plugs[i]); current_pos += plugs[i] -> box.width + bar -> plug_separator + 2 * plugs[i] -> box.borderwidth; } else { current_pos += (++n == n_spaces ? shift+delta : shift); } } else { for (i = 0; i < bar -> nplugs; i++) if (plugs[i]) if (plugs[i] -> type == PlugClass) { plugs[i] -> box.y = current_pos; plugs[i] -> box.x = (bar -> box.width - plugs[i]->box.width - 2 * plugs[i] -> box.borderwidth) / 2; current_pos += plugs[i] -> box.height + bar -> plug_separator + 2 * plugs[i] -> box.borderwidth; } else { plugs[i] -> box.y = current_pos; plugs[i] -> box.x = 0; if (((Bar) plugs[i]) -> ewidth) plugs[i] -> box.height = 1 + (++n == n_spaces ? shift+delta : shift); else if (bar -> nplugs == 1) plugs[i] -> box.height = bar -> box.height - 2 * plugs[i] -> box.borderwidth; else plugs[i] -> box.height = CalcNaturalBarWidth(plugs[i]); plugs[i] -> box.width = bar -> box.width - 2 * plugs[i] -> box.borderwidth; UpdateBarLength(plugs[i]); current_pos += plugs[i] -> box.height + bar -> plug_separator + 2 * plugs[i] -> box.borderwidth; } else { current_pos += (++n == n_spaces ? shift+delta : shift); } } } int NaturalBarLength(bar) Bar bar; { Plug *plugs; int i; if (!bar) return 0; if (bar -> direction == HORIZONTAL) { bar -> box.width = CalcNaturalBarLength(bar); } else { bar -> box.height = CalcNaturalBarLength(bar); } return 2 * bar -> box.borderwidth + (bar -> direction == HORIZONTAL ? bar -> box.width : bar -> box.height); } BarEventHandler(bar, evt) Bar bar; XEvent *evt; { int i; switch (evt -> type) { case Expose: XClearWindow(dpy, bar -> hook); break; case GWMUserEvent: /* TODO: no more test on plugs masks*/ WLFsm_action(bar -> fsm, bar, evt); if (GWM_Propagate_user_events) for (i = 0; i < bar -> nplugs; i++) if ((bar -> plugs[i])) { WOOL_send(WOOL_process_event, bar -> plugs[i], (bar -> plugs[i], evt)); } break; default: WLFsm_action(bar -> fsm, bar, evt); } } ReconfigureBar(bar, culprit) Bar bar; Wob culprit; /* parent or plug */ { int i, width, height, must_resize = 1; if (!bar) return; width = bar -> box.width; height = bar -> box.height; if (culprit != (Wob) bar -> parent) { /* from plug or bar below */ UpdateBarWidth(bar); WOOL_send(WOOL_reconfigure, bar -> parent, (bar -> parent, bar)); } else { /* from above */ if (culprit && culprit -> type != BarClass) UpdateBarLength(bar); XMoveResizeWindow(dpy, bar -> hook, bar -> box.x, bar -> box.y, bar -> box.width, bar -> box.height); for (i = 0; i < bar -> nplugs; i++) if (bar -> plugs[i]) if (bar -> plugs[i] -> type == PlugClass) ReconfigurePlug(bar -> plugs[i], bar); else ReconfigureBar(bar -> plugs[i], bar); #ifdef SHAPE if (bar -> shaped || (bar -> shaped = BarIsShaped(bar))) UpdateBarShape(bar); #endif /* SHAPE */ XClearWindow(dpy, bar -> hook); } } set_bar_bitmap(bar, wl_pixmap) Bar bar; WOOL_OBJECT wl_pixmap; { int shaped_tile = 0; if (((wl_pixmap -> type == WLAtom) && (wl_pixmap != TRU) && (wl_pixmap != NIL)) || wl_pixmap -> type == WLList) return; if (bar -> tile == TRU) shaped_tile = -1; else if (TileIsShaped(bar -> tile)) shaped_tile = 1; decrease_reference(bar -> tile); increase_reference(bar -> tile = wl_pixmap); if ((shaped_tile == -1) && (bar -> tile == TRU)) shaped_tile = 0; /* No reconfigure necessary if it remains TRU */ else if ((bar -> tile == TRU) || TileIsShaped(bar -> tile)) shaped_tile = 1; if (wl_pixmap == NIL) XSetWindowBackground(dpy, bar->hook, bar -> box.background); else if (wl_pixmap -> type == WLPixmap) XSetWindowBackgroundPixmap(dpy, bar->hook, ((WOOL_Pixmap) wl_pixmap) -> pixmap); /* Reconfigure only if anything will change */ if (shaped_tile || ((!bar -> nplugs) && ((bar -> direction == HORIZONTAL ? bar -> box.height : bar -> box.width) != CalcNaturalBarWidth(bar) || (bar -> direction == HORIZONTAL ? bar -> box.width : bar -> box.height) != CalcNaturalBarLength(bar)))) { ReconfigureBar(bar, 0); } XClearWindow(dpy, bar -> hook); } #ifdef SHAPE /* non-rectangular extension */ int BarIsShaped(bar) Bar bar; { int i; if ((bar -> tile == TRU) || TileIsShaped(bar -> tile)) return 1; for (i = 0; i < bar -> nplugs; i++) if (bar -> plugs[i]) if (bar -> plugs[i] -> type == PlugClass) { if (((Plug) bar -> plugs[i]) -> graphic -> type == WLPixmap && (((WOOL_Pixmap) (((Plug) bar -> plugs[i]) -> graphic))->mask)) return 1; } else { if (((Bar) bar -> plugs[i]) -> shaped) return 1; } return 0; } UpdateBarShape(bar) Bar bar; { XRectangle rect, rect2; Plug *plugs; int i; int shaped_tile = TileIsShaped(bar -> tile); rect.x = - bar -> box.borderwidth; rect.y = - bar -> box.borderwidth; rect.width = bar -> box.width + 2 * bar -> box.borderwidth; rect.height = bar -> box.height + 2 * bar -> box.borderwidth; XShapeCombineRectangles(dpy, bar -> hook, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0); /* transparent tile */ if (bar -> tile == TRU || shaped_tile) { rect2.x = 0; rect2.y = 0; rect2.width = bar -> box.width; rect2.height = bar -> box.height; XShapeCombineRectangles(dpy, bar -> hook, ShapeBounding, 0, 0, &rect2, 1, ShapeSubtract, 0); } /* shaped tile */ if (shaped_tile) { int x_offset, y_offset; /* we do the tiling ourselves by hand */ for (x_offset = 0; x_offset < bar -> box.width; x_offset += ((WOOL_Pixmap) (bar -> tile)) -> width) { for (y_offset = 0; y_offset < bar -> box.height; y_offset += ((WOOL_Pixmap) (bar -> tile))->height) { XShapeCombineMask(dpy, bar -> hook, ShapeBounding, x_offset, y_offset, ((WOOL_Pixmap) (bar -> tile)) -> mask, ShapeUnion); } } } plugs = (Plug *) & ((bar -> plugs)[0]); for (i = 0; i < bar -> nplugs; i++) if (plugs[i]) { rect2.x = plugs[i] -> box.x + plugs[i] -> box.borderwidth; rect2.y = plugs[i] -> box.y + plugs[i] -> box.borderwidth; rect2.width = plugs[i] -> box.width; rect2.height = plugs[i] -> box.height; XShapeCombineRectangles(dpy, bar -> hook, ShapeBounding, 0, 0, &rect2, 1, ShapeSubtract, 0); XShapeCombineShape(dpy, bar -> hook, ShapeBounding, rect2.x, rect2.y, plugs[i] -> hook, ShapeBounding, ShapeUnion); } XShapeCombineRectangles(dpy, bar -> hook, ShapeBounding, 0, 0, &rect, 1, ShapeIntersect, 0); } #endif /* SHAPE */