diff --git a/WINGs/wwindow.c b/WINGs/wwindow.c index 5293f87b..a04ab6ae 100644 --- a/WINGs/wwindow.c +++ b/WINGs/wwindow.c @@ -606,8 +606,8 @@ void WMSetWindowMiniwindowPixmap(WMWindow * win, WMPixmap * pixmap) void WMSetWindowMiniwindowTitle(WMWindow * win, const char *title) { - if ((win->miniTitle && !title) || (!win->miniTitle && title) - || (title && win->miniTitle && strcoll(title, win->miniTitle) != 0)) { + if (win && ((win->miniTitle && !title) || (!win->miniTitle && title) + || (title && win->miniTitle && strcoll(title, win->miniTitle) != 0))) { if (win->miniTitle) wfree(win->miniTitle); diff --git a/WPrefs.app/Preferences.c b/WPrefs.app/Preferences.c index 7d772139..b6b78913 100644 --- a/WPrefs.app/Preferences.c +++ b/WPrefs.app/Preferences.c @@ -39,7 +39,7 @@ typedef struct _Panel { WMPopUpButton *posiP; WMFrame *ballF; - WMButton *ballB[4]; + WMButton *ballB[5]; WMFrame *optF; WMButton *bounceB; @@ -136,8 +136,9 @@ static void showData(_Panel * panel) WMSetButtonSelected(panel->ballB[0], GetBoolForKey("WindowTitleBalloons")); WMSetButtonSelected(panel->ballB[1], GetBoolForKey("MiniwindowTitleBalloons")); - WMSetButtonSelected(panel->ballB[2], GetBoolForKey("AppIconBalloons")); - WMSetButtonSelected(panel->ballB[3], GetBoolForKey("HelpBalloons")); + WMSetButtonSelected(panel->ballB[2], GetBoolForKey("MiniwindowApercuBalloons")); + WMSetButtonSelected(panel->ballB[3], GetBoolForKey("AppIconBalloons")); + WMSetButtonSelected(panel->ballB[4], GetBoolForKey("HelpBalloons")); } static void storeData(_Panel * panel) @@ -198,8 +199,9 @@ static void storeData(_Panel * panel) SetBoolForKey(WMGetButtonSelected(panel->bounceRaisB), "RaiseAppIconsWhenBouncing"); SetBoolForKey(WMGetButtonSelected(panel->ballB[0]), "WindowTitleBalloons"); SetBoolForKey(WMGetButtonSelected(panel->ballB[1]), "MiniwindowTitleBalloons"); - SetBoolForKey(WMGetButtonSelected(panel->ballB[2]), "AppIconBalloons"); - SetBoolForKey(WMGetButtonSelected(panel->ballB[3]), "HelpBalloons"); + SetBoolForKey(WMGetButtonSelected(panel->ballB[2]), "MiniwindowApercuBalloons"); + SetBoolForKey(WMGetButtonSelected(panel->ballB[3]), "AppIconBalloons"); + SetBoolForKey(WMGetButtonSelected(panel->ballB[4]), "HelpBalloons"); } static void createPanel(Panel * p) @@ -251,26 +253,27 @@ static void createPanel(Panel * p) /***************** Balloon Text ****************/ panel->ballF = WMCreateFrame(panel->box); - WMResizeWidget(panel->ballF, 240, 109); + WMResizeWidget(panel->ballF, 240, 126); WMMoveWidget(panel->ballF, 265, 10); - WMSetFrameTitle(panel->ballF, _("Show balloon text for...")); + WMSetFrameTitle(panel->ballF, _("Show balloon for...")); - for (i = 0; i < 4; i++) { + for (i = 0; i < 5; i++) { panel->ballB[i] = WMCreateSwitchButton(panel->ballF); WMResizeWidget(panel->ballB[i], 210, 20); WMMoveWidget(panel->ballB[i], 15, 16 + i * 22); } WMSetButtonText(panel->ballB[0], _("incomplete window titles")); WMSetButtonText(panel->ballB[1], _("miniwindow titles")); - WMSetButtonText(panel->ballB[2], _("application/dock icons")); - WMSetButtonText(panel->ballB[3], _("internal help")); + WMSetButtonText(panel->ballB[2], _("miniwindow apercus")); + WMSetButtonText(panel->ballB[3], _("application/dock icons")); + WMSetButtonText(panel->ballB[4], _("internal help")); WMMapSubwidgets(panel->ballF); /***************** Options ****************/ panel->optF = WMCreateFrame(panel->box); - WMResizeWidget(panel->optF, 240, 101); - WMMoveWidget(panel->optF, 265, 124); + WMResizeWidget(panel->optF, 240, 91); + WMMoveWidget(panel->optF, 265, 136); WMSetFrameTitle(panel->optF, _("AppIcon bouncing")); panel->bounceB = WMCreateSwitchButton(panel->optF); @@ -279,21 +282,21 @@ static void createPanel(Panel * p) WMSetButtonText(panel->bounceB, _("Disable AppIcon bounce.")); panel->bounceUrgB = WMCreateSwitchButton(panel->optF); - WMResizeWidget(panel->bounceUrgB, 210, 30); - WMMoveWidget(panel->bounceUrgB, 15, 39); + WMResizeWidget(panel->bounceUrgB, 210, 28); + WMMoveWidget(panel->bounceUrgB, 15, 37); WMSetButtonText(panel->bounceUrgB, _("Bounce AppIcon when the application wants attention.")); WMSetButtonSelected(panel->bounceUrgB, True); /* defaults to true */ panel->bounceRaisB = WMCreateSwitchButton(panel->optF); - WMResizeWidget(panel->bounceRaisB, 210, 25); - WMMoveWidget(panel->bounceRaisB, 15, 70); + WMResizeWidget(panel->bounceRaisB, 210, 23); + WMMoveWidget(panel->bounceRaisB, 15, 65); WMSetButtonText(panel->bounceRaisB, _("Raise AppIcons when bouncing.")); WMMapSubwidgets(panel->optF); /***************** Workspace border ****************/ panel->borderF = WMCreateFrame(panel->box); - WMResizeWidget(panel->borderF, 240, 80); + WMResizeWidget(panel->borderF, 240, 82); WMMoveWidget(panel->borderF, 15, 145); WMSetFrameTitle(panel->borderF, _("Workspace border")); diff --git a/src/WindowMaker.h b/src/WindowMaker.h index d0212932..5553d5b3 100644 --- a/src/WindowMaker.h +++ b/src/WindowMaker.h @@ -392,7 +392,8 @@ extern struct WPreferences { /* balloon text */ char window_balloon; - char miniwin_balloon; + char miniwin_title_balloon; + char miniwin_apercu_balloon; char appicon_balloon; char help_balloon; diff --git a/src/actions.c b/src/actions.c index a767072f..ae326a11 100644 --- a/src/actions.c +++ b/src/actions.c @@ -1094,6 +1094,40 @@ void wIconifyWindow(WWindow * wwin) wwin->icon = icon_create_for_wwindow(wwin); wwin->icon->mapped = 1; + + /* extract the window screenshot everytime, as the option can be enable anytime */ + if (wwin->client_win && wwin->flags.mapped) { + RImage *apercu; + XImage *pimg; + unsigned int w, h; + int x, y; + Window baz; + + XRaiseWindow(dpy, wwin->frame->core->window); + XTranslateCoordinates(dpy, wwin->client_win, wwin->screen_ptr->root_win, 0, 0, &x, &y, &baz); + + w = attribs.width; + h = attribs.height; + + if (x - attribs.x + attribs.width > wwin->screen_ptr->scr_width) + w = wwin->screen_ptr->scr_width - x + attribs.x; + + if (y - attribs.y + attribs.height > wwin->screen_ptr->scr_height) + h = wwin->screen_ptr->scr_height - y + attribs.y; + + pimg = XGetImage(dpy, wwin->client_win, 0, 0, w, h, AllPlanes, ZPixmap); + if (pimg) { + apercu = RCreateImageFromXImage(wwin->screen_ptr->rcontext, pimg, NULL); + XDestroyImage(pimg); + + if (apercu) { + set_icon_apercu(wwin->icon, apercu); + RReleaseImage(apercu); + } else { + wwarning("window apercu creation failed"); + } + } + } } wwin->flags.miniaturized = 1; diff --git a/src/balloon.c b/src/balloon.c index b9c77bb2..1fae947d 100644 --- a/src/balloon.c +++ b/src/balloon.c @@ -2,6 +2,7 @@ * Window Maker window manager * * Copyright (c) 1998-2003 Alfredo K. Kojima + * Copyright (c) 2014 Window Maker Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,6 +43,7 @@ #include "appicon.h" #include "workspace.h" #include "balloon.h" +#include "misc.h" typedef struct _WBalloon { @@ -59,6 +61,7 @@ typedef struct _WBalloon { WMHandlerID timer; Pixmap contents; + Pixmap apercu; char mapped; char ignoreTimer; @@ -376,6 +379,71 @@ static void showText(WScreen *scr, int x, int y, int h, int w, const char *text) } #endif /* !SHAPED_BALLOON */ +static void showApercu(WScreen *scr, int x, int y, int height, int width, char *title, Pixmap apercu) +{ + Pixmap pixmap; + WMFont *font = scr->info_text_font; + int titleHeight = 0; + char *shortenTitle = title; + + if (scr->balloon->contents) + XFreePixmap(dpy, scr->balloon->contents); + + if (wPreferences.miniwin_title_balloon) { + shortenTitle = ShrinkString(font, title, width - APERCU_BORDER); + titleHeight = countLines(shortenTitle) * WMFontHeight(font) + 4; + height += titleHeight; + } + + if (x < 0) + x = 0; + else if (x + width > scr->scr_width - 1) + x = scr->scr_width - width - APERCU_BORDER; + + if (y - height - 2 < 0) { + y += wPreferences.icon_size; + if (y < 0) + y = 0; + } else { + y -= height + 2; + } + + if (scr->window_title_texture[0]) + XSetForeground(dpy, scr->draw_gc, scr->window_title_texture[0]->any.color.pixel); + else + XSetForeground(dpy, scr->draw_gc, scr->light_pixel); + + pixmap = XCreatePixmap(dpy, scr->root_win, width, height, scr->w_depth); + XFillRectangle(dpy, pixmap, scr->draw_gc, 0, 0, width, height); + + if (shortenTitle && wPreferences.miniwin_title_balloon) { + drawMultiLineString(scr->wmscreen, pixmap, scr->window_title_color[0], font, + APERCU_BORDER, APERCU_BORDER, shortenTitle, strlen(shortenTitle)); + wfree(shortenTitle); + } + + XCopyArea(dpy, apercu, pixmap, scr->draw_gc, + 0, 0, (wPreferences.icon_size - 1 - APERCU_BORDER) * 2, + (wPreferences.icon_size - 1 - APERCU_BORDER) * 2, + APERCU_BORDER, APERCU_BORDER + titleHeight); + +#ifdef SHAPED_BALLOON + XShapeCombineMask(dpy, scr->balloon->window, ShapeBounding, 0, 0, None, ShapeSet); +#endif + XResizeWindow(dpy, scr->balloon->window, width, height); + XMoveWindow(dpy, scr->balloon->window, x, y); + + XSetWindowBackgroundPixmap(dpy, scr->balloon->window, pixmap); + + XClearWindow(dpy, scr->balloon->window); + XMapRaised(dpy, scr->balloon->window); + + + scr->balloon->contents = pixmap; + + scr->balloon->mapped = 1; +} + static void showBalloon(WScreen * scr) { int x, y; @@ -389,7 +457,13 @@ static void showBalloon(WScreen * scr) scr->balloon->prevType = 0; return; } - showText(scr, x, y, scr->balloon->h, w, scr->balloon->text); + + if (wPreferences.miniwin_apercu_balloon && scr->balloon->apercu != None) + /* used to display either the apercu alone or the apercu and the title */ + showApercu(scr, x, y, (wPreferences.icon_size - 1) * 2, (wPreferences.icon_size - 1) * 2, + scr->balloon->text, scr->balloon->apercu); + else + showText(scr, x, y, scr->balloon->h, w, scr->balloon->text); } static void frameBalloon(WObjDescriptor * object) @@ -420,7 +494,9 @@ static void miniwindowBalloon(WObjDescriptor * object) } scr->balloon->h = icon->core->height; scr->balloon->text = wstrdup(icon->icon_name); + scr->balloon->apercu = icon->apercu; scr->balloon->objectWindow = icon->core->window; + if ((scr->balloon->prevType == object->parent_type || scr->balloon->prevType == WCLASS_APPICON) && scr->balloon->ignoreTimer) { XUnmapWindow(dpy, scr->balloon->window); @@ -522,6 +598,8 @@ void wBalloonEnteredObject(WScreen * scr, WObjDescriptor * object) wfree(scr->balloon->text); scr->balloon->text = NULL; + scr->balloon->apercu = None; + if (!object) { wBalloonHide(scr); balloon->ignoreTimer = 0; @@ -538,7 +616,7 @@ void wBalloonEnteredObject(WScreen * scr, WObjDescriptor * object) appiconBalloon(object); break; case WCLASS_MINIWINDOW: - if (wPreferences.miniwin_balloon) + if (wPreferences.miniwin_title_balloon || wPreferences.miniwin_apercu_balloon) miniwindowBalloon(object); break; case WCLASS_APPICON: diff --git a/src/defaults.c b/src/defaults.c index 266684ba..155fe6f7 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -458,7 +458,9 @@ WDefaultEntry optionList[] = { {"WindowTitleBalloons", "NO", NULL, &wPreferences.window_balloon, getBool, NULL, NULL, NULL}, {"MiniwindowTitleBalloons", "NO", NULL, - &wPreferences.miniwin_balloon, getBool, NULL, NULL, NULL}, + &wPreferences.miniwin_title_balloon, getBool, NULL, NULL, NULL}, + {"MiniwindowApercuBalloons", "NO", NULL, + &wPreferences.miniwin_apercu_balloon, getBool, NULL, NULL, NULL}, {"AppIconBalloons", "NO", NULL, &wPreferences.appicon_balloon, getBool, NULL, NULL, NULL}, {"HelpBalloons", "NO", NULL, diff --git a/src/icon.c b/src/icon.c index b811a4f6..e1321fae 100644 --- a/src/icon.c +++ b/src/icon.c @@ -225,6 +225,9 @@ void wIconDestroy(WIcon *icon) if (icon->pixmap) XFreePixmap(dpy, icon->pixmap); + if (icon->apercu) + XFreePixmap(dpy, icon->apercu); + unset_icon_image(icon); wCoreDestroy(icon->core); @@ -584,6 +587,23 @@ void set_icon_image_from_image(WIcon *icon, RImage *image) icon->file_image = image; } +void set_icon_apercu(WIcon *icon, RImage *image) +{ + Pixmap tmp; + RImage *scaled_apercu; + WScreen *scr = icon->core->screen_ptr; + + scaled_apercu = RSmoothScaleImage(image, (wPreferences.icon_size - 1 - APERCU_BORDER) * 2, + (wPreferences.icon_size - 1 - APERCU_BORDER) * 2 ); + + if (RConvertImage(scr->rcontext, scaled_apercu, &tmp)) { + if (icon->apercu != None) + XFreePixmap(dpy, icon->apercu); + icon->apercu = tmp; + } + RReleaseImage(scaled_apercu); +} + void wIconUpdate(WIcon *icon) { WWindow *wwin = NULL; diff --git a/src/icon.h b/src/icon.h index 347814be..af82f5c2 100644 --- a/src/icon.h +++ b/src/icon.h @@ -29,6 +29,8 @@ #define TILE_CLIP 1 #define TILE_DRAWER 2 +#define APERCU_BORDER 2 + typedef struct WIcon { WCoreWindow *core; WWindow *owner; /* owner window */ @@ -48,6 +50,7 @@ typedef struct WIcon { unsigned int highlighted:1; Pixmap pixmap; + Pixmap apercu; WMHandlerID handlerID; /* timer handler ID for cycling select * color */ @@ -74,5 +77,6 @@ char *get_name_for_instance_class(const char *wm_instance, const char *wm_class) void wIconSetHighlited(WIcon *icon, Bool flag); void set_icon_image_from_image(WIcon *icon, RImage *image); +void set_icon_apercu(WIcon *icon, RImage *image); #endif /* WMICON_H_ */