void move_to_workspace(WWinObj *obj, int ws) { WWinObj *tmp; int ows; if(ws>=SCREEN->n_workspaces) return; if(ws<0 && ws!=WORKSPACE_STICKY) ws=SCREEN->current_workspace; tmp=obj; while(obj!=NULL){ ows=obj->workspace; obj->workspace=ws; if(visible_workspace(ws)){ do_map_winobj(obj); if(WTHING_IS(obj, WTHING_FRAME) && (ws==WORKSPACE_STICKY || ows==WORKSPACE_STICKY)) draw_frame_bar((WFrame*)obj, TRUE); }else{ unmap_winobj(obj); } if(WTHING_IS(obj, WTHING_FRAME)) set_client_workspaces(obj); obj=traverse_winobjs(obj, tmp); } update_winlist(); }
static void redraw_wwin(WWindow *wwin) { if(WTHING_IS(wwin, WFrame)) draw_frame((WFrame*)wwin, FALSE); else if(WTHING_IS(wwin, WInput)) input_draw((WInput*)wwin, FALSE); }
static WObj *do_find_at(WObj *obj, int x, int y) { WWsSplit *split; WWindow *wwin; WRectangle geom; if(!WTHING_IS(obj, WWsSplit)){ if(!WTHING_IS(obj, WFrame)) return NULL; wwin=(WWindow*)obj; if(x<wwin->geom.x || x>=(wwin->geom.x+wwin->geom.w) || y<wwin->geom.y || y>=(wwin->geom.y+wwin->geom.h)) return NULL; return obj; } split=(WWsSplit*)obj; if(x<split->geom.x || x>=(split->geom.x+split->geom.w) || y<split->geom.y || y>=(split->geom.y+split->geom.h)) return NULL; obj=do_find_at(split->tl, x, y); if(obj==NULL) obj=do_find_at(split->br, x, y); return obj; }
void menu_motion(WThing *thing, XMotionEvent *ev, int dx, int dy, WFunction *func, WFuncArg arg) { WMenu *menu; int ret; if(!WTHING_IS(thing, WTHING_MENU)) return; menu=(WMenu*)thing; if(!menu_select_at(menu, ev->x_root, ev->y_root)){ thing=find_thing(ev->subwindow); if(thing==(WThing*)menu || thing==NULL || !WTHING_IS(thing, WTHING_MENU)){ end_scroll(); return; } wglobal.grab_holder=thing; menu=(WMenu*)thing; if(!menu_select_at(menu, ev->x_root, ev->y_root)){ end_scroll(); return; } } if(test_scroll(menu, ev->x_root, ev->y_root)) start_scroll(menu); }
WWinObj *winobj_of(WThing *thing) { if(WTHING_IS(thing, WTHING_WINOBJ)) return (WWinObj*)thing; if(WTHING_IS(thing, WTHING_CLIENTWIN)) return (WWinObj*)CWIN_FRAME((WClientWin*)thing); return NULL; }
static void handle_focus_in(const XFocusChangeEvent *ev) { WThing *thing; WWindow *wwin; WScreen *scr; Colormap cmap=None; if(ev->mode==NotifyGrab || ev->detail > NotifyNonlinearVirtual) return; thing=FIND_WINDOW_T(ev->window, WThing); if(thing==NULL) return; /* Set current screen */ scr=SCREEN_OF(thing); wglobal.current_screen=scr; if(ev->window==scr->root.win){ if(ev->detail!=NotifyNonlinear && ev->detail!=NotifyNonlinearVirtual) restore_focus(scr); return; } if(ev->mode==NotifyUngrab){ if(WTHING_IS(thing, WFrame) && !IS_ACTIVE_FRAME(thing)) restore_focus(scr); return; } /* Handle colormap */ if(WTHING_IS(thing, WClientWin)) cmap=((WClientWin*)thing)->cmap; install_cmap(scr, cmap); /* Set active WWindow etc. */ if(WTHING_IS(thing, WWindow)){ wwin=(WWindow*)thing; if(wwin->xic!=NULL) XSetICFocus(wwin->xic); } wwin=window_of(thing); if(wglobal.current_wswindow==wwin) return; if(wglobal.current_wswindow!=NULL) deactivate(wglobal.current_wswindow); if(wwin!=NULL) activate(wwin); }
void destroy_thing(WThing *t) { if(WTHING_IS(t, WTHING_FRAME)) destroy_frame((WFrame*)t); else if(WTHING_IS(t, WTHING_DOCK)) destroy_dock((WDock*)t); else if(WTHING_IS(t, WTHING_MENU)) destroy_menu_tree((WMenu*)t); else if(WTHING_IS(t, WTHING_CLIENTWIN)) unmanage_clientwin((WClientWin*)t); }
static void res_draw_moveres(WScreen *scr, WWindow *wwin) { int w, h, x, y; WClientWin *cwin; if(rtmp.dir==HORIZONTAL){ x=rtmp.winpostmp; w=rtmp.winsizetmp; h=wwin->geom.h; y=wwin->geom.y; }else{ x=wwin->geom.x; w=wwin->geom.w; y=rtmp.winpostmp; h=rtmp.winsizetmp; } if(WTHING_IS(wwin, WFrame)){ w+=FRAME_CLIENT_WOFF(scr); h+=FRAME_CLIENT_HOFF(scr); if(((WFrame*)wwin)->current_client!=NULL && (cwin=FIRST_THING(((WFrame*)wwin)->current_client, WClientWin))!=NULL){ cwin_size(scr, &w, &h, &(cwin->size_hints)); }else{ w/=scr->w_unit; h/=scr->h_unit; } } set_moveres_size(scr, w, h); }
void dodo_switch_workspace(int num) { WScreen *scr=SCREEN; WThing *thing, *next; WWinObj *obj; int old; old=scr->current_workspace; if(old==num) return; scr->current_workspace=num; for(thing=scr->t_children; thing!=NULL; thing=next){ next=thing->t_next; if(!WTHING_IS(thing, WTHING_WINOBJ)) continue; obj=(WWinObj*)thing; if(WWINOBJ_IS_STICKY(obj)) continue; if(on_current_workspace(obj)) do_map_winobj(obj); else if(obj->workspace==old) do_unmap_winobj(obj); } set_integer_property(scr->root, wglobal.atom_workspace_num, scr->current_workspace); }
static bool resize_handler(WThing *thing, XEvent *xev) { XKeyEvent *ev=&xev->xkey; WScreen *scr; WBinding *binding=NULL; WBindmap **bindptr; if(!resize_mode){ return TRUE; } if(ev->type==KeyRelease) return FALSE; assert(thing && WTHING_IS(thing, WWindow)); binding=lookup_binding(&wglobal.moveres_bindmap, ACT_KEYPRESS, ev->state, ev->keycode); if(!binding) return FALSE; if(binding){ /* Get the screen now for waitrel grab - the thing might * have been destroyed when call_binding returns. */ scr=SCREEN_OF(thing); call_binding(binding, thing); } return !resize_mode; }
WWinObj *find_winobj_of(Window win) { WThing *thing=find_thing(win); if(thing==NULL) return NULL; if(WTHING_IS(thing, WTHING_FRAME)) return (WWinObj*)thing; if(WTHING_IS(thing, WTHING_CLIENTWIN) && thing->t_parent!=NULL && WTHING_IS(thing->t_parent, WTHING_WINOBJ)) return (WWinObj*)thing->t_parent; return NULL; }
static void handle_expose(const XExposeEvent *ev) { WWindow *wwin; WScreen *scr; XEvent tmp; while(XCheckWindowEvent(wglobal.dpy, ev->window, ExposureMask, &tmp)) /* nothing */; wwin=FIND_WINDOW_T(ev->window, WWindow); if(wwin!=NULL){ redraw_wwin(wwin); return; } if(wglobal.grab_holder==NULL || !WTHING_IS(wglobal.grab_holder, WClient)) return; FOR_ALL_SCREENS(scr){ if(scr->grdata.tabdrag_win==ev->window){ draw_tabdrag((WClient*)wglobal.grab_holder); break; } } }
void do_set_focus(WThing *thing) { WFrame *frame; WClientWin *cwin=NULL; Window win; if(WTHING_IS_UNFOCUSABLE(thing)) return; if(WTHING_IS(thing, WTHING_WINOBJ)){ if(!on_current_workspace((WWinObj*)thing)){ if(wglobal.current_winobj!=NULL) return; thing=(WThing*)SCREEN; } } if(WTHING_IS(thing, WTHING_FRAME)){ frame=(WFrame*)thing; if(!WFRAME_IS_NORMAL(frame) || frame->current_cwin==NULL){ /* The frame is in shade mode or missing client window. * Just sink keyboard input events in the tab bar. */ win=frame->bar_win; }else{ cwin=frame->current_cwin; win=cwin->client_win; } }else if(WTHING_IS(thing, WTHING_CLIENTWIN)){ cwin=(WClientWin*)thing; win=cwin->client_win; }else if(WTHING_IS(thing, WTHING_MENU)){ win=((WMenu*)thing)->menu_win; }else if(WTHING_IS(thing, WTHING_SCREEN)){ win=SCREEN->root; /*if(SCREEN->current_cmap!=None) XInstallColormap(wglobal.dpy, SCREEN->default_cmap);*/ }else{ return; } XSetInputFocus(wglobal.dpy, win, RevertToParent, CurrentTime); if(cwin!=NULL && cwin->flags&CWIN_P_WM_TAKE_FOCUS) send_clientmsg(cwin->client_win, wglobal.atom_wm_take_focus); }
WFrame *find_frame_of(Window win) { WWinObj *winobj=find_winobj_of(win); if(winobj==NULL || !WTHING_IS(winobj, WTHING_FRAME)) return NULL; return (WFrame*)winobj; }
WThing *find_thing_t(Window win, int type) { WThing *thing=find_thing(win); if(thing==NULL || !WTHING_IS(thing, type)) return NULL; return thing; }
static WMenu *topmenu(WMenu *menu) { WMenu *top=menu; while(top->stack_above!=NULL && WTHING_IS(top->stack_above, WTHING_MENU)) top=(WMenu*)top->stack_above; return top; }
static WThing *get_next_thing(WThing *first, int filt) { while(first!=NULL){ if(filt==0 || WTHING_IS(first, filt)) break; first=first->t_next; }; return first; }
static void tmr_end_resize(WTimer *unused) { WThing *holder; if(!resize_mode){ return; } holder=grab_get_holder(resize_handler); assert(holder && WTHING_IS(holder, WWindow)); end_resize((WWindow*)holder); }
static bool try_focus(WThing *next) { if(WTHING_IS(next, WTHING_WINOBJ) && !WTHING_IS_UNFOCUSABLE(next) && on_current_workspace((WWinObj*)next)){ do_set_focus(next); return TRUE; } return FALSE; }
void destroy_contextual_menus() { WWinObj *next, *obj=SCREEN->winobj_stack_lists[LVL_MENU]; while(obj!=NULL){ next=obj->stack_next; if(WTHING_IS(obj, WTHING_MENU)) do_destroy_menu_tree((WMenu*)obj, TRUE, TRUE); obj=next; } }
static void attachlist_menudata_exec(WMenuEnt *entry, WThing *context) { WWinObj *obj=winobj_of(context); if(!WTHING_IS(obj, WTHING_FRAME)) return; if(entry->u.winlist.clientwin==NULL) return; attachdetach_clientwin((WFrame*)obj, entry->u.winlist.clientwin, FALSE, 0, 0); }
static void move_menu(WMenu *menu, int dx, int dy) { WWinObj *p; do_move(menu, dx, dy); p=menu->stack_above_list; while(p!=NULL){ if(WTHING_IS(p, WTHING_MENU)) do_move((WMenu*)p, dx, dy); p=traverse_winobjs(p, (WWinObj*)menu); } }
/* Destroy a menu and all its submenus. */ static void do_destroy_menu_tree(WMenu *menu, bool setsel, bool contextual_only) { WWinObj *tmpobj=NULL, *p, *next; WWinObj *parent=menu->stack_above; p=init_traverse_winobjs_b((WWinObj*)menu, &tmpobj); for(; p!=NULL; p=next){ next=traverse_winobjs_b(p, (WWinObj*)menu, &tmpobj); if(!WTHING_IS(p, WTHING_MENU)) continue; if(contextual_only && !(p->flags&WMENU_CONTEXTUAL)) continue; /* destroy the menu */ parent=p->stack_above; do_destroy_menu((WMenu*)p); if(setsel && parent!=NULL && WTHING_IS(parent, WTHING_MENU)) menu_set_selected((WMenu*)parent, NO_ENTRY); } }
void menu_button(WThing *thing, XButtonEvent *ev, WFunction *func, WFuncArg arg) { WMenu *menu; int x, y, entry; if(!WTHING_IS(thing, WTHING_MENU)) return; menu=(WMenu*)thing; x=ev->x_root-menu->x; y=ev->y_root-menu->y; entry=entry_at(menu, x, y); if(ev->type==ButtonPress){ /* press */ if(entry==menu->selected){ menu_set_selected(menu, NO_ENTRY); }else{ menu_set_selected(menu, entry); show_selected_submenu(menu); } return; } end_scroll(); /* release */ if(entry>=0){ if(menu->selected==entry) menu_execute_selected(menu); }else if(entry!=ENTRY_TITLE && !(menu->flags&WMENU_KEEP)){ finish_menu(menu, FALSE); } destroy_contextual_menus(); }
static void activate(WWindow *wwin) { set_current_wswindow(wwin); if(WTHING_IS(wwin, WFrame)) activate_frame((WFrame*)wwin); }
/* Create a menu window */ static WMenu* create_menu(WMenuData *mdata, WThing *context, int x, int y, WMenu *parent) { int w, h, th, eh; int flags=0; Window win; WMenu *menu; if(mdata->init_func!=NULL && mdata->nref==0) mdata->init_func(mdata, context); if(mdata->flags&WMENUDATA_CONTEXTUAL){ if(context==NULL || WTHING_IS(context, WTHING_SCREEN) || WTHING_IS(context, WTHING_MENU)) return NULL; flags|=(WMENU_NOTITLE|WMENU_CONTEXTUAL); }else{ context=NULL; } if(mdata->nref!=0) flags|=(WMENU_NOTITLE|WMENU_CONTEXTUAL); if(mdata->title==NULL) flags|=(WMENU_NOTITLE|WMENU_CONTEXTUAL); if(parent!=NULL) flags|=parent->flags&(WMENU_NOTITLE|WMENU_CONTEXTUAL); /* */ w=menu_width(mdata, flags); h=menu_height(mdata); /* Don't display empty menus */ if(w==0 || h==0) return NULL; /* */ menu=ALLOC(WMenu); if(menu==NULL){ warn_err(); return NULL; } WTHING_INIT(menu, WTHING_MENU); th=FONT_HEIGHT(GRDATA->font)+2*CF_MENUTITLE_V_SPACE; eh=FONT_HEIGHT(GRDATA->menu_font)+2*CF_MENUENT_V_SPACE; if(parent==NULL){ x-=w/2; y+=th/(flags&WMENU_NOTITLE ? 2 : -2 ); }else if(!(flags&WMENU_NOTITLE)){ y-=th; } if(flags&WMENU_NOTITLE) th=0; h+=th; win=create_simple_window(x, y, w, h, GRDATA->base_colors.pixels[WCG_PIX_BG]); menu->menu_win=win; menu->x=x; menu->y=y; menu->w=w; menu->h=h; menu->title_height=th; menu->entry_height=eh; menu->flags=flags; menu->selected=NO_ENTRY; menu->data=mdata; menu->context=context; if(mdata->nref++==0) mdata->inst1=menu; XSelectInput(wglobal.dpy, win, MENU_MASK); XSaveContext(wglobal.dpy, win, wglobal.win_context, (XPointer)menu); if(parent==NULL) add_winobj((WWinObj*)menu, WORKSPACE_STICKY, LVL_MENU); else add_winobj_above((WWinObj*)menu, (WWinObj*)parent); map_winobj((WWinObj*)menu); return menu; }
static void deactivate(WWindow *wwin) { wglobal.current_wswindow=NULL; if(WTHING_IS(wwin, WFrame)) deactivate_frame((WFrame*)wwin); }