/*
 * startmenu.cc
 *
 * Copyright (C) 1995-2001 Kenichi Kourai
 *
 * 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, 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
 * along with qvwm; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include "main.h"
#include "misc.h"
#include "qvwm.h"
#include "util.h"
#include "menu.h"
#include "startmenu.h"
#include "taskbar.h"
#include "tbutton.h"
#include "qvwmrc.h"
#include "pixmap_image.h"
#include "callback.h"
#include "timer.h"
#include "bitmaps/folder32.xpm"
#include "bitmaps/icon32.xpm"
#include "bitmaps/logo_qvwm11.xpm"

QvImage* StartMenu::imgLogoMark;
QvImage* StartMenu::imgStart[2];

StartMenu::StartMenu(MenuElem* mItem)
: Menu(mItem, fsStartMenu, NULL, rootQvwm,
       imgLogoMark->GetSize().width + 5, 2, 2, imgStart[0], imgStart[1])
{
  XSetWindowAttributes attributes;
  unsigned long valueMask;
  Dim szLogo = imgLogoMark->GetSize();

  attributes.background_pixel = StartMenuLogoColor.pixel;
  valueMask = CWBackPixel;
  
  logo = XCreateWindow(display, frame,
		       MenuFrameWidth, MenuFrameWidth,
		       szLogo.width, rc.height - MenuFrameWidth * 2,
		       0, CopyFromParent, InputOutput,
		       CopyFromParent, valueMask, &attributes);
  XSaveContext(display, logo, context, (caddr_t)this);

  /*
   * Report events even on the logo.
   */
  Rect rect;
  int sep = 0;

  itemFocus = new Window[nitems];

  for (int i = 0; i < nitems; i++) {
    if (func[i] != Q_SEPARATOR) {
      attributes.event_mask = ButtonPressMask | ButtonReleaseMask |
	                      EnterWindowMask |
			      OwnerGrabButtonMask | ExposureMask | 
			      PointerMotionMask;
      rect.y = MenuFrameWidth + (i - sep) * itemHeight + sep * SeparatorHeight;
      rect.height = itemHeight;
    }
    else {
      attributes.event_mask = ButtonPressMask | ButtonReleaseMask |
		     	      OwnerGrabButtonMask | ExposureMask;
      rect.y = MenuFrameWidth + (i - sep) * itemHeight + sep * SeparatorHeight;
      rect.height = SeparatorHeight;
      sep++;
    }

    rect.x = MenuFrameWidth;
    rect.width = rc.width - MenuFrameWidth * 2;

    /*
     * Create transparent wrapper window on logo and menu item.
     */
    itemFocus[i] = XCreateWindow(display, frame,
				 rect.x, rect.y, rect.width, rect.height,
				 0, CopyFromParent, InputOnly, CopyFromParent,
				 CWEventMask, &attributes);
    XSaveContext(display, itemFocus[i], context, (caddr_t)this);
  }

  XResizeWindow(display, frame, rc.width, rc.height);
}

StartMenu::~StartMenu()
{
  XDeleteContext(display, logo, context);
  XDestroyWindow(display, logo);

  for (int i = 0; i < nitems; i++) {
    XDeleteContext(display, itemFocus[i], context);
    XDestroyWindow(display, itemFocus[i]);
  }
}

/*
 * MapMenu --
 *   Map start menu according to taskbar position.
 */
void StartMenu::MapMenu()
{
  Rect rect;
  int dir;

  if (UseTaskbar)
    if (TaskbarAutoHide && taskBar->IsHiding())
      taskBar->ShowTaskbar();

  ASSERT(rootQvwm);
  ASSERT(rootQvwm->tButton);
  
  rootQvwm->tButton->SetState(Button::PUSH);
  rootQvwm->SetFocus();
  rootQvwm->tButton->DrawButton();

  if (UseTaskbar) {
    switch (taskBar->GetPos()) {
    case Taskbar::BOTTOM:
      rect = taskBar->GetRect();
      rc.x = 2;
      rc.y = rect.y - rc.height + 4;
      fDir = RIGHT;
      dir = GD_UP;
      break;
      
    case Taskbar::TOP:
      rect = taskBar->GetRect();
      rc.x = 2;
      rc.y = rect.height-4 - Taskbar::INC_HEIGHT *
	((rect.height - Taskbar::BASE_HEIGHT) / Taskbar::INC_HEIGHT);
      fDir = RIGHT;
      dir = GD_DOWN;
      break;
      
    case Taskbar::LEFT:
      rc.x = 2;
      rc.y = TaskbarButton::BUTTON_HEIGHT + 2;
      fDir = RIGHT;
      dir = GD_RIGHT;
      break;
      
    case Taskbar::RIGHT:
      {
	Rect rcRoot = rootQvwm->GetRect();
	
	rc.x = rcRoot.width - rc.width - 2;
	rc.y = TaskbarButton::BUTTON_HEIGHT + 2;
	fDir = LEFT;
	dir = GD_LEFT;
	break;
      }

    default:
      dir = 0;  // XXX for warning
      ASSERT(False);
    }
  }
  else {
    Rect rcRoot = rootQvwm->GetRect();

    rc.x = 2;
    rc.y = rcRoot.height - rc.height - 2;
    dir = GD_UP;
  }
    
  Menu::MapMenu(rc.x, rc.y, dir);

  XRaiseWindow(display, logo);
  for (int i = 0; i < nitems; i++)
    XRaiseWindow(display, itemFocus[i]);

  XSelectInput(display, rootQvwm->tButton->GetFrameWin(), 
	       ExposureMask | ButtonPressMask | ButtonReleaseMask |
	       Button1MotionMask);
}

/*
 * UnmapMenu --
 *   Unmap start menu.
 */
void StartMenu::UnmapMenu()
{
  Menu::UnmapMenu();

  ASSERT(rootQvwm);
  ASSERT(rootQvwm->tButton);

  rootQvwm->tButton->SetState(Button::NORMAL);
  rootQvwm->tButton->DrawButton();

  XSelectInput(display, rootQvwm->tButton->GetFrameWin(),
	       ExposureMask | ButtonPressMask | ButtonReleaseMask |
	       Button1MotionMask | OwnerGrabButtonMask);

  if (UseTaskbar && TaskbarAutoHide) {
    Window junkRoot, junkChild;
    Point ptRoot, ptChild;
    unsigned int mask;

    XQueryPointer(display, root, &junkRoot, &junkChild,
		  &ptRoot.x, &ptRoot.y, &ptChild.x, &ptChild.y, &mask);
    if (InRect(ptRoot, taskBar->GetScreenRectOnShowing())) {
      BasicCallback* cb;
      cb = new Callback<Taskbar>(taskBar, &Taskbar::HideTaskbar);
      timer->SetTimeout(TaskbarHideDelay, cb);
    }
  }
}

/*
 * DrawMenu --
 *   Draw start menu.
 */
void StartMenu::DrawMenu(Window win)
{
  Menu::DrawMenu(win);

  Dim szLogo = imgLogoMark->GetSize();
  Point offset(0, rc.height - szLogo.height - MenuFrameWidth * 2);
  
  imgLogoMark->Display(logo, offset);
}

/*
 * FindItem --
 *   Find the menu item corresponding to win.
 */
int StartMenu::FindItem(Window win)
{
  for (int i = 0; i < nitems; i++)
    if (win == item[i] || win == itemFocus[i])
      return i;

  return -1;
}

void StartMenu::ExecFunction(FuncNumber fn, int num)
{
  if (fn == Q_DIR) {
    ASSERT(num >= 0 && num < nitems);

    // delayed menu creation
    if (next[num] == NULL) {
      ASSERT(childItem[num]);
      next[num] = new Menu(childItem[num], fsCascadeMenu, this, qvWm,
			   5, 2, 2, imgMenu[0], imgMenu[1]);
    }
  }

  Menu::ExecFunction(fn, num);
}

void StartMenu::Initialize()
{
  imgStart[0] = new PixmapImage(folder32);
  imgStart[1] = new PixmapImage(icon32);

  if (StartMenuLogoImage) {
    imgLogoMark = CreateImageFromFile(StartMenuLogoImage, timer);
    if (imgLogoMark)
      return;
  }

  imgLogoMark = new PixmapImage(logo_qvwm11);
}


syntax highlighted by Code2HTML, v. 0.9.1