#include "Titlebar.h" #include "Windowmanager.h" #include "Frame.h" #include "Desktop.h" #include "Icon.h" #include "Theme.h" #include #include #include #include #include #include #include #include #include #include "config.h" #include "debug.h" extern bool grab(); extern void grab_cursor(bool grab); int Titlebar::box_type = 0; int Titlebar::label_align = FL_ALIGN_LEFT; int Titlebar::default_height = 20; //Fl_Config wm_config(fl_find_config_file("wmanager.conf", true)); static Fl_Menu_ *title_menu=0; Frame *menu_frame=0; //This is set to frame,where menu were popped up // this is called when user clicks the buttons: void Frame::cb_button_close(Fl_Button* b) { close(); } void Frame::cb_button_kill(Fl_Button* b) { kill(); } /* static void animate(int fx, int fy, int fw, int fh, int tx, int ty, int tw, int th) { # undef max # define max(a,b) (a) > (b) ? (a) : (b) double max_steps = max( (tw-fw), (th-fh) ); double min_steps = max( (fw-tw), (fh-th) ); double steps = max(max_steps, min_steps); steps/=Frame::animate_speed; double sx = max( ((double)(fx-tx)/steps), ((double)(tx-fx)/steps) ); double sy = max( ((double)(fy-ty)/steps), ((double)(ty-fy)/steps) ); double sw = max( ((double)(fw-tw)/steps), ((double)(tw-fw)/steps) ); double sh = max( ((double)(fh-th)/steps), ((double)(th-fh)/steps) ); int xinc = fx < tx ? 1 : -1; int yinc = fy < ty ? 1 : -1; int winc = fw < tw ? 1 : -1; int hinc = fh < th ? 1 : -1; double rx=fx,ry=fy,rw=fw,rh=fh; XGrabServer(fl_display); while(steps-- > 0) { rx+=(sx*xinc); ry+=(sy*yinc); rw+=(sw*winc); rh+=(sh*hinc); draw_overlay((int)rx, (int)ry, (int)rw, (int)rh); Fl::sleep(10); XFlush(fl_display); } clear_overlay(); XUngrabServer(fl_display); } void Frame::cb_button_max(Fl_Button* b) { if(maximized) { if(Frame::animate) { ::animate(x(), y(), w(), h(), restore_x, restore_y, restore_w, restore_h); } set_size(restore_x, restore_y, restore_w, restore_h); maximized = false; } else { bool m = true; restore_x = x(); restore_y = y(); restore_w = w(); restore_h = h(); int W=root->w(), H=root->h(); W-=offset_w; H-=offset_h; if(ICCCM::get_size(this, W, H)) { m=false; } W+=offset_w; H+=offset_h; if(Frame::animate) { ::animate(x(), y(), w(), h(), root->x(), root->y(), root->w(), root->h()); } set_size(root->x(), root->y(), W, H); maximized = m; redraw(); } } */ void Frame::cb_button_max(Fl_Button* b) { if(maximized) restore(); else maximize(); } void Frame::cb_button_min(Fl_Button* b) { iconize(); } // Min/Max/Close button symbols drawing stuff: extern int fl_add_symbol(const char *name, void (*drawit)(Fl_Color), int scalable); #define vv(x,y) fl_vertex(x,y) void draw_cl(Fl_Color col) { fl_rotate(45); fl_color(col); vv(-0.9f,-0.12f); vv(-0.9f,0.12f); vv(0.9f,0.12f); vv(0.9f,-0.12f); fl_fill_stroke(FL_DARK3); vv(-0.12f,-0.9f); vv(-0.12f,0.9f); vv(0.12f,0.9f); vv(0.12f,-0.9f); fl_fill_stroke(FL_DARK3); } #define MAX_OF .6f void draw_max(Fl_Color col) { fl_color(col); vv(-MAX_OF, -MAX_OF); vv(MAX_OF, -MAX_OF); vv(MAX_OF,-MAX_OF+0.4); vv(-MAX_OF,-MAX_OF+0.4); fl_fill(); vv(MAX_OF,-MAX_OF); vv(MAX_OF,MAX_OF); vv(-MAX_OF,MAX_OF); vv(-MAX_OF,-MAX_OF); fl_stroke(); } #define MIN_OF .5f void draw_min(Fl_Color col) { fl_color(col); vv(-MIN_OF, MIN_OF); vv(MIN_OF, MIN_OF); vv(MIN_OF, MIN_OF+.2f); vv(-MIN_OF, MIN_OF+.2f); fl_fill(); } // static callbacks for efltk: void button_cb_close(Fl_Widget *w, void *d) { Frame *f = d ? (Frame *)d : menu_frame; f->cb_button_close((Fl_Button*)w); } void button_cb_kill(Fl_Widget *w, void *d) { Frame *f = d ? (Frame *)d : menu_frame; f->cb_button_kill((Fl_Button*)w); } void button_cb_max(Fl_Widget *w, void *d) { Frame *f = d ? (Frame *)d : menu_frame; f->cb_button_max((Fl_Button*)w); } void button_cb_min(Fl_Widget *w, void *d) { Frame *f = d ? (Frame *)d : menu_frame; f->cb_button_min((Fl_Button*)w); } void Titlebar::cb_change_desktop(Fl_Widget *w, void *data) { Desktop *d = (Desktop*)data; menu_frame->desktop_ = d; if(d && d!=Desktop::current()) { Desktop::current(d); menu_frame->raise(); } menu_frame->send_desktop(); menu_frame=0; } void update_desktops(Fl_Group *g) { g->clear(); g->begin(); Fl_Item *i; i = new Fl_Item(_("Sticky")); i->type(Fl_Item::TOGGLE); i->callback(Titlebar::cb_change_desktop); if(menu_frame->desktop()) { i->clear_value(); i->user_data(0); } else { i->set_value(); i->user_data(Desktop::current()); } new Fl_Divider(); for(uint n=0; nname()); i->type(Fl_Item::RADIO); if(menu_frame->desktop()==d) i->set_value(); else i->clear_value(); i->callback(Titlebar::cb_change_desktop, d); } g->end(); } #include "WMWindow.h" #include #include #include #include Fl_Button *ok_button; Fl_Value_Input *w_width, *w_height; //Fl_Input *size; static WMWindow *win = 0; static void real_set_size_cb(Fl_Widget *w, void *d) { Frame *f = (Frame*)d; int W = (int)w_width->value(); int H = (int)w_height->value(); ICCCM::get_size(f, W, H); f->set_size(f->x(), f->y(), W, H); f->redraw(); win->destroy(); } static void close_set_size_cb(Fl_Widget *w, void *d) { win->destroy(); } static void set_size_cb(Fl_Widget *w, void *d) { win = new WMWindow(300, 110, _("Set size")); Fl_Box *b = new Fl_Box(5, 5, 295, 15, _("Set size to window:")); b->label_font(b->label_font()->bold()); Fl_String tmplabel = menu_frame->label(); if (tmplabel.length() > 50) tmplabel = tmplabel.sub_str(0,20) + " ... " + tmplabel.sub_str(tmplabel.length()-20,20); b = new Fl_Box(0, 20, 296, 15, tmplabel); w_width = new Fl_Value_Input(45, 45, 90, 20, _("width:")); w_width->step(1); w_height = new Fl_Value_Input(195, 45, 90, 20, _("height:")); w_height->step(1); new Fl_Divider(5, 70, 290, 10); Fl_Button *but = ok_button = new Fl_Button(60,80,85,25, _("&OK")); but->callback(real_set_size_cb); but = new Fl_Button(155, 80, 85, 25, _("&Cancel")); but->callback(close_set_size_cb); win->end(); w_width->value(menu_frame->w()); w_height->value(menu_frame->h()); ok_button->user_data(menu_frame); win->callback(close_set_size_cb); win->show(); } void Titlebar::popup_menu(Frame *frame) { menu_frame = frame; static Fl_Widget *max; static Fl_Widget *set_size; static Fl_Widget *min; static Fl_Group *desktop; if(!title_menu) { title_menu = new Fl_Menu_(); max=title_menu->add(_("Maximize"), 0, button_cb_max); min=title_menu->add(_("Minimize"), 0, button_cb_min); set_size=title_menu->add(_("Set size"), 0, set_size_cb, 0, FL_MENU_DIVIDER); desktop=(Fl_Group*)title_menu->add(_("To Desktop"), 0, 0, 0, FL_SUBMENU|FL_MENU_DIVIDER); title_menu->add(_("Kill"), 0, button_cb_kill); title_menu->add(_("Close"), 0, button_cb_close); title_menu->end(); } update_desktops(desktop); if(menu_frame->maximized) max->label(_("Restore")); else max->label(_("Maximize")); // we don't want animation for dialogs and utils frames // MWM hints can set MAXIMIZE and MINIMIZE options separately // so we must check them each if(menu_frame->window_type() == TYPE_NORMAL) { if(menu_frame->decor_flag(MAXIMIZE)) { max->activate(); set_size->activate(); } if(menu_frame->decor_flag(MINIMIZE)) min->activate(); } else { max->deactivate(); set_size->deactivate(); min->deactivate(); } title_menu->Fl_Group::focus(-1); title_menu->popup(Fl::event_x_root(), Fl::event_y_root()); menu_frame = 0; } Titlebar_Button::Titlebar_Button(int type) : Fl_Button(0,0,0,0), m_type(type) { focus_box(FL_NO_BOX); label_type(FL_SYMBOL_LABEL); switch(m_type) { case TITLEBAR_MAX_UP: label("@mx"); break; case TITLEBAR_MIN_UP: label("@ii"); break; case TITLEBAR_CLOSE_UP: label("@xx"); break; }; } void Titlebar_Button::draw() { int idx = m_type; if(flags() & FL_VALUE) idx++; Fl_Image *i = Theme::image(idx); if(i) { Fl_Flags scale = 0; if(i->height()!=h()) scale = FL_ALIGN_SCALE; i->draw(0,0,w(),h(), scale); } else { Fl_Button::draw(); } } Titlebar::Titlebar(int x,int y,int w,int h,const char *l) : Fl_Window(x,y,w,h,0), _close(TITLEBAR_CLOSE_UP), _max(TITLEBAR_MAX_UP), _min(TITLEBAR_MIN_UP) { f = (Frame *)parent(); title_icon = 0; text_w=0; static bool init = false; if(!init) { fl_add_symbol("xx", draw_cl, 1); fl_add_symbol("mx", draw_max, 1); fl_add_symbol("ii", draw_min, 1); init = true; } setting_changed(); end(); } Titlebar::~Titlebar() { } void Titlebar::setting_changed() { _close.callback(button_cb_close, f); _max.callback(button_cb_max, f); _min.callback(button_cb_min, f); if(Titlebar::default_height != h()) { h(Titlebar::default_height); f->updateBorder(); } layout(); redraw(); } void Titlebar::show() { if(!shown()) create(); XMapWindow(fl_display, fl_xid(this)); XRaiseWindow(fl_display, fl_xid(this)); } void Titlebar::hide() { if(shown()) XUnmapWindow(fl_display, fl_xid(this)); } #define set_box(b) if(box()!=b) box(b); break void Titlebar::layout() { if(Theme::use_theme()) { if(box()!=FL_FLAT_BOX) box(FL_FLAT_BOX); } else { switch(box_type) { default: case 0: set_box(FL_FLAT_BOX); case 1: set_box(FL_HOR_SHADE_FLAT_BOX); case 2: set_box(FL_THIN_DOWN_BOX); case 3: set_box(FL_UP_BOX); case 4: set_box(FL_DOWN_BOX); case 5: set_box(FL_PLASTIC_BOX); } } int W = w()-box()->dx(); int lsize = h()/2+2; label_size(lsize); // Try to detect what buttons are showed if(!f->func_flag(MINIMIZE)) _min.deactivate(); else _min.activate(); if(!f->func_flag(MAXIMIZE)) _max.deactivate(); else _max.activate(); if(!f->decor_flag(MINIMIZE) || f->frame_flag(KEEP_ASPECT)) _min.hide(); if(!f->decor_flag(MAXIMIZE) || f->frame_flag(KEEP_ASPECT)) _max.hide(); if(f->size_hints->min_width==f->size_hints->max_width || f->transient_for_xid) { _min.hide(); _max.hide(); } else { _min.show(); _max.show(); } int offset=0; int s = h(); int mid = 0; if(!Theme::use_theme()) { s -= 4; mid = 2; offset=2; } int bx = W-s-offset; _close.resize(bx, mid, s, s); if(_close.visible()) bx -= s+offset; _max.resize(bx, mid, s, s); if(_max.visible()) bx -= s+offset; _min.resize(bx, mid, s, s); text_w = bx - (f->decor_flag(SYSMENU)?h():0) - 10; fl_font(label_font(), label_size()); if(!f->label().empty()) { Fl_Widget::label(fl_cut_line(f->label(), text_w)); if(strcmp(label(), f->label())) { tooltip(f->label()); } else { tooltip(""); } } else { label(""); tooltip(""); } // Reset layout flags Fl_Widget::layout(); } void Titlebar::draw() { DBG("Titlebar::draw(): %s", label().c_str()); if(Theme::use_theme() && Theme::image(TITLEBAR_BG)) { int X=0, Y=0, W=w(), H=h(); Theme::image(TITLEBAR_BG)->draw(X,Y,W,H,FL_ALIGN_SCALE); } else { draw_box(); } int s=h()-4; // Resize and set image & mask if(f->icon() && f->decor_flag(SYSMENU)) { title_icon = f->icon()->get_icon(s, s); } else title_icon = 0; int tx = box()->dx()+1; if(title_icon) { title_icon->draw(2,2, s, s); tx += s + 5; // Separate text a few pixels from icon } draw_label(tx, 0, text_w, h(), Titlebar::label_align); draw_child(_close); draw_child(_max); draw_child(_min); } int Titlebar::handle(int event) { static bool grabbed=false; static int dx,dy,nx,ny; switch(event) { case FL_PUSH: { if(grabbed) return 1; dx = Fl::event_x_root()-f->x(); dy = Fl::event_y_root()-f->y(); nx = Fl::event_x_root()-dx; ny = Fl::event_y_root()-dy; // Send event to buttons... for(int i = children(); i--;) { Fl_Widget& o = *child(i); int mx = Fl::event_x() - o.x() - 2; int my = Fl::event_y() - o.y() - 2; if (mx >= 0 && mx < o.w() && my >= 0 && my < o.h()+4) if(child(i)->send(event)) { extern bool handle_title; handle_title = false; return 1; } } if(Fl::event_clicks() && Fl::event_button()==1) { // we don't want animation for dialogs and utils frames if(f->window_type() == TYPE_NORMAL && f->decor_flag(MAXIMIZE)) f->cb_button_max(0); Fl::event_clicks(0); return 1; } else if (Fl::event_button()==3) { Titlebar::popup_menu(f); return 1; } return 1; } case FL_RELEASE: { if(Fl::event_state(FL_BUTTON1)) return 1; if(grabbed) { if(!Frame::do_opaque) { clear_overlay(); f->set_size(nx, ny, f->w(), f->h()); XUngrabServer(fl_display); } grab_cursor(false); grabbed = false; } if(root->get_cursor()==FL_CURSOR_MOVE) root->set_default_cursor(); if (Fl::event_is_click()) { f->activate(); f->raise(); } return 1; } case FL_DRAG: { if(Fl::event_is_click()) return 1; // don't drag yet if(!Fl::event_state(FL_BUTTON1)) return 0; // Change to MOVE cursor if(root->get_cursor()!=FL_CURSOR_MOVE) { root->set_cursor(FL_CURSOR_MOVE, FL_WHITE, FL_BLACK); } // We need to grab server while moving, // since if underlying window redraws our overlay will fuck up... if(!grabbed) { if(!Frame::do_opaque) XGrabServer(fl_display); grab_cursor(true); grabbed=true; } nx = Fl::event_x_root()-dx; ny = Fl::event_y_root()-dy; f->handle_move(nx, ny); return 1; } // default: // return 1; } return 0; }