--- 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<BaseMenuItem>;
-
- 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<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem> *temp_mi;
-
- LinkedListIterator<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem> *temp_mi;
-
- hide(this);
-
- LinkedListIterator<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem>;
+
+ 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<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem> *temp_mi;
+
+ LinkedListIterator<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem> *temp_mi;
+
+ hide(this);
+
+ LinkedListIterator<BaseMenuItem> 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<BaseMenuItem> 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<BaseMenuItem> 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;
+}