--- sapphire-0.15.8.orig/Makefile +++ sapphire-0.15.8/Makefile @@ -14,7 +14,9 @@ LIBS = -lXext -lX11 # If you change this, remember to change it in windowmanager.cc (line 34), -# and in data/menu/default (lines 43-47, the themes section). +# and in data/menu/default (lines 43-47, the themes section). Sapphire no +# longer segfaults if it can't find its menus or themes, but it will always +# give you the defaults, and won't warn you that this has happened. CONFIGURATION_PATH=/usr/share/sapphire # DEBUG = Outputs debug information @@ -55,7 +57,7 @@ $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@ install: all - install -s sapphire $(DESTDIR)$(prefix)/bin/ + install sapphire $(DESTDIR)$(prefix)/bin/ install -d $(DESTDIR)$(CONFIGURATION_PATH)/ --- sapphire-0.15.8.orig/basemenu.cc +++ sapphire-0.15.8/basemenu.cc @@ -1,1085 +1,1085 @@ -/* - * Copyright (C) 1999,2000,2001 Frank Hale - * frankhale@yahoo.com - * http://sapphire.sourceforge.net/ - * - * Updated: 3 Nov 2001 - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -#include "sapphire.hh" - -BaseMenu::BaseMenu() { - - menu_pix=None; - select_pix=None; - title_pix=None; - - select_gc = None; - menu_gc = None; - back_gc = None; - - mi = new LinkedList; - - menu.menuTitle="Sapphire Menu"; - - menu.hasTitle=False; - - bottom_edge=False; - right_edge=False; - - counter=0; - - extra_width=0; - - font = XLoadQueryFont(wm->getDisplay(), wm->getTheme()->getMenuFont()); - - create_mask = CWBackPixmap | - CWBackPixel | - CWBorderPixel | - CWOverrideRedirect | - CWEventMask; - - attrib.background_pixmap = None; - attrib.background_pixel = wm->getBackgroundColor().pixel; - attrib.border_pixel = wm->getBorderColor().pixel; - attrib.override_redirect = True; - attrib.event_mask = ButtonPressMask | - ButtonReleaseMask | - PointerMotionMask | - ExposureMask | - EnterWindowMask | - LeaveWindowMask; - - - //gv.background = wm->getBackgroundColor().pixel; - //select_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile , &gv); - //back_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile, &gv); - - menu.x = 1; - menu.y = 1; - menu.x_move = 1; - menu.y_move = 1; - menu.height=1; - menu.width=1; - - menu.total_item_height=1; - - item_width = menu.width; - item_height = font->ascent + font->descent + 8; - - menu.window = - XCreateWindow(wm->getDisplay(), wm->getRootWindow(), menu.x, menu.y, - menu.width, menu.height, 1, DefaultDepth(wm->getDisplay(), wm->getScreen()), - InputOutput, DefaultVisual(wm->getDisplay(), wm->getScreen()), create_mask, &attrib); - - menu.title = - XCreateWindow(wm->getDisplay(), menu.window, 0, 0, - menu.width, item_height, 0, DefaultDepth(wm->getDisplay(), wm->getScreen()), - InputOutput, DefaultVisual(wm->getDisplay(), wm->getScreen()), create_mask, &attrib); - - menu.item_window = - XCreateWindow(wm->getDisplay(), menu.window, 0, item_height - 2, - menu.width, menu.height-item_height, 0, DefaultDepth(wm->getDisplay(), wm->getScreen()), - InputOutput, DefaultVisual(wm->getDisplay(), wm->getScreen()), create_mask, &attrib); - - curs = XDefineCursor(wm->getDisplay(), menu.window, XCreateFontCursor(wm->getDisplay(), XC_left_ptr)); - - - menu.isVisible = False; - - curr = new BaseMenuItem(); - - curr = None; - - enterOnce = True; -} - -BaseMenu::~BaseMenu() { - mi->removeAll(); - - XDestroyWindow(wm->getDisplay(), menu.title); - XDestroyWindow(wm->getDisplay(), menu.item_window); - XDestroyWindow(wm->getDisplay(), menu.window); - - XFreeGC(wm->getDisplay(), menu_gc); - XFreeGC(wm->getDisplay(), select_gc); - XFreeGC(wm->getDisplay(), back_gc); - - wm->getImageControl()->removeImage(title_pix); - wm->getImageControl()->removeImage(menu_pix); - wm->getImageControl()->removeImage(select_pix); - wm->getImageControl()->removeImage(menufont_pix); - - delete mi; - delete curr; -} - -// This updates all graphics contexts, gradient pixmaps and determines placement of all menu items. -void BaseMenu::update_all() -{ - LinkedListIterator it(mi); - - int temp_width=0; - int temp_ascent=0; - int temp_descent=0; - - unsigned int count=0; - unsigned int char_count=0; - - menu.total_item_height=1; - - // If menu is created with no items lets make a few defaults - // so things work out nice. - - if (mi->count() == 0) - { - char_count = strlen(menu.menuTitle); - - menu.width = XTextWidth(wm->getXFont(), menu.menuTitle, strlen(menu.menuTitle)); - - XTextExtents(font, menu.menuTitle , char_count, &direction, &ascent, - &descent, &overall); - - temp_width = overall.width; - temp_ascent = overall.ascent; - temp_descent= overall.descent; - - menu.width = temp_width + 40; - item_width = temp_ascent + temp_descent + 8; - menu.height = item_height; - - menu.total_item_height = item_height+3; - - } else { - - //============================================================= - - for(; it.current(); it++) - { - char_count = strlen(it.current()->name); - - XTextExtents(font, it.current()->name , char_count, &direction, &ascent, - &descent, &overall); - - if (char_count < strlen(menu.menuTitle)) { - - char_count = strlen(menu.menuTitle); - - XTextExtents(font, menu.menuTitle , char_count, &direction, &ascent, - &descent, &overall); - } - - if (char_count > count) { - count = char_count; - temp_width = overall.width; - temp_ascent = overall.ascent; - temp_descent= overall.descent; - } - - menu.width = temp_width + 40; - item_width = temp_ascent + temp_descent + 8; - menu.height = item_height * mi->count(); - - it.current()->item_x = item_width/2+4; - it.current()->item_y = item_height/2+4+menu.total_item_height; - - menu.total_item_height += item_height; - } - - menu.total_item_height += item_height; - - } - - menu.width+=extra_width; - - setTitleVisible(menu.hasTitle); - - createMenuImage(); - createMenuSelectImage(); - createMenuTitleImage(); - createMenuFontImage(); - - XClearWindow(wm->getDisplay(), menu.title); - XClearWindow(wm->getDisplay(), menu.item_window); - - XGCValues gv; - gv.tile = select_pix; - select_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile , &gv); - XSetFillStyle(wm->getDisplay(), select_gc, FillTiled); - - gv.tile = menu_pix; - back_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile, &gv); - XSetFillStyle(wm->getDisplay(), back_gc, FillTiled); - - gv.font = font->fid; - gv.tile = menufont_pix; - menu_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile | GCFont, &gv); - XSetFillStyle(wm->getDisplay(), menu_gc, FillTiled); - - testMenuEdgeDetect(this); - - if (menu.y + menu.height >= wm->getYRes()) - { - bottom_edge=True; - }else { - - bottom_edge=False; - } - - if(bottom_edge) - { - XMoveWindow(wm->getDisplay(), menu.window, menu.x, wm->getYRes() - menu.height - item_height - 4); - } -} - -// This updates all graphics contexts, gradient pixmaps and determines placement of all menu items. -void BaseMenu::update_menu() -{ - LinkedListIterator it(mi); - - int temp_width=0; - int temp_ascent=0; - int temp_descent=0; - - unsigned int count=0; - unsigned int char_count=0; - - menu.total_item_height=1; - - // If menu is created with no items lets make a few defaults - // so things work out nice. - - if (mi->count() == 0) - { - char_count = strlen(menu.menuTitle); - - menu.width = XTextWidth(wm->getXFont(), menu.menuTitle, strlen(menu.menuTitle)); - - XTextExtents(font, menu.menuTitle , char_count, &direction, &ascent, - &descent, &overall); - - temp_width = overall.width; - temp_ascent = overall.ascent; - temp_descent= overall.descent; - - menu.width = temp_width + 40; - item_width = temp_ascent + temp_descent + 8; - menu.height = item_height; - - menu.total_item_height = item_height+3; - - } else { - - //============================================================= - - for(; it.current(); it++) - { - char_count = strlen(it.current()->name); - - XTextExtents(font, it.current()->name , char_count, &direction, &ascent, - &descent, &overall); - - if (char_count < strlen(menu.menuTitle)) { - - char_count = strlen(menu.menuTitle); - - XTextExtents(font, menu.menuTitle , char_count, &direction, &ascent, - &descent, &overall); - } - - if (char_count > count) { - count = char_count; - temp_width = overall.width; - temp_ascent = overall.ascent; - temp_descent= overall.descent; - } - - menu.width = temp_width + 40; - item_width = temp_ascent + temp_descent + 8; - menu.height = item_height * mi->count(); - - it.current()->item_x = item_width/2+4; - it.current()->item_y = item_height/2+4+menu.total_item_height; - - menu.total_item_height += item_height; - } - - menu.total_item_height += item_height; - - } - - menu.width+=extra_width; - - setTitleVisible(menu.hasTitle); -} - -void BaseMenu::hide() -{ - XUnmapWindow(wm->getDisplay(), menu.window); -} - -void BaseMenu::setTitleVisible(bool s) -{ - menu.hasTitle=s; - - if(menu.hasTitle) - { - XResizeWindow(wm->getDisplay(), menu.window, menu.width, menu.total_item_height); - XResizeWindow(wm->getDisplay(), menu.title, menu.width, item_height); - XMoveResizeWindow(wm->getDisplay(), menu.item_window, - 0, - item_height, - menu.width, - menu.total_item_height); - - } else { - XResizeWindow(wm->getDisplay(), menu.window, menu.width, menu.total_item_height - item_height); - XResizeWindow(wm->getDisplay(), menu.title, menu.width, item_height); - XMoveResizeWindow(wm->getDisplay(), menu.item_window, - 0, 0, - menu.width, - menu.total_item_height); - } -} - -void BaseMenu::reconfigure() -{ - XGCValues gv; - - XFreeFont(wm->getDisplay(), font); - font = XLoadQueryFont(wm->getDisplay(), wm->getTheme()->getMenuFont()); - update_menu(); - - XFreePixmap(wm->getDisplay(), title_pix); - XFreePixmap(wm->getDisplay(), menu_pix); - XFreePixmap(wm->getDisplay(), select_pix); - XFreePixmap(wm->getDisplay(), menufont_pix); - - createMenuImage(); - createMenuSelectImage(); - createMenuTitleImage(); - createMenuFontImage(); - - XClearWindow(wm->getDisplay(), menu.title); - XClearWindow(wm->getDisplay(), menu.item_window); - - XFreeGC(wm->getDisplay(), menu_gc); - XFreeGC(wm->getDisplay(), select_gc); - XFreeGC(wm->getDisplay(), back_gc); - - gv.tile = select_pix; - select_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile , &gv); - XSetFillStyle(wm->getDisplay(), select_gc, FillTiled); - - gv.tile = menu_pix; - back_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile, &gv); - XSetFillStyle(wm->getDisplay(), back_gc, FillTiled); - - gv.font = font->fid; - gv.tile = menufont_pix; - menu_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile | GCFont, &gv); - XSetFillStyle(wm->getDisplay(), menu_gc, FillTiled); - - redraw(); -} - -// Redraws the entire contents of the menu. -void BaseMenu::redraw() -{ - //int text_width=0; - - // We need an Iterator for our menu items. This lets us traverse through - // the list and paint each menu item. - LinkedListIterator it(mi); - - for(; it.current(); it++) - { - if(strcmp(it.current()->name, "separator")==0) - { - XDrawLine(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x - 14, it.current()->item_y-5, menu.width-1, it.current()->item_y-5); - XDrawLine(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x - 14, it.current()->item_y-6, menu.width-1, it.current()->item_y-6); - } else { - - XDrawString(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x, - it.current()->item_y + 2, it.current()->name, strlen(it.current()->name)); - - if(it.current()->sub) - { - XDrawRectangle(wm->getDisplay(), menu.item_window, menu_gc, - it.current()->item_x + menu.width - 35, - it.current()->item_y - 7, - 8, - 8); - } - } - - // Draws a bounding box around each menu item. This helped me figure out the algorithm to test which item the - // pointer was over. - // - //XDrawRectangle(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x - 14, it.current()->item_y - 14, menu.width-1, it.current()->item_y + item_height - 15); - - } - - XDrawString(wm->getDisplay(), menu.title, menu_gc, - 8, 16 , menu.menuTitle, strlen(menu.menuTitle)); - - //text_width=XTextWidth(wm->font, menu.menuTitle, strlen(menu.menuTitle)); - - //XDrawString(wm->getDisplay(), menu.title, menu_gc, - // menu.width/2 - text_width/2, - // 14 , - // menu.menuTitle, strlen(menu.menuTitle)); -} - -// Redraws a single menu item on the menu. -void BaseMenu::redraw(BaseMenuItem *i) -{ - if(strcmp(i->name, "separator")==0) - { - XDrawLine(wm->getDisplay(), menu.item_window, menu_gc, i->item_x - 14, i->item_y-5, menu.width-1, i->item_y-5); - XDrawLine(wm->getDisplay(), menu.item_window, menu_gc, i->item_x - 14, i->item_y-6, menu.width-1, i->item_y-6); - } else { - - XDrawString(wm->getDisplay(), menu.item_window, menu_gc, - i->item_x, i->item_y + 2, i->name, strlen(i->name)); - - if(i->sub) - { - XDrawRectangle(wm->getDisplay(), menu.item_window, menu_gc, - i->item_x + menu.width - 35, - i->item_y - 7, - 8, - 8); - } - - } - - // Draws a bounding box around each menu item. This helped me figure out the algorithm to test which item the - // pointer was over. - // - //XDrawRectangle(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x - 14, it.current()->item_y - 14, menu.width-1, it.current()->item_y + item_height - 15); - -} - -void BaseMenu::insert(char *n, BaseMenu *sub) -{ - BaseMenuItem *item = new BaseMenuItem(); - - item->name = new char[strlen(n)+1]; - strcpy(item->name, n); - - item->sub = sub; - - // defaults - item->isSelected=False; - item->exec = ""; - item->function = 0; - item->item_x = item->item_y = 0; - - mi->insert(item); -} - -void BaseMenu::insert(char *n, char *exec, int func) -{ - BaseMenuItem *item = new BaseMenuItem(); - - char *buffer = new char[100]; - if (exec[0] == '~') - { - sprintf(buffer, "%s%s", getenv("HOME"), exec+1); - strcpy(exec, buffer); - } - delete [] buffer; - - item->exec = new char[strlen(exec)+1]; - strcpy(item->exec, exec); - - item->name = new char[strlen(n)+1]; - strcpy(item->name, n); - - item->function = func; - - // defaults - item->isSelected=False; - item->sub = None; - item->item_x = item->item_y = 0; - - mi->insert(item); -} - - -void BaseMenu::insert(char *n, char *exec, BaseMenu *sub, int func) -{ - BaseMenuItem *item = new BaseMenuItem(); - - char *buffer = new char[100]; - if (exec[0] == '~') - { - sprintf(buffer, "%s%s", getenv("HOME"), exec+1); - strcpy(exec, buffer); - } - delete [] buffer; - - item->exec = new char[strlen(exec)+1]; - strcpy(item->exec, exec); - - item->name = new char[strlen(n)+1]; - strcpy(item->name, n); - - item->isSelected=False; - item->sub = sub; - item->function = func; - item->item_x = item->item_y = 0; - - mi->insert(item); -} - -int BaseMenu::remove(BaseMenuItem* element) -{ - mi->remove(element); - - return mi->count(); -} - -void BaseMenu::removeAll() -{ - mi->removeAll(); - - update_all(); -} - -void BaseMenu::execute(char *s) -{ - char command[strlen(s)+8]; - - sprintf(command, "exec %s &", s); - system(command); -} - -void BaseMenu::show() -{ - int mouse_x=0; - int mouse_y=0; - - // Gets the coordinates of the mouse - getMousePosition(&mouse_x, &mouse_y); - - // Check to make sure menu will be displayed on the screen. - if (mouse_x + menu.width > wm->getXRes()) { - menu.x = wm->getXRes() - menu.width - 1; - - right_edge=True; - } else { - menu.x = mouse_x; - - right_edge=False; - } - - if (mouse_y + menu.height > wm->getYRes()) { - menu.y = wm->getYRes() - menu.height - item_height - 4; - - bottom_edge=True; - }else { - - menu.y = mouse_y; - - bottom_edge=False; - } - - // Move the menu to the position of the mouse pointer - XMoveWindow(wm->getDisplay(), menu.window, menu.x, menu.y); - - // Show the menu windows - XMapRaised(wm->getDisplay(), menu.window); - XMapSubwindows(wm->getDisplay(),menu.window); - - menu.isVisible=True; -} - -void BaseMenu::getMousePosition(int *x, int *y) -{ - Window dw1=None; - Window dw2=None; - int t1=0; - int t2=0; - unsigned int t3=0; - - XQueryPointer(wm->getDisplay(), wm->getRootWindow(), &dw1, &dw2, x, y, &t1, &t2, &t3); -} - -void BaseMenu::show(int x, int y) -{ - menu.x = x; - menu.y = y; - - XMoveWindow(wm->getDisplay(), menu.window, x, y); - - // Show the menu windows - XMapSubwindows(wm->getDisplay(),menu.window); - XMapRaised(wm->getDisplay(), menu.window); - - XClearWindow(wm->getDisplay(), menu.item_window); - - menu.isVisible=True; -} - -void BaseMenu::showSub(BaseMenu *sub, int x, int y) -{ - sub->menu.x = x; - sub->menu.y = y; - - XMoveWindow(wm->getDisplay(), sub->menu.window, x, y); - - // Show the menu windows - XMapSubwindows(wm->getDisplay(), sub->menu.window); - XMapRaised(wm->getDisplay(), sub->menu.window); - - sub->menu.isVisible=True; -} - -void BaseMenu::hide(BaseMenu *sub) -{ - - if (sub->menu.isVisible) - { - // hide the menu windows - XUnmapSubwindows(wm->getDisplay(), sub->menu.window); - XUnmapWindow(wm->getDisplay(), sub->menu.window); - - sub->menu.isVisible=False; - } - -} - -BaseMenuItem *BaseMenu::findMenuItem(int x, int y) -{ - int item_xpos2=0; - int item_ypos2=0; - - if(mi->count()) - { - LinkedListIterator it(mi); - for(; it.current(); it++) - { - - // Draws a bounding box around each menu item. This helped me figure out the algorithm to test which item the - // pointer was over. - // - //XDrawRectangle(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x - 14, - // it.current()->item_y - 14, menu.width-1, it.current()->item_y + item_height - 15); - - - item_xpos2 = menu.width-1; - item_ypos2 = it.current()->item_y + item_height - 15; - - if ( (x >= it.current()->item_x - 14) && - (x < item_xpos2) && - (y >= it.current()->item_y - 14) && - (y < item_ypos2) - ) - { - - return it.current(); - } - } - } - - return NULL; -} - -void BaseMenu::handle_button_press_event(XButtonEvent *e) -{ - switch (e->button) - { - case Button1: - { - if(e->window == menu.title) move(); - else if (curr) handle_button1_press(curr); - break; - } - - case Button2: - { - if(curr) handle_button2_press(curr); - break; - } - - case Button3: - { - if (curr) handle_button3_press(curr); - break; - } - } -} - -void BaseMenu::handle_button_release_event(XButtonEvent *e) -{ - switch (e->button) { - case Button1: - { - if (curr) { - - handle_button1_release(curr); - - switch( curr->function ) - { - // function 1 is wm shutdown - case 1: - { - wm->quit_nicely(); - } - break; - - case 2: // do nothing this is a menu separator - { - } - break; - - case 3: // This will start another window manager - { - //wm->start_another_windowmanager(curr->exec); - } - break; - - case 4: // restart Sapphire - { - wm->restart(); - } - break; - - case 5: // reconfigure Sapphire (theme, menu) - { - wm->reconfigureMenu(); - } - break; - - case 6: // change theme - { - Toolbar *t = wm->getToolbar(); - t->setStartMenuButtonStateNotPressed(); - t->getToolbarMenu()->hide(t->getToolbarMenu()); - - wm->getRootMenu()->hideAllVisibleSubmenus(); - wm->changeTheme(curr->exec); - } - break; - - default: // Default is to execute a command or file - { - Toolbar *t = wm->getToolbar(); - t->setStartMenuButtonStateNotPressed(); - t->getToolbarMenu()->hide(t->getToolbarMenu()); - wm->getRootMenu()->hideAllVisibleSubmenus(); - execute(curr->exec); - } - break; - } - } - - break; - } - - case Button2: - { - if (curr) handle_button2_release(curr); - break; - } - - case Button3: - { - if(e->window == menu.title) hideAllVisibleSubmenus(); - else if (curr) handle_button3_release(curr); - break; - } - } -} - -void BaseMenu::move() -{ - wm->setMenu(this); - wm->setMenuEvent(true); -} - -void BaseMenu::setMenuPos(int x, int y) -{ - menu.x = x; - menu.y = y; - - XMoveWindow(wm->getDisplay(), menu.window, x, y); -} - -void BaseMenu::handle_enter_notify(XCrossingEvent *e) -{ - if(curr) - { - LinkedList *temp_mi; - - LinkedListIterator it(mi); - for(; it.current(); it++) - { - if (it.current()->sub && it.current()->sub->menu.isVisible) - { - it.current()->sub->hide(it.current()->sub); - - temp_mi = it.current()->sub->mi; - - LOOP: - - LinkedListIterator n(temp_mi); - for(; n.current(); n++) - { - if(n.current()->sub && n.current()->sub->menu.isVisible) - { - n.current()->sub->hide(n.current()->sub); - - temp_mi = n.current()->sub->mi; - - goto LOOP; - } - } - } - } - - XFillRectangle(wm->getDisplay(), menu.item_window, select_gc, - 0, - curr->item_y - 15, - item_width - item_height - 2, - item_height - 1 - ); - - if(curr->sub) - { - testMenuEdgeDetect(curr->sub); - - if(curr->sub->right_edge) - { - if(curr->sub->bottom_edge) - showSub(curr->sub,menu.x - curr->sub->menu.width - 1, wm->getYRes() - curr->sub->menu.height - 27); - else - showSub(curr->sub,menu.x - curr->sub->menu.width - 1, menu.y + curr->item_y - 15); - } - else { - if(curr->sub->bottom_edge) - { - showSub(curr->sub,menu.x + menu.width + 1, wm->getYRes() - curr->sub->menu.height - 27); - } - else { - showSub(curr->sub,menu.x + menu.width + 1, menu.y + curr->item_y - 15); - } - } - } - redraw(curr); - } -} - -void BaseMenu::handle_leave_notify(XCrossingEvent *e) -{ - if(curr) - { - XFillRectangle(wm->getDisplay(), menu.item_window, back_gc, - 0, - curr->item_y -15, - item_width - item_height - 2, - item_height - 1); - - redraw(curr); - curr = NULL; - } -} - -void BaseMenu::hideAllVisibleSubmenus() -{ - LinkedList *temp_mi; - - hide(this); - - LinkedListIterator it(mi); - for(; it.current(); it++) - { - if (it.current()->sub && it.current()->sub->menu.isVisible) - { - it.current()->sub->hide(it.current()->sub); - - temp_mi = it.current()->sub->mi; - - LOOP: // Yuck I'm using a goto... ;-( - - LinkedListIterator n(temp_mi); - for(; n.current(); n++) - { - if(n.current()->sub && n.current()->sub->menu.isVisible) - { - n.current()->sub->hide(n.current()->sub); - - temp_mi = n.current()->sub->mi; - - goto LOOP; - } - } - } - } -} - -void BaseMenu::setAllMenuTitlesVisible(BaseMenu *sub, bool s) -{ - sub->setTitleVisible(s); - - LinkedListIterator it(sub->mi); - for(; it.current(); it++) - { - if (it.current()->sub) setAllMenuTitlesVisible(it.current()->sub, s); - } -} - -void BaseMenu::handle_expose_event(XExposeEvent *e) -{ - if(e->count == 0) redraw(); -} - -void BaseMenu::handle_motion_notify_event(XMotionEvent *e) -{ - // for moving the menu. - menu.x_move = e->x; - menu.y_move = e->y; - - //---------------------- - XEvent temp; - - if(e->window == menu.title) { /* DO NOTHING */ } - else if(e->window == menu.item_window) - { - BaseMenuItem *i = findMenuItem(e->x, e->y); - - if (i && enterOnce) - { - curr = i; - - if(! strcmp(i->name, "separator")==0) handle_enter_notify(&temp.xcrossing); - - enterOnce=False; - } else { - - - BaseMenuItem *i = findMenuItem(e->x, e->y); - - if (i != curr) - { - handle_leave_notify(&temp.xcrossing); - - curr = i; - - enterOnce=True; - } - } - } -} - -void BaseMenu::handle_config_notify_event(XConfigureEvent *e) -{ -} - -void BaseMenu::createMenuImage() -{ - unsigned long style=0; - - style = wm->getTheme()->getMenuStyle(); - - menu_pix = wm->getImageControl()->renderImage( - //"menu_frame", - menu.width, - menu.height, - style, - wm->getTheme()->getMenuColorFrom(), - wm->getTheme()->getMenuColorTo() - ); - - XSetWindowBackgroundPixmap(wm->getDisplay(), menu.item_window, menu_pix); -} - -void BaseMenu::createMenuSelectImage() -{ - unsigned long style=0; - - style = wm->getTheme()->getMenuSelectStyle(); - - select_pix = wm->getImageControl()->renderImage( - //"menu_select", - menu.width, - item_height, - style, - wm->getTheme()->getMenuSelectColorFrom(), - wm->getTheme()->getMenuSelectColorTo() - ); -} - -void BaseMenu::createMenuFontImage() -{ - unsigned long style=0; - - style = wm->getTheme()->getFontStyle(); - - menufont_pix = wm->getImageControl()->renderImage( - //"menu_font", - font->ascent, - font->descent, - style, - wm->getTheme()->getMenuFontColorFrom(), - wm->getTheme()->getMenuFontColorTo() - ); -} - -void BaseMenu::createMenuTitleImage() -{ - unsigned long style=0; - - style = wm->getTheme()->getMenuTitleStyle(); - - title_pix = wm->getImageControl()->renderImage( - //"menu_title", - menu.width, - item_height+1, - style, - wm->getTheme()->getMenuTitleColorFrom(), - wm->getTheme()->getMenuTitleColorTo() - ); - - XSetWindowBackgroundPixmap(wm->getDisplay(), menu.title, title_pix); -} - -void BaseMenu::testMenuEdgeDetect(BaseMenu *sub) -{ - int mouse_x=0; - int mouse_y=0; - - bool rightEdge=False; - bool bottomEdge=False; - - // Gets the coordinates of the mouse - getMousePosition(&mouse_x, &mouse_y); - - rightEdge = ( ( this->menu.x + sub->menu.width + 150 ) < (wm->getXRes()) ) ? True : False; - - bottomEdge = ( mouse_y + sub->menu.height >= wm->getYRes() ) ? True : False; - - // Check to make sure menu will be displayed on the screen. - if (rightEdge) sub->right_edge=False; - else sub->right_edge=True; - - if (bottomEdge) sub->bottom_edge=True; - else sub->bottom_edge=False; -} +/* + * Copyright (C) 1999,2000,2001 Frank Hale + * frankhale@yahoo.com + * http://sapphire.sourceforge.net/ + * + * Updated: 3 Nov 2001 + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#include "sapphire.hh" + +BaseMenu::BaseMenu() { + + menu_pix=None; + select_pix=None; + title_pix=None; + + select_gc = None; + menu_gc = None; + back_gc = None; + + mi = new LinkedList; + + menu.menuTitle="Sapphire Menu"; + + menu.hasTitle=False; + + bottom_edge=False; + right_edge=False; + + counter=0; + + extra_width=0; + + font = XLoadQueryFont(wm->getDisplay(), wm->getTheme()->getMenuFont()); + + create_mask = CWBackPixmap | + CWBackPixel | + CWBorderPixel | + CWOverrideRedirect | + CWEventMask; + + attrib.background_pixmap = None; + attrib.background_pixel = wm->getBackgroundColor().pixel; + attrib.border_pixel = wm->getBorderColor().pixel; + attrib.override_redirect = True; + attrib.event_mask = ButtonPressMask | + ButtonReleaseMask | + PointerMotionMask | + ExposureMask | + EnterWindowMask | + LeaveWindowMask; + + + //gv.background = wm->getBackgroundColor().pixel; + //select_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile , &gv); + //back_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile, &gv); + + menu.x = 1; + menu.y = 1; + menu.x_move = 1; + menu.y_move = 1; + menu.height=1; + menu.width=1; + + menu.total_item_height=1; + + item_width = menu.width; + item_height = font->ascent + font->descent + 8; + + menu.window = + XCreateWindow(wm->getDisplay(), wm->getRootWindow(), menu.x, menu.y, + menu.width, menu.height, 1, DefaultDepth(wm->getDisplay(), wm->getScreen()), + InputOutput, DefaultVisual(wm->getDisplay(), wm->getScreen()), create_mask, &attrib); + + menu.title = + XCreateWindow(wm->getDisplay(), menu.window, 0, 0, + menu.width, item_height, 0, DefaultDepth(wm->getDisplay(), wm->getScreen()), + InputOutput, DefaultVisual(wm->getDisplay(), wm->getScreen()), create_mask, &attrib); + + menu.item_window = + XCreateWindow(wm->getDisplay(), menu.window, 0, item_height - 2, + menu.width, menu.height-item_height, 0, DefaultDepth(wm->getDisplay(), wm->getScreen()), + InputOutput, DefaultVisual(wm->getDisplay(), wm->getScreen()), create_mask, &attrib); + + curs = XDefineCursor(wm->getDisplay(), menu.window, XCreateFontCursor(wm->getDisplay(), XC_left_ptr)); + + + menu.isVisible = False; + + curr = new BaseMenuItem(); + + curr = None; + + enterOnce = True; +} + +BaseMenu::~BaseMenu() { + mi->removeAll(); + + XDestroyWindow(wm->getDisplay(), menu.title); + XDestroyWindow(wm->getDisplay(), menu.item_window); + XDestroyWindow(wm->getDisplay(), menu.window); + + XFreeGC(wm->getDisplay(), menu_gc); + XFreeGC(wm->getDisplay(), select_gc); + XFreeGC(wm->getDisplay(), back_gc); + + wm->getImageControl()->removeImage(title_pix); + wm->getImageControl()->removeImage(menu_pix); + wm->getImageControl()->removeImage(select_pix); + wm->getImageControl()->removeImage(menufont_pix); + + delete mi; + delete curr; +} + +// This updates all graphics contexts, gradient pixmaps and determines placement of all menu items. +void BaseMenu::update_all() +{ + LinkedListIterator it(mi); + + int temp_width=0; + int temp_ascent=0; + int temp_descent=0; + + unsigned int count=0; + unsigned int char_count=0; + + menu.total_item_height=1; + + // If menu is created with no items lets make a few defaults + // so things work out nice. + + if (mi->count() == 0) + { + char_count = strlen(menu.menuTitle); + + menu.width = XTextWidth(wm->getXFont(), menu.menuTitle, strlen(menu.menuTitle)); + + XTextExtents(font, menu.menuTitle , char_count, &direction, &ascent, + &descent, &overall); + + temp_width = overall.width; + temp_ascent = overall.ascent; + temp_descent= overall.descent; + + menu.width = temp_width + 40; + item_width = temp_ascent + temp_descent + 8; + menu.height = item_height; + + menu.total_item_height = item_height+3; + + } else { + + //============================================================= + + for(; it.current(); it++) + { + char_count = strlen(it.current()->name); + + XTextExtents(font, it.current()->name , char_count, &direction, &ascent, + &descent, &overall); + + if (char_count < strlen(menu.menuTitle)) { + + char_count = strlen(menu.menuTitle); + + XTextExtents(font, menu.menuTitle , char_count, &direction, &ascent, + &descent, &overall); + } + + if (char_count > count) { + count = char_count; + temp_width = overall.width; + temp_ascent = overall.ascent; + temp_descent= overall.descent; + } + + menu.width = temp_width + 40; + item_width = temp_ascent + temp_descent + 8; + menu.height = item_height * mi->count(); + + it.current()->item_x = item_width/2+4; + it.current()->item_y = item_height/2+4+menu.total_item_height; + + menu.total_item_height += item_height; + } + + menu.total_item_height += item_height; + + } + + menu.width+=extra_width; + + setTitleVisible(menu.hasTitle); + + createMenuImage(); + createMenuSelectImage(); + createMenuTitleImage(); + createMenuFontImage(); + + XClearWindow(wm->getDisplay(), menu.title); + XClearWindow(wm->getDisplay(), menu.item_window); + + XGCValues gv; + gv.tile = select_pix; + select_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile , &gv); + XSetFillStyle(wm->getDisplay(), select_gc, FillTiled); + + gv.tile = menu_pix; + back_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile, &gv); + XSetFillStyle(wm->getDisplay(), back_gc, FillTiled); + + gv.font = font->fid; + gv.tile = menufont_pix; + menu_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile | GCFont, &gv); + XSetFillStyle(wm->getDisplay(), menu_gc, FillTiled); + + testMenuEdgeDetect(this); + + if (menu.y + menu.height >= wm->getYRes()) + { + bottom_edge=True; + }else { + + bottom_edge=False; + } + + if(bottom_edge) + { + XMoveWindow(wm->getDisplay(), menu.window, menu.x, wm->getYRes() - menu.height - item_height - 4); + } +} + +// This updates all graphics contexts, gradient pixmaps and determines placement of all menu items. +void BaseMenu::update_menu() +{ + LinkedListIterator it(mi); + + int temp_width=0; + int temp_ascent=0; + int temp_descent=0; + + unsigned int count=0; + unsigned int char_count=0; + + menu.total_item_height=1; + + // If menu is created with no items lets make a few defaults + // so things work out nice. + + if (mi->count() == 0) + { + char_count = strlen(menu.menuTitle); + + menu.width = XTextWidth(wm->getXFont(), menu.menuTitle, strlen(menu.menuTitle)); + + XTextExtents(font, menu.menuTitle , char_count, &direction, &ascent, + &descent, &overall); + + temp_width = overall.width; + temp_ascent = overall.ascent; + temp_descent= overall.descent; + + menu.width = temp_width + 40; + item_width = temp_ascent + temp_descent + 8; + menu.height = item_height; + + menu.total_item_height = item_height+3; + + } else { + + //============================================================= + + for(; it.current(); it++) + { + char_count = strlen(it.current()->name); + + XTextExtents(font, it.current()->name , char_count, &direction, &ascent, + &descent, &overall); + + if (char_count < strlen(menu.menuTitle)) { + + char_count = strlen(menu.menuTitle); + + XTextExtents(font, menu.menuTitle , char_count, &direction, &ascent, + &descent, &overall); + } + + if (char_count > count) { + count = char_count; + temp_width = overall.width; + temp_ascent = overall.ascent; + temp_descent= overall.descent; + } + + menu.width = temp_width + 40; + item_width = temp_ascent + temp_descent + 8; + menu.height = item_height * mi->count(); + + it.current()->item_x = item_width/2+4; + it.current()->item_y = item_height/2+4+menu.total_item_height; + + menu.total_item_height += item_height; + } + + menu.total_item_height += item_height; + + } + + menu.width+=extra_width; + + setTitleVisible(menu.hasTitle); +} + +void BaseMenu::hide() +{ + XUnmapWindow(wm->getDisplay(), menu.window); +} + +void BaseMenu::setTitleVisible(bool s) +{ + menu.hasTitle=s; + + if(menu.hasTitle) + { + XResizeWindow(wm->getDisplay(), menu.window, menu.width, menu.total_item_height); + XResizeWindow(wm->getDisplay(), menu.title, menu.width, item_height); + XMoveResizeWindow(wm->getDisplay(), menu.item_window, + 0, + item_height, + menu.width, + menu.total_item_height); + + } else { + XResizeWindow(wm->getDisplay(), menu.window, menu.width, menu.total_item_height - item_height); + XResizeWindow(wm->getDisplay(), menu.title, menu.width, item_height); + XMoveResizeWindow(wm->getDisplay(), menu.item_window, + 0, 0, + menu.width, + menu.total_item_height); + } +} + +void BaseMenu::reconfigure() +{ + XGCValues gv; + + XFreeFont(wm->getDisplay(), font); + font = XLoadQueryFont(wm->getDisplay(), wm->getTheme()->getMenuFont()); + update_menu(); + + XFreePixmap(wm->getDisplay(), title_pix); + XFreePixmap(wm->getDisplay(), menu_pix); + XFreePixmap(wm->getDisplay(), select_pix); + XFreePixmap(wm->getDisplay(), menufont_pix); + + createMenuImage(); + createMenuSelectImage(); + createMenuTitleImage(); + createMenuFontImage(); + + XClearWindow(wm->getDisplay(), menu.title); + XClearWindow(wm->getDisplay(), menu.item_window); + + XFreeGC(wm->getDisplay(), menu_gc); + XFreeGC(wm->getDisplay(), select_gc); + XFreeGC(wm->getDisplay(), back_gc); + + gv.tile = select_pix; + select_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile , &gv); + XSetFillStyle(wm->getDisplay(), select_gc, FillTiled); + + gv.tile = menu_pix; + back_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile, &gv); + XSetFillStyle(wm->getDisplay(), back_gc, FillTiled); + + gv.font = font->fid; + gv.tile = menufont_pix; + menu_gc = XCreateGC(wm->getDisplay(), wm->getRootWindow(), GCTile | GCFont, &gv); + XSetFillStyle(wm->getDisplay(), menu_gc, FillTiled); + + redraw(); +} + +// Redraws the entire contents of the menu. +void BaseMenu::redraw() +{ + //int text_width=0; + + // We need an Iterator for our menu items. This lets us traverse through + // the list and paint each menu item. + LinkedListIterator it(mi); + + for(; it.current(); it++) + { + if(strcmp(it.current()->name, "separator")==0) + { + XDrawLine(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x - 14, it.current()->item_y-5, menu.width-1, it.current()->item_y-5); + XDrawLine(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x - 14, it.current()->item_y-6, menu.width-1, it.current()->item_y-6); + } else { + + XDrawString(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x, + it.current()->item_y + 2, it.current()->name, strlen(it.current()->name)); + + if(it.current()->sub) + { + XDrawRectangle(wm->getDisplay(), menu.item_window, menu_gc, + it.current()->item_x + menu.width - 35, + it.current()->item_y - 7, + 8, + 8); + } + } + + // Draws a bounding box around each menu item. This helped me figure out the algorithm to test which item the + // pointer was over. + // + //XDrawRectangle(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x - 14, it.current()->item_y - 14, menu.width-1, it.current()->item_y + item_height - 15); + + } + + XDrawString(wm->getDisplay(), menu.title, menu_gc, + 8, 16 , menu.menuTitle, strlen(menu.menuTitle)); + + //text_width=XTextWidth(wm->font, menu.menuTitle, strlen(menu.menuTitle)); + + //XDrawString(wm->getDisplay(), menu.title, menu_gc, + // menu.width/2 - text_width/2, + // 14 , + // menu.menuTitle, strlen(menu.menuTitle)); +} + +// Redraws a single menu item on the menu. +void BaseMenu::redraw(BaseMenuItem *i) +{ + if(strcmp(i->name, "separator")==0) + { + XDrawLine(wm->getDisplay(), menu.item_window, menu_gc, i->item_x - 14, i->item_y-5, menu.width-1, i->item_y-5); + XDrawLine(wm->getDisplay(), menu.item_window, menu_gc, i->item_x - 14, i->item_y-6, menu.width-1, i->item_y-6); + } else { + + XDrawString(wm->getDisplay(), menu.item_window, menu_gc, + i->item_x, i->item_y + 2, i->name, strlen(i->name)); + + if(i->sub) + { + XDrawRectangle(wm->getDisplay(), menu.item_window, menu_gc, + i->item_x + menu.width - 35, + i->item_y - 7, + 8, + 8); + } + + } + + // Draws a bounding box around each menu item. This helped me figure out the algorithm to test which item the + // pointer was over. + // + //XDrawRectangle(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x - 14, it.current()->item_y - 14, menu.width-1, it.current()->item_y + item_height - 15); + +} + +void BaseMenu::insert(char *n, BaseMenu *sub) +{ + BaseMenuItem *item = new BaseMenuItem(); + + item->name = new char[strlen(n)+1]; + strcpy(item->name, n); + + item->sub = sub; + + // defaults + item->isSelected=False; + item->exec = ""; + item->function = 0; + item->item_x = item->item_y = 0; + + mi->insert(item); +} + +void BaseMenu::insert(char *n, char *exec, int func) +{ + BaseMenuItem *item = new BaseMenuItem(); + + char *buffer = new char[100]; + if (exec[0] == '~') + { + sprintf(buffer, "%s%s", getenv("HOME"), exec+1); + strcpy(exec, buffer); + } + delete [] buffer; + + item->exec = new char[strlen(exec)+1]; + strcpy(item->exec, exec); + + item->name = new char[strlen(n)+1]; + strcpy(item->name, n); + + item->function = func; + + // defaults + item->isSelected=False; + item->sub = None; + item->item_x = item->item_y = 0; + + mi->insert(item); +} + + +void BaseMenu::insert(char *n, char *exec, BaseMenu *sub, int func) +{ + BaseMenuItem *item = new BaseMenuItem(); + + char *buffer = new char[100]; + if (exec[0] == '~') + { + sprintf(buffer, "%s%s", getenv("HOME"), exec+1); + strcpy(exec, buffer); + } + delete [] buffer; + + item->exec = new char[strlen(exec)+1]; + strcpy(item->exec, exec); + + item->name = new char[strlen(n)+1]; + strcpy(item->name, n); + + item->isSelected=False; + item->sub = sub; + item->function = func; + item->item_x = item->item_y = 0; + + mi->insert(item); +} + +int BaseMenu::remove(BaseMenuItem* element) +{ + mi->remove(element); + + return mi->count(); +} + +void BaseMenu::removeAll() +{ + mi->removeAll(); + + update_all(); +} + +void BaseMenu::execute(char *s) +{ + char command[strlen(s)+8]; + + sprintf(command, "exec %s &", s); + system(command); +} + +void BaseMenu::show() +{ + int mouse_x=0; + int mouse_y=0; + + // Gets the coordinates of the mouse + getMousePosition(&mouse_x, &mouse_y); + + // Check to make sure menu will be displayed on the screen. + if (mouse_x + menu.width > wm->getXRes()) { + menu.x = wm->getXRes() - menu.width - 1; + + right_edge=True; + } else { + menu.x = mouse_x; + + right_edge=False; + } + + if (mouse_y + menu.height > wm->getYRes()) { + menu.y = wm->getYRes() - menu.height - item_height - 4; + + bottom_edge=True; + }else { + + menu.y = mouse_y; + + bottom_edge=False; + } + + // Move the menu to the position of the mouse pointer + XMoveWindow(wm->getDisplay(), menu.window, menu.x, menu.y); + + // Show the menu windows + XMapRaised(wm->getDisplay(), menu.window); + XMapSubwindows(wm->getDisplay(),menu.window); + + menu.isVisible=True; +} + +void BaseMenu::getMousePosition(int *x, int *y) +{ + Window dw1=None; + Window dw2=None; + int t1=0; + int t2=0; + unsigned int t3=0; + + XQueryPointer(wm->getDisplay(), wm->getRootWindow(), &dw1, &dw2, x, y, &t1, &t2, &t3); +} + +void BaseMenu::show(int x, int y) +{ + menu.x = x; + menu.y = y; + + XMoveWindow(wm->getDisplay(), menu.window, x, y); + + // Show the menu windows + XMapSubwindows(wm->getDisplay(),menu.window); + XMapRaised(wm->getDisplay(), menu.window); + + XClearWindow(wm->getDisplay(), menu.item_window); + + menu.isVisible=True; +} + +void BaseMenu::showSub(BaseMenu *sub, int x, int y) +{ + sub->menu.x = x; + sub->menu.y = y; + + XMoveWindow(wm->getDisplay(), sub->menu.window, x, y); + + // Show the menu windows + XMapSubwindows(wm->getDisplay(), sub->menu.window); + XMapRaised(wm->getDisplay(), sub->menu.window); + + sub->menu.isVisible=True; +} + +void BaseMenu::hide(BaseMenu *sub) +{ + + if (sub->menu.isVisible) + { + // hide the menu windows + XUnmapSubwindows(wm->getDisplay(), sub->menu.window); + XUnmapWindow(wm->getDisplay(), sub->menu.window); + + sub->menu.isVisible=False; + } + +} + +BaseMenuItem *BaseMenu::findMenuItem(int x, int y) +{ + int item_xpos2=0; + int item_ypos2=0; + + if(mi->count()) + { + LinkedListIterator it(mi); + for(; it.current(); it++) + { + + // Draws a bounding box around each menu item. This helped me figure out the algorithm to test which item the + // pointer was over. + // + //XDrawRectangle(wm->getDisplay(), menu.item_window, menu_gc, it.current()->item_x - 14, + // it.current()->item_y - 14, menu.width-1, it.current()->item_y + item_height - 15); + + + item_xpos2 = menu.width-1; + item_ypos2 = it.current()->item_y + item_height - 15; + + if ( (x >= it.current()->item_x - 14) && + (x < item_xpos2) && + (y >= it.current()->item_y - 14) && + (y < item_ypos2) + ) + { + + return it.current(); + } + } + } + + return NULL; +} + +void BaseMenu::handle_button_press_event(XButtonEvent *e) +{ + switch (e->button) + { + case Button1: + { + if(e->window == menu.title) move(); + else if (curr) handle_button1_press(curr); + break; + } + + case Button2: + { + if(curr) handle_button2_press(curr); + break; + } + + case Button3: + { + if (curr) handle_button3_press(curr); + break; + } + } +} + +void BaseMenu::handle_button_release_event(XButtonEvent *e) +{ + switch (e->button) { + case Button1: + { + if (curr) { + + handle_button1_release(curr); + + switch( curr->function ) + { + // function 1 is wm shutdown + case 1: + { + wm->quit_nicely(); + } + break; + + case 2: // do nothing this is a menu separator + { + } + break; + + case 3: // This will start another window manager + { + wm->start_another_windowmanager(curr->exec); + } + break; + + case 4: // restart Sapphire + { + wm->restart(); + } + break; + + case 5: // reconfigure Sapphire (theme, menu) + { + wm->reconfigureMenu(); + } + break; + + case 6: // change theme + { + Toolbar *t = wm->getToolbar(); + t->setStartMenuButtonStateNotPressed(); + t->getToolbarMenu()->hide(t->getToolbarMenu()); + + wm->getRootMenu()->hideAllVisibleSubmenus(); + wm->changeTheme(curr->exec); + } + break; + + default: // Default is to execute a command or file + { + Toolbar *t = wm->getToolbar(); + t->setStartMenuButtonStateNotPressed(); + t->getToolbarMenu()->hide(t->getToolbarMenu()); + wm->getRootMenu()->hideAllVisibleSubmenus(); + execute(curr->exec); + } + break; + } + } + + break; + } + + case Button2: + { + if (curr) handle_button2_release(curr); + break; + } + + case Button3: + { + if(e->window == menu.title) hideAllVisibleSubmenus(); + else if (curr) handle_button3_release(curr); + break; + } + } +} + +void BaseMenu::move() +{ + wm->setMenu(this); + wm->setMenuEvent(true); +} + +void BaseMenu::setMenuPos(int x, int y) +{ + menu.x = x; + menu.y = y; + + XMoveWindow(wm->getDisplay(), menu.window, x, y); +} + +void BaseMenu::handle_enter_notify(XCrossingEvent *e) +{ + if(curr) + { + LinkedList *temp_mi; + + LinkedListIterator it(mi); + for(; it.current(); it++) + { + if (it.current()->sub && it.current()->sub->menu.isVisible) + { + it.current()->sub->hide(it.current()->sub); + + temp_mi = it.current()->sub->mi; + + LOOP: + + LinkedListIterator n(temp_mi); + for(; n.current(); n++) + { + if(n.current()->sub && n.current()->sub->menu.isVisible) + { + n.current()->sub->hide(n.current()->sub); + + temp_mi = n.current()->sub->mi; + + goto LOOP; + } + } + } + } + + XFillRectangle(wm->getDisplay(), menu.item_window, select_gc, + 0, + curr->item_y - 15, + item_width - item_height - 2, + item_height - 1 + ); + + if(curr->sub) + { + testMenuEdgeDetect(curr->sub); + + if(curr->sub->right_edge) + { + if(curr->sub->bottom_edge) + showSub(curr->sub,menu.x - curr->sub->menu.width - 1, wm->getYRes() - curr->sub->menu.height - 27); + else + showSub(curr->sub,menu.x - curr->sub->menu.width - 1, menu.y + curr->item_y - 15); + } + else { + if(curr->sub->bottom_edge) + { + showSub(curr->sub,menu.x + menu.width + 1, wm->getYRes() - curr->sub->menu.height - 27); + } + else { + showSub(curr->sub,menu.x + menu.width + 1, menu.y + curr->item_y - 15); + } + } + } + redraw(curr); + } +} + +void BaseMenu::handle_leave_notify(XCrossingEvent *e) +{ + if(curr) + { + XFillRectangle(wm->getDisplay(), menu.item_window, back_gc, + 0, + curr->item_y -15, + item_width - item_height - 2, + item_height - 1); + + redraw(curr); + curr = NULL; + } +} + +void BaseMenu::hideAllVisibleSubmenus() +{ + LinkedList *temp_mi; + + hide(this); + + LinkedListIterator it(mi); + for(; it.current(); it++) + { + if (it.current()->sub && it.current()->sub->menu.isVisible) + { + it.current()->sub->hide(it.current()->sub); + + temp_mi = it.current()->sub->mi; + + LOOP: // Yuck I'm using a goto... ;-( + + LinkedListIterator n(temp_mi); + for(; n.current(); n++) + { + if(n.current()->sub && n.current()->sub->menu.isVisible) + { + n.current()->sub->hide(n.current()->sub); + + temp_mi = n.current()->sub->mi; + + goto LOOP; + } + } + } + } +} + +void BaseMenu::setAllMenuTitlesVisible(BaseMenu *sub, bool s) +{ + sub->setTitleVisible(s); + + LinkedListIterator it(sub->mi); + for(; it.current(); it++) + { + if (it.current()->sub) setAllMenuTitlesVisible(it.current()->sub, s); + } +} + +void BaseMenu::handle_expose_event(XExposeEvent *e) +{ + if(e->count == 0) redraw(); +} + +void BaseMenu::handle_motion_notify_event(XMotionEvent *e) +{ + // for moving the menu. + menu.x_move = e->x; + menu.y_move = e->y; + + //---------------------- + XEvent temp; + + if(e->window == menu.title) { /* DO NOTHING */ } + else if(e->window == menu.item_window) + { + BaseMenuItem *i = findMenuItem(e->x, e->y); + + if (i && enterOnce) + { + curr = i; + + if(! strcmp(i->name, "separator")==0) handle_enter_notify(&temp.xcrossing); + + enterOnce=False; + } else { + + + BaseMenuItem *i = findMenuItem(e->x, e->y); + + if (i != curr) + { + handle_leave_notify(&temp.xcrossing); + + curr = i; + + enterOnce=True; + } + } + } +} + +void BaseMenu::handle_config_notify_event(XConfigureEvent *e) +{ +} + +void BaseMenu::createMenuImage() +{ + unsigned long style=0; + + style = wm->getTheme()->getMenuStyle(); + + menu_pix = wm->getImageControl()->renderImage( + //"menu_frame", + menu.width, + menu.height, + style, + wm->getTheme()->getMenuColorFrom(), + wm->getTheme()->getMenuColorTo() + ); + + XSetWindowBackgroundPixmap(wm->getDisplay(), menu.item_window, menu_pix); +} + +void BaseMenu::createMenuSelectImage() +{ + unsigned long style=0; + + style = wm->getTheme()->getMenuSelectStyle(); + + select_pix = wm->getImageControl()->renderImage( + //"menu_select", + menu.width, + item_height, + style, + wm->getTheme()->getMenuSelectColorFrom(), + wm->getTheme()->getMenuSelectColorTo() + ); +} + +void BaseMenu::createMenuFontImage() +{ + unsigned long style=0; + + style = wm->getTheme()->getFontStyle(); + + menufont_pix = wm->getImageControl()->renderImage( + //"menu_font", + font->ascent, + font->descent, + style, + wm->getTheme()->getMenuFontColorFrom(), + wm->getTheme()->getMenuFontColorTo() + ); +} + +void BaseMenu::createMenuTitleImage() +{ + unsigned long style=0; + + style = wm->getTheme()->getMenuTitleStyle(); + + title_pix = wm->getImageControl()->renderImage( + //"menu_title", + menu.width, + item_height+1, + style, + wm->getTheme()->getMenuTitleColorFrom(), + wm->getTheme()->getMenuTitleColorTo() + ); + + XSetWindowBackgroundPixmap(wm->getDisplay(), menu.title, title_pix); +} + +void BaseMenu::testMenuEdgeDetect(BaseMenu *sub) +{ + int mouse_x=0; + int mouse_y=0; + + bool rightEdge=False; + bool bottomEdge=False; + + // Gets the coordinates of the mouse + getMousePosition(&mouse_x, &mouse_y); + + rightEdge = ( ( this->menu.x + sub->menu.width + 150 ) < (wm->getXRes()) ) ? True : False; + + bottomEdge = ( mouse_y + sub->menu.height >= wm->getYRes() ) ? True : False; + + // Check to make sure menu will be displayed on the screen. + if (rightEdge) sub->right_edge=False; + else sub->right_edge=True; + + if (bottomEdge) sub->bottom_edge=True; + else sub->bottom_edge=False; +} --- sapphire-0.15.8.orig/data/menu/default +++ sapphire-0.15.8/data/menu/default @@ -1,5 +1,7 @@ menu(Sapphire 0.15.x) { +include-menu-defs + submenu (terminals) { exec (xterm) {xterm -bg black -fg white} --- sapphire-0.15.8.orig/debian/README.Debian +++ sapphire-0.15.8/debian/README.Debian @@ -0,0 +1,14 @@ +sapphire for Debian +------------------- + +The CONFIGURATION_PATH is /usr/share/sapphire, not /usr/local/share/sapphire. +Also, the menu files are in /etc/X11/sapphire/menu, but I put in a symlink so +that shouldn't bother anyone. + +If you install the 'menu' package, you'll get an automatically updated +'Debian' submenu of installed programs. If you want to edit the items outside +the 'Debian' submenu, edit the file /etc/X11/sapphire/menu/default-menu and +force an update by running update-menus as root. It will generate the other +two files in that directory, and sapphire will read the 'default' file. + + -- Chris Boyle , Mon, 17 Dec 2001 09:48:50 +0000 --- sapphire-0.15.8.orig/debian/changelog +++ sapphire-0.15.8/debian/changelog @@ -0,0 +1,145 @@ +sapphire (0.15.8-9.1) unstable; urgency=medium + + * Non-maintainer upload. + * Remove the obsolete dh_desktop call. (Closes: #817306) + + -- Adrian Bunk Fri, 13 Jan 2017 14:31:12 +0200 + +sapphire (0.15.8-9) unstable; urgency=low + + * Acknowledge NMU; thanks Moritz. + * Depend on xfonts-100dpi|xfonts-75dpi (the default font is lucida). + (closes: #510264) + * Fix debian/watch. (closes: #450076, #529138) + * Don't strip in Makefile, leave it to conditional dh_strip. + (closes: #437953) + * Don't use absolute path for update-alternatives. (closes: #510938) + * Bump Standards-Version to 3.8.1.0. + * Fix menu section. + * Add Homepage field. + * Bump debhelper version to 7. + * Catch errors from make clean. + * Use dh_prep, not dh_clean -k. + + -- Chris Boyle Mon, 25 May 2009 05:05:43 +0100 + +sapphire (0.15.8-8.1) unstable; urgency=low + + * Non-maintainer upload. + * Add missing buid-deps on x11proto-xext-dev and libxext-dev, fixes + FTBFS (Closes: #487003) + + -- Moritz Muehlenhoff Fri, 27 Jun 2008 23:12:18 +0200 + +sapphire (0.15.8-8) unstable; urgency=low + + * Add outputencoding to menu-method, thanks Bill Alombert. + (closes: #393082) + * Fix interpreter in menu-method. + * Bump Standards-Version to 3.7.2.2. + + -- Chris Boyle Sat, 28 Oct 2006 14:12:45 +0100 + +sapphire (0.15.8-7) unstable; urgency=low + + * Update Build-Depends for Xorg. (closes: #347057) + + -- Chris Boyle Fri, 13 Jan 2006 00:48:53 +0000 + +sapphire (0.15.8-6) unstable; urgency=low + + * Add .desktop file. (closes: #330061) + * Bump Standards-Version to 3.6.2. + * Update GPL declaration in debian/copyright. + + -- Chris Boyle Sun, 16 Oct 2005 16:34:36 +0100 + +sapphire (0.15.8-5) unstable; urgency=low + + * Fix description tyops, thanks Jens Nachtigall + . (closes: #272212) + + -- Chris Boyle Sat, 27 Nov 2004 22:34:05 +0000 + +sapphire (0.15.8-4) unstable; urgency=low + + * Bumped standards-version to 3.6.1.0. + * Fixed debian/watch file (sourceforge ftp layout). + + -- Chris Boyle Sun, 28 Mar 2004 19:18:05 +0100 + +sapphire (0.15.8-3) unstable; urgency=low + + * Finished upstream's incomplete support for switching window + managers, added a new "wmexec" menu item type, changed menu-method + to use it instead of my half-assed kludge using "skill sapphire". + (closes: #182430) + * Corrected version string in windowmanager.cc:30. + + -- Chris Boyle Wed, 20 Aug 2003 13:45:35 +0100 + +sapphire (0.15.8-2) unstable; urgency=low + + * Changed maintainer address, now here I *really* haven't been paying + attention. (note: hmm, no new upstream release in all this time, I + guess he's working on aewm++ instead) + * Added support for DEB_BUILD_OPTIONS. + * Bumped standards version to 3.6.0. + * Building using pbuilder. + + -- Chris Boyle Fri, 25 Jul 2003 13:57:49 +0100 + +sapphire (0.15.8-1) unstable; urgency=medium + + * New upstream release. + - Incorporates all source changes I've made so far (the bugfixes + from previous versions). + * Fixed build failure on g++ 2.96 (#include was missing in + linkedlist.cc), hence the urgency. (closes: #128371) + * Added support for switching to a different wm and bumped alternatives + priority to 50 accordingly. + * Added support for "text" menu items (calling x-terminal-emulator). + * Cleaned up some "dh_make'isms" (comments from the example debian + files that were still lying around). + + -- Chris Boyle Wed, 9 Jan 2002 19:38:10 +0000 + +sapphire (0.15.7-2) unstable; urgency=low + + * Fixed build failure with g++ 3.0 by changing use of "or" as a variable + name in image.cc (patch from LaMont Jones ). + (closes: #126830) + * Other changes for g++ 3.0 from the same patch ("using namespace std;" + and use of "friend class" instead of "friend" a few times). + * Added the manpage to the alternatives system as a slave link. + * Fixed "postrm: unknown argument" problems. That message will appear + (harmlessly) on upgrading from the previous version, but hopefully + for the last time. + + -- Chris Boyle Mon, 31 Dec 2001 10:34:46 +0100 + +sapphire (0.15.7-1) unstable; urgency=low + + * Initial Release. (closes: #82572) + * Added install(1) commands in Makefile instead of data.inst script, to + allow use of DESTDIR. + * Changed CONFIGURATION_PATH to /usr/share/sapphire + * Moved the menus to /etc/X11/sapphire/menu but symlinked it so it doesn't + bother the program. + * Fixed some segfaults that would happen if we couldn't open the menu file, + or a theme. + * Made sure the default theme is always loaded if another one isn't, to fix + another segfault where bits of the Theme object were uninitialized. + * Fixed a segfault in RootMenu::parseMenuConfigurationFile() (rootmenu.cc, + line 39) that for some reason was only manifesting when I changed the + CONFIGURATION_PATH (fault was that the configuration_home variable was too + small by 1). + * Added a menu-method to get the Debian menu. + * Added apostrophe as an allowed character in commands in the menu file. + * Added backslash support to menulex.cc, and used it in the menu method to + allow brackets in program titles. + * Fixed a bug which would rearrange the menu if the tree depth was too + great (by keeping track of position with a local variable in + MenuLex::submenu, not 4 global variables). + + -- Chris Boyle Mon, 17 Dec 2001 09:48:50 +0000 --- sapphire-0.15.8.orig/debian/compat +++ sapphire-0.15.8/debian/compat @@ -0,0 +1 @@ +7 --- sapphire-0.15.8.orig/debian/control +++ sapphire-0.15.8/debian/control @@ -0,0 +1,22 @@ +Source: sapphire +Section: x11 +Priority: optional +Maintainer: Chris Boyle +Build-Depends: debhelper (>= 7), libx11-dev, docbook-to-man, x11proto-xext-dev, libxext-dev +Standards-Version: 3.8.1.0 +Homepage: http://sourceforge.net/projects/sapphire + +Package: sapphire +Architecture: any +Depends: ${shlibs:Depends} +Provides: x-window-manager +Suggests: menu (>>1.5) +Recommends: xfonts-100dpi | xfonts-75dpi +Description: A minimal but configurable X11R6 window manager + Sapphire is a window manager for X11R6. It is fairly minimal in + what it provides on screen: one toolbar, the usual window borders + and a popup menu from the root window. + . + It supports themes as X resource files, and the menu is editable. + If you install the 'menu' package, you'll get an automatically updated + 'Debian' submenu of installed programs. --- sapphire-0.15.8.orig/debian/copyright +++ sapphire-0.15.8/debian/copyright @@ -0,0 +1,27 @@ +This package was debianized by Chris Boyle on +Mon, 17 Dec 2001 09:48:50 +0000. + +It was downloaded from ftp://ftp.sourceforge.net/pub/sourceforge/sapphire/ + +Upstream Author: Frank Hale + +Copyright: + +Copyright (C) 1999,2000,2001 Frank Hale +frankhale@yahoo.com +http://sapphire.sourceforge.net/ + + 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. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in file /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth + Floor, Boston, MA 02110-1301, USA. --- sapphire-0.15.8.orig/debian/dirs +++ sapphire-0.15.8/debian/dirs @@ -0,0 +1,2 @@ +usr/bin +etc/X11/sapphire --- sapphire-0.15.8.orig/debian/docs +++ sapphire-0.15.8/debian/docs @@ -0,0 +1,4 @@ +HISTORY +ISSUES +NEWS +README --- sapphire-0.15.8.orig/debian/links +++ sapphire-0.15.8/debian/links @@ -0,0 +1 @@ +etc/X11/sapphire/menu usr/share/sapphire/menu --- sapphire-0.15.8.orig/debian/menu +++ sapphire-0.15.8/debian/menu @@ -0,0 +1,2 @@ +?package(sapphire):needs="wm" section="Window Managers"\ + title="Sapphire" command="/usr/bin/sapphire" --- sapphire-0.15.8.orig/debian/menu-method +++ sapphire-0.15.8/debian/menu-method @@ -0,0 +1,50 @@ +#!/usr/bin/install-menu +# +# menu-method for Sapphire window manager +# Copyright (C) 2001 Chris Boyle +# +# 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 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. +# +# On Debian systems, the complete text of the GNU General Public +# License can be found in /usr/share/common-licenses/GPL +# + +!include menu.h + +outputencoding="ASCII" + +function item($i, $t, $c) = \ + nstring(add("1",level())," ") $i " (" esc($t,"(){}[]") ") {" \ + esc($c,"(){}[]") "}\n" + +supported + x11= item("exec", $title, $command) +# wm= item("exec", $title, "sh -c 'skill sapphire; exec " $command "'") + wm= item("wmexec", $title, $command) + text= item("exec", $title, "x-terminal-emulator -T '" $title "' -e " $command) +endsupported + +treewalk="(cm)" +startmenu= \ + nstring(add("1",level())," ") "submenu (" $title ")\n" \ + nstring(add("1",level())," ") "{\n" +endmenu=nstring(add("1",level())," ") "}\n" +submenutitle="" + +# no comment support?!? +preoutput="" + +# user's version won't actually be read (yet) +userprefix=".sapphire/menu" +rootprefix="/etc/X11/sapphire/menu" +genmenu="menu-defs.hook" +examplercfile="default-menu" +rcfile="default" --- sapphire-0.15.8.orig/debian/postinst +++ sapphire-0.15.8/debian/postinst @@ -0,0 +1,53 @@ +#! /bin/sh +# postinst script for sapphire +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see /usr/share/doc/packaging-manual/ +# +# quoting from the policy: +# Any necessary prompting should almost always be confined to the +# post-installation script, and should be protected with a conditional +# so that unnecessary prompting doesn't happen if a package's +# installation fails and the `postinst' is called with `abort-upgrade', +# `abort-remove' or `abort-deconfigure'. + +case "$1" in + configure) + if [ -x `which update-alternatives` ]; then + update-alternatives \ + --install /usr/bin/x-window-manager x-window-manager \ + /usr/bin/sapphire 50 \ + --slave /usr/share/man/man1/x-window-manager.1.gz \ + x-window-manager.1.gz /usr/share/man/man1/sapphire.1.gz + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 0 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + --- sapphire-0.15.8.orig/debian/postrm +++ sapphire-0.15.8/debian/postrm @@ -0,0 +1,39 @@ +#! /bin/sh +# postrm script for sapphire +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' overwrit>r> +# for details, see /usr/share/doc/packaging-manual/ + +case "$1" in + purge|failed-upgrade|abort-install|disappear) + # files generated by the menu-method + rm -f /etc/X11/sapphire/menu/menu-defs.hook \ + /etc/X11/sapphire/menu/default + ;; + + remove|upgrade|abort-upgrade) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 0 + +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + --- sapphire-0.15.8.orig/debian/prerm +++ sapphire-0.15.8/debian/prerm @@ -0,0 +1,39 @@ +#! /bin/sh +# prerm script for sapphire +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see /usr/share/doc/packaging-manual/ + +case "$1" in + remove|upgrade|deconfigure) + if [ -x `which update-alternatives` ]; then + update-alternatives --remove x-window-manager \ + /usr/bin/sapphire + fi + ;; + failed-upgrade) + ;; + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 0 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + --- sapphire-0.15.8.orig/debian/rules +++ sapphire-0.15.8/debian/rules @@ -0,0 +1,86 @@ +#!/usr/bin/make -f +# Based on sample debian/rules from debhelper, +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + COMPILER_FLAGS += CFLAGS="-O0 -g -Wall" +else + COMPILER_FLAGS += CFLAGS="-O2 -g -Wall" +endif + +#configure: configure-stamp +#configure-stamp: +# dh_testdir +# # Add here commands to configure the package. +# +# +# touch configure-stamp + +#build: configure-stamp build-stamp +build: build-stamp +build-stamp: + dh_testdir + + # compile the package + $(MAKE) $(COMPILER_FLAGS) + + /usr/bin/docbook-to-man debian/sapphire.sgml > debian/sapphire.1 + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + # clean up after the build process + [ ! -f Makefile ] || $(MAKE) clean + + rm -f debian/sapphire.1 + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_prep + dh_installdirs + + # install the package into debian/sapphire + $(MAKE) install DESTDIR=$(CURDIR)/debian/sapphire + + mv debian/sapphire/usr/share/sapphire/menu debian/sapphire/etc/X11/sapphire/menu + mv debian/sapphire/etc/X11/sapphire/menu/default debian/sapphire/etc/X11/sapphire/menu/default-menu + mkdir -p debian/sapphire/usr/share/xsessions + install -m 644 debian/sapphire.desktop debian/sapphire/usr/share/xsessions/sapphire.desktop + +# build architecture-independent files +binary-indep: build install +# We have nothing to do by default. + +# build architecture-dependent files +binary-arch: build install + dh_testdir + dh_testroot + dh_installdocs +# dh_installexamples + dh_installmenu + dh_installman debian/sapphire.1 + dh_installchangelogs ChangeLog + dh_link +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + dh_strip +endif + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure --- sapphire-0.15.8.orig/debian/sapphire.desktop +++ sapphire-0.15.8/debian/sapphire.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=sapphire +Comment=minimal but configurable window manager +Exec=sapphire +Terminal=False +TryExec=sapphire +Type=Application + +[Window Manager] +SessionManaged=false + --- sapphire-0.15.8.orig/debian/sapphire.sgml +++ sapphire-0.15.8/debian/sapphire.sgml @@ -0,0 +1,175 @@ + manpage.1'. You may view + the manual page with: `docbook-to-man manpage.sgml | nroff -man | + less'. A typical entry in a Makefile or Makefile.am is: + +manpage.1: manpage.sgml + docbook-to-man $< > $@ + --> + + + Chris"> + Boyle"> + + December 17, 2001"> + + 1"> + cmb@debian.org"> + + SAPPHIRE"> + + + Debian GNU/Linux"> + GNU"> +]> + + + +
+ &dhemail; +
+ + &dhfirstname; + &dhsurname; + + + 2001 + &dhusername; + + &dhdate; +
+ + &dhucpackage; + + &dhsection; + + + &dhpackage; + + minimal but configurable window manager + + + + &dhpackage; + + + + + + DESCRIPTION + + This manual page documents briefly the + &dhpackage; command. + + This manual page was written for the &debian; distribution + because the original program does not have a manual page. + + &dhpackage; is a minimal but configurable + window manager for X11R6. It supports themes in the form of X resource + files, and has a customisable menu. + + The Debian version receives Debian menu entries automatically + in a "Debian" submenu by default, you can add entries + specifically to sapphire (in the rest of the menu) in the + default-menu file. For more information, see + update-menus (1) and the FILES section below. + + Users can also set their own options in + $HOME/.sapphire/wmconf (an X resource file). + + + + OPTIONS + + + + + + Use the X-server display 'displayname'. + + + + + + Show version of program. + + + + + + FILES + + + + /etc/X11/sapphire/menu/default-menu + menu entries specific to sapphire (you can edit this one, it's + a conffile) + + + /etc/X11/sapphire/menu/menudefs.hook + Debian menu entries in sapphire's format, not + read directly, do not edit (edit default-menu + instead) + + + /etc/X11/sapphire/menu/default + this menu file is the one sapphire actually reads, it is + automatically generated from the other two by update-menus, do not edit + (edit default-menu instead) + + + $HOME/.sapphire/wmconf + user-specific options + + + /usr/share/sapphire/themes + themes directory, all of the above may refer to themes from + here (the files themselves are X resource files) + + + + + HISTORY + + Sapphire was originally developed from Decklin Foster's aewm, and + also uses some code from Blackbox (for gradients). + + + SEE ALSO + + XFree86 (1), update-menus (1). + + + + AUTHOR + + This manual page was written by &dhusername; <&dhemail;> for + the &debian; system (but may be used by others). Permission is + granted to copy, distribute and/or modify this document under + the terms of the GNU Free Documentation + License, Version 1.1 or any later version published by the Free + Software Foundation; with no Invariant Sections, no Front-Cover + Texts and no Back-Cover Texts. + + +
+ + --- sapphire-0.15.8.orig/debian/watch +++ sapphire-0.15.8/debian/watch @@ -0,0 +1,2 @@ +version=3 +http://sf.net/sapphire/sapphire-(.+)\.tar\.gz --- sapphire-0.15.8.orig/linkedlist.cc +++ sapphire-0.15.8/linkedlist.cc @@ -21,6 +21,7 @@ */ +#include #include #include "linkedlist.hh" using namespace std; --- sapphire-0.15.8.orig/menulex.cc +++ sapphire-0.15.8/menulex.cc @@ -1,427 +1,487 @@ -/* - * Copyright (C) 1999,2000,2001 Frank Hale - * frankhale@yahoo.com - * http://sapphire.sourceforge.net/ - * - * Updated: 3 Nov 2001 - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -#include "sapphire.hh" - -MenuLex::MenuLex(char *filename, RootMenu *menu) : Scanner(filename) -{ - root = menu; - - menulist = wm->getMenuList(); - - error=false; - - submenus=1; - - name=new char[255]; - exe=new char[255]; -} - -MenuLex::~MenuLex() -{ - delete [] name; - delete [] exe; -} - -BaseMenu* MenuLex::getLastMenu() -{ - if(menulist->count()) - return menulist->last(); - - return NULL; -} - -BaseMenu* MenuLex::getMenu(int index) -{ - int counter=0; - - if(index==0) return root; - - LinkedListIterator it(menulist); - for(; it.current(); it++) - { - if(counter==index) return it.current(); - - counter++; - } - - return NULL; -} - - -void MenuLex::parse() -{ - // Check to see if this menu file is gramatically correct. - do { - - getNextToken(); - - } while(menu(true)); - - // If we didn't get any errors when we validated the menu - // then lets build the menu. - if(!error) { - - rewind(); - - do { - - getNextToken(); - - } while(menu(false)); - - LinkedListIterator it(menulist); - for(; it.current(); it++) - { - it.current()->update_all(); - } - } - else { - - // If there was an error use the default menu. - - root->defaultMenu(); - } - -} - -bool MenuLex::menu(bool validate) -{ - if(match("menu")) - { - getNextToken(); - - if(match("(")) - { - clearToken(); - getNextToken(true); - strcpy(name, currentToken()); - //printf("name = %s\n", currentToken()); - - if(! validate) - root->setMenuTitle(name); - - getNextToken(); - if(match(")")) - { - getNextToken(); - - if(match("{")) - { - getNextToken(); - - if(match("}")) - { - printf("There was an error parsing your menu configuration file, I have to use the default menu because of this problem.\n"); - error = true; - return true; - } else - { - - while(statement(root, validate)) { - getNextToken(); - } - - if(match("}")) - { - return true; - } else { - printf("missing } near (%s)\n", name); - error = true; - return false; - } - - } - } else { - printf("missing { near menu\n"); - error = true; - return false; - } - - } else { - printf("missing ) near menu\n"); - error = true; - return false; - } - - } else { - printf("missing ( near menu\n"); - error = true; - return false; - } - } - - return false; -} - -bool MenuLex::submenu(BaseMenu *sub, bool validate) -{ +/* + * Copyright (C) 1999,2000,2001 Frank Hale + * frankhale@yahoo.com + * http://sapphire.sourceforge.net/ + * + * Updated: 3 Nov 2001 + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#include "sapphire.hh" + +MenuLex::MenuLex(char *filename, RootMenu *menu) : Scanner(filename) +{ + root = menu; + + menulist = wm->getMenuList(); + + error=false; + + submenus=1; + + name=new char[255]; + exe=new char[255]; +} + +MenuLex::~MenuLex() +{ + delete [] name; + delete [] exe; +} + +BaseMenu* MenuLex::getLastMenu() +{ + if(menulist->count()) + return menulist->last(); + + return NULL; +} + +BaseMenu* MenuLex::getMenu(int index) +{ + int counter=0; + + if(index==0) return root; + + LinkedListIterator it(menulist); + for(; it.current(); it++) + { + if(counter==index) return it.current(); + + counter++; + } + + return NULL; +} + + +void MenuLex::parse() +{ + // Check to see if this menu file is gramatically correct. + do { + + getNextToken(); + + } while(menu(true)); + + // If we didn't get any errors when we validated the menu + // then lets build the menu. + if(!error) { + + rewind(); + + do { + + getNextToken(); + + } while(menu(false)); + + LinkedListIterator it(menulist); + for(; it.current(); it++) + { + it.current()->update_all(); + } + } + else { + + // If there was an error use the default menu. + + root->defaultMenu(); + } + +} + +bool MenuLex::menu(bool validate) +{ + if(match("menu")) + { + getNextToken(); + + if(match("(")) + { + clearToken(); + getNextToken(true); + strcpy(name, currentToken()); + //printf("name = %s\n", currentToken()); + + if(! validate) + root->setMenuTitle(name); + + getNextToken(); + if(match(")")) + { + getNextToken(); + + if(match("{")) + { + getNextToken(); + + if(match("}")) + { + printf("There was an error parsing your menu configuration file, I have to use the default menu because of this problem.\n"); + error = true; + return true; + } else + { + + while(statement(root, validate)) { + getNextToken(); + } + + if(match("}")) + { + return true; + } else { + printf("missing } near (%s)\n", name); + error = true; + return false; + } + + } + } else { + printf("missing { near menu\n"); + error = true; + return false; + } + + } else { + printf("missing ) near menu\n"); + error = true; + return false; + } + + } else { + printf("missing ( near menu\n"); + error = true; + return false; + } + } + + return false; +} + +bool MenuLex::submenu(BaseMenu *sub, bool validate) +{ BaseMenu *child=NULL; - if(match("submenu")) - { - getNextToken(); - - if(match("(")) - { - clearToken(); - getNextToken(true); - strcpy(name, currentToken()); - - getNextToken(); - if(match(")")) - { - getNextToken(); - - if(match("{")) - { - getNextToken(); - - if(! validate) - { + if(match("submenu")) + { + getNextToken(); + + if(match("(")) + { + clearToken(); + getNextToken(true); + strcpy(name, currentToken()); + + getNextToken(); + if(match(")")) + { + getNextToken(); + + if(match("{")) + { + getNextToken(); + + if(! validate) + { child = new BaseMenu(); child->setMenuTitle(name); menulist->insert(child); sub->insert(name, child); - } - - while(statement(child, validate)) { - getNextToken(); - } - - if(match("}")) - { - if(! validate) - { - submenus=0; - } - - return true; - } - - } else { - printf("missing { near submenu\n"); - error = true; - return false; - } - - } else { - printf("missing ) near submenu\n"); - error = true; - return false; - } - - } else { - printf("missing ( near submenu\n"); - error = true; - return false; - } - } - - return false; -} - -bool MenuLex::separator(BaseMenu *sub, bool validate) -{ - if(match("separator")) - { - if(! validate) - sub->insert("separator", "", 2); - - return true; - } - - return false; -} - -bool MenuLex::exit(BaseMenu* sub, bool validate) -{ - if(match("exit")) - { - if(! validate) - sub->insert("exit", "", 1); - - return true; - } - - return false; -} - -bool MenuLex::restart(BaseMenu* sub, bool validate) -{ - if(match("restart")) - { - if(! validate) - sub->insert("restart", "", 4); - - return true; - } - - return false; -} - -bool MenuLex::reconfigure(BaseMenu* sub, bool validate) -{ - if(match("reconfigure")) - { - if(! validate) - sub->insert("reconfigure", "", 5); - - return true; - } - - return false; -} - -bool MenuLex::exec(BaseMenu *sub, bool validate) -{ - if(match("exec")) - { - getNextToken(); - - if(match("(")) - { - clearToken(); - getNextToken(true); - strcpy(name, currentToken()); - //printf("name = %s\n", name); - - getNextToken(); - if(match(")")) - { - getNextToken(); - - if(match("{")) - { - clearToken(); - getNextToken(true); - - strcpy(exe, currentToken()); - //printf("exec: %s\n", currentToken()); - - if(! validate) - { - //printf("sub1's name = %s | inserting %s\n", sub1->getMenuTitle(), name); - sub->insert(name, exe, 0); - } - - getNextToken(); - - if(match("}")) - return true; - - } else { - printf("missing { near exec\n"); - error = true; - return false; - } - - } else { - printf("missing ) near exec\n"); - error = true; - return false; - } - - } else { - printf("missing ( near exec\n"); - error = true; - return false; - } - } - - return false; -} - -bool MenuLex::theme(BaseMenu *sub, bool validate) -{ - if(match("theme")) - { - getNextToken(); - - if(match("(")) - { - clearToken(); - getNextToken(true); - strcpy(name, currentToken()); - //printf("theme name = %s\n", name); - - getNextToken(); - if(match(")")) - { - getNextToken(); - - if(match("{")) - { - clearToken(); - getNextToken(true); - - - strcpy(exe, currentToken()); - //printf("theme patch: %s\n", currentToken()); - - if(! validate) - { - //printf("sub1's name = %s | inserting %s\n", sub1->getMenuTitle(), name); - sub->insert(name, exe, 6); - } - - getNextToken(); - - if(match("}")) - return true; - - } else { - printf("missing { near theme\n"); - error = true; - return false; - } - - } else { - printf("missing ) near theme\n"); - error = true; - return false; - } - - } else { - printf("missing ( near theme\n"); - error = true; - return false; - } - } - - return false; -} - -bool MenuLex::statement(BaseMenu *sub, bool validate) -{ - // This dispatches each statement function. - - if(submenu(sub, validate)) return true; - if(exec(sub, validate)) return true; - if(theme(sub, validate)) return true; - if(separator(sub, validate)) return true; - if(exit(sub, validate)) return true; - if(restart(sub, validate)) return true; - if(reconfigure(sub, validate)) return true; - - return false; -} + } + + while(statement(child, validate)) { + getNextToken(); + } + + if(match("}")) + { + if(! validate) + { + submenus=0; + } + + return true; + } + + } else { + printf("missing { near submenu\n"); + error = true; + return false; + } + + } else { + printf("missing ) near submenu\n"); + error = true; + return false; + } + + } else { + printf("missing ( near submenu\n"); + error = true; + return false; + } + } + + return false; +} + +bool MenuLex::separator(BaseMenu *sub, bool validate) +{ + if(match("separator")) + { + if(! validate) + sub->insert("separator", "", 2); + + return true; + } + + return false; +} + +bool MenuLex::exit(BaseMenu* sub, bool validate) +{ + if(match("exit")) + { + if(! validate) + sub->insert("exit", "", 1); + + return true; + } + + return false; +} + +bool MenuLex::restart(BaseMenu* sub, bool validate) +{ + if(match("restart")) + { + if(! validate) + sub->insert("restart", "", 4); + + return true; + } + + return false; +} + +bool MenuLex::reconfigure(BaseMenu* sub, bool validate) +{ + if(match("reconfigure")) + { + if(! validate) + sub->insert("reconfigure", "", 5); + + return true; + } + + return false; +} + +bool MenuLex::exec(BaseMenu *sub, bool validate) +{ + if(match("exec")) + { + getNextToken(); + + if(match("(")) + { + clearToken(); + getNextToken(true); + strcpy(name, currentToken()); + //printf("name = %s\n", name); + + getNextToken(); + if(match(")")) + { + getNextToken(); + + if(match("{")) + { + clearToken(); + getNextToken(true); + + strcpy(exe, currentToken()); + //printf("exec: %s\n", currentToken()); + + if(! validate) + { + //printf("sub1's name = %s | inserting %s\n", sub1->getMenuTitle(), name); + sub->insert(name, exe, 0); + } + + getNextToken(); + + if(match("}")) + return true; + + } else { + printf("missing { near exec\n"); + error = true; + return false; + } + + } else { + printf("missing ) near exec\n"); + error = true; + return false; + } + + } else { + printf("missing ( near exec\n"); + error = true; + return false; + } + } + + return false; +} + +bool MenuLex::wmexec(BaseMenu *sub, bool validate) +{ + if(match("wmexec")) + { + getNextToken(); + + if(match("(")) + { + clearToken(); + getNextToken(true); + strcpy(name, currentToken()); + //printf("name = %s\n", name); + + getNextToken(); + if(match(")")) + { + getNextToken(); + + if(match("{")) + { + clearToken(); + getNextToken(true); + + strcpy(exe, currentToken()); + //printf("wmexec: %s\n", currentToken()); + + if(! validate) + { + //printf("sub1's name = %s | inserting %s\n", sub1->getMenuTitle(), name); + sub->insert(name, exe, 3); + } + + getNextToken(); + + if(match("}")) + return true; + + } else { + printf("missing { near wmexec\n"); + error = true; + return false; + } + + } else { + printf("missing ) near wmexec\n"); + error = true; + return false; + } + + } else { + printf("missing ( near wmexec\n"); + error = true; + return false; + } + } + + return false; +} + +bool MenuLex::theme(BaseMenu *sub, bool validate) +{ + if(match("theme")) + { + getNextToken(); + + if(match("(")) + { + clearToken(); + getNextToken(true); + strcpy(name, currentToken()); + //printf("theme name = %s\n", name); + + getNextToken(); + if(match(")")) + { + getNextToken(); + + if(match("{")) + { + clearToken(); + getNextToken(true); + + + strcpy(exe, currentToken()); + //printf("theme patch: %s\n", currentToken()); + + if(! validate) + { + //printf("sub1's name = %s | inserting %s\n", sub1->getMenuTitle(), name); + sub->insert(name, exe, 6); + } + + getNextToken(); + + if(match("}")) + return true; + + } else { + printf("missing { near theme\n"); + error = true; + return false; + } + + } else { + printf("missing ) near theme\n"); + error = true; + return false; + } + + } else { + printf("missing ( near theme\n"); + error = true; + return false; + } + } + + return false; +} + +bool MenuLex::statement(BaseMenu *sub, bool validate) +{ + // This dispatches each statement function. + + if(submenu(sub, validate)) return true; + if(exec(sub, validate)) return true; + if(wmexec(sub, validate)) return true; + if(theme(sub, validate)) return true; + if(separator(sub, validate)) return true; + if(exit(sub, validate)) return true; + if(restart(sub, validate)) return true; + if(reconfigure(sub, validate)) return true; + + return false; +} --- sapphire-0.15.8.orig/menulex.hh +++ sapphire-0.15.8/menulex.hh @@ -1,64 +1,65 @@ -/* - * Copyright (C) 1999,2000,2001 Frank Hale - * frankhale@yahoo.com - * http://sapphire.sourceforge.net/ - * - * Updated: 3 Nov 2001 - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -#ifndef _MENULEX_HH_ -#define _MENULEX_HH_ - -class MenuLex : public Scanner -{ -private: /* variables */ - - char* name; // Name displayed in menu title - char* exe; - - RootMenu *root; - - LinkedList *menulist; - - int submenus; - - bool error; - -public: /* Constructor, Destructor and Member functions */ - MenuLex(char *filename, RootMenu *menu); - ~MenuLex(); - - void parse(); - -private: /* Member functions */ - bool menu(bool validate); - bool exec(BaseMenu *sub, bool validate); - bool theme(BaseMenu *sub, bool validate); - bool submenu(BaseMenu *sub, bool validate); - bool separator(BaseMenu *sub, bool validate); - bool exit(BaseMenu* sub, bool validate); - bool restart(BaseMenu* sub, bool validate); - bool reconfigure(BaseMenu* sub, bool validate); - - BaseMenu* getMenu(int index); - BaseMenu* getLastMenu(); - - bool statement(BaseMenu *sub, bool validate); -}; - -#endif +/* + * Copyright (C) 1999,2000,2001 Frank Hale + * frankhale@yahoo.com + * http://sapphire.sourceforge.net/ + * + * Updated: 3 Nov 2001 + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifndef _MENULEX_HH_ +#define _MENULEX_HH_ + +class MenuLex : public Scanner +{ +private: /* variables */ + + char* name; // Name displayed in menu title + char* exe; + + RootMenu *root; + + LinkedList *menulist; + + int submenus; + + bool error; + +public: /* Constructor, Destructor and Member functions */ + MenuLex(char *filename, RootMenu *menu); + ~MenuLex(); + + void parse(); + +private: /* Member functions */ + bool menu(bool validate); + bool exec(BaseMenu *sub, bool validate); + bool wmexec(BaseMenu *sub, bool validate); + bool theme(BaseMenu *sub, bool validate); + bool submenu(BaseMenu *sub, bool validate); + bool separator(BaseMenu *sub, bool validate); + bool exit(BaseMenu* sub, bool validate); + bool restart(BaseMenu* sub, bool validate); + bool reconfigure(BaseMenu* sub, bool validate); + + BaseMenu* getMenu(int index); + BaseMenu* getLastMenu(); + + bool statement(BaseMenu *sub, bool validate); +}; + +#endif --- sapphire-0.15.8.orig/windowmanager.cc +++ sapphire-0.15.8/windowmanager.cc @@ -1,860 +1,865 @@ -/* - * Copyright (C) 1999,2000,2001 Frank Hale - * frankhale@yahoo.com - * http://sapphire.sourceforge.net/ - * - * Updated: 3 Nov 2001 - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include "windowmanager.hh" - -WindowManager *wm; - -char* windowmanager_author = "Frank Hale"; -char* windowmanager_author_email = "frankhale@yahoo.com"; -char* windowmanager_name = "sapphire"; -char* windowmanager_version = "Sapphire 0.15.7pre7 (Blackberry)"; -char* windowmanager_usage = "[-display ] [-version]\n"; -char* windowmanager_exit_message = "\nThank you for using Sapphire.\n\nPlease Send all bug reports, suggestions, ideas, patches to frankhale@yahoo.com\n"; - -char* configuration_home = "/usr/share/sapphire"; - -char* HOME; - -// This function sets up default values for variables, gets command line args, -// sets up our signal handlers, and performs initialization of certain things -// to get ready for the window manager to start managing windows. -WindowManager::WindowManager(int argc, char **argv) -{ - ::wm = this; - - HOME = new char[strlen(getenv("HOME"))+1]; - strcpy(HOME, getenv("HOME")); - - font_pix = None; - - menu_event = false; - - clock_format = "%m %d %H:%M"; - toolbar_visible = true; - toolbar_position = false; - - configurationPath = NULL; - windowmanager_conf = NULL; - display = NULL; - - XSetWindowAttributes attr; - XColor dummy; - - head_client = new Client(); - - // Allocate memory for our linked lists. - ClientList = new LinkedList; - menulist = new LinkedList; - extramenulist = new LinkedList; - - for (int i = 1; i < argc; i++) - { - if ((strcmp(argv[i], "-display")==0) && i+1dpy, XC_left_ptr)); - - // Atoms - xa_wm_state = XInternAtom(dpy, "WM_STATE", False); - xa_wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False); - xa_wm_protos = XInternAtom(dpy, "WM_PROTOCOLS", False); - xa_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - xa_wm_cmapwins = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False); - xa_wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False); - xa_wm_motif_hints = XInternAtom(dpy, "_MOTIF_WM_HINTS", False); - - foreground_color = DEFAULT_FOREGROUND_COLOR; - background_color = DEFAULT_BACKGROUND_COLOR; - border_color = DEFAULT_BORDER_COLOR; - - // Colors - XAllocNamedColor(dpy, DefaultColormap(dpy, screen), foreground_color, &xforeground_color, &dummy); - XAllocNamedColor(dpy, DefaultColormap(dpy, screen), background_color, &xbackground_color, &dummy); - XAllocNamedColor(dpy, DefaultColormap(dpy, screen), border_color, &xborder_color, &dummy); - - colors_per_channel = 4; - image_dither = True; - - image_control = new BImageControl(); - image_control->installRootColormap(); - - theme = new Theme(); - - getCurrentTheme(); - - font = theme->getFont(); - menufont = theme->getMenuFont(); - - xfont = XLoadQueryFont(dpy, font); - - if (!xfont) - { - // We should really check here to see if we can - // find another font just incase. Dying here without - // checking again is not cool! - - err("the default font was not found, aborting."); - exit(-1); - } - - iheight = xfont->ascent + xfont->descent + 2 * DEFAULT_SPACE; - - font_position = iheight - xfont->descent; - - if(! QueryShapeExtentions()) - { - printf("What no shape extentions, God you must be using an old X11 release.\n\nHave a nice life\n\nBa Bye...\n\n"); - } - - move_curs = XCreateFontCursor(dpy, XC_fleur); - resize_curs = XCreateFontCursor(dpy, XC_plus); - left_arrow = XCreateFontCursor(dpy, XC_left_ptr); - - createFontPixmap(); - - gv.font = xfont->fid; - gv.tile = font_pix; - string_gc = XCreateGC(dpy, root, GCTile | GCFont , &gv); - XSetFillStyle(dpy, string_gc, FillTiled); - - gv.foreground = xborder_color.pixel; - gv.line_width = DEFAULT_BORDER_SIZE; - border_gc = XCreateGC(dpy, root, GCForeground | GCLineWidth, &gv); - - gv.function = GXinvert; - gv.subwindow_mode = IncludeInferiors; - invert_gc = XCreateGC(dpy, root, GCFunction | GCSubwindowMode | GCLineWidth, &gv); - - attr.event_mask = SubstructureRedirectMask | - SubstructureNotifyMask | - ColormapChangeMask | - ButtonPressMask | - ButtonReleaseMask | - PropertyChangeMask | - PointerMotionMask | - FocusChangeMask | - KeyPressMask | - ExposureMask ; - - XChangeWindowAttributes(dpy, root, CWEventMask, &attr); - - xres = WidthOfScreen(ScreenOfDisplay(wm->dpy, wm->screen)); - yres = HeightOfScreen(ScreenOfDisplay(wm->dpy, wm->screen)); - - rm = new RootMenu(); - t = new Toolbar(); - im = new IconMenu(); - - addToMenuList(rm); - rm->parseMenuConfigurationFile(); - - t->getToolbarMenu()->addMenu("icon menu", im); - t->getToolbarMenu()->addMenu("root menu", rm); - t->getToolbarMenu()->update_all(); - - scan_windows(); - - do_event_loop(); -} - -WindowManager::~WindowManager() -{ - unsigned int i, nwins; - Window dw1, dw2, *wins; - Client *temp_client=NULL; - - XQueryTree(dpy, root, &dw1, &dw2, &wins, &nwins); - for (i = 0; i < nwins; i++) - { - temp_client = head_client->find_client(wins[i]); - - if(temp_client) - { - temp_client->remove_client(temp_client); - } - - } - XFree(wins); - - ClientList->removeAll(); - - delete head_client; - delete ClientList; - - image_control->removeImage(font_pix); - - XFreeFont(dpy, xfont); - - XFreeGC(dpy, invert_gc); - XFreeGC(dpy, string_gc); - XFreeGC(dpy, border_gc); - - delete t; - delete rm; - delete im; - - menulist->removeAll(); - - extramenulist->removeAll(); - - delete menulist; - delete extramenulist; - - delete theme; - - - - delete image_control; - - delete [] HOME; - delete [] windowmanager_conf; - delete [] configurationPath; -} - -void WindowManager::getCurrentTheme() -{ - XrmDatabase resource_db; - XrmValue value; - char *value_type; - FILE* currentTheme; - bool themeLoaded = false; - - windowmanager_conf = new char[strlen(HOME) + 32]; - sprintf(windowmanager_conf, "%s/.sapphire/wmconf", HOME); - - if((currentTheme = fopen(windowmanager_conf, "r"))!=NULL) - { - fclose(currentTheme); - - XrmInitialize(); - - resource_db = XrmGetFileDatabase(windowmanager_conf); - - if (XrmGetResource(resource_db, "toolbar.visible", - "Toolbar.Visible", &value_type, &value)) - { - if(strcmp(value.addr, "true")==0) - { - theme->setToolbarVisible(); - toolbar_visible=true; - } else { - toolbar_visible=false; - } - } - - if (XrmGetResource(resource_db, "toolbar.position", - "Toolbar.Position", &value_type, &value)) - { - if(strcmp(value.addr, "top")==0) - { - theme->setToolbarTop(); - toolbar_position = true; - } else { - toolbar_position = false; - } - } - - // Clock format - if (XrmGetResource(resource_db,"clock.format","Clock.Format",&value_type,&value)) - { - clock_format= new char[value.size]; - strcpy(clock_format,value.addr); - } else { - clock_format="%m %d %H:%M"; - } - - if (XrmGetResource(resource_db, "start.theme", - "Start.Theme", &value_type, &value)) - { - char *buffer = new char[value.size+strlen(HOME)]; - - strcpy(buffer, value.addr); - - if (value.addr[0] == '~') - { - sprintf(buffer, "%s%s", HOME, value.addr+1); - } - - if((currentTheme = fopen(buffer, "r"))!=NULL) - { - fclose(currentTheme); - theme->parseTheme(buffer); - themeLoaded=true; - } - - delete [] buffer; - } - - XrmDestroyDatabase(resource_db); - - } +/* + * Copyright (C) 1999,2000,2001 Frank Hale + * frankhale@yahoo.com + * http://sapphire.sourceforge.net/ + * + * Updated: 3 Nov 2001 + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "windowmanager.hh" + +WindowManager *wm; + +char* windowmanager_author = "Frank Hale"; +char* windowmanager_author_email = "frankhale@yahoo.com"; +char* windowmanager_name = "sapphire"; +char* windowmanager_version = "Sapphire 0.15.8"; +char* windowmanager_usage = "[-display ] [-version]\n"; +char* windowmanager_exit_message = "\nThank you for using Sapphire.\n\nPlease Send all bug reports, suggestions, ideas, patches to frankhale@yahoo.com\n"; + +char* configuration_home = "/usr/share/sapphire"; + +char* HOME; + +// This function sets up default values for variables, gets command line args, +// sets up our signal handlers, and performs initialization of certain things +// to get ready for the window manager to start managing windows. +WindowManager::WindowManager(int argc, char **argv) +{ + ::wm = this; + + HOME = new char[strlen(getenv("HOME"))+1]; + strcpy(HOME, getenv("HOME")); + + font_pix = None; + + menu_event = false; + + clock_format = "%m %d %H:%M"; + toolbar_visible = true; + toolbar_position = false; + + configurationPath = NULL; + windowmanager_conf = NULL; + display = NULL; + + XSetWindowAttributes attr; + XColor dummy; + + head_client = new Client(); + + // Allocate memory for our linked lists. + ClientList = new LinkedList; + menulist = new LinkedList; + extramenulist = new LinkedList; + + for (int i = 1; i < argc; i++) + { + if ((strcmp(argv[i], "-display")==0) && i+1dpy, XC_left_ptr)); + + // Atoms + xa_wm_state = XInternAtom(dpy, "WM_STATE", False); + xa_wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False); + xa_wm_protos = XInternAtom(dpy, "WM_PROTOCOLS", False); + xa_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + xa_wm_cmapwins = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False); + xa_wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + xa_wm_motif_hints = XInternAtom(dpy, "_MOTIF_WM_HINTS", False); + + foreground_color = DEFAULT_FOREGROUND_COLOR; + background_color = DEFAULT_BACKGROUND_COLOR; + border_color = DEFAULT_BORDER_COLOR; + + // Colors + XAllocNamedColor(dpy, DefaultColormap(dpy, screen), foreground_color, &xforeground_color, &dummy); + XAllocNamedColor(dpy, DefaultColormap(dpy, screen), background_color, &xbackground_color, &dummy); + XAllocNamedColor(dpy, DefaultColormap(dpy, screen), border_color, &xborder_color, &dummy); + + colors_per_channel = 4; + image_dither = True; + + image_control = new BImageControl(); + image_control->installRootColormap(); + + theme = new Theme(); + + getCurrentTheme(); + + font = theme->getFont(); + menufont = theme->getMenuFont(); + + xfont = XLoadQueryFont(dpy, font); + + if (!xfont) + { + // We should really check here to see if we can + // find another font just incase. Dying here without + // checking again is not cool! + + err("the default font was not found, aborting."); + exit(-1); + } + + iheight = xfont->ascent + xfont->descent + 2 * DEFAULT_SPACE; + + font_position = iheight - xfont->descent; + + if(! QueryShapeExtentions()) + { + printf("What no shape extentions, God you must be using an old X11 release.\n\nHave a nice life\n\nBa Bye...\n\n"); + } + + move_curs = XCreateFontCursor(dpy, XC_fleur); + resize_curs = XCreateFontCursor(dpy, XC_plus); + left_arrow = XCreateFontCursor(dpy, XC_left_ptr); + + createFontPixmap(); + + gv.font = xfont->fid; + gv.tile = font_pix; + string_gc = XCreateGC(dpy, root, GCTile | GCFont , &gv); + XSetFillStyle(dpy, string_gc, FillTiled); + + gv.foreground = xborder_color.pixel; + gv.line_width = DEFAULT_BORDER_SIZE; + border_gc = XCreateGC(dpy, root, GCForeground | GCLineWidth, &gv); + + gv.function = GXinvert; + gv.subwindow_mode = IncludeInferiors; + invert_gc = XCreateGC(dpy, root, GCFunction | GCSubwindowMode | GCLineWidth, &gv); + + attr.event_mask = SubstructureRedirectMask | + SubstructureNotifyMask | + ColormapChangeMask | + ButtonPressMask | + ButtonReleaseMask | + PropertyChangeMask | + PointerMotionMask | + FocusChangeMask | + KeyPressMask | + ExposureMask ; + + XChangeWindowAttributes(dpy, root, CWEventMask, &attr); + + xres = WidthOfScreen(ScreenOfDisplay(wm->dpy, wm->screen)); + yres = HeightOfScreen(ScreenOfDisplay(wm->dpy, wm->screen)); + + rm = new RootMenu(); + t = new Toolbar(); + im = new IconMenu(); + + addToMenuList(rm); + rm->parseMenuConfigurationFile(); + + t->getToolbarMenu()->addMenu("icon menu", im); + t->getToolbarMenu()->addMenu("root menu", rm); + t->getToolbarMenu()->update_all(); + + scan_windows(); + + do_event_loop(); +} + +WindowManager::~WindowManager() +{ + unsigned int i, nwins; + Window dw1, dw2, *wins; + Client *temp_client=NULL; + + XQueryTree(dpy, root, &dw1, &dw2, &wins, &nwins); + for (i = 0; i < nwins; i++) + { + temp_client = head_client->find_client(wins[i]); + + if(temp_client) + { + temp_client->remove_client(temp_client); + } + + } + XFree(wins); + + ClientList->removeAll(); + + delete head_client; + delete ClientList; + + image_control->removeImage(font_pix); + + XFreeFont(dpy, xfont); + + XFreeGC(dpy, invert_gc); + XFreeGC(dpy, string_gc); + XFreeGC(dpy, border_gc); + + delete t; + delete rm; + delete im; + + menulist->removeAll(); + + extramenulist->removeAll(); + + delete menulist; + delete extramenulist; + + delete theme; + + + + delete image_control; + + delete [] HOME; + delete [] windowmanager_conf; + delete [] configurationPath; +} + +void WindowManager::getCurrentTheme() +{ + XrmDatabase resource_db; + XrmValue value; + char *value_type; + FILE* currentTheme; + bool themeLoaded = false; + + windowmanager_conf = new char[strlen(HOME) + 32]; + sprintf(windowmanager_conf, "%s/.sapphire/wmconf", HOME); + + if((currentTheme = fopen(windowmanager_conf, "r"))!=NULL) + { + fclose(currentTheme); + + XrmInitialize(); + + resource_db = XrmGetFileDatabase(windowmanager_conf); + + if (XrmGetResource(resource_db, "toolbar.visible", + "Toolbar.Visible", &value_type, &value)) + { + if(strcmp(value.addr, "true")==0) + { + theme->setToolbarVisible(); + toolbar_visible=true; + } else { + toolbar_visible=false; + } + } + + if (XrmGetResource(resource_db, "toolbar.position", + "Toolbar.Position", &value_type, &value)) + { + if(strcmp(value.addr, "top")==0) + { + theme->setToolbarTop(); + toolbar_position = true; + } else { + toolbar_position = false; + } + } + + // Clock format + if (XrmGetResource(resource_db,"clock.format","Clock.Format",&value_type,&value)) + { + clock_format= new char[value.size]; + strcpy(clock_format,value.addr); + } else { + clock_format="%m %d %H:%M"; + } + + if (XrmGetResource(resource_db, "start.theme", + "Start.Theme", &value_type, &value)) + { + char *buffer = new char[value.size+strlen(HOME)]; + + strcpy(buffer, value.addr); + + if (value.addr[0] == '~') + { + sprintf(buffer, "%s%s", HOME, value.addr+1); + } + + if((currentTheme = fopen(buffer, "r"))!=NULL) + { + fclose(currentTheme); + theme->parseTheme(buffer); + themeLoaded=true; + } + + delete [] buffer; + } + + XrmDestroyDatabase(resource_db); + + } if (! themeLoaded) { - char* defaultTheme = new char[strlen(configuration_home) + 32]; - sprintf(defaultTheme, "%s/themes/default.theme", configuration_home); - - theme->parseTheme(defaultTheme); - theme->setToolbarVisible(); - - delete [] defaultTheme; - } -} - -void WindowManager::createFontPixmap() -{ - unsigned long style=0; - - style = wm->getTheme()->getFontStyle(); - - font_pix = wm->getImageControl()->renderImage( - //"xfont", - xfont->ascent, - xfont->descent, - style, - wm->getTheme()->getFontColorFrom(), - wm->getTheme()->getFontColorTo() - ); -} - -// We really should have some way to check if the menu needs -// reconfiguring. It shouldn't do anymore processing than -// it needs to. -void WindowManager::reconfigureMenu() -{ - XGrabServer(dpy); - - if(menulist->count()) - { - menulist->removeAll(); - - rm->removeAll(); - addToMenuList(rm); - rm->parseMenuConfigurationFile(); - } - - XUngrabServer(dpy); -} - -int WindowManager::QueryShapeExtentions() -{ - int dummy2; - - return shape = XShapeQueryExtension(dpy, &shape_event, &dummy2); -} - -void WindowManager::scan_windows() -{ - unsigned int i, nwins; - Window dw1, dw2, *wins; - XWindowAttributes attr; - - XQueryTree(dpy, root, &dw1, &dw2, &wins, &nwins); - for (i = 0; i < nwins; i++) { - XGetWindowAttributes(dpy, wins[i], &attr); - if (!attr.override_redirect && attr.map_state == IsViewable) - head_client->make_new_client(wins[i]); - } - XFree(wins); -} - -void WindowManager::do_event_loop() -{ - XEvent ev; - - BaseMenu *m = None; - - int xfd = ConnectionNumber(wm->dpy); - - int dx=0,dy=0; - - for (;;) - { - if(XPending(wm->dpy)) - { - XNextEvent(wm->dpy, &ev); - - switch (ev.type) - { - case ButtonPress: - { - head_client->handle_button_press_event(&ev.xbutton); - t->do_button_press_event(&ev.xbutton); - - m = findInMenuList(&ev.xbutton.window); - - if(m) - { - m->handle_button_press_event(&ev.xbutton); - } - - switch(ev.xbutton.button) - { - case 2: { - if(ev.xbutton.window == root) - { - t->setStartMenuButtonStateNotPressed(); - - im->update_all(); - im->setAllMenuTitlesVisible(im,True); - im->show(); - } - - break; - } - - case 3: { - - if(ev.xbutton.window == root) - { - t->setStartMenuButtonStateNotPressed(); - - rm->hideAllVisibleSubmenus(); - - reconfigureMenu(); - - rm->setAllMenuTitlesVisible(rm, True); - rm->show(); - } - break; - } - - default: - { - if(ev.xbutton.window == root) - { - t->setStartMenuButtonStateNotPressed(); - - im->setAllMenuTitlesVisible(im, False); - im->hide(im); - - rm->setAllMenuTitlesVisible(rm, False); - rm->hideAllVisibleSubmenus(); - rm->hide(rm); - } - - } - break; - - } - break; - } - - case ButtonRelease: - { - m = findInMenuList(&ev.xbutton.window); - - if(m) - m->handle_button_release_event(&ev.xbutton); - - switch(ev.xbutton.button) - { - case 1: - case 2: - case 3: - default: - { - if(menu_event) - { - wm->ungrabPointer(); - menu_event=false; - } - - } - break; - } - - - break; - } - - case ConfigureRequest: - { - head_client->handle_configure_request(&ev.xconfigurerequest); - - break; - } - - case ConfigureNotify: - { - break; - } - - case DestroyNotify: - { - head_client->handle_destroy_notify(&ev.xdestroywindow); - break; - } - - case MapRequest: - { - head_client->handle_map_request(&ev.xmaprequest); - - break; - } - - case UnmapNotify: - { - head_client->handle_unmap_event(&ev.xunmap); - break; - } - - case ClientMessage: - { - head_client->handle_client_message(&ev.xclient); - break; - } - - case ColormapNotify: - { - head_client->handle_colormap_change(&ev.xcolormap); - break; - } - - case PropertyNotify: - { - head_client->handle_property_change(&ev.xproperty); - break; - } - - case LeaveNotify: - { - m = findInMenuList(&ev.xcrossing.window); - - if(m) - m->handle_leave_notify(&ev.xcrossing); - - break; - } - - case EnterNotify: - { - head_client->handle_enter_event(&ev.xcrossing); - - m = findInMenuList(&ev.xcrossing.window); - - if(m) - m->handle_enter_notify(&ev.xcrossing); - break; - } - - case MotionNotify: - { - if(menu_event) - { - grabPointer(root, ButtonReleaseMask | PointerMotionMask, move_curs); - dx = ev.xmotion.x_root - menu->menu.x_move; - dy = ev.xmotion.y_root - menu->menu.y_move; - menu->menu.x = dx; - menu->menu.y = dy; - XMoveWindow(dpy, menu->menu.window, dx, dy); - } - - m = findInMenuList(&ev.xmotion.window); - - if(m) - m->handle_motion_notify_event(&ev.xmotion); - - break; - } - - case Expose: - { - head_client->handle_expose_event(&ev.xexpose); - t->handle_expose_event(&ev.xexpose); - - rm->handle_expose_event(&ev.xexpose); - - m = findInMenuList(&ev.xexpose.window); - - if(m) - m->handle_expose_event(&ev.xexpose); - - break; - } - - default: - { - if (wm->shape && ev.type == wm->shape_event) - head_client->handle_shape_change((XShapeEvent *)&ev); - break; - } - - - } - - } else { - - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(xfd, &rfds); - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1000; - - select(xfd + 1, &rfds, 0, 0, &tv); - - t->checkClock(); - } - - } - - -} - -// Function: -// -// void WindowManager::quit_nicely() -// -// Purpose: -// -// This functions sole purpose in life is to preform clean up so that we can -// shutdown Sapphire safely. -// -// Returns: -// -// This function returns nothing. -// -void WindowManager::quit_nicely() -{ - saveCurrentTheme(); - - this->~WindowManager(); - - XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); - XInstallColormap(dpy, DefaultColormap(dpy, screen)); - XCloseDisplay(dpy); - - printf("%s", windowmanager_exit_message); - - exit(0); -} - -void WindowManager::restart() -{ - saveCurrentTheme(); - - this->~WindowManager(); - - XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); - - XInstallColormap(dpy, DefaultColormap(dpy, screen)); - - XCloseDisplay(dpy); - - execl("/bin/sh", "sh", "-c", windowmanager_name, 0); -} - -BaseMenu* WindowManager::findInMenuList(Window *w) -{ - if(extramenulist->count()) - { - LinkedListIterator mx(extramenulist); - - for(; mx.current(); mx++) - { - if(*w == mx.current()->getMenuWindow() || - *w == mx.current()->getMenuTitleWindow() || - *w == mx.current()->getMenuItemWindow()) - { - return mx.current(); - } - } - - } - - if(menulist->count()) - { - LinkedListIterator my(menulist); - - for(; my.current(); my++) - { - if(*w == my.current()->getMenuWindow() || - *w == my.current()->getMenuTitleWindow() || - *w == my.current()->getMenuItemWindow()) - { - return my.current(); - } - } - - - } - - return NULL; -} - -void WindowManager::grabPointer(Window w, unsigned int mask, Cursor curs) -{ - if (! XGrabPointer(dpy, w, False, mask, GrabModeAsync, GrabModeAsync, None, curs, CurrentTime) == GrabSuccess ) - return; -} - -void WindowManager::ungrabPointer() -{ - XUngrabPointer(dpy, CurrentTime); -} - -void WindowManager::changeTheme(char* themeFile) -{ - image_control->removeAllImages(); - - theme->parseTheme(themeFile); - - XFreeFont(dpy, xfont); - XFreeGC(dpy, string_gc); - if(font_pix) XFreePixmap(dpy, font_pix); - - xfont = XLoadQueryFont(dpy, theme->getFont()); - - if(!xfont) - { - err("the font specified in the current theme was not found, using default font."); - - xfont = XLoadQueryFont(dpy, font); - } - - font_position = iheight - xfont->descent; - - createFontPixmap(); - - gv.font = xfont->fid; - gv.tile = font_pix; - string_gc = XCreateGC(dpy, root, GCTile | GCFont , &gv); - XSetFillStyle(dpy, string_gc, FillTiled); - - t->changeTheme(); - - if(ClientList->count()) - { - LinkedListIterator c(ClientList); - for(; c.current(); c++) - { - c.current()->themeChange(c.current()); - } - } - - if(menulist->count()) - { - LinkedListIterator mx(menulist); - for(; mx.current(); mx++) - { - mx.current()->reconfigure(); - } - } - - if(extramenulist->count()) - { - LinkedListIterator my(extramenulist); - for(; my.current(); my++) - { - my.current()->reconfigure(); - } - } -} - -void WindowManager::saveCurrentTheme() -{ - // Hopefully I've gotten the bugs out of this function - // Only time will tell.... - - char* save_theme = theme->getCurrentTheme(); - - FILE *wmconf; - - if((wmconf = fopen(windowmanager_conf, "w"))==NULL) - { - char *sapphire_config_dir = new char[strlen(HOME)+30]; - sprintf(sapphire_config_dir, "%s/.sapphire", HOME); - - printf("sapphire_config_dir = %s\n", sapphire_config_dir); - - mkdir(sapphire_config_dir, S_IRWXU); - - delete [] sapphire_config_dir; - - if((wmconf = fopen(windowmanager_conf, "w"))==NULL) - { - perror("error:\n"); - exit(-1); - } - } - - if(toolbar_visible) - fprintf(wmconf, "toolbar.visible: true\n"); - else - fprintf(wmconf, "toolbar.visible: false\n"); - - if(toolbar_position) - fprintf(wmconf, "toolbar.position: top\n"); - else - fprintf(wmconf, "toolbar.position: bottom\n"); - - fprintf(wmconf, "start.theme: %s\n", save_theme); - fprintf(wmconf, "clock.format: %s\n", clock_format); - //fprintf(wmconf, "desktops.count: %d\n", max_desktops); - - fclose(wmconf); -} + char* defaultTheme = new char[strlen(configuration_home) + 32]; + sprintf(defaultTheme, "%s/themes/default.theme", configuration_home); + + theme->parseTheme(defaultTheme); + theme->setToolbarVisible(); + + delete [] defaultTheme; + } +} + +void WindowManager::createFontPixmap() +{ + unsigned long style=0; + + style = wm->getTheme()->getFontStyle(); + + font_pix = wm->getImageControl()->renderImage( + //"xfont", + xfont->ascent, + xfont->descent, + style, + wm->getTheme()->getFontColorFrom(), + wm->getTheme()->getFontColorTo() + ); +} + +// We really should have some way to check if the menu needs +// reconfiguring. It shouldn't do anymore processing than +// it needs to. +void WindowManager::reconfigureMenu() +{ + XGrabServer(dpy); + + if(menulist->count()) + { + menulist->removeAll(); + + rm->removeAll(); + addToMenuList(rm); + rm->parseMenuConfigurationFile(); + } + + XUngrabServer(dpy); +} + +int WindowManager::QueryShapeExtentions() +{ + int dummy2; + + return shape = XShapeQueryExtension(dpy, &shape_event, &dummy2); +} + +void WindowManager::scan_windows() +{ + unsigned int i, nwins; + Window dw1, dw2, *wins; + XWindowAttributes attr; + + XQueryTree(dpy, root, &dw1, &dw2, &wins, &nwins); + for (i = 0; i < nwins; i++) { + XGetWindowAttributes(dpy, wins[i], &attr); + if (!attr.override_redirect && attr.map_state == IsViewable) + head_client->make_new_client(wins[i]); + } + XFree(wins); +} + +void WindowManager::do_event_loop() +{ + XEvent ev; + + BaseMenu *m = None; + + int xfd = ConnectionNumber(wm->dpy); + + int dx=0,dy=0; + + for (;;) + { + if(XPending(wm->dpy)) + { + XNextEvent(wm->dpy, &ev); + + switch (ev.type) + { + case ButtonPress: + { + head_client->handle_button_press_event(&ev.xbutton); + t->do_button_press_event(&ev.xbutton); + + m = findInMenuList(&ev.xbutton.window); + + if(m) + { + m->handle_button_press_event(&ev.xbutton); + } + + switch(ev.xbutton.button) + { + case 2: { + if(ev.xbutton.window == root) + { + t->setStartMenuButtonStateNotPressed(); + + im->update_all(); + im->setAllMenuTitlesVisible(im,True); + im->show(); + } + + break; + } + + case 3: { + + if(ev.xbutton.window == root) + { + t->setStartMenuButtonStateNotPressed(); + + rm->hideAllVisibleSubmenus(); + + reconfigureMenu(); + + rm->setAllMenuTitlesVisible(rm, True); + rm->show(); + } + break; + } + + default: + { + if(ev.xbutton.window == root) + { + t->setStartMenuButtonStateNotPressed(); + + im->setAllMenuTitlesVisible(im, False); + im->hide(im); + + rm->setAllMenuTitlesVisible(rm, False); + rm->hideAllVisibleSubmenus(); + rm->hide(rm); + } + + } + break; + + } + break; + } + + case ButtonRelease: + { + m = findInMenuList(&ev.xbutton.window); + + if(m) + m->handle_button_release_event(&ev.xbutton); + + switch(ev.xbutton.button) + { + case 1: + case 2: + case 3: + default: + { + if(menu_event) + { + wm->ungrabPointer(); + menu_event=false; + } + + } + break; + } + + + break; + } + + case ConfigureRequest: + { + head_client->handle_configure_request(&ev.xconfigurerequest); + + break; + } + + case ConfigureNotify: + { + break; + } + + case DestroyNotify: + { + head_client->handle_destroy_notify(&ev.xdestroywindow); + break; + } + + case MapRequest: + { + head_client->handle_map_request(&ev.xmaprequest); + + break; + } + + case UnmapNotify: + { + head_client->handle_unmap_event(&ev.xunmap); + break; + } + + case ClientMessage: + { + head_client->handle_client_message(&ev.xclient); + break; + } + + case ColormapNotify: + { + head_client->handle_colormap_change(&ev.xcolormap); + break; + } + + case PropertyNotify: + { + head_client->handle_property_change(&ev.xproperty); + break; + } + + case LeaveNotify: + { + m = findInMenuList(&ev.xcrossing.window); + + if(m) + m->handle_leave_notify(&ev.xcrossing); + + break; + } + + case EnterNotify: + { + head_client->handle_enter_event(&ev.xcrossing); + + m = findInMenuList(&ev.xcrossing.window); + + if(m) + m->handle_enter_notify(&ev.xcrossing); + break; + } + + case MotionNotify: + { + if(menu_event) + { + grabPointer(root, ButtonReleaseMask | PointerMotionMask, move_curs); + dx = ev.xmotion.x_root - menu->menu.x_move; + dy = ev.xmotion.y_root - menu->menu.y_move; + menu->menu.x = dx; + menu->menu.y = dy; + XMoveWindow(dpy, menu->menu.window, dx, dy); + } + + m = findInMenuList(&ev.xmotion.window); + + if(m) + m->handle_motion_notify_event(&ev.xmotion); + + break; + } + + case Expose: + { + head_client->handle_expose_event(&ev.xexpose); + t->handle_expose_event(&ev.xexpose); + + rm->handle_expose_event(&ev.xexpose); + + m = findInMenuList(&ev.xexpose.window); + + if(m) + m->handle_expose_event(&ev.xexpose); + + break; + } + + default: + { + if (wm->shape && ev.type == wm->shape_event) + head_client->handle_shape_change((XShapeEvent *)&ev); + break; + } + + + } + + } else { + + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(xfd, &rfds); + + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 1000; + + select(xfd + 1, &rfds, 0, 0, &tv); + + t->checkClock(); + } + + } + + +} + +// Function: +// +// void WindowManager::quit_nicely() +// +// Purpose: +// +// This functions sole purpose in life is to preform clean up so that we can +// shutdown Sapphire safely. +// +// Returns: +// +// This function returns nothing. +// +void WindowManager::quit_nicely() +{ + saveCurrentTheme(); + + this->~WindowManager(); + + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XInstallColormap(dpy, DefaultColormap(dpy, screen)); + XCloseDisplay(dpy); + + printf("%s", windowmanager_exit_message); + + exit(0); +} + +void WindowManager::restart() +{ + start_another_windowmanager(windowmanager_name); +} + +void WindowManager::start_another_windowmanager(char * wmCommand) +{ + saveCurrentTheme(); + + this->~WindowManager(); + + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + + XInstallColormap(dpy, DefaultColormap(dpy, screen)); + + XCloseDisplay(dpy); + + execl("/bin/sh", "sh", "-c", wmCommand, 0); +} + +BaseMenu* WindowManager::findInMenuList(Window *w) +{ + if(extramenulist->count()) + { + LinkedListIterator mx(extramenulist); + + for(; mx.current(); mx++) + { + if(*w == mx.current()->getMenuWindow() || + *w == mx.current()->getMenuTitleWindow() || + *w == mx.current()->getMenuItemWindow()) + { + return mx.current(); + } + } + + } + + if(menulist->count()) + { + LinkedListIterator my(menulist); + + for(; my.current(); my++) + { + if(*w == my.current()->getMenuWindow() || + *w == my.current()->getMenuTitleWindow() || + *w == my.current()->getMenuItemWindow()) + { + return my.current(); + } + } + + + } + + return NULL; +} + +void WindowManager::grabPointer(Window w, unsigned int mask, Cursor curs) +{ + if (! XGrabPointer(dpy, w, False, mask, GrabModeAsync, GrabModeAsync, None, curs, CurrentTime) == GrabSuccess ) + return; +} + +void WindowManager::ungrabPointer() +{ + XUngrabPointer(dpy, CurrentTime); +} + +void WindowManager::changeTheme(char* themeFile) +{ + image_control->removeAllImages(); + + theme->parseTheme(themeFile); + + XFreeFont(dpy, xfont); + XFreeGC(dpy, string_gc); + if(font_pix) XFreePixmap(dpy, font_pix); + + xfont = XLoadQueryFont(dpy, theme->getFont()); + + if(!xfont) + { + err("the font specified in the current theme was not found, using default font."); + + xfont = XLoadQueryFont(dpy, font); + } + + font_position = iheight - xfont->descent; + + createFontPixmap(); + + gv.font = xfont->fid; + gv.tile = font_pix; + string_gc = XCreateGC(dpy, root, GCTile | GCFont , &gv); + XSetFillStyle(dpy, string_gc, FillTiled); + + t->changeTheme(); + + if(ClientList->count()) + { + LinkedListIterator c(ClientList); + for(; c.current(); c++) + { + c.current()->themeChange(c.current()); + } + } + + if(menulist->count()) + { + LinkedListIterator mx(menulist); + for(; mx.current(); mx++) + { + mx.current()->reconfigure(); + } + } + + if(extramenulist->count()) + { + LinkedListIterator my(extramenulist); + for(; my.current(); my++) + { + my.current()->reconfigure(); + } + } +} + +void WindowManager::saveCurrentTheme() +{ + // Hopefully I've gotten the bugs out of this function + // Only time will tell.... + + char* save_theme = theme->getCurrentTheme(); + + FILE *wmconf; + + if((wmconf = fopen(windowmanager_conf, "w"))==NULL) + { + char *sapphire_config_dir = new char[strlen(HOME)+30]; + sprintf(sapphire_config_dir, "%s/.sapphire", HOME); + + printf("sapphire_config_dir = %s\n", sapphire_config_dir); + + mkdir(sapphire_config_dir, S_IRWXU); + + delete [] sapphire_config_dir; + + if((wmconf = fopen(windowmanager_conf, "w"))==NULL) + { + perror("error:\n"); + exit(-1); + } + } + + if(toolbar_visible) + fprintf(wmconf, "toolbar.visible: true\n"); + else + fprintf(wmconf, "toolbar.visible: false\n"); + + if(toolbar_position) + fprintf(wmconf, "toolbar.position: top\n"); + else + fprintf(wmconf, "toolbar.position: bottom\n"); + + fprintf(wmconf, "start.theme: %s\n", save_theme); + fprintf(wmconf, "clock.format: %s\n", clock_format); + //fprintf(wmconf, "desktops.count: %d\n", max_desktops); + + fclose(wmconf); +} --- sapphire-0.15.8.orig/windowmanager.hh +++ sapphire-0.15.8/windowmanager.hh @@ -1,216 +1,217 @@ -/* - * Copyright (C) 1999,2000,2001 Frank Hale - * frankhale@yahoo.com - * http://sapphire.sourceforge.net/ - * - * Updated: 3 Nov 2001 - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -#ifndef _WM_HH_ -#define _WM_HH_ - -#include "sapphire.hh" - -class WindowManager -{ - -private: /* variables */ - - LinkedList *menulist; - LinkedList *extramenulist; - LinkedList *ClientList; - - Client *head_client; - - Toolbar *t; - IconMenu *im; - RootMenu *rm; - Theme *theme; - BImageControl *image_control; - BaseMenu *menu; - - Atom xa_wm_state; - Atom xa_wm_change_state; - Atom xa_wm_protos; - Atom xa_wm_delete; - Atom xa_wm_cmapwins; - Atom xa_wm_take_focus; - Atom xa_wm_motif_hints; - - Window root; - - Display *dpy; - - Visual *visual; - - Pixmap font_pix; - - XFontStruct *xfont; - - XGCValues gv; - - XColor xforeground_color; - XColor xbackground_color; - XColor xborder_color; - - GC invert_gc; - GC string_gc; - GC border_gc; - - Cursor move_curs; - Cursor resize_curs; - Cursor left_arrow; - - char *display; - char *font; - char *menufont; - char *foreground_color; - char *background_color; - char *border_color; - - int depth; - int xres; - int yres; - int shape_event; - int colors_per_channel; - int toolbar_position; - int toolbar_visible; - int screen; - int iheight; - int font_position; - - bool image_dither; - bool shape; - bool menu_event; - - // Configuration file stuff - char *clock_format; - char *configurationPath; - char *windowmanager_conf; - - static KeySym AltKeys[]; -public: - - // member functions below - - WindowManager(int argc, char **argv); - ~WindowManager(); - - XColor getBorderColor() const { return xborder_color; } - XColor getForegroundColor() const { return xforeground_color; } - XColor getBackgroundColor() const { return xbackground_color; } - - GC getInvertGC() const { return invert_gc; } - GC getStringGC() const { return string_gc; } - GC getBorderGC() const { return border_gc; } - - int getIHeight() const { return iheight; } - char* getMenuFont() const { return menufont; } - - Cursor getMoveCursor() const { return move_curs; } - Cursor getResizeCursor() const { return resize_curs; } - Cursor getLeftArrowCursor() const { return left_arrow; } - - XFontStruct* getXFont() const { return xfont; } - - bool getShape() const { return shape; } - - void setShape(bool s) { shape=s; } - - int getFontPosition() const { return font_position; } - - Theme* getTheme() const { return theme; } - - void changeTheme(char* themeFile); - - // Client List member functions - void insertClient(Client *c) { ClientList->insert(c); } - void removeClient(Client *c) { ClientList->remove(c); } - - unsigned int getClientCount() const { return ClientList->count(); } - LinkedList* getClientListObject() const { return ClientList; } - - // Server Grab member functions - void Grab() { XGrabServer(dpy); } - void Ungrab() { XUngrabServer(dpy); } - void SyncUngrab() { XSync(dpy, False); XUngrabServer(dpy); } - - void addToMenuList(BaseMenu *m) { menulist->insert(m); } - void addToExtraMenuList(BaseMenu *m) { extramenulist->insert(m); } - void reconfigureMenu(); - void removeFromMenuList(BaseMenu *m) { menulist->remove(m); } - LinkedList* getMenuList() { return menulist; } - BaseMenu* findInMenuList(Window *w); - - Atom getWMChangeStateAtom() const { return xa_wm_change_state; } - Atom getWMStateAtom() const { return xa_wm_state; } - Atom getWMDeleteAtom() const { return xa_wm_delete; } - Atom getWMProtocolsAtom() const { return xa_wm_protos; } - Atom getWMFocusAtom() const { return xa_wm_take_focus; } - Atom getWMColormapAtom() const { return xa_wm_cmapwins; } - Atom getMotifWMHintsAtom() const { return xa_wm_motif_hints; } - - int getDepth() const { return depth; } - int getScreen() const { return screen; } - Visual* getVisual() const { return visual; } - int getColorsPerChannel() const { return colors_per_channel; } - bool getImageDither() const { return image_dither; } - BImageControl *getImageControl() const { return image_control; } - - Display* getDisplay() const { return dpy; } - Window getRootWindow() const { return root; } - - RootMenu* getRootMenu() const { return rm; } - IconMenu* getIconMenu() const { return im; } - Toolbar* getToolbar() const { return t; } - - void grabPointer(Window w, unsigned int mask, Cursor curs); - void ungrabPointer(); - - void quit_nicely(); - void restart(); - - int getXRes() const { return xres; } - int getYRes() const { return yres; } - - char* getClockFormat() const { return clock_format; } - //void handleKeyPress(XEvent *ev); - - // desktop is from 0 to 15, inclusive (not a bit mask like in changeDesktop) - void goToDesktop(int desktop); - void goToNextDesktop(); - void goToPreviousDesktop(); - - void setMenu(BaseMenu* bm) { menu=bm; } - void setMenuEvent(bool me) { menu_event=me; } - -private: /* member functions */ - - int QueryShapeExtentions(); - - void scan_windows(); - void do_event_loop(); - void createFontPixmap(); - void createMenuFontPixmap(); - void saveCurrentTheme(); - void getCurrentTheme(); -}; - -extern WindowManager *wm; - -#endif +/* + * Copyright (C) 1999,2000,2001 Frank Hale + * frankhale@yahoo.com + * http://sapphire.sourceforge.net/ + * + * Updated: 3 Nov 2001 + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifndef _WM_HH_ +#define _WM_HH_ + +#include "sapphire.hh" + +class WindowManager +{ + +private: /* variables */ + + LinkedList *menulist; + LinkedList *extramenulist; + LinkedList *ClientList; + + Client *head_client; + + Toolbar *t; + IconMenu *im; + RootMenu *rm; + Theme *theme; + BImageControl *image_control; + BaseMenu *menu; + + Atom xa_wm_state; + Atom xa_wm_change_state; + Atom xa_wm_protos; + Atom xa_wm_delete; + Atom xa_wm_cmapwins; + Atom xa_wm_take_focus; + Atom xa_wm_motif_hints; + + Window root; + + Display *dpy; + + Visual *visual; + + Pixmap font_pix; + + XFontStruct *xfont; + + XGCValues gv; + + XColor xforeground_color; + XColor xbackground_color; + XColor xborder_color; + + GC invert_gc; + GC string_gc; + GC border_gc; + + Cursor move_curs; + Cursor resize_curs; + Cursor left_arrow; + + char *display; + char *font; + char *menufont; + char *foreground_color; + char *background_color; + char *border_color; + + int depth; + int xres; + int yres; + int shape_event; + int colors_per_channel; + int toolbar_position; + int toolbar_visible; + int screen; + int iheight; + int font_position; + + bool image_dither; + bool shape; + bool menu_event; + + // Configuration file stuff + char *clock_format; + char *configurationPath; + char *windowmanager_conf; + + static KeySym AltKeys[]; +public: + + // member functions below + + WindowManager(int argc, char **argv); + ~WindowManager(); + + XColor getBorderColor() const { return xborder_color; } + XColor getForegroundColor() const { return xforeground_color; } + XColor getBackgroundColor() const { return xbackground_color; } + + GC getInvertGC() const { return invert_gc; } + GC getStringGC() const { return string_gc; } + GC getBorderGC() const { return border_gc; } + + int getIHeight() const { return iheight; } + char* getMenuFont() const { return menufont; } + + Cursor getMoveCursor() const { return move_curs; } + Cursor getResizeCursor() const { return resize_curs; } + Cursor getLeftArrowCursor() const { return left_arrow; } + + XFontStruct* getXFont() const { return xfont; } + + bool getShape() const { return shape; } + + void setShape(bool s) { shape=s; } + + int getFontPosition() const { return font_position; } + + Theme* getTheme() const { return theme; } + + void changeTheme(char* themeFile); + + // Client List member functions + void insertClient(Client *c) { ClientList->insert(c); } + void removeClient(Client *c) { ClientList->remove(c); } + + unsigned int getClientCount() const { return ClientList->count(); } + LinkedList* getClientListObject() const { return ClientList; } + + // Server Grab member functions + void Grab() { XGrabServer(dpy); } + void Ungrab() { XUngrabServer(dpy); } + void SyncUngrab() { XSync(dpy, False); XUngrabServer(dpy); } + + void addToMenuList(BaseMenu *m) { menulist->insert(m); } + void addToExtraMenuList(BaseMenu *m) { extramenulist->insert(m); } + void reconfigureMenu(); + void removeFromMenuList(BaseMenu *m) { menulist->remove(m); } + LinkedList* getMenuList() { return menulist; } + BaseMenu* findInMenuList(Window *w); + + Atom getWMChangeStateAtom() const { return xa_wm_change_state; } + Atom getWMStateAtom() const { return xa_wm_state; } + Atom getWMDeleteAtom() const { return xa_wm_delete; } + Atom getWMProtocolsAtom() const { return xa_wm_protos; } + Atom getWMFocusAtom() const { return xa_wm_take_focus; } + Atom getWMColormapAtom() const { return xa_wm_cmapwins; } + Atom getMotifWMHintsAtom() const { return xa_wm_motif_hints; } + + int getDepth() const { return depth; } + int getScreen() const { return screen; } + Visual* getVisual() const { return visual; } + int getColorsPerChannel() const { return colors_per_channel; } + bool getImageDither() const { return image_dither; } + BImageControl *getImageControl() const { return image_control; } + + Display* getDisplay() const { return dpy; } + Window getRootWindow() const { return root; } + + RootMenu* getRootMenu() const { return rm; } + IconMenu* getIconMenu() const { return im; } + Toolbar* getToolbar() const { return t; } + + void grabPointer(Window w, unsigned int mask, Cursor curs); + void ungrabPointer(); + + void quit_nicely(); + void restart(); + void start_another_windowmanager(char * wmCommand); + + int getXRes() const { return xres; } + int getYRes() const { return yres; } + + char* getClockFormat() const { return clock_format; } + //void handleKeyPress(XEvent *ev); + + // desktop is from 0 to 15, inclusive (not a bit mask like in changeDesktop) + void goToDesktop(int desktop); + void goToNextDesktop(); + void goToPreviousDesktop(); + + void setMenu(BaseMenu* bm) { menu=bm; } + void setMenuEvent(bool me) { menu_event=me; } + +private: /* member functions */ + + int QueryShapeExtentions(); + + void scan_windows(); + void do_event_loop(); + void createFontPixmap(); + void createMenuFontPixmap(); + void saveCurrentTheme(); + void getCurrentTheme(); +}; + +extern WindowManager *wm; + +#endif