1
0
mirror of https://github.com/gryf/wmaker.git synced 2026-07-11 16:36:38 +02:00
Files
wmaker/src/wsmap.c
T
David Maciejak ac75047aef Fix mini workspace compiler warnings
The patch is to fix warnings like:
wsmap.c: In function "update_mini_workspace":
wsmap.c:451:55: warning: "%d" directive output may be truncated writing between 1 and 11 bytes into a region of size 10 [-Wformat-truncation=]
  451 |                         snprintf(name, sizeof(name), "%d", general_index);
2023-02-17 21:51:06 +00:00

567 lines
18 KiB
C

/* 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
*/
static int wsmap_bulk_index;
static WMPixmap *frame_bg_focused;
static 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 *mini_preview;
mini_preview = RCreateImageFromXImage(scr->rcontext, pimg, NULL);
XDestroyImage(pimg);
if (mini_preview) {
RImage *tmp = scr->workspaces[scr->current_workspace]->map;
if (tmp)
RReleaseImage(tmp);
scr->workspaces[scr->current_workspace]->map =
RSmoothScaleImage(mini_preview,
scr->scr_width / WORKSPACE_MAP_RATIO,
scr->scr_height / WORKSPACE_MAP_RATIO);
RReleaseImage(mini_preview);
}
}
}
static void workspace_map_slide(WWorkspaceMap *wsmap)
{
if (wsmap->edge == WD_TOP)
slide_window(WMWidgetXID(wsmap->win), 0, -1 * wsmap->wsheight, wsmap->xcount, wsmap->ycount);
else
slide_window(WMWidgetXID(wsmap->win), 0, wsmap->scr->scr_height, wsmap->xcount, wsmap->ycount);
}
static void workspace_map_unslide(WWorkspaceMap *wsmap)
{
if (wsmap->edge == WD_TOP)
slide_window(WMWidgetXID(wsmap->win), wsmap->xcount, wsmap->ycount, 0, -1 * wsmap->wsheight);
else
slide_window(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);
w_global.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)
{
unsigned short workspace_index;
int mini_workspace_cnt;
char name[6];
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), "%hu", 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;
if (scr->workspace_count == 0)
return NULL;
wsmap = wmalloc(sizeof(*wsmap));
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;
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)
{
unsigned short local_index, general_index;
int mini_workspace_cnt;
char name[6];
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), "%hu", 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);
w_global.process_workspacemap_event = True;
while (w_global.process_workspacemap_event) {
WMMaskEvent(dpy, KeyPressMask | KeyReleaseMask | ExposureMask
| PointerMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask, &ev);
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)) {
w_global.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);
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);
}
}