diff --git a/client.c b/client.c index 89b3bae..dbfbfe6 100644 --- a/client.c +++ b/client.c @@ -19,7 +19,6 @@ extern struct Library *XLibBase; extern Display *dpy; extern XContext client_context, screen_context; extern Client *activeclient; -extern Scrn *menuactive; extern void setfocus(Window); Client *clients=NULL; @@ -322,8 +321,6 @@ void rmclient(Client *c) closescreen(); scr = c->scr; if(c->active) { - if(!menuactive) - setfocus(None); c->active=False; activeclient = NULL; XInstallColormap(dpy, scr->cmap); diff --git a/frame.c b/frame.c index 98330c6..191dddf 100644 --- a/frame.c +++ b/frame.c @@ -511,51 +511,6 @@ void redrawclient(Client *c) redraw(c, c->resize); } -extern Client *clickclient; -extern Window clickwindow; -extern Scrn *mbdclick, *mbdscr; - -void clickenter() -{ - if((scr=mbdscr)&& clickwindow == scr->menubardepth) { - mbdclick = scr; - redrawmenubar(scr, scr->menubardepth); - } else { - scr = clickclient->scr; - redraw(clickclient, clickclient->clicked=clickwindow); - } -} - -void clickleave() -{ - if((scr=mbdscr)&& clickwindow == scr->menubardepth) { - mbdclick = NULL; - redrawmenubar(scr, scr->menubardepth); - } else { - scr = clickclient->scr; - clickclient->clicked=None; - redraw(clickclient, clickwindow); - } -} - -void gadgetclicked(Client *c, Window w, XEvent *e) -{ - scr=c->scr; - redraw(c, clickwindow=(clickclient=c)->clicked=w); -} - -void gadgetaborted(Client *c) -{ - Window w; - scr=c->scr; - if((w=c->clicked)) { - c->clicked=None; - redraw(c, w); - } - clickwindow=None; - clickclient=NULL; -} - static Client *topmostmappedclient(Window *children, unsigned int nchildren) { int n; @@ -726,37 +681,93 @@ raisebottommostclient(Scrn *scr) XFree(children); } +extern void get_drag_event(XEvent *event); -void gadgetunclicked(Client *c, XEvent *e) +static Bool is_inside(int x0, int y0, int w, int h, int x, int y) { - extern void adjusticon(Icon *); - Window w; - scr=c->scr; - if((w=c->clicked)) { - c->clicked=None; - redraw(c, w); - if(w==c->close) { - if((c->proto & Pdelete)&&!(e->xbutton.state&ShiftMask)) - sendcmessage(c->window, ATOMS[WM_PROTOCOLS], ATOMS[WM_DELETE_WINDOW]); - else - XKillClient(dpy, c->window); - } else if(w==c->depth) - raiselowerclient(c, -1); - else if(w==c->zoom) { - XWindowAttributes xwa; - XGetWindowAttributes(dpy, c->parent, &xwa); - XMoveWindow(dpy, c->parent, c->x=c->zoomx, c->y=c->zoomy); - resizeclientwindow(c, c->zoomw+c->framewidth, c->zoomh+c->frameheight); - c->zoomx=xwa.x; - c->zoomy=xwa.y; - c->zoomw=xwa.width-c->framewidth; - c->zoomh=xwa.height-c->frameheight; -/* XWarpPointer(dpy, None, c->zoom, 0, 0, 0, 0, 23/2, scr->h5); */ - sendconfig(c); - } else if(w==c->iconify) { - iconify(c); + if (w == 0 || h == 0) + return True; /* caller do not care about where click got released */ + return x >= x0 && y >= y0 && x < x0 + w && y < y0 + h; +} + +enum click { + CLICK_OUT = 0, /* click failed or released outside button */ + CLICK_IN = 1, /* click released inside button */ + CLICK_ALT = 2, /* click released inside button, while Shift pressed */ +}; + +/* check if Button1 is pressed AND released with cursor inside window */ +static enum click got_clicked(Client *c, Window w, Cursor curs, Time time) +{ + XWindowAttributes xwa; + int status; + + XSync(dpy, False); + if (!XGetWindowAttributes(dpy, w, &xwa)) + return CLICK_OUT; + status = XGrabPointer(dpy, w, True, ButtonPressMask|ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, False, curs, time); + if (status != AlreadyGrabbed && status != GrabSuccess) + return CLICK_OUT; + c->clicked = w; + redraw(c, w); + for (;;) { + XEvent event; + + get_drag_event(&event); + if (event.type == ButtonRelease || event.type == ButtonPress) { + c->clicked = None; + redraw(c, w); + XUngrabPointer(dpy, event.xbutton.time); + if (event.type == ButtonPress) + return CLICK_OUT; + if (event.xbutton.button != Button1) + return CLICK_OUT; + if (!is_inside(0, 0, xwa.width, xwa.height, event.xbutton.x, event.xbutton.y)) + return CLICK_OUT; + if (event.xbutton.button & ShiftMask) + return CLICK_ALT; + return CLICK_IN; } } - clickwindow=None; - clickclient=NULL; +} + +void click_close(Client *c, Time time) +{ + enum click click = got_clicked(c, c->close, None, time); + if (click == CLICK_OUT) + return; + else if ((c->proto & Pdelete) && click != CLICK_ALT) + sendcmessage(c->window, ATOMS[WM_PROTOCOLS], ATOMS[WM_DELETE_WINDOW]); + else + XKillClient(dpy, c->window); +} + +void click_depth(Client *c, Time time) +{ + if (got_clicked(c, c->depth, None, time)) { + raiselowerclient(c, -1); + } +} + +void click_zoom(Client *c, Time time) +{ + if (got_clicked(c, c->zoom, None, time)) { + XWindowAttributes xwa; + XGetWindowAttributes(dpy, c->parent, &xwa); + XMoveWindow(dpy, c->parent, c->x=c->zoomx, c->y=c->zoomy); + resizeclientwindow(c, c->zoomw+c->framewidth, c->zoomh+c->frameheight); + c->zoomx=xwa.x; + c->zoomy=xwa.y; + c->zoomw=xwa.width-c->framewidth; + c->zoomh=xwa.height-c->frameheight; + sendconfig(c); + } +} + +void click_iconify(Client *c, Time time) +{ + if (got_clicked(c, c->iconify, None, time)) { + iconify(c); + } } diff --git a/main.c b/main.c index 937ede7..a50aabe 100644 --- a/main.c +++ b/main.c @@ -72,9 +72,7 @@ typedef struct _DragIcon { } DragIcon; Display *dpy = NULL; -Client *activeclient=NULL, *clickclient=NULL; -Window clickwindow=None; -Scrn *menuactive=NULL; +Client *activeclient=NULL; Bool shape_extn=False; char *x_server=NULL; char *free_screentitle=NULL; @@ -97,24 +95,19 @@ static unsigned int meta_mask, switch_mask; static char **main_argv; -extern Scrn *mbdclick, *mbdscr; - extern void reparent(Client *); extern void redraw(Client *, Window); extern void redrawclient(Client *); extern void redrawmenubar(Scrn *, Window); extern void resizeclientwindow(Client *c, int, int); -extern void gadgetclicked(Client *c, Window w, XEvent *e); -extern void gadgetunclicked(Client *c, XEvent *e); -extern void gadgetaborted(Client *c); -extern void clickenter(void); -extern void clickleave(void); -extern void menu_on(void); -extern void menu_off(void); +extern void click_close(Client *c, Time time); +extern void click_iconify(Client *c, Time time); +extern void click_zoom(Client *c, Time time); +extern void click_depth(Client *c, Time time); +extern void drag_menu(Scrn *s); extern void menubar_enter(Window); extern void menubar_leave(Window); extern void *getitembyhotkey(KeySym); -extern void menuaction(void *); extern Scrn *getscreenbyroot(Window); extern void assimilate(Window, int, int); extern void deselect_all_icons(Scrn *); @@ -381,9 +374,10 @@ static Bool grab_for_motion(Window w, Window confine, Cursor curs, Time time, in return False; } -static void get_drag_event(XEvent *event) +void get_drag_event(XEvent *event) { - static const unsigned int DRAG_MASK = ButtonPressMask|ButtonReleaseMask|Button1MotionMask; + static const unsigned int DRAG_MASK = + ButtonPressMask|ButtonReleaseMask|PointerMotionMask|EnterWindowMask|LeaveWindowMask; for (;;) { fd_set rfds = master_fd_set; @@ -1188,8 +1182,6 @@ int main(int argc, char *argv[]) XGrabButton(dpy, Button1, AnyModifier, c->parent, True, ButtonPressMask, GrabModeSync, GrabModeAsync, None, wm_curs); - if(!menuactive) - setfocus(None); } if(c && (event.xunmap.window==c->window)) { if((!c->reparenting) && c->parent != c->scr->root) { @@ -1365,12 +1357,7 @@ int main(int argc, char *argv[]) } break; case EnterNotify: - if(menuactive) { - scr=menuactive; - menubar_enter(event.xcrossing.window); - } else if(clickwindow && event.xcrossing.window == clickwindow) - clickenter(); - else if(c) { + if(c) { if((!c->active) && (c->state==NormalState) && prefs.focus!=FOC_CLICKTOTYPE) { if(activeclient) { @@ -1389,17 +1376,10 @@ int main(int argc, char *argv[]) } break; case LeaveNotify: - if(menuactive) { - scr=menuactive; - menubar_leave(event.xcrossing.window); - } else if(clickwindow && event.xcrossing.window == clickwindow) - clickleave(); - else if(c) { + if(c) { if(c->active && event.xcrossing.window==c->parent && event.xcrossing.detail!=NotifyInferior && prefs.focus == FOC_FOLLOWMOUSE) { - if(!menuactive) - setfocus(None); c->active=False; activeclient = NULL; instcmap(None); @@ -1411,7 +1391,7 @@ int main(int argc, char *argv[]) } break; case ButtonPress: - if(clickwindow==None && event.xbutton.button==Button1 && !menuactive) { + if(event.xbutton.button==Button1) { if(c) { if((!c->active) && prefs.focus==FOC_CLICKTOTYPE && (c->state==NormalState)) { @@ -1449,8 +1429,15 @@ int main(int argc, char *argv[]) else if(event.xbutton.window==c->window || event.xbutton.window==c->parent) ; - else - gadgetclicked(c, event.xbutton.window, &event); + else if (event.xbutton.window == c->close) { + click_close(c, event.xbutton.time); + } else if (event.xbutton.window == c->iconify) { + click_iconify(c, event.xbutton.time); + } else if (event.xbutton.window == c->depth) { + click_depth(c, event.xbutton.time); + } else if (event.xbutton.window == c->zoom) { + click_zoom(c, event.xbutton.time); + } } else if(i && event.xbutton.window==i->window) { abortfocus(); if(i->selected && (event.xbutton.time-last_icon_click)scr, event.xbutton.time, event.xbutton.x_root, event.xbutton.y_root); } } else if(scr&&event.xbutton.window==scr->menubardepth) { - clickwindow=scr->menubardepth; - mbdclick=mbdscr=scr; - redrawmenubar(scr, scr->menubardepth); + click_screendepth(scr, event.xbutton.time); } else if(scr&&event.xbutton.window==scr->menubar && scr->back!=scr->root) { drag_screen(scr, event.xbutton.time, event.xbutton.x_root, event.xbutton.y_root); @@ -1476,39 +1461,17 @@ int main(int argc, char *argv[]) event.xbutton.x, event.xbutton.y); } else ; } else if(event.xbutton.button==3) { - if(scr&&(scr==mbdscr)&&clickwindow==scr->menubardepth) { - mbdclick=NULL; - clickwindow=None; - redrawmenubar(scr, scr->menubardepth); - } else if(clickclient) { - gadgetaborted(clickclient); - } else if(scr&&!menuactive) { - menu_on(); - menuactive=scr; + if(c == NULL && scr != NULL) { + drag_menu(scr); } } - if(prefs.focus == FOC_CLICKTOTYPE && !menuactive) { + if(prefs.focus == FOC_CLICKTOTYPE) { XSync(dpy,0); XAllowEvents(dpy,ReplayPointer,CurrentTime); XSync(dpy,0); } break; case ButtonRelease: - if(event.xbutton.button==Button1) { - if(clickclient) - gadgetunclicked(clickclient, &event); - else if((scr=mbdscr)&& clickwindow==scr->menubardepth) { - if(mbdclick) { - mbdclick=NULL; - redrawmenubar(scr, scr->menubardepth); - screentoback(); - } - clickwindow=None; - } - } else if(event.xbutton.button==Button3 && (scr=menuactive)) { - menu_off(); - menuactive=NULL; - } break; case MotionNotify: break; diff --git a/menu.c b/menu.c index 81830db..f6c04a1 100644 --- a/menu.c +++ b/menu.c @@ -50,7 +50,7 @@ extern void setfocus(Window); extern void flushmodules(); extern void wberror(Scrn *, char *); -Scrn *mbdclick=NULL, *mbdscr=NULL; +Scrn *mbdclick=NULL; static struct ToolItem { struct ToolItem *next; @@ -594,7 +594,7 @@ void redrawmenubar(Scrn *scr, Window w) } } else if(w==scr->menubardepth) { /* Menubar depth widget */ - if(!mbdclick) { + if(mbdclick != scr) { XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[SHADOWPEN]); XDrawRectangle(dpy, w, scr->menubargc, 4, scr->h2, 10, scr->h6-scr->h2); } @@ -602,12 +602,12 @@ void redrawmenubar(Scrn *scr, Window w) XFillRectangle(dpy, w, scr->menubargc, 8, scr->h4, 10, scr->h8-scr->h4); XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[SHADOWPEN]); XDrawRectangle(dpy, w, scr->menubargc, 8, scr->h4, 10, scr->h8-scr->h4); - if(mbdclick) + if(mbdclick == scr) XDrawRectangle(dpy, w, scr->menubargc, 4, scr->h2, 10, scr->h6-scr->h2); - XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[mbdclick?SHADOWPEN:SHINEPEN]); + XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[mbdclick==scr?SHADOWPEN:SHINEPEN]); XDrawLine(dpy, w, scr->menubargc, 0, 0, 22, 0); XDrawLine(dpy, w, scr->menubargc, 0, 0, 0, scr->bh-2); - XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[mbdclick?SHINEPEN:SHADOWPEN]); + XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[mbdclick==scr?SHINEPEN:SHADOWPEN]); XDrawLine(dpy, w, scr->menubargc, 0, scr->bh-1, 22, scr->bh-1); XDrawLine(dpy, w, scr->menubargc, 22, 0, 22, scr->bh-1); } else { @@ -642,6 +642,8 @@ void redrawmenubar(Scrn *scr, Window w) static void leave_item(struct Item *i, Window w) { + if (i == NULL) + return; if(i==activesubitem) activesubitem=NULL; if(i==activeitem) { @@ -708,7 +710,7 @@ static void enter_menu(struct Menu *m, Window w) } } -void menubar_enter(Window w) +static void menubar_enter(Window w) { struct Menu *m; struct Item *i; @@ -732,7 +734,7 @@ void menubar_enter(Window w) } } -void menubar_leave(Window w) +static void menubar_leave(Window w) { if(activesubitem && activesubitem->win==w) leave_item(activesubitem, w); @@ -740,24 +742,6 @@ void menubar_leave(Window w) leave_item(activeitem, w); } -void menu_on() -{ - Window r, c; - int rx, ry, x, y; - unsigned int m; - - if(scr->menubarparent) { - XMapRaised(dpy, scr->menubarparent); - XRaiseWindow(dpy, scr->menubar); - XGrabPointer(dpy, scr->back, True, ButtonPressMask|ButtonReleaseMask| - EnterWindowMask|LeaveWindowMask, GrabModeAsync, GrabModeAsync, - scr->back, wm_curs, CurrentTime); - XSetInputFocus(dpy, scr->menubar, RevertToParent, CurrentTime); - if(XQueryPointer(dpy, scr->menubarparent, &r, &c, &rx, &ry, &x, &y, &m)) - menubar_enter(c); - } -} - void menuaction(struct Item *i, struct Item *si) { extern void restart_amiwm(void); @@ -887,57 +871,6 @@ void menuaction(struct Item *i, struct Item *si) } } -void menu_off() -{ - struct Menu *oa; - struct Item *oi, *osi; - - if(scr->menubarparent) { - Window r,p,*children; - unsigned int nchildren; - XUngrabPointer(dpy, CurrentTime); - setfocus((activeclient && activeclient->state==NormalState? - activeclient->window:None)); - XUnmapWindow(dpy, scr->menubarparent); - if(XQueryTree(dpy, scr->back, &r, &p, &children, &nchildren)) { - int n; - Client *c2; - for(n=0; nparent) - break; - if(nmenubar; - XRestackWindows(dpy, ws, 2); - } - if(children) XFree(children); - } - } - if((osi=activesubitem)) - leave_item(osi, osi->win); - if((oi=activeitem)) - leave_item(oi, oi->win); - if((oa=activesubmenu)) { - activesubmenu=NULL; - if(oa->parent) - XUnmapWindow(dpy, oa->parent); - } - if((oa=activemenu)) { - activemenu=NULL; - if(oa->parent) - XUnmapWindow(dpy, oa->parent); - XSetWindowBackground(dpy, oa->win, scr->dri.dri_Pens[BARBLOCKPEN]); - XClearWindow(dpy, oa->win); - redraw_menu(oa, oa->win); - } - if(oi) { - XSync(dpy, False); - menuaction(oi, osi); - } -} - struct Item *getitembyhotkey(KeySym key) { struct Menu *m; @@ -1023,3 +956,61 @@ struct Item *own_items(struct module *m, Scrn *s, endlink->next = c; return chain; } + +void drag_menu(Scrn *s) +{ + extern void get_drag_event(XEvent *event); + Window w; + struct Item *saved_item = NULL; + struct Item *saved_subitem = NULL; + + if (s->menubarparent == None) + return; + XMapRaised(dpy, s->menubarparent); + XRaiseWindow(dpy, s->menubar); + XGrabPointer(dpy, s->back, True, ButtonPressMask|ButtonReleaseMask| + EnterWindowMask|LeaveWindowMask, GrabModeAsync, GrabModeAsync, + s->back, wm_curs, CurrentTime); + if(XQueryPointer(dpy, s->menubarparent, &(Window){0}, &w, + &(int){0}, &(int){0}, &(int){0}, &(int){0}, &(unsigned){0})) + menubar_enter(w); + for (;;) { + XEvent event; + + get_drag_event(&event); + if (event.type == ButtonRelease && event.xbutton.button == Button3) { + XUngrabPointer(dpy, event.xbutton.time); + break; + } else if (event.type == EnterNotify) { + menubar_enter(event.xcrossing.window); + } else if (event.type == LeaveNotify) { + menubar_leave(event.xcrossing.window); + } + } + XUnmapWindow(dpy, s->menubarparent); + saved_item = activeitem; + saved_subitem = activesubitem; + if(activesubitem != NULL) + leave_item(activesubitem, activesubitem->win); + if(activeitem != NULL) + leave_item(activeitem, activeitem->win); + if(activesubmenu != NULL) { + if(activesubmenu->parent) + XUnmapWindow(dpy, activesubmenu->parent); + activesubmenu=NULL; + } + if(activemenu != NULL) { + struct Menu *saved_menu = activemenu; + activemenu=NULL; + if(saved_menu->parent) + XUnmapWindow(dpy, saved_menu->parent); + XSetWindowBackground(dpy, saved_menu->win, s->dri.dri_Pens[BARBLOCKPEN]); + XClearWindow(dpy, saved_menu->win); + redraw_menu(saved_menu, saved_menu->win); + } + if(saved_item != NULL) { + XSync(dpy, False); + menuaction(saved_item, saved_subitem); + } + XLowerWindow(dpy, s->menubar); +} diff --git a/screen.c b/screen.c index c17a251..49acf41 100644 --- a/screen.c +++ b/screen.c @@ -418,3 +418,38 @@ Scrn *getscreenbyroot(Window w) { return getscreenbyrootext(w, 0); } + +void click_screendepth(Scrn *s, Time time) +{ + extern void redrawmenubar(Scrn *, Window); + extern void get_drag_event(XEvent *event); + extern Scrn *mbdclick; + int status; + + XSync(dpy, False); + status = XGrabPointer(dpy, s->menubardepth, True, ButtonPressMask|ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, False, None, time); + if (status != AlreadyGrabbed && status != GrabSuccess) + return; + mbdclick = s; + redrawmenubar(s, s->menubardepth); + for (;;) { + XEvent event; + + get_drag_event(&event); + if (event.type == ButtonRelease || event.type == ButtonPress) { + mbdclick = NULL; + redrawmenubar(s, s->menubardepth); + XUngrabPointer(dpy, event.xbutton.time); + if (event.type == ButtonPress) + return; + if (event.xbutton.x < 0 || event.xbutton.y < 0) + return; /* pointer to left/top of button */ + if (event.xbutton.x >= 23 || event.xbutton.y >= s->bh) + return; /* pointer to right/bottom of button */ + if(event.xbutton.window == s->menubardepth) + screentoback(); + return; + } + } +} diff --git a/screen.h b/screen.h index 26fef64..4235550 100644 --- a/screen.h +++ b/screen.h @@ -46,6 +46,7 @@ extern void closescreen(); extern Scrn * openscreen(char *, Window); extern void realizescreens(); extern void screentoback(); +extern void click_screendepth(Scrn *s, Time time); void closescreen(); Scrn *openscreen(char *deftitle, Window root);