diff --git a/src/clientwin.c b/src/clientwin.c index 8b9d609..e3530ba 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -170,6 +170,8 @@ clientwin_get_disp_mode(session_t *ps, ClientWin *cw, bool isViewable) { case CLIDISP_FILLED: case CLIDISP_NONE: return *p; + case CLIDISP_DESKTOP: + return *p; } } @@ -282,6 +284,8 @@ clientwin_update2(ClientWin *cw) { clientwin_free_res2(ps, cw); switch (cw->mode) { + case CLIDISP_DESKTOP: + break; case CLIDISP_NONE: break; case CLIDISP_FILLED: @@ -347,6 +351,9 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) } switch (cw->mode) { + case CLIDISP_DESKTOP: + source = cw->origin; + break; case CLIDISP_NONE: break; case CLIDISP_FILLED: @@ -388,6 +395,7 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) XRenderComposite(ps->dpy, PictOpOver, source, mask, cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); } + if (CLIDISP_ZOMBIE_ICON == cw->mode || CLIDISP_THUMBNAIL_ICON == cw->mode) { assert(cw->icon_pict && cw->icon_pict->pict); img_composite_params_t params = IMG_COMPOSITE_PARAMS_INIT; @@ -401,9 +409,7 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) } // Tinting - if (cw->mode >= CLIDISP_ZOMBIE) // tint only thumbnail { - // here the client window is being tinted XRenderColor *tint = &cw->mainwin->normalTint; if (cw->focused) tint = &cw->mainwin->highlightTint; @@ -460,6 +466,29 @@ clientwin_schedule_repair(ClientWin *cw, XRectangle *area) cw->damaged = true; } +void clientwin_round_corners(ClientWin *cw) { + session_t* ps = cw->mainwin->ps; + int dia = 2 * ps->o.cornerRadius; + int w = cw->mini.width; + int h = cw->mini.height; + XGCValues xgcv; + Pixmap mask = XCreatePixmap(ps->dpy, cw->mini.window, w, h, 1); + GC shape_gc = XCreateGC(ps->dpy, mask, 0, &xgcv); + + XSetForeground(ps->dpy, shape_gc, 0); + XFillRectangle(ps->dpy, mask, shape_gc, 0, 0, w, h); + XSetForeground(ps->dpy, shape_gc, 1); + XFillArc(ps->dpy, mask, shape_gc, 0, 0, dia, dia, 0, 360 * 64); + XFillArc(ps->dpy, mask, shape_gc, w-dia-1, 0, dia, dia, 0, 360 * 64); + XFillArc(ps->dpy, mask, shape_gc, 0, h-dia-1, dia, dia, 0, 360 * 64); + XFillArc(ps->dpy, mask, shape_gc, w-dia-1, h-dia-1, dia, dia, 0, 360 * 64); + XFillRectangle(ps->dpy, mask, shape_gc, ps->o.cornerRadius, 0, w-dia, h); + XFillRectangle(ps->dpy, mask, shape_gc, 0, ps->o.cornerRadius, w, h-dia); + XShapeCombineMask(ps->dpy, cw->mini.window, ShapeBounding, 0, 0, mask, ShapeSet); + XFreePixmap(ps->dpy, mask); + XFreeGC(ps->dpy, shape_gc); +} + void clientwin_move(ClientWin *cw, float f, int x, int y, float timeslice) { @@ -765,26 +794,3 @@ clientwin_action(ClientWin *cw, enum cliop action) { return 0; } - -void clientwin_round_corners(ClientWin *cw) { - session_t* ps = cw->mainwin->ps; - int dia = 2 * ps->o.cornerRadius; - int w = cw->mini.width; - int h = cw->mini.height; - XGCValues xgcv; - Pixmap mask = XCreatePixmap(ps->dpy, cw->mini.window, w, h, 1); - GC shape_gc = XCreateGC(ps->dpy, mask, 0, &xgcv); - - XSetForeground(ps->dpy, shape_gc, 0); - XFillRectangle(ps->dpy, mask, shape_gc, 0, 0, w, h); - XSetForeground(ps->dpy, shape_gc, 1); - XFillArc(ps->dpy, mask, shape_gc, 0, 0, dia, dia, 0, 360 * 64); - XFillArc(ps->dpy, mask, shape_gc, w-dia-1, 0, dia, dia, 0, 360 * 64); - XFillArc(ps->dpy, mask, shape_gc, 0, h-dia-1, dia, dia, 0, 360 * 64); - XFillArc(ps->dpy, mask, shape_gc, w-dia-1, h-dia-1, dia, dia, 0, 360 * 64); - XFillRectangle(ps->dpy, mask, shape_gc, ps->o.cornerRadius, 0, w-dia, h); - XFillRectangle(ps->dpy, mask, shape_gc, 0, ps->o.cornerRadius, w, h-dia); - XShapeCombineMask(ps->dpy, cw->mini.window, ShapeBounding, 0, 0, mask, ShapeSet); - XFreePixmap(ps->dpy, mask); - XFreeGC(ps->dpy, shape_gc); -} diff --git a/src/mainwin.h b/src/mainwin.h index 11ad087..359ab7f 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -50,7 +50,7 @@ struct _mainwin_t { Picture normalPicture, highlightPicture, shadowPicture; ClientWin *pressed, *focus; - dlist *clientondesktop, *focuslist; + dlist *clientondesktop, *focuslist, *desktopwins, *dminis; struct _Tooltip *tooltip; KeySym *keysyms_Up; diff --git a/src/skippy.c b/src/skippy.c index 056a717..6c9b2d7 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -365,11 +365,11 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) return; } -static void +static bool init_layout(MainWin *mw, Window focus, Window leader) { if (!mw->clientondesktop) - return; + return true; dlist_sort(mw->clientondesktop, clientwin_sort_func, 0); @@ -400,14 +400,14 @@ init_layout(MainWin *mw, Window focus, Window leader) mw->yoff = yoff; } - return; + return true; } -static void -init_desktop_layout(MainWin *mw, Window focus, Window leader) +static bool +init_paging_layout(MainWin *mw, Window focus, Window leader) { if (!mw->clients) - return; + return true; int screencount = wm_get_desktops(mw->ps); if (screencount == -1) @@ -448,10 +448,105 @@ init_desktop_layout(MainWin *mw, Window focus, Window leader) cw->src.y += (win_desktop_y - current_desktop_y) * (mw->height + mw->distance); } - dlist_sort(mw->clientondesktop, sort_cw_by_row, 0); - mw->focuslist = mw->clientondesktop; + // create windows which represent each virtual desktop + int current_desktop = wm_get_current_desktop(mw->ps); + for (int j=0; jcolormap, + /*.event_mask = ButtonPressMask | ButtonReleaseMask | KeyPressMask + | KeyReleaseMask | EnterWindowMask | LeaveWindowMask + | PointerMotionMask | ExposureMask | FocusChangeMask,*/ + .override_redirect = false, + // exclude window frame + }; + Window desktopwin = XCreateWindow(mw->ps->dpy, + mw->window, + 0, 0, 0, 0, + 0, mw->depth, InputOnly, mw->visual, + CWColormap | CWBackPixel | CWBorderPixel | CWEventMask | CWOverrideRedirect, &sattr); + if (!desktopwin) return false; + + if (!mw->desktopwins) + mw->desktopwins = dlist_add(NULL, &desktopwin); + else + mw->desktopwins = dlist_add(mw->desktopwins, &desktopwin); - return; + ClientWin *cw = clientwin_create(mw, desktopwin); + if (!cw) return false; + + cw->slots = desktop_idx; + + { + static const char *PREFIX = "virtual desktop "; + const int len = strlen(PREFIX) + 20; + char *str = allocchk(malloc(len)); + snprintf(str, len, "%s%d", PREFIX, cw->slots); + wm_wid_set_info(cw->mainwin->ps, cw->mini.window, str, None); + free(str); + } + + cw->zombie = false; + cw->mode = CLIDISP_DESKTOP; + + cw->x = cw->src.x = (i * (mw->width + mw->distance)) * mw->multiplier; + cw->y = cw->src.y = (j * (mw->height + mw->distance)) * mw->multiplier; + cw->src.width = mw->width; + cw->src.height = mw->height; + + clientwin_move(cw, mw->multiplier, mw->xoff, mw->yoff, 1); + + if (!mw->dminis) + mw->dminis = dlist_add(NULL, cw); + else + dlist_add(mw->dminis, cw); + + XRaiseWindow(mw->ps->dpy, cw->mini.window); + + if (cw->slots == current_desktop) { + mw->client_to_focus = cw; + mw->revert_focus_win = cw->wid_client; + mw->client_to_focus_on_cancel = cw; + mw->client_to_focus->focused = 1; + } + } + } + + mw->focuslist = mw->dminis; + + return true; +} + +static void +desktopwin_map(ClientWin *cw) +{ + session_t *ps = cw->mainwin->ps; + + free_damage(ps, &cw->damage); + free_pixmap(ps, &cw->pixmap); + + XUnmapWindow(ps->dpy, cw->mini.window); + XSetWindowBackgroundPixmap(ps->dpy, cw->mini.window, None); + + XRenderPictureAttributes pa = { }; + + if (cw->origin) + free_picture(ps, &cw->origin); + cw->origin = XRenderCreatePicture(ps->dpy, + None, cw->mainwin->format, CPSubwindowMode, &pa); + XRenderSetPictureFilter(ps->dpy, cw->origin, FilterBest, 0, 0); + + XCompositeRedirectWindow(ps->dpy, cw->src.window, + CompositeRedirectAutomatic); + cw->redirected = true; + + clientwin_render(cw); + + XMapWindow(ps->dpy, cw->mini.window); + XRaiseWindow(ps->dpy, cw->mini.window); } static inline const char * @@ -559,52 +654,45 @@ init_focus(MainWin *mw, Window leader) { session_t *ps = mw->ps; // Get the currently focused window and select which mini-window to focus - { - dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) mw->revert_focus_win); + dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) mw->revert_focus_win); - // check if the user specified --prev or --next on the cmdline - if(ps->o.focus_initial) - { + // check if the user specified --prev or --next on the cmdline + if(ps->o.focus_initial) + { - // ps->mainwin->ignore_next_refocus = 1; - // ps->mainwin->ignore_next_refocus = 2; - // ps->mainwin->ignore_next_refocus = 4; + // ps->mainwin->ignore_next_refocus = 1; + // ps->mainwin->ignore_next_refocus = 2; + // ps->mainwin->ignore_next_refocus = 4; - if(ps->o.focus_initial == FI_PREV) + if(ps->o.focus_initial == FI_PREV) + { + // here, mw->focuslist is the first (dlist*) item in the list + if (iter == mw->focuslist) + iter = dlist_last(mw->focuslist); + else { - // here, mw->focuslist is the first (dlist*) item in the list - if (iter == mw->focuslist) - iter = dlist_last(mw->focuslist); - else - { - dlist *i = mw->focuslist; - for (; i != NULL; i = i->next) - if (i->next && i->next == iter) - break; - iter = i; - } + dlist *i = mw->focuslist; + for (; i != NULL; i = i->next) + if (i->next && i->next == iter) + break; + iter = i; } - else if(ps->o.focus_initial == FI_NEXT) - iter = iter->next; - } + else if(ps->o.focus_initial == FI_NEXT) + iter = iter->next; - // then clear this flag, so daemon not remember on its next activation - ps->o.focus_initial = 0; - - if (!iter) - iter = mw->focuslist; + } - // mw->focus = (ClientWin *) iter->data; - mw->client_to_focus = (ClientWin *) iter->data; - mw->client_to_focus_on_cancel = (ClientWin *) iter->data; - // mw->focus->focused = 1; + // then clear this flag, so daemon not remember on its next activation + ps->o.focus_initial = 0; + if (!iter) + return; - mw->client_to_focus->focused = 1; - // focus_miniw(ps, mw->client_to_focus); - } + mw->client_to_focus = (ClientWin *) iter->data; + mw->client_to_focus_on_cancel = (ClientWin *) iter->data; + mw->client_to_focus->focused = 1; } static bool @@ -637,20 +725,18 @@ skippy_activate(MainWin *mw, Window leader, bool paging) } if (paging) { - init_desktop_layout(mw, mw->revert_focus_win, leader); - if (!mw->clientondesktop) { - printfef(false, "(): Failed to build layout."); + if (!init_paging_layout(mw, mw->revert_focus_win, leader)) { + printfef(false, "(): init_paging_layout() failed."); return false; } - mw->focuslist = mw->clientondesktop; } else { - init_layout(mw, mw->revert_focus_win, leader); - if (!mw->clientondesktop) { - printfef(false, "(): Failed to build layout."); + if (!init_layout(mw, mw->revert_focus_win, leader)) { + printfef(false, "(): init_layout() failed."); return false; } } + init_focus(mw, leader); foreach_dlist(mw->clients) { @@ -744,7 +830,14 @@ mainloop(session_t *ps, bool activate_on_start) { // Focus the client window only after the main window get unmapped and // keyboard gets ungrabbed. if (mw->client_to_focus) { - childwin_focus(mw->client_to_focus); + if (paging) { + childwin_focus(mw->client_to_focus); + wm_set_desktop_ewmh(ps, mw->client_to_focus->slots); + //daemon_count_clients(mw, 0, 0); + //mw->client_to_focus = dlist_first(mw->clientondesktop)->data; + } + else + childwin_focus(mw->client_to_focus); mw->client_to_focus = NULL; refocus = false; pending_damage = false; @@ -760,6 +853,17 @@ mainloop(session_t *ps, bool activate_on_start) { refocus = false; } + // free all mini desktop representations + dlist_free_with_func(mw->dminis, (dlist_free_func) clientwin_destroy); + mw->dminis = NULL; + + foreach_dlist (mw->desktopwins) { + XDestroyWindow(ps->dpy, (Window) (iter->data)); + //XSelectInput(ps->dpy, (Window) (iter->data), 0); + } + dlist_free(mw->desktopwins); + mw->desktopwins = NULL; + // Catch all errors, but remove all events XSync(ps->dpy, False); XSync(ps->dpy, True); @@ -804,6 +908,12 @@ mainloop(session_t *ps, bool activate_on_start) { focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); + if (paging) { + foreach_dlist (mw->dminis) { + desktopwin_map(((ClientWin *) iter->data)); + } + } + /* Map the main window and run our event loop */ if (!ps->o.lazyTrans && !mw->mapped) mainwin_map(mw); @@ -883,9 +993,14 @@ mainloop(session_t *ps, bool activate_on_start) { } else if (mw && (ps->xinfo.damage_ev_base + XDamageNotify == ev.type)) { //printfdf(false, "(): else if (ev.type == XDamageNotify) {"); - dlist *iter = dlist_find(ps->mainwin->clients, clientwin_cmp_func, - (void *) wid); pending_damage = true; + dlist *iter = dlist_find(ps->mainwin->clients, + clientwin_cmp_func, (void *) wid); + if (iter) { + ((ClientWin *)iter->data)->damaged = true; + } + iter = dlist_find(ps->mainwin->dminis, + clientwin_cmp_func, (void *) wid); if (iter) { ((ClientWin *)iter->data)->damaged = true; } @@ -906,7 +1021,10 @@ mainloop(session_t *ps, bool activate_on_start) { else if (mw && mw->tooltip && wid == mw->tooltip->window) tooltip_handle(mw->tooltip, &ev); else if (mw && wid) { - for (dlist *iter = mw->clientondesktop; iter; iter = iter->next) { + dlist *iter = mw->clientondesktop; + if (paging) + iter = mw->dminis; + for (; iter; iter = iter->next) { ClientWin *cw = (ClientWin *) iter->data; if (cw->mini.window == wid) { if (!(POLLIN & r_fd[1].revents)) @@ -925,8 +1043,12 @@ mainloop(session_t *ps, bool activate_on_start) { pending_damage = false; foreach_dlist(mw->clientondesktop) { if (((ClientWin *) iter->data)->damaged) - { clientwin_repair(iter->data); + } + + if (paging) { + foreach_dlist (mw->dminis) { + desktopwin_map(((ClientWin *) iter->data)); } } last_rendered = time_in_millis(); diff --git a/src/skippy.h b/src/skippy.h index 0bf7b30..5f3bf29 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -164,6 +164,7 @@ typedef struct { } keydef_t; typedef enum { + CLIDISP_DESKTOP = -1, CLIDISP_NONE, CLIDISP_FILLED, CLIDISP_ICON,