This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project wmaker-crm.git.
The branch, next has been updated discards 577481d76af08197214a24039281efd0f4c33fe0 (commit) discards f464856f55ddf8d29b7e1d2ee1b71640bcc694c8 (commit) discards 1b0ecc4e40f73a8bf7a5e3793a5ef5b0231cd327 (commit) discards f9d517d0371e94f1293c334f1db4d678f55d0977 (commit) discards 441b561c814767c1b70eea5a7391d5bcc678ccac (commit) discards 120a0b992716fa5fb320844219a6ef323b5a2b64 (commit) discards 213606b61c518e5c29a285660f7505c031fe034b (commit) discards faf52eec57064bff3602379d2f2a5e05906cecf9 (commit) discards 1e1bf8c54c137d2e260422dcdd6a4c634cd1fa0a (commit) via d387ccd49a63ad6ef696239a8d1cd602eb5980a7 (commit) via a864f1988fd7fd044633b319c40a8f0ab1b85658 (commit) via c94fc4ba39f2b3a0b8e3ed5e56a35c42cc36cd01 (commit) via 467b7ee4560f124f7469a2a630cb35d477cc0444 (commit) via c10469264d70075a26a13ac2db5281822a2a2210 (commit) via 47ac986b5336869236fefb748a066d936c590f19 (commit) via 12babda9e7050a95789cc4173b072e2e815e1fbc (commit) via 80f18f60d239499d3d266bf3a6a7e5e78374aca7 (commit) via 10371836ed5637c2faf718873b5866c7a8314134 (commit) This update added new revisions after undoing existing revisions. That is to say, the old revision is not a strict subset of the new revision. This situation occurs when you --force push a change and generate a repository containing something like this: * -- * -- B -- O -- O -- O (577481d76af08197214a24039281efd0f4c33fe0) N -- N -- N (d387ccd49a63ad6ef696239a8d1cd602eb5980a7) When this happens we assume that you've already had alert emails for all of the O revisions, and so we here report only the revisions in the N branch from the common base, B. Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- http://repo.or.cz/w/wmaker-crm.git/commit/d387ccd49a63ad6ef696239a8d1cd602eb5980a7 commit d387ccd49a63ad6ef696239a8d1cd602eb5980a7 Author: David Maciejak <david.macie...@gmail.com> Date: Thu Dec 4 13:37:36 2014 +0700 wmaker: add core workspace pager functions This patch is adding the core code needed to run the workspace pager. Currently when called, a new frame presenting mini workspace images are displayed at the bottom of the screen above other windows. When clicking on one of the miniatures, the workspace is switched and the frame is closed. Drawbacks: a screenshot of the workspace is used for the miniatures. This screenshot is taken only when a workspace switched event occurs. First, it means that the workspace switching process can be longer than usual. Secondly, updated minitatures can only be available when the workspace is "opened" (cause windows have to be mapped to be able to be copied). So when wmaker is (re)started or when for example a window is moved to another workspace the corresponding miniature is NOT updated. (I did not find a clean and easy way to do so, feel free to share if you have some ideas) diff --git a/src/Makefile.am b/src/Makefile.am index 6c20e63a..a7aa1d09 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -107,7 +107,9 @@ wmaker_SOURCES = wmspec.h wmspec.c workspace.c - workspace.h + workspace.h + wsmap.c + wsmap.h if WM_OSDEP_BSD wmaker_SOURCES += osdep_bsd.c diff --git a/src/event.c b/src/event.c index 9a8a3e3f..6b2e0db0 100644 --- a/src/event.c +++ b/src/event.c @@ -77,6 +77,7 @@ #include "event.h" #include "winmenu.h" #include "switchmenu.h" +#include "wsmap.h" #define MOD_MASK wPreferences.modifier_mask @@ -1606,6 +1607,12 @@ static void handleKeyPress(XEvent * event) wSelectWindow(wwin, !wwin->flags.selected); } break; + + case WKBD_WORKSPACEMAP: + if (!wPreferences.disable_workspace_pager) + StartWorkspaceMap(scr); + break; + case WKBD_FOCUSNEXT: StartWindozeCycle(wwin, event, True, False); break; diff --git a/src/misc.c b/src/misc.c index 3b9299d4..a12a97de 100644 --- a/src/misc.c +++ b/src/misc.c @@ -245,7 +245,7 @@ void SlideWindows(Window *wins[], int n, int from_x, int from_y, int to_x, int t if (slide_delay > 0) { wusleep(slide_delay * 1000L); } else { - wusleep(10); + wusleep(1000L); } if (time(NULL) - time0 > MAX_ANIMATION_TIME) break; diff --git a/src/workspace.c b/src/workspace.c index 107db2aa..165e3011 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -49,6 +49,7 @@ #include "wmspec.h" #include "xinerama.h" #include "event.h" +#include "wsmap.h" #define MC_NEW 0 #define MC_DESTROY_LAST 1 @@ -160,6 +161,8 @@ Bool wWorkspaceDelete(WScreen * scr, int workspace) } else { if (scr->workspaces[i]->name) wfree(scr->workspaces[i]->name); + if (scr->workspaces[i]->map) + RReleaseImage(scr->workspaces[i]->map); wfree(scr->workspaces[i]); } } @@ -473,6 +476,9 @@ void wWorkspaceForceChange(WScreen * scr, int workspace) if (workspace >= MAX_WORKSPACES || workspace < 0) return; + if (!wPreferences.disable_workspace_pager && !process_workspacemap_event) + wWorkspaceMapUpdate(scr); + SendHelperMessage(scr, 'C', workspace + 1, NULL); if (workspace > scr->workspace_count - 1) diff --git a/src/workspace.h b/src/workspace.h index 69d1b187..0c93a2fc 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -27,6 +27,7 @@ typedef struct WWorkspace { char *name; struct WDock *clip; + RImage *map; } WWorkspace; void wWorkspaceMake(WScreen *scr, int count); diff --git a/src/wsmap.c b/src/wsmap.c new file mode 100755 index 00000000..e1064fc6 --- /dev/null +++ b/src/wsmap.c @@ -0,0 +1,566 @@ +/* wsmap.c - worskpace map + * + * Window Maker window manager + * + * Copyright (c) 2014 Window Maker Team - David Maciejak + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "wconfig.h" + +#include <stdlib.h> +#include <stdio.h> + +#ifdef USE_XSHAPE +#include <X11/extensions/shape.h> +#endif + +#include "screen.h" +#include "window.h" +#include "misc.h" +#include "workspace.h" +#include "wsmap.h" + +#include "WINGs/WINGsP.h" + + +static const int WORKSPACE_MAP_RATIO = 10; +static const int WORKSPACE_SEPARATOR_WIDTH = 12; +static const int mini_workspace_per_line = 5; + +/* + * Used to store the index of the tenth displayed mini workspace + * will be 0 for workspaces number 0 to 9 + * 1 for workspaces number 10 -> 19 + */ +int wsmap_bulk_index; +WMPixmap *frame_bg_focused; +WMPixmap *frame_bg_unfocused; + +typedef struct { + WScreen *scr; + WMWindow *win; + int xcount, ycount; + int wswidth, wsheight; + int mini_workspace_width, mini_workspace_height; + int edge; + int border_width; +} WWorkspaceMap; + +typedef struct { + WMButton *workspace_img_button; + WMLabel *workspace_label; +} W_WorkspaceMap; + +void wWorkspaceMapUpdate(WScreen *scr) +{ + XImage *pimg; + + pimg = XGetImage(dpy, scr->root_win, 0, 0, + scr->scr_width, scr->scr_height, + AllPlanes, ZPixmap); + if (pimg) { + RImage *apercu; + + apercu = RCreateImageFromXImage(scr->rcontext, pimg, NULL); + XDestroyImage(pimg); + + if (apercu) { + RImage *tmp = scr->workspaces[scr->current_workspace]->map; + + if (tmp) + RReleaseImage(tmp); + + scr->workspaces[scr->current_workspace]->map = + RSmoothScaleImage(apercu, + scr->scr_width / WORKSPACE_MAP_RATIO, + scr->scr_height / WORKSPACE_MAP_RATIO); + RReleaseImage(apercu); + } + } +} + +static void workspace_map_slide(WWorkspaceMap *wsmap) +{ + if (wsmap->edge == WD_TOP) + SlideWindow(WMWidgetXID(wsmap->win), 0, -1 *wsmap->wsheight, wsmap->xcount, wsmap->ycount); + else + SlideWindow(WMWidgetXID(wsmap->win), 0, wsmap->scr->scr_height, wsmap->xcount, wsmap->ycount); +} + +static void workspace_map_unslide(WWorkspaceMap *wsmap) +{ + if (wsmap->edge == WD_TOP) + SlideWindow(WMWidgetXID(wsmap->win), wsmap->xcount, wsmap->ycount, 0, -1 * wsmap->wsheight); + else + SlideWindow(WMWidgetXID(wsmap->win), wsmap->xcount, wsmap->ycount, 0, wsmap->scr->scr_height); +} + +static void workspace_map_destroy(WWorkspaceMap *wsmap) +{ + workspace_map_unslide(wsmap); + WMUnmapWidget(wsmap->win); + + if (wsmap->win) { + Window info_win = wsmap->scr->info_window; + XEvent ev; + + ev.xclient.type = ClientMessage; + ev.xclient.message_type = w_global.atom.wm.ignore_focus_events; + ev.xclient.format = 32; + ev.xclient.data.l[0] = True; + + XSendEvent(dpy, info_win, True, EnterWindowMask, &ev); + WMUnmapWidget(wsmap->win); + + ev.xclient.data.l[0] = False; + XSendEvent(dpy, info_win, True, EnterWindowMask, &ev); + WMDestroyWidget(wsmap->win); + + if (frame_bg_focused) + WMReleasePixmap(frame_bg_focused); + if (frame_bg_unfocused) + WMReleasePixmap(frame_bg_unfocused); + } + wfree(wsmap); +} + +static void selected_workspace_callback(WMWidget *w, void *data) +{ + WWorkspaceMap *wsmap = (WWorkspaceMap *) data; + WMButton *click_button = w; + + if (w && wsmap) { + int workspace_id = atoi(WMGetButtonText(click_button)); + + wWorkspaceChange(wsmap->scr, workspace_id); + process_workspacemap_event = False; + } +} + +static void set_workspace_map_background_image(WWorkspaceMap *wsmap) +{ + Pixmap pixmap, mask; + + if (wPreferences.wsmbackTexture->any.type == WTEX_PIXMAP) { + RImage *tmp = wTextureRenderImage(wPreferences.wsmbackTexture, wsmap->wswidth, wsmap->wsheight, WREL_FLAT); + + if (!tmp) + return; + + RConvertImageMask(wsmap->scr->rcontext, tmp, &pixmap, &mask, 250); + RReleaseImage(tmp); + + if (!pixmap) + return; + + XSetWindowBackgroundPixmap(dpy, WMWidgetXID(wsmap->win), pixmap); + +#ifdef USE_XSHAPE + if (mask && w_global.xext.shape.supported) + XShapeCombineMask(dpy, WMWidgetXID(wsmap->win), ShapeBounding, 0, 0, mask, ShapeSet); +#endif + + if (pixmap) + XFreePixmap(dpy, pixmap); + if (mask) + XFreePixmap(dpy, mask); + } +} + +static void workspace_map_show(WWorkspaceMap *wsmap) +{ + WMMapSubwidgets(wsmap->win); + WMMapWidget(wsmap->win); + workspace_map_slide(wsmap); +} + +static WMPixmap *get_frame_background_color(WWorkspaceMap *wsmap, unsigned int width, unsigned int height, int type) +{ + RImage *img; + WMPixmap *pix; + + if (!wsmap->scr->window_title_texture[type]) + return NULL; + + img = wTextureRenderImage(wsmap->scr->window_title_texture[type], width, height, WREL_FLAT); + if (!img) + return NULL; + + pix = WMCreatePixmapFromRImage(wsmap->scr->wmscreen, img, 128); + RReleaseImage(img); + + return pix; +} + +static void workspace_map_realize(WWorkspaceMap *wsmap, WMFrame *frame_border, W_WorkspaceMap *wsmap_array) +{ + int i, mini_workspace_cnt, general_index; + WMPixmap *frame_border_pixmap; + WMSize label_size; + + WMRealizeWidget(wsmap->win); + set_workspace_map_background_image(wsmap); + + frame_border_pixmap = get_frame_background_color(wsmap, wsmap->wswidth, wsmap->border_width, WS_FOCUSED); + WMSetWidgetBackgroundPixmap(frame_border, frame_border_pixmap); + WMReleasePixmap(frame_border_pixmap); + + label_size = WMGetViewSize(W_VIEW(wsmap_array[0].workspace_label)); + frame_bg_focused = get_frame_background_color(wsmap, label_size.width, label_size.height, WS_FOCUSED); + frame_bg_unfocused = get_frame_background_color(wsmap, label_size.width, label_size.height, WS_UNFOCUSED); + + mini_workspace_cnt = (wsmap->scr->workspace_count <= 2 * mini_workspace_per_line) ? wsmap->scr->workspace_count : 2 * mini_workspace_per_line; + for (i = 0; i < mini_workspace_cnt; i++) { + general_index = i + wsmap_bulk_index * 2 * mini_workspace_per_line; + if (general_index == wsmap->scr->current_workspace) { + WMSetWidgetBackgroundPixmap(wsmap_array[i].workspace_label, frame_bg_focused); + WMSetLabelTextColor(wsmap_array[i].workspace_label, wsmap->scr->window_title_color[WS_FOCUSED]); + } else { + WMSetWidgetBackgroundPixmap(wsmap_array[i].workspace_label, frame_bg_unfocused); + WMSetLabelTextColor(wsmap_array[i].workspace_label, wsmap->scr->window_title_color[WS_UNFOCUSED]); + } + } +} + +static WMPixmap *enlight_workspace(WScreen *scr, RImage *mini_wkspace_map) +{ + RImage *tmp = RCloneImage(mini_wkspace_map); + RColor color; + WMPixmap *icon; + + color.red = color.green = color.blue = 0; + color.alpha = 160; + RLightImage(tmp, &color); + icon = WMCreatePixmapFromRImage(scr->wmscreen, tmp, 128); + RReleaseImage(tmp); + + return icon; +} + +static WMPixmap *dummy_background_pixmap(WWorkspaceMap *wsmap) +{ + RImage *img; + WMPixmap *icon; + + img = RCreateImage(wsmap->wswidth, wsmap->wsheight, 0); + + if (!img) + return NULL; + + /* the workspace texture is not saved anywhere, so just using the default unfocus color */ + if (wsmap->scr->window_title_texture[WS_UNFOCUSED]) { + RColor frame_bg_color; + + frame_bg_color.red = wsmap->scr->window_title_texture[WS_UNFOCUSED]->solid.normal.red; + frame_bg_color.green = wsmap->scr->window_title_texture[WS_UNFOCUSED]->solid.normal.green; + frame_bg_color.blue = wsmap->scr->window_title_texture[WS_UNFOCUSED]->solid.normal.blue; + RFillImage(img, &frame_bg_color); + } + + icon = WMCreatePixmapFromRImage(wsmap->scr->wmscreen, img, 128); + RReleaseImage(img); + + return icon; +} + +static void show_mini_workspace(WWorkspaceMap *wsmap, W_WorkspaceMap *wsmap_array, int max_mini_workspace) +{ + int index, space_width; + int border_width_adjustement = (wsmap->edge == WD_TOP) ? 0 : wsmap->border_width; + int font_height = WMFontHeight(wsmap->scr->info_text_font); + + if (max_mini_workspace > mini_workspace_per_line) + space_width = (wsmap->wswidth - mini_workspace_per_line * wsmap->mini_workspace_width) / (mini_workspace_per_line + 1); + else + space_width = (wsmap->wswidth - max_mini_workspace * wsmap->mini_workspace_width) / (max_mini_workspace + 1); + + for (index = 0; index < max_mini_workspace; index++) { + int i , j; + + j = index; + + if (index >= mini_workspace_per_line) { + i = 1; + j -= mini_workspace_per_line; + } else { + i = 0; + } + if (wsmap_array[index].workspace_img_button) { + WMResizeWidget(wsmap_array[index].workspace_img_button, wsmap->mini_workspace_width, wsmap->mini_workspace_height); + WMMoveWidget(wsmap_array[index].workspace_img_button, j * wsmap->mini_workspace_width + (j + 1) * space_width, + border_width_adjustement + WORKSPACE_SEPARATOR_WIDTH + + i * (wsmap->mini_workspace_height + 2 * WORKSPACE_SEPARATOR_WIDTH) + font_height); + WMMapWidget(wsmap_array[index].workspace_img_button); + } + if (wsmap_array[index].workspace_label) { + WMResizeWidget(wsmap_array[index].workspace_label, wsmap->mini_workspace_width, font_height); + WMMoveWidget(wsmap_array[index].workspace_label, j * wsmap->mini_workspace_width + (j + 1) * space_width, + border_width_adjustement + WORKSPACE_SEPARATOR_WIDTH + + i * (wsmap->mini_workspace_height + 2 * WORKSPACE_SEPARATOR_WIDTH)); + WMMapWidget(wsmap_array[index].workspace_label); + } + } +} + +static void hide_mini_workspace(W_WorkspaceMap *wsmap_array, int i) +{ + if (wsmap_array[i].workspace_img_button) + WMUnmapWidget(wsmap_array[i].workspace_img_button); + if (wsmap_array[i].workspace_label) + WMUnmapWidget(wsmap_array[i].workspace_label); +} + +static WMPixmap *get_mini_workspace(WWorkspaceMap *wsmap, int index) { + if (!wsmap->scr->workspaces[index]->map) + return dummy_background_pixmap(wsmap); + + if (index == wsmap->scr->current_workspace) + return enlight_workspace(wsmap->scr, wsmap->scr->workspaces[index]->map); + + return WMCreatePixmapFromRImage(wsmap->scr->wmscreen, wsmap-> scr->workspaces[index]->map, 128); +} + +static void create_mini_workspace(WScreen *scr, WWorkspaceMap *wsmap, W_WorkspaceMap *wsmap_array) +{ + int workspace_index; + int mini_workspace_cnt; + char name[10]; + WMButton *mini_workspace_btn; + WMPixmap *icon; + + /* by default display the 10 first mini workspaces */ + wsmap_bulk_index = 0; + mini_workspace_cnt = (scr->workspace_count <= 2 * mini_workspace_per_line) ? scr->workspace_count : 2 * mini_workspace_per_line; + for (workspace_index = 0; workspace_index < mini_workspace_cnt; workspace_index++) { + mini_workspace_btn = WMCreateButton(wsmap->win, WBTOnOff); + WMSetButtonBordered(mini_workspace_btn, 0); + WMLabel *workspace_name_label = WMCreateLabel(wsmap->win); + WMSetLabelFont(workspace_name_label, scr->info_text_font); + WMSetLabelText(workspace_name_label, scr->workspaces[workspace_index]->name); + + wsmap_array[workspace_index].workspace_img_button = mini_workspace_btn; + wsmap_array[workspace_index].workspace_label = workspace_name_label; + + WMSetButtonImagePosition(mini_workspace_btn, WIPImageOnly); + icon = get_mini_workspace(wsmap, workspace_index); + if (icon) { + WMSetButtonImage(mini_workspace_btn, icon); + WMReleasePixmap(icon); + } + + snprintf(name, sizeof(name), "%d", workspace_index); + WMSetButtonText(mini_workspace_btn, name); + WMSetButtonAction(mini_workspace_btn, selected_workspace_callback, wsmap); + } + show_mini_workspace(wsmap, wsmap_array, mini_workspace_cnt); +} + +static WWorkspaceMap *create_workspace_map(WScreen *scr, W_WorkspaceMap *wsmap_array, int edge) +{ + WWorkspaceMap *wsmap = wmalloc(sizeof(WWorkspaceMap)); + + wsmap->border_width = 5; + wsmap->edge = edge; + wsmap->mini_workspace_width = scr->scr_width / WORKSPACE_MAP_RATIO; + wsmap->mini_workspace_height = scr->scr_height / WORKSPACE_MAP_RATIO; + + if (scr->workspace_count == 0) + return NULL; + + wsmap->scr = scr; + wsmap->win = WMCreateWindow(scr->wmscreen, "wsmap"); + wsmap->wswidth = WidthOfScreen(DefaultScreenOfDisplay(dpy)); + wsmap->wsheight = WMFontHeight(scr->info_text_font) + (wsmap->mini_workspace_height + 2 * WORKSPACE_SEPARATOR_WIDTH) * + (scr->workspace_count > mini_workspace_per_line ? 2 : 1); + + if (wPreferences.wsmbackTexture->any.type == WTEX_SOLID) { + WMColor *tmp = WMCreateRGBColor(scr->wmscreen, + wPreferences.wsmbackTexture->any.color.red, + wPreferences.wsmbackTexture->any.color.green, + wPreferences.wsmbackTexture->any.color.blue, + False); + WMSetWidgetBackgroundColor(wsmap->win, tmp); + WMReleaseColor(tmp); + } + WMResizeWidget(wsmap->win, wsmap->wswidth, wsmap->wsheight + wsmap->border_width); + + WMFrame *framel = WMCreateFrame(wsmap->win); + WMResizeWidget(framel, wsmap->wswidth, wsmap->border_width); + WMSetFrameRelief(framel, WRSimple); + wWorkspaceMapUpdate(scr); + + wsmap->xcount = 0; + if (edge == WD_TOP) { + wsmap->ycount = 0; + WMMoveWidget(framel, 0, wsmap->wsheight); + } else { + wsmap->ycount = scr->scr_height - wsmap->wsheight - wsmap->border_width; + WMMoveWidget(framel, 0, 0); + } + + create_mini_workspace(scr, wsmap, wsmap_array); + workspace_map_realize(wsmap, framel, wsmap_array); + + return wsmap; +} + +static void update_mini_workspace(WWorkspaceMap *wsmap, W_WorkspaceMap *wsmap_array, int bulk_of_ten) +{ + int local_index, general_index; + int mini_workspace_cnt; + char name[10]; + WMPixmap *icon; + + if (bulk_of_ten == wsmap_bulk_index) + return; + + if (bulk_of_ten < 0) + return; + + if (wsmap->scr->workspace_count <= bulk_of_ten * 2 * mini_workspace_per_line) + return; + + wsmap_bulk_index = bulk_of_ten; + + mini_workspace_cnt = wsmap->scr->workspace_count - wsmap_bulk_index * 2 * mini_workspace_per_line; + if (mini_workspace_cnt > 2 * mini_workspace_per_line) + mini_workspace_cnt = 2 * mini_workspace_per_line; + + for (local_index = 0; local_index < 2 * mini_workspace_per_line; local_index++) { + general_index = local_index + wsmap_bulk_index * 2 * mini_workspace_per_line; + if (general_index < wsmap->scr->workspace_count) { + /* updating label */ + WMSetLabelText(wsmap_array[local_index].workspace_label, wsmap-> scr->workspaces[general_index]->name); + snprintf(name, sizeof(name), "%d", general_index); + WMSetButtonText(wsmap_array[local_index].workspace_img_button, name); + + /* updating label background*/ + if (general_index == wsmap->scr->current_workspace) { + WMSetWidgetBackgroundPixmap(wsmap_array[local_index].workspace_label, frame_bg_focused); + WMSetLabelTextColor(wsmap_array[local_index].workspace_label, wsmap->scr->window_title_color[WS_FOCUSED]); + } else { + WMSetWidgetBackgroundPixmap(wsmap_array[local_index].workspace_label, frame_bg_unfocused); + WMSetLabelTextColor(wsmap_array[local_index].workspace_label, wsmap->scr->window_title_color[WS_UNFOCUSED]); + } + + icon = get_mini_workspace(wsmap, general_index); + if (icon) { + WMSetButtonImage(wsmap_array[local_index].workspace_img_button, icon); + WMReleasePixmap(icon); + } + } else { + if (local_index < wsmap->scr->workspace_count) + hide_mini_workspace(wsmap_array, local_index); + } + } + show_mini_workspace(wsmap, wsmap_array, mini_workspace_cnt); +} + +static void handle_event(WWorkspaceMap *wsmap, W_WorkspaceMap *wsmap_array) +{ + XEvent ev; + int modifiers; + KeyCode escKey = XKeysymToKeycode(dpy, XK_Escape); + + XGrabKeyboard(dpy, WMWidgetXID(wsmap->win), False, GrabModeAsync, GrabModeAsync, CurrentTime); + XGrabPointer(dpy, WMWidgetXID(wsmap->win), True, + ButtonMotionMask | ButtonReleaseMask | ButtonPressMask, + GrabModeAsync, GrabModeAsync, WMWidgetXID(wsmap->win), None, CurrentTime); + + process_workspacemap_event = True; + while (process_workspacemap_event) { + WMMaskEvent(dpy, KeyPressMask | KeyReleaseMask | ExposureMask + | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask, &ev); + + if (!wsmap) + break; + modifiers = ev.xkey.state & w_global.shortcut.modifiers_mask; + + switch (ev.type) { + case KeyPress: + if (ev.xkey.keycode == escKey || (wKeyBindings[WKBD_WORKSPACEMAP].keycode != 0 && + wKeyBindings[WKBD_WORKSPACEMAP].keycode == ev.xkey.keycode && + wKeyBindings[WKBD_WORKSPACEMAP].modifier == modifiers)) { + process_workspacemap_event = False; + } else { + KeySym ks; + int bulk_id; + + XLookupString(&ev.xkey, NULL, 16, &ks, NULL); + + bulk_id = -1; + if (ks >= 0x30 && ks <= 0x39) + bulk_id = ks - 0x30; + else + if (ks == XK_Left) + bulk_id = wsmap_bulk_index - 1; + else if (ks == XK_Right) + bulk_id = wsmap_bulk_index + 1; + + if (bulk_id >= 0) + update_mini_workspace(wsmap, wsmap_array, bulk_id); + } + break; + + case ButtonPress: + switch (ev.xbutton.button) { + case Button6: + update_mini_workspace(wsmap, wsmap_array, wsmap_bulk_index - 1); + break; + case Button7: + update_mini_workspace(wsmap, wsmap_array, wsmap_bulk_index + 1); + break; + default: + WMHandleEvent(&ev); + } + break; + + default: + WMHandleEvent(&ev); + break; + } + } + + XUngrabPointer(dpy, CurrentTime); + XUngrabKeyboard(dpy, CurrentTime); + + if (wsmap) + workspace_map_destroy(wsmap); +} + +static WWorkspaceMap *init_workspace_map(WScreen *scr, W_WorkspaceMap *wsmap_array) +{ + WWorkspaceMap *wsmap; + + wsmap = create_workspace_map(scr, wsmap_array, WD_BOTTOM); + return wsmap; +} + +void StartWorkspaceMap(WScreen *scr) +{ + WWorkspaceMap *wsmap; + W_WorkspaceMap wsmap_array[2 * mini_workspace_per_line]; + + /* save the current screen before displaying the workspace map */ + wWorkspaceMapUpdate(scr); + + wsmap = init_workspace_map(scr, wsmap_array); + if (wsmap) { + workspace_map_show(wsmap); + handle_event(wsmap, wsmap_array); + } +} diff --git a/src/wsmap.h b/src/wsmap.h new file mode 100644 index 00000000..2133bd52 --- /dev/null +++ b/src/wsmap.h @@ -0,0 +1,28 @@ +/* + * Window Maker window manager + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program, see the file COPYING. + */ + +#ifndef WSMAP_H +#define WSMAP_H + +Bool process_workspacemap_event; + +void wWorkspaceMapUpdate(WScreen *scr); +void StartWorkspaceMap(WScreen *scr); + +#endif http://repo.or.cz/w/wmaker-crm.git/commit/a864f1988fd7fd044633b319c40a8f0ab1b85658 commit a864f1988fd7fd044633b319c40a8f0ab1b85658 Author: David Maciejak <david.macie...@gmail.com> Date: Thu Dec 4 13:34:56 2014 +0700 wmaker: add workspace pager underlying configuration This path is adding the functions and variables needed for workspace pager preferences. An option to enable/disable the workspace pager, and one to set a default background image. diff --git a/WindowMaker/Defaults/WindowMaker.in b/WindowMaker/Defaults/WindowMaker.in index 5b6203b3..c68feeff 100644 --- a/WindowMaker/Defaults/WindowMaker.in +++ b/WindowMaker/Defaults/WindowMaker.in @@ -3,6 +3,7 @@ PopupSwitchMenu = NO; MenuStyle = normal; DisableMiniwindows = NO; + DisableWorkspacePager = NO; OpenTransientOnOwnerWorkspace = NO; EdgeResistance = 30; WorkspaceBorderSize = 0; diff --git a/src/WindowMaker.h b/src/WindowMaker.h index 0663b546..ce0a86c9 100644 --- a/src/WindowMaker.h +++ b/src/WindowMaker.h @@ -393,6 +393,8 @@ extern struct WPreferences { char sticky_icons; /* If miniwindows will be onmipresent */ char dont_confirm_kill; /* do not confirm Kill application */ char disable_miniwindows; + char disable_workspace_pager; + char dont_blink; /* do not blink icon selection */ /* Appearance options */ @@ -455,6 +457,8 @@ extern struct WPreferences { RImage *swtileImage; RImage *swbackImage[9]; + union WTexture *wsmbackTexture; + int show_clip_title; struct { diff --git a/src/defaults.c b/src/defaults.c index fff239f2..b1b5050a 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -4,6 +4,8 @@ * * Copyright (c) 1997-2003 Alfredo K. Kojima * Copyright (c) 1998-2003 Dan Pascu + * 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 @@ -144,6 +146,7 @@ static WDECallbackUpdate setHightlightText; static WDECallbackUpdate setKeyGrab; static WDECallbackUpdate setDoubleClick; static WDECallbackUpdate setIconPosition; +static WDECallbackUpdate setWorkspaceMapBackground; static WDECallbackUpdate setClipTitleFont; static WDECallbackUpdate setClipTitleColor; @@ -348,7 +351,9 @@ WDefaultEntry staticOptionList[] = { {"ClipMergedInDock", "NO", NULL, NULL, getBool, setClipMergedInDock, NULL, NULL}, {"DisableMiniwindows", "NO", NULL, - &wPreferences.disable_miniwindows, getBool, NULL, NULL, NULL} + &wPreferences.disable_miniwindows, getBool, NULL, NULL, NULL}, + {"DisableWorkspacePager", "NO", NULL, + &wPreferences.disable_workspace_pager, getBool, NULL, NULL, NULL} }; #define NUM2STRING_(x) #x @@ -598,6 +603,8 @@ WDefaultEntry optionList[] = { NULL, getColor, setFrameFocusedBorderColor, NULL, NULL}, {"FrameSelectedBorderColor", "white", NULL, NULL, getColor, setFrameSelectedBorderColor, NULL, NULL}, + {"WorkspaceMapBack", "(solid, black)", NULL, + NULL, getTexture, setWorkspaceMapBackground, NULL, NULL}, /* keybindings */ @@ -659,6 +666,8 @@ WDefaultEntry optionList[] = { NULL, getKeybind, setKeyGrab, NULL, NULL}, {"SelectKey", "None", (void *)WKBD_SELECT, NULL, getKeybind, setKeyGrab, NULL, NULL}, + {"WorkspaceMapKey", "None", (void *)WKBD_WORKSPACEMAP, + NULL, getKeybind, setKeyGrab, NULL, NULL}, {"FocusNextKey", "None", (void *)WKBD_FOCUSNEXT, NULL, getKeybind, setKeyGrab, NULL, NULL}, {"FocusPrevKey", "None", (void *)WKBD_FOCUSPREV, @@ -3242,6 +3251,22 @@ static int updateUsableArea(WScreen * scr, WDefaultEntry * entry, void *bar, voi return 0; } +static int setWorkspaceMapBackground(WScreen *scr, WDefaultEntry *entry, void *tdata, void *foo) +{ + WTexture **texture = tdata; + + /* Parameter not used, but tell the compiler that it is ok */ + (void) entry; + (void) foo; + + if (wPreferences.wsmbackTexture) + wTextureDestroy(scr, wPreferences.wsmbackTexture); + + wPreferences.wsmbackTexture = *texture; + + return REFRESH_WINDOW_TEXTURES; +} + static int setMenuStyle(WScreen * scr, WDefaultEntry * entry, void *tdata, void *foo) { /* Parameter not used, but tell the compiler that it is ok */ diff --git a/src/keybind.h b/src/keybind.h index 4aaadd47..87a5cdc3 100644 --- a/src/keybind.h +++ b/src/keybind.h @@ -69,6 +69,7 @@ enum { WKBD_RAISELOWER, WKBD_MOVERESIZE, WKBD_SHADE, + WKBD_WORKSPACEMAP, WKBD_FOCUSNEXT, WKBD_FOCUSPREV, WKBD_GROUPNEXT, http://repo.or.cz/w/wmaker-crm.git/commit/c94fc4ba39f2b3a0b8e3ed5e56a35c42cc36cd01 commit c94fc4ba39f2b3a0b8e3ed5e56a35c42cc36cd01 Author: David Maciejak <david.macie...@gmail.com> Date: Thu Dec 4 13:30:27 2014 +0700 WPrefs: add workspace pager configuration This patch is adding a checkbox in the expert zone to disable completely the workspace pager and add an entry in keyshortcut preference to set the shortcut used to open the pager with the action "Open workspace pager". The default frame background can be configured by setting an optional variable "WorkspaceMapBack" from WindowMaker conf file as in: WorkspaceMapBack = (tpixmap, "/tmp/testme.png", gray20); or WorkspaceMapBack = (solid, "#2c2482"); diff --git a/WPrefs.app/Expert.c b/WPrefs.app/Expert.c index 84e4eb40..dc455dd8 100644 --- a/WPrefs.app/Expert.c +++ b/WPrefs.app/Expert.c @@ -43,6 +43,9 @@ static const struct { { N_("Disable miniwindows (icons for minimized windows). For use with KDE/GNOME."), /* default: */ False, OPTION_WMAKER, "DisableMiniwindows" }, + { N_("Disable workspace pager"), + /* default: */ False, OPTION_WMAKER, "DisableWorkspacePager" }, + { N_("Do not set non-WindowMaker specific parameters (do not use xset)."), /* default: */ False, OPTION_USERDEF, "NoXSetStuff" }, diff --git a/WPrefs.app/KeyboardShortcuts.c b/WPrefs.app/KeyboardShortcuts.c index 414d479f..6984a918 100644 --- a/WPrefs.app/KeyboardShortcuts.c +++ b/WPrefs.app/KeyboardShortcuts.c @@ -102,6 +102,7 @@ static const struct { { "GroupPrevKey", N_("Focus previous group window") }, /* Workspace Related */ + { "WorkspaceMapKey", N_("Open workspace pager") }, { "NextWorkspaceKey", N_("Switch to next workspace") }, { "PrevWorkspaceKey", N_("Switch to previous workspace") }, { "LastWorkspaceKey", N_("Switch to last used workspace") }, http://repo.or.cz/w/wmaker-crm.git/commit/467b7ee4560f124f7469a2a630cb35d477cc0444 commit 467b7ee4560f124f7469a2a630cb35d477cc0444 Author: David Maciejak <david.macie...@gmail.com> Date: Fri Dec 5 06:08:48 2014 +0700 WINGs: increment version This patch is incrementing version number as the API changed. diff --git a/WINGs/WINGs/WINGs.h b/WINGs/WINGs/WINGs.h index ca7be553..47981744 100644 --- a/WINGs/WINGs/WINGs.h +++ b/WINGs/WINGs/WINGs.h @@ -26,7 +26,7 @@ #include <WINGs/WUtil.h> #include <X11/Xlib.h> -#define WINGS_H_VERSION 20140612 +#define WINGS_H_VERSION 20141205 #ifdef __cplusplus diff --git a/configure.ac b/configure.ac index d7ccdaec..65b12c42 100644 --- a/configure.ac +++ b/configure.ac @@ -47,7 +47,7 @@ WRASTER_VERSION=$WRASTER_CURRENT:$WRASTER_REVISION:$WRASTER_AGE AC_SUBST(WRASTER_VERSION) dnl dnl libWINGs -WINGS_CURRENT=3 +WINGS_CURRENT=4 WINGS_REVISION=0 WINGS_AGE=0 WINGS_VERSION=$WINGS_CURRENT:$WINGS_REVISION:$WINGS_AGE http://repo.or.cz/w/wmaker-crm.git/commit/c10469264d70075a26a13ac2db5281822a2a2210 commit c10469264d70075a26a13ac2db5281822a2a2210 Author: David Maciejak <david.macie...@gmail.com> Date: Thu Dec 4 13:25:55 2014 +0700 WINGs: add functions to set widget background image With this patch we can set widget background image. As now, only background color was available. diff --git a/WINGs/WINGs/WINGs.h b/WINGs/WINGs/WINGs.h index e460ef43..ca7be553 100644 --- a/WINGs/WINGs/WINGs.h +++ b/WINGs/WINGs/WINGs.h @@ -930,6 +930,10 @@ void WMSetWidgetBackgroundColor(WMWidget *w, WMColor *color); WMColor* WMGetWidgetBackgroundColor(WMWidget *w); +void WMSetWidgetBackgroundPixmap(WMWidget *w, WMPixmap *pix); + +WMPixmap *WMGetWidgetBackgroundPixmap(WMWidget *w); + void WMMapSubwidgets(WMWidget *w); void WMUnmapSubwidgets(WMWidget *w); diff --git a/WINGs/WINGs/WINGsP.h b/WINGs/WINGs/WINGsP.h index 2484b25d..fc18b1cb 100644 --- a/WINGs/WINGs/WINGsP.h +++ b/WINGs/WINGs/WINGsP.h @@ -572,6 +572,8 @@ struct W_View { void *hangedData; /* data holder for user program */ WMColor *backColor; + WMPixmap *backImage; + Cursor cursor; @@ -664,6 +666,8 @@ void W_ResizeView(W_View *view, unsigned int width, unsigned int height); void W_SetViewBackgroundColor(W_View *view, WMColor *color); +void W_SetViewBackgroundPixmap(W_View *view, WMPixmap *pix); + void W_SetViewCursor(W_View *view, Cursor cursor); void W_SetFocusOfTopLevel(W_View *toplevel, W_View *view); diff --git a/WINGs/widgets.c b/WINGs/widgets.c index 75b44e70..87fa9d62 100644 --- a/WINGs/widgets.c +++ b/WINGs/widgets.c @@ -960,6 +960,21 @@ WMColor *WMGetWidgetBackgroundColor(WMWidget * w) return W_VIEW(w)->backColor; } +void WMSetWidgetBackgroundPixmap(WMWidget *w, WMPixmap *pix) +{ + if (!pix) + return; + + W_SetViewBackgroundPixmap(W_VIEW(w), pix); + if (W_VIEW(w)->flags.mapped) + WMRedisplayWidget(w); +} + +WMPixmap *WMGetWidgetBackgroundPixmap(WMWidget *w) +{ + return W_VIEW(w)->backImage; +} + void WMRaiseWidget(WMWidget * w) { W_RaiseView(W_VIEW(w)); diff --git a/WINGs/wmisc.c b/WINGs/wmisc.c index 331dc401..ba4c8a6a 100644 --- a/WINGs/wmisc.c +++ b/WINGs/wmisc.c @@ -220,12 +220,20 @@ W_PaintTextAndImage(W_View * view, int wrap, WMColor * textColor, W_Font * font, XFillRectangle(screen->display, d, WMColorGC(backColor), 0, 0, view->size.width, view->size.height); } else { + if (view->attribs.background_pixmap) { #ifndef DOUBLE_BUFFER - XClearWindow(screen->display, d); + XClearWindow(screen->display, d); #else - XSetForeground(screen->display, screen->copyGC, view->attribs.background_pixel); - XFillRectangle(screen->display, d, screen->copyGC, 0, 0, view->size.width, view->size.height); + XCopyArea(screen->display, view->attribs.background_pixmap, d, screen->copyGC, 0, 0, view->size.width, view->size.height, 0, 0); #endif + } else { +#ifndef DOUBLE_BUFFER + XClearWindow(screen->display, d); +#else + XSetForeground(screen->display, screen->copyGC, view->attribs.background_pixel); + XFillRectangle(screen->display, d, screen->copyGC, 0, 0, view->size.width, view->size.height); +#endif + } } if (relief == WRFlat) { diff --git a/WINGs/wview.c b/WINGs/wview.c index 20662447..610e640a 100644 --- a/WINGs/wview.c +++ b/WINGs/wview.c @@ -100,7 +100,8 @@ static W_View *createView(W_Screen * screen, W_View * parent) view->attribFlags = CWEventMask | CWBitGravity; view->attribs = defAtts; - view->attribFlags |= CWBackPixel | CWColormap | CWBorderPixel; + view->attribFlags |= CWBackPixel | CWColormap | CWBorderPixel | CWBackPixmap; + view->attribs.background_pixmap = None; view->attribs.background_pixel = W_PIXEL(screen->gray); view->attribs.border_pixel = W_PIXEL(screen->black); view->attribs.colormap = screen->colormap; @@ -496,6 +497,20 @@ void W_SetViewBackgroundColor(W_View * view, WMColor * color) } } +void W_SetViewBackgroundPixmap(W_View *view, WMPixmap *pix) +{ + if (view->backImage) + WMReleasePixmap(view->backImage); + view->backImage = WMRetainPixmap(pix); + + view->attribFlags |= CWBackPixmap; + view->attribs.background_pixmap = pix->pixmap; + if (view->flags.realized) { + XSetWindowBackgroundPixmap(view->screen->display, view->window, pix->pixmap); + XClearWindow(view->screen->display, view->window); + } +} + void W_SetViewCursor(W_View * view, Cursor cursor) { view->cursor = cursor; http://repo.or.cz/w/wmaker-crm.git/commit/47ac986b5336869236fefb748a066d936c590f19 commit 47ac986b5336869236fefb748a066d936c590f19 Author: Christophe CURIS <christophe.cu...@free.fr> Date: Fri Dec 5 18:02:43 2014 +0100 Make sub-directories visible the automake's "dist*" targets We have a few directories with source codes that we tell configure to prepare, but we do not actually want them built during normal operations (tests and examples only). However, there are some special targets brought by automake which still need to see them, so this patch adds these directories to the list, but only for these rules, we keep them unvisited by the normal build process. The wanted side effect of this is that now "make distcheck" works untill the end as expectable. Signed-off-by: Christophe CURIS <christophe.cu...@free.fr> diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index 03c6e289..017f1d7e 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -3,6 +3,7 @@ AUTOMAKE_OPTIONS = SUBDIRS = WINGs . po Documentation Resources +DIST_SUBDIRS = $(SUBDIRS) Tests Examples Extras libWINGs_la_LDFLAGS = -version-info @WINGS_VERSION@ libWUtil_la_LDFLAGS = -version-info @WUTIL_VERSION@ diff --git a/wrlib/Makefile.am b/wrlib/Makefile.am index a9e6e83d..c21c0ced 100644 --- a/wrlib/Makefile.am +++ b/wrlib/Makefile.am @@ -1,6 +1,7 @@ ## automake input file for wrlib SUBDIRS = . +DIST_SUBDIRS = $(SUBDIRS) tests AUTOMAKE_OPTIONS = http://repo.or.cz/w/wmaker-crm.git/commit/12babda9e7050a95789cc4173b072e2e815e1fbc commit 12babda9e7050a95789cc4173b072e2e815e1fbc Author: Christophe CURIS <christophe.cu...@free.fr> Date: Fri Dec 5 18:02:42 2014 +0100 WPrefs: link against math library because it is used in a few places The code is making use of a few of the libm functions, but it looks like gcc adds automatically the libm dependency (either by trying to be smart or as an inherited dependency?). Apparently, when compiling with clang-3.5 the function 'round' still needs the use of math library (the others do not seem to), so this patch adds it to the list of link libraries, which is more portable. Signed-off-by: Christophe CURIS <christophe.cu...@free.fr> diff --git a/WPrefs.app/Makefile.am b/WPrefs.app/Makefile.am index c1424262..f77ddd4a 100644 --- a/WPrefs.app/Makefile.am +++ b/WPrefs.app/Makefile.am @@ -57,5 +57,6 @@ WPrefs_LDADD = $(top_builddir)/WINGs/libWUtil.la $(top_builddir)/wrlib/libwraster.la @XLFLAGS@ @XLIBS@ + @LIBM@ @FCLIBS@ @INTLIBS@ http://repo.or.cz/w/wmaker-crm.git/commit/80f18f60d239499d3d266bf3a6a7e5e78374aca7 commit 80f18f60d239499d3d266bf3a6a7e5e78374aca7 Author: Christophe CURIS <christophe.cu...@free.fr> Date: Fri Dec 5 18:02:41 2014 +0100 WPrefs: Use standard C declaration of array instead of GNU syntax As pointed by Clang, the declaration of array was using the GNU old syntax, not the standard C. diff --git a/WPrefs.app/Appearance.c b/WPrefs.app/Appearance.c index 9e0e8a6a..c8cbc75e 100644 --- a/WPrefs.app/Appearance.c +++ b/WPrefs.app/Appearance.c @@ -97,9 +97,9 @@ static const struct { const char *db_value; const char *file_name; } menu_style[] = { - [MSTYLE_NORMAL] { "normal", "msty1" }, - [MSTYLE_SINGLE] { "singletexture", "msty2" }, - [MSTYLE_FLAT] { "flat", "msty3" } + [MSTYLE_NORMAL] = { "normal", "msty1" }, + [MSTYLE_SINGLE] = { "singletexture", "msty2" }, + [MSTYLE_FLAT] = { "flat", "msty3" } }; /********************************************************************/ @@ -107,9 +107,9 @@ static const struct { const char *label; const char *db_value; } wintitle_align[] = { - [WALeft] { N_("Left"), "left" }, - [WACenter] { N_("Center"), "center" }, - [WARight] { N_("Right"), "right" } + [WALeft] = { N_("Left"), "left" }, + [WACenter] = { N_("Center"), "center" }, + [WARight] = { N_("Right"), "right" } }; /********************************************************************/ http://repo.or.cz/w/wmaker-crm.git/commit/10371836ed5637c2faf718873b5866c7a8314134 commit 10371836ed5637c2faf718873b5866c7a8314134 Author: Christophe CURIS <christophe.cu...@free.fr> Date: Fri Dec 5 18:02:40 2014 +0100 wmaker: work around compilers that do not support nested functions There are a few cases in which nested functions are an helpful way to write code, as this is explained in 'script/nested-func-to-macro.sh'. However, some compiler do not support them (like clang), so this patch proposes an elegant solution, where developers can get the benefit of them, but for users they are automatically converted to C macro if needed. The advantage of this solution is that we keep the code simple, there is no hack in the source (like #ifdef and code duplication), yet still having the full advantages. The translation is done according to what have been detected by configure (see the WM_PROG_CC_NESTEDFUNC macro) so that user has nothing to do. Signed-off-by: Christophe CURIS <christophe.cu...@free.fr> diff --git a/Makefile.am b/Makefile.am index 7fd4174b..34038cb7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,7 +36,8 @@ EXTRA_DIST = TODO BUGS BUGFORM FAQ FAQ.I18N INSTALL INSTALL-WMAKER README.definable-cursor The-perfect-Window-Maker-patch.txt README COPYING.WTFPL autogen.sh - email-clients.txt checkpatch.pl update-changelog.pl + email-clients.txt checkpatch.pl update-changelog.pl + script/nested-func-to-macro.sh if USE_LCOV coverage-reset: diff --git a/configure.ac b/configure.ac index 7097e9d9..d7ccdaec 100644 --- a/configure.ac +++ b/configure.ac @@ -158,6 +158,12 @@ AS_IF([test "x$debug" = "xyes"], AX_CFLAGS_GCC_OPTION([-Wno-deprecated-declarations]) ]) + +dnl Support for Nested Functions by the compiler +dnl ============================================ +WM_PROG_CC_NESTEDFUNC + + dnl Posix thread dnl ================= AX_PTHREAD @@ -905,6 +911,9 @@ AS_IF([test "x$debug" = "xyes"], [AS_ECHO(["Debug enabled: CFLAGS = $CFLAGS"]) ]) echo +AS_IF([test "x$wm_cv_prog_cc_nestedfunc" != "xyes"], + [AC_MSG_WARN([[Your compiler does not support Nested Function, work-around enabled]])]) + dnl WM_PRINT_REDCRAP_BUG_STATUS AS_IF([test "x$enable_jpeg" = xno], [dnl diff --git a/m4/wm_prog_cc_c11.m4 b/m4/wm_prog_cc_c11.m4 index fbdbffb7..cf846998 100644 --- a/m4/wm_prog_cc_c11.m4 +++ b/m4/wm_prog_cc_c11.m4 @@ -46,3 +46,41 @@ AS_CASE([$wm_cv_prog_cc_c11], [no|native], [], [CFLAGS="$CFLAGS $wm_cv_prog_cc_c11"]) ]) + + +# WM_PROG_CC_NESTEDFUNC +# --------------------- +# +# Check if the compiler support declaring Nested Functions (that means +# declaring a function inside another function). +# +# If the compiler does not support them, then the Automake conditional +# USE_NESTED_FUNC will be set to false, in which case the Makefile will +# use the script 'scripts/nested-func-to-macro.sh' to generate a modified +# source with the nested function transformed into a Preprocessor Macro. +AC_DEFUN_ONCE([WM_PROG_CC_NESTEDFUNC], +[AC_CACHE_CHECK([if compiler supports nested functions], [wm_cv_prog_cc_nestedfunc], + [AC_COMPILE_IFELSE( + [AC_LANG_SOURCE([[ +int main(int narg, char **argv) +{ + int local_variable; + + int nested_function(int argument) + { + /* Checking we have access to upper level's scope, otherwise it is of no use */ + return local_variable + argument; + } + + /* To avoid a warning for unused parameter, that may falsely fail */ + (void) argv; + + /* Initialise using the parameter to main so the compiler won't be tempted to optimise too much */ + local_variable = narg + 1; + + return nested_function(2); +}]]) ], + [wm_cv_prog_cc_nestedfunc=yes], + [wm_cv_prog_cc_nestedfunc=no]) ]) +AM_CONDITIONAL([USE_NESTED_FUNC], [test "x$wm_cv_prog_cc_nestedfunc" != "xno"])dnl +]) diff --git a/script/nested-func-to-macro.sh b/script/nested-func-to-macro.sh new file mode 100755 index 00000000..416400fd --- /dev/null +++ b/script/nested-func-to-macro.sh @@ -0,0 +1,216 @@ +#!/bin/sh +########################################################################### +# +# Window Maker window manager +# +# Copyright (c) 2014 Christophe CURIS +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +########################################################################### +# +# nested-func-to-macro.sh: +# from a C source file specified with "-i", convert the functions +# specified with "-f" into preprocessor macros ("#define") and save the +# result as the file specified with "-o" +# +# The goal is to process nested functions (functions defined inside other +# functions), because some compilers do not support that, despite the +# advantages against macros: +# - there is no side effect on arguments, like what macros does; +# - the compiler can check the type used for arguments; +# - the compiler can decide wether it is best to inline them or not; +# - they are better handled by text editors, mainly for indentation but +# also because there is no more '' at end of lines; +# - generaly, error message from the compiler are a lot clearer. +# +# As opposed to simple static functions, there is a strong benefit because +# they can access the local variables of the function in which they are +# defined without needing extra arguments that may get complicated. +# +# These added values are important for developpement because they help keep +# code simple (and so maintainable and with lower bug risk). +# +# Because this script convert them to macros (only if 'configure' detected +# that the compiler does not support nested functions, see the macro +# WM_PROG_CC_NESTEDFUNC), there are a few constraints when writing such +# nested functions in the code: +# +# - you cannot use the function's address (example: callback), but that +# would be a bad idea anyway (in best case there's a penalty issue, in +# worst case it can crash the program); +# +# - you should be careful on what you're doing with the arguments of the +# function, otherwise the macro's side effects will re-appear; +# +# - you may need some extra '{}' when calling the function in an +# if/for/while/... construct, because of the difference between a function +# call and the macro that will be replaced (the macro will contain its own +# pair of '{}' which will be followed by the ';' you use for the function +# call; +# +# - the prototype of the function must be on a single line, it must not +# spread across multiple lines or replace will fail; +# +# - you should follow the project's coding style, as hacky stuff may +# make the script generate crap. And you don't want that to happen. +# +########################################################################### +# +# Please note that this script is writen in sh+awk on purpose: this script +# is gonna be run on the machine of the person who is trying to compile +# WindowMaker, and as such we cannot be sure to find any scripting language +# in a known version and that works (python/ruby/tcl/perl/php/you-name-it). +# +# So for portability, we stick to the same sh+awk constraint as Autotools +# to limit the problem, see for example: +# http://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Portable-Shell.html +# +########################################################################### + +# Report an error on stderr and exit with status 1 to tell make could not work +arg_error() { + echo "$0: $@" >&2 + exit 1 +} + +# print help and exit with success status +print_help() { + echo "$0: convert nested functions into macros in C source" + echo "Usage: $0 [options...] input_file" + echo "valid options are:" + echo " -f name : add 'name' to the list of function to process" + echo " -o file : set output file" + exit 0 +} + +# Extract command line arguments +while [ $# -gt 0 ]; do + case $1 in + -f) + shift + echo "$1" | grep -q '^[A-Z_a-z][A-Z_a-z0-9]*$' || arg_error "function name "$1" is not valid" + function_list="$function_list $1" + ;; + + -h|-help|--help) print_help ;; + -o) shift ; output_file="$1" ;; + -*) arg_error "unknow option '$1'" ;; + + *) + [ "x$input_file" = "x" ] || arg_error "only 1 input file can be specified, not "$input_file" and "$1"" + input_file="$1" + ;; + esac + shift +done + +# Check consistency of command-line +[ "x$input_file" = "x" ] && arg_error "no source file given" +[ "x$function_list" = "x" ] && arg_error "no function name were given, nothing to do" +[ "x$output_file" = "x" ] && arg_error "no output file name specified" + +[ -r "$input_file" ] || arg_error "source file "$input_file" is not readable" + +# Declare a function that takes care of converting the function code into a +# macro definition. All the code is considered part of the C function's body +# until we have matched the right number of {} pairs +awk_function_handler=' +function replace_definition(func_name) +{ + # Isolate the list of arguments from the rest of the line + # This code could be updated to handle arg list over multiple lines, but + # it would add unnecessary complexity because a function that big should + # probably be global static + arg_start = index($0, "("); + arg_end = index($0, ")"); + argsubstr = substr($0, arg_start + 1, arg_end - arg_start - 1); + remain = substr($0, arg_end); + + $0 = "#define " func_name "(" + + # Remove the types from the list of arguments + split(argsubstr, arglist, /,/); + separator = ""; + for (i = 1; i <= length(arglist); i++) { + argname = substr(arglist[i], match(arglist[i], /[A-Z_a-z][A-Z_a-z0-9]*$/)); + $0 = $0 separator argname; + separator = ", "; + } + delete arglist; + $0 = $0 remain; + + # Count the number of pairs of {} and take next line until we get our matching count + is_first_line = 1; + nb_pair = 0; + while (1) { + # Count the opening braces + split($0, dummy, /{/); + nb_pair = nb_pair + (length(dummy) - 1); + delete dummy; + + # Count the closing braces + split($0, dummy, /}/); + nb_pair = nb_pair - (length(dummy) - 1); + delete dummy; + + # If we found the end of the function, stop now + if (nb_pair <= 0 && !is_first_line) { + # Note that we count on awk that is always executing the match-all + # pattern to print the current line in the $0 pattern + break; + } + + # Otherwise, print current line with the macro continuation mark and grab + # next line to process it + $0 = $0 " \"; + print; + getline; + is_first_line = 0; + } + + # We mark the current macro as defined so it can be undefined at the end + func_defined[func_name] = 1; +}' + +# Build the list of awk pattern matching for each function: +# The regular expression matches function definition by the name of the function +# that must be preceeded by at least one keyword (likely the return type), but +# nothing like a math operator or other esoteric sign +for function in $function_list ; do + awk_function_handler="$awk_function_handler +/^[ ]*([A-Za-z][A-Za-z_0-9]*[ ])+${function}[ ]*\(/ { + replace_definition("${function}"); +}" +done + +# Finishing, undefine the macro at the most appropriate place we can easily +# guess +awk_function_handler="$awk_function_handler +/^\}/ { + # If we are at the end of a function definition, undefine all macros that + # have been defined so far + for (func_name in func_defined) { + print "#undef " func_name; + delete func_defined[func_name]; + } +} +# Print all other lines as-is +{ print } +" + +# Find the specified functions and transform them into macros +awk "$awk_function_handler" < "$input_file" > "$output_file" diff --git a/src/Makefile.am b/src/Makefile.am index 41a7e83e..6c20e63a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,7 +49,6 @@ wmaker_SOURCES = main.h menu.c menu.h - misc.c misc.h monitor.c monitor.h @@ -123,6 +122,20 @@ if WM_OSDEP_GENERIC wmaker_SOURCES += osdep_stub.c endif +if USE_NESTED_FUNC +wmaker_SOURCES += misc.c +else +nodist_wmaker_SOURCES = misc.hack_nf.c + +CLEANFILES = $(nodist_wmaker_SOURCES) + +misc.hack_nf.c: misc.c $(top_srcdir)/script/nested-func-to-macro.sh + $(top_srcdir)/script/nested-func-to-macro.sh + $(srcdir)/misc.c -o $(builddir)/misc.hack_nf.c + -f "append_string" -f "append_modifier" +endif + + AM_CFLAGS = AM_CPPFLAGS = diff --git a/src/misc.c b/src/misc.c index 51eb1ee6..3b9299d4 100644 --- a/src/misc.c +++ b/src/misc.c @@ -763,8 +763,10 @@ char *GetShortcutKey(WShortKey key) char buffer[256]; char *wr; - void append_string(const char *string) + void append_string(const char *text) { + const char *string = text; + while (*string) { if (wr >= buffer + sizeof(buffer) - 1) break; @@ -774,10 +776,11 @@ char *GetShortcutKey(WShortKey key) void append_modifier(int modifier_index, const char *fallback_name) { - if (wPreferences.modifier_labels[modifier_index]) + if (wPreferences.modifier_labels[modifier_index]) { append_string(wPreferences.modifier_labels[modifier_index]); - else + } else { append_string(fallback_name); + } } key_name = XKeysymToString(XkbKeycodeToKeysym(dpy, key.keycode, 0, 0)); ----------------------------------------------------------------------- Summary of changes: WINGs/WINGs/WINGs.h | 2 +- WPrefs.app/Expert.c | 4 +- WPrefs.app/KeyboardShortcuts.c | 2 +- src/Makefile.am | 2 + src/WindowMaker.h | 4 +- src/defaults.c | 32 ++++++++-------- src/event.c | 10 +++-- src/workspace.c | 8 ++-- src/wsmap.c | 82 +++++++++++++++++++++++++--------------- src/wsmap.h | 25 ++++++++++++ 10 files changed, 110 insertions(+), 61 deletions(-) repo.or.cz automatic notification. Contact project admin crma...@gmail.com if you want to unsubscribe, or site admin ad...@repo.or.cz if you receive no reply. -- wmaker-crm.git ("The Window Maker window manager") -- To unsubscribe, send mail to wmaker-dev-unsubscr...@lists.windowmaker.org.