00001
00002
00003
00004
00005
00006 #include "menu.h"
00007
00008 #include <sstream>
00009
00010 #include "action.h"
00011 #include "clientbar.h"
00012 #include "cursors.h"
00013 #include "draw.h"
00014 #include "font.h"
00015 #include "kernel.h"
00016 #include "label.h"
00017 #include "logger.h"
00018 #include "monitor.h"
00019 #include "theme.h"
00020 #include "util.h"
00021 #include "workspace.h"
00022 #include "xcore.h"
00023 #include "xfont.h"
00024
00026
00027 Item::Item(string name, void *data, Type type) {
00028 data_ = data;
00029 type_ = type;
00030
00031 switch (type_) {
00032 case WORKSPACE:
00033 {
00034 Workspace *workspace = (Workspace *)data;
00035 Monitor *monitor = workspace->attached();
00036 if (workspace->clients()->size()
00037 || monitor->detachedClients()->size()
00038 || monitor->stickyClients()->size())
00039 {
00040 addItem(new Item(name, 0, ROOTITEM));
00041 addItem(new Item("", 0, SEPARATOR));
00042 name_ = name + " >>";
00043 }
00044 else {
00045 name_ = name;
00046 }
00047 if (workspace == monitor->focused()) {
00048 name_ = "* " + name_;
00049 }
00050 else {
00051 name_ = " " + name_;
00052 }
00053 }
00054 break;
00055 case DCLIENT:
00056 name_ = "+ " + name;
00057 break;
00058 case ROOTITEM:
00059 name_ = "<< " + name;
00060 break;
00061 case SEPARATOR:
00062 name_ = " -----------------------";
00063 break;
00064 default:
00065 name_ = " " + name;
00066 break;
00067 }
00068 }
00069
00070 Item::~Item() {
00071
00072 while (items_.size()) {
00073 Item *item = items_.front();
00074 items_.erase(items_.begin());
00075 delete item;
00076 }
00077 }
00078
00079 LItem *Item::items() {
00080 return &items_;
00081 }
00082
00083 void Item::addItem(Item *item) {
00084 item->setParent(this);
00085 items_.push_back(item);
00086 }
00087
00088 void Item::removeItem(Item *item) {
00089 item->setParent(0);
00090 items_.remove(item);
00091 }
00092
00093 Item::Type Item::type() const {
00094 return type_;
00095 }
00096
00097 string Item::name() const {
00098 return name_;
00099 }
00100
00101 unsigned int Item::size() {
00102 return items_.size();
00103 }
00104
00105 Item *Item::parent() const {
00106 return parent_;
00107 }
00108
00109 void Item::setParent(Item *parent) {
00110 parent_ = parent;
00111 }
00112
00113 void *Item::data() const {
00114 return data_;
00115 }
00116
00118
00119 Menu::Menu(Monitor *monitor)
00120 : Widget(monitor, new Rectangle(0, 0, 1, 1))
00121 {
00122 theme_ = this->monitor()->theme();
00123 root_ = subRoot_ = selected_ = 0;
00124
00125 label_ = new Label(this->monitor(), window(), Label::LEFT, gc());
00126 label_->setX(1);
00127 label_->setY(1);
00128 label_->setWidth(1);
00129 label_->setHeight(this->monitor()->font()->height() + 2);
00130
00131 initActions();
00132 }
00133
00134 Menu::~Menu() {
00135
00136 }
00137
00138 void Menu::initActions() {
00139
00140 MBindings *actionBindings = KERNEL->actionBindings();
00141 string actions = Util::get(KERNEL->commonSettings(), "menu.actions");
00142
00143 string actionName = "";
00144 bool proceed = actions.size();
00145 for (string::iterator it = actions.begin(); proceed; it++) {
00146
00147 if ((*it != ',') && (it != actions.end())) {
00148 actionName += *it;
00149 }
00150 else {
00151 Action *action = Util::get(actionBindings, actionName);
00152 if (action) {
00153 actions_.push_back(action);
00154 }
00155 else {
00156 LOGWARN("unknown action '" + actionName + "' in menu setup");
00157 }
00158 actionName = "";
00159 }
00160 proceed = it != actions.end();
00161 }
00162
00163 }
00164
00165 void Menu::updateItemTree() {
00166
00167 if (root_) {
00168 delete root_;
00169 }
00170 root_ = new Item("", 0, Item::ROOT);
00171 subRoot_ = root_;
00172
00173
00174 for (LAction::iterator it = actions_.begin(); it != actions_.end(); it++) {
00175 Action *action = *it;
00176 if (action->isValid()) {
00177 root_->addItem(new Item(action->id(), action, Item::ACTION));
00178 }
00179 }
00180 if (root_->items()->size()) {
00181 root_->addItem(new Item("", 0, Item::SEPARATOR));
00182 }
00183
00184
00185 for (LWorkspace::iterator it = monitor()->begin();
00186 it != monitor()->end(); it++)
00187 {
00188 Workspace *workspace = *it;
00189 Item *wsItem = new Item(workspace->name(), workspace, Item::WORKSPACE);
00190 LClient *clients = workspace->clients();
00191 for (LClient::iterator it = clients->begin(); it != clients->end(); it++) {
00192 Client *client = *it;
00193 if (client->mode() != Client::STICKY) {
00194 wsItem->addItem(new Item(client->name(), client, Item::CLIENT));
00195 }
00196 }
00197 CClient *stickyClients = monitor()->stickyClients();
00198 for (LClient::iterator it = stickyClients->begin();
00199 it != stickyClients->end(); it++)
00200 {
00201 Client *client = *it;
00202 wsItem->addItem(new Item(client->name(), client, Item::CLIENT));
00203 }
00204 CClient *detachedClients = monitor()->detachedClients();
00205 if (detachedClients->size()) {
00206 if (workspace->clients()->size() || clients->size()) {
00207 wsItem->addItem(new Item("", 0, Item::SEPARATOR));
00208 }
00209 for (LClient::iterator it = detachedClients->begin();
00210 it != detachedClients->end(); it++)
00211 {
00212 Client *client = *it;
00213 wsItem->addItem(new Item(client->name(), client, Item::DCLIENT));
00214 }
00215 }
00216 root_->addItem(wsItem);
00217 }
00218 }
00219
00220 void Menu::show() {
00221 KERNEL->setMenuMode(true);
00222 isVisible_ = true;
00223 XCORE->showRaised(window());
00224 updateItemTree();
00225 manage();
00226 }
00227
00228 void Menu::hide() {
00229 KERNEL->setMenuMode(false);
00230 isVisible_ = false;
00231 XCORE->hide(window());
00232 }
00233
00234 void Menu::illuminate() {
00235
00236 Rectangle rect(*this);
00237 rect.setX(0);
00238 rect.setY(0);
00239 LOGDEBUG("drawing solid background");
00240
00241 XCORE->raise(window());
00242 XCORE->setForeground(gc(), theme_->BAR_BACKGROUND);
00243 XCORE->fillRectangle(window(), gc(), &rect);
00244 LItem *items = subRoot_->items();
00245
00246 unsigned int offsetY = 1;
00247 unsigned int i = 0;
00248 for (LItem::iterator it = items->begin(); it != items->end(); it++) {
00249 Item *item = *it;
00250 label_->setY(offsetY + i * label_->height());
00251 label_->setText(item->name());
00252 if ((item == selected_) && (item->type() != Item::SEPARATOR)) {
00253 label_->update(theme_->LABEL_BACKGROUND_FOCUSSED,
00254 theme_->LABEL_TEXT_FOCUSSED,
00255 theme_->LABEL_SHINE_FOCUSSED,
00256 theme_->LABEL_SHADOW_FOCUSSED,
00257 true, true);
00258 }
00259 else {
00260 label_->update(theme_->LABEL_BACKGROUND_NORMAL,
00261 theme_->LABEL_TEXT_NORMAL,
00262 theme_->LABEL_SHINE_NORMAL,
00263 theme_->LABEL_SHADOW_NORMAL);
00264 }
00265 i++;
00266 }
00267
00268 Draw::drawRectBorder(window(), gc(), &rect,
00269 theme_->BAR_SHINE, theme_->BAR_SHADOW);
00270 }
00271
00272 void Menu::manage() {
00273
00274 if (!isVisible()) {
00275 return;
00276 }
00277
00278 unsigned int maxWidth = 0;
00279 LItem *items = subRoot_->items();
00280 for (LItem::iterator it = items->begin(); it != items->end(); it++) {
00281 Item *item = *it;
00282 label_->setText(item->name());
00283 if (label_->textWidth() > maxWidth) {
00284 maxWidth = label_->textWidth() + 10;
00285 }
00286 }
00287 label_->setWidth(maxWidth);
00288 setWidth(maxWidth + 2);
00289 setHeight(items->size() * label_->height() + 2);
00290
00291 if (monitor()->clientBar()->y()) {
00292 setY(monitor()->height() - monitor()->clientBar()->height() - height());
00293 }
00294 else {
00295 setY(monitor()->clientBar()->height());
00296 }
00297
00298
00299 resize();
00300 illuminate();
00301 }
00302
00303 void Menu::handleButtonPress(XButtonEvent *event) {
00304 XCORE->raise(window());
00305 if (selected_) {
00306 switch (selected_->type()) {
00307 case Item::WORKSPACE:
00308 {
00309 Workspace *workspace = (Workspace *)selected_->data();
00310 if (event->button == Button1) {
00311 if (selected_->items()->size()) {
00312 subRoot_ = selected_;
00313 manage();
00314 }
00315 else {
00316 monitor()->focus(workspace);
00317 escape();
00318 }
00319 }
00320 else if (event->button == Button3) {
00321 monitor()->focus(workspace);
00322 updateItemTree();
00323 manage();
00324 }
00325 }
00326 break;
00327 case Item::ROOTITEM:
00328 subRoot_ = subRoot_->parent();
00329 manage();
00330 break;
00331 case Item::ACTION:
00332 {
00333 Action *action = (Action *)selected_->data();
00334 if (action->isValid()) {
00335 action->perform();
00336 escape();
00337 }
00338 }
00339 break;
00340 case Item::CLIENT:
00341 {
00342 Workspace *workspace = (Workspace *)subRoot_->data();
00343 Client *client = (Client *)selected_->data();
00344 if (event->button == Button3) {
00345 monitor()->detachClient(client);
00346 if (monitor()->focused() != workspace) {
00347 monitor()->attachLastClient();
00348 }
00349 }
00350 else {
00351 monitor()->focus(workspace);
00352 workspace->focus(client);
00353 if (event->button == Button2) {
00354 XCORE->warpPointer(client->clientWindow(),
00355 client->width() / 2,
00356 client->height() / 2);
00357 }
00358 }
00359 escape();
00360 }
00361 break;
00362 case Item::DCLIENT:
00363 {
00364 Client *client = (Client *)selected_->data();
00365 monitor()->attachDetachedClient((Workspace *)subRoot_->data(),
00366 client);
00367 if (event->button == Button2) {
00368 XCORE->warpPointer(client->clientWindow(),
00369 client->x() + client->width() / 2,
00370 client->y() + client->height() / 2);
00371 }
00372 escape();
00373 }
00374 break;
00375 default:
00376 break;
00377 }
00378 }
00379 }
00380
00381 void Menu::escape() {
00382 monitor()->clientBar()->toggleMenuMode();
00383 }
00384
00385 void Menu::handleMotionNotify(XMotionEvent *event) {
00386
00387 unsigned int selItem = event->y / label_->height();
00388 ostringstream oss;
00389 oss << "eventY=" << event->y << " selItem=" << selItem;
00390 LOGDEBUG(oss.str());
00391
00392 unsigned int i = 0;
00393 LItem *items = subRoot_->items();
00394 for (LItem::iterator it = items->begin(); it != items->end(); it++) {
00395 Item *item = *it;
00396 if (selItem == i) {
00397 if (item == selected_) {
00398 LOGDEBUG("no redraw");
00399 return;
00400 }
00401 selected_ = item;
00402 illuminate();
00403 return;
00404 }
00405 i++;
00406 }
00407 selected_ = 0;
00408 }