278 lines
6.8 KiB
C
278 lines
6.8 KiB
C
/*
|
|
* Window Maker window manager
|
|
*
|
|
* Copyright (c) 1998-2003 Alfredo K. Kojima
|
|
* Copyright (c) 2014-2016 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.
|
|
*/
|
|
|
|
#include "wconfig.h"
|
|
|
|
#ifdef BALLOON_TEXT
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <wraster.h>
|
|
|
|
#include "WindowMaker.h"
|
|
#include "screen.h"
|
|
#include "texture.h"
|
|
#include "framewin.h"
|
|
#include "icon.h"
|
|
#include "appicon.h"
|
|
#include "workspace.h"
|
|
#include "balloon.h"
|
|
#include "misc.h"
|
|
|
|
|
|
|
|
#define TOP 0
|
|
#define BOTTOM 1
|
|
#define LEFT 0
|
|
#define RIGHT 2
|
|
|
|
static int countLines(const char *text)
|
|
{
|
|
const char *p = text;
|
|
int h = 1;
|
|
|
|
while (*p) {
|
|
if (*p == '\n' && p[1] != 0)
|
|
h++;
|
|
p++;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
static int getMaxStringWidth(WMFont *font, const char *text)
|
|
{
|
|
const char *p = text;
|
|
const char *pb = p;
|
|
int pos = 0;
|
|
int w = 0, wt;
|
|
|
|
while (*p) {
|
|
if (*p == '\n') {
|
|
wt = WMWidthOfString(font, pb, pos);
|
|
if (wt > w)
|
|
w = wt;
|
|
pos = 0;
|
|
pb = p + 1;
|
|
} else {
|
|
pos++;
|
|
}
|
|
p++;
|
|
}
|
|
if (pos > 0) {
|
|
wt = WMWidthOfString(font, pb, pos);
|
|
if (wt > w)
|
|
w = wt;
|
|
}
|
|
return w;
|
|
}
|
|
|
|
static void showBalloon(WScreen *scr)
|
|
{
|
|
scr->balloon->timer = NULL;
|
|
scr->balloon->ignoreTimer = 1;
|
|
|
|
wm_backend->balloon_show(scr, scr->balloon);
|
|
}
|
|
|
|
static void frameBalloon(WObjDescriptor *object)
|
|
{
|
|
WFrameWindow *fwin = (WFrameWindow *) object->parent;
|
|
WScreen *scr = fwin->core->screen_ptr;
|
|
|
|
if (fwin->titlebar != object->self || !fwin->flags.is_client_window_frame) {
|
|
wBalloonHide(scr);
|
|
return;
|
|
}
|
|
if (fwin->title && fwin->flags.incomplete_title) {
|
|
scr->balloon->h = (fwin->titlebar ? fwin->titlebar->height : 0);
|
|
scr->balloon->text = wstrdup(fwin->title);
|
|
scr->balloon->objectWindow = fwin->core->window;
|
|
scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY, (WMCallback *) showBalloon, scr);
|
|
}
|
|
}
|
|
|
|
static void miniwindowBalloon(WObjDescriptor *object)
|
|
{
|
|
WIcon *icon = (WIcon *) object->parent;
|
|
WScreen *scr = icon->core->screen_ptr;
|
|
|
|
if (!icon->icon_name) {
|
|
wBalloonHide(scr);
|
|
return;
|
|
}
|
|
scr->balloon->h = icon->core->height;
|
|
scr->balloon->text = wstrdup(icon->icon_name);
|
|
scr->balloon->mini_preview = icon->mini_preview;
|
|
scr->balloon->objectWindow = icon->core->window;
|
|
|
|
if ((scr->balloon->prevType == object->parent_type || scr->balloon->prevType == WCLASS_APPICON)
|
|
&& scr->balloon->ignoreTimer) {
|
|
wm_backend->window_unmap((WNativeWindow)scr->balloon->window);
|
|
showBalloon(scr);
|
|
} else {
|
|
scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY, (WMCallback *) showBalloon, scr);
|
|
}
|
|
}
|
|
|
|
static void appiconBalloon(WObjDescriptor *object)
|
|
{
|
|
WAppIcon *aicon = (WAppIcon *) object->parent;
|
|
WScreen *scr = aicon->icon->core->screen_ptr;
|
|
char *tmp;
|
|
|
|
/* Show balloon if it is the Clip and the workspace name is > 5 chars */
|
|
if (object->parent == scr->clip_icon) {
|
|
if (strlen(scr->workspaces[scr->current_workspace]->name) > 5) {
|
|
scr->balloon->text = wstrdup(scr->workspaces[scr->current_workspace]->name);
|
|
} else {
|
|
wBalloonHide(scr);
|
|
return;
|
|
}
|
|
} else if (aicon->command && aicon->wm_class) {
|
|
int len;
|
|
WApplication *app;
|
|
unsigned int app_win_cnt = 0;
|
|
const char *display_name;
|
|
|
|
if (object->parent_type == WCLASS_DOCK_ICON) {
|
|
if (aicon->main_window) {
|
|
app = wApplicationOf(aicon->main_window);
|
|
if (app && app->main_window_desc && app->main_window_desc->fake_group)
|
|
app_win_cnt = app->main_window_desc->fake_group->retainCount - 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check to see if it is a GNUstep app, because in this case we use the instance
|
|
* instead of the class, otherwise the user will not be able to distinguish what
|
|
* is being referred.
|
|
*/
|
|
if (strcmp(aicon->wm_class, "GNUstep") == 0)
|
|
display_name = aicon->wm_instance;
|
|
else
|
|
display_name = aicon->wm_class;
|
|
|
|
len = strlen(aicon->command) + strlen(display_name) + 8;
|
|
|
|
if (app_win_cnt > 0)
|
|
len += 1 + snprintf(NULL, 0, "%u", app_win_cnt);
|
|
|
|
tmp = wmalloc(len);
|
|
if (app_win_cnt > 0)
|
|
snprintf(tmp, len, "%u %s\n(%s)", app_win_cnt, display_name, aicon->command);
|
|
else
|
|
snprintf(tmp, len, "%s\n(%s)", aicon->wm_instance, aicon->command);
|
|
scr->balloon->text = tmp;
|
|
|
|
} else if (aicon->command) {
|
|
scr->balloon->text = wstrdup(aicon->command);
|
|
} else if (aicon->wm_class) {
|
|
/* Check to see if it is a GNUstep App */
|
|
if (strcmp(aicon->wm_class, "GNUstep") == 0)
|
|
scr->balloon->text = wstrdup(aicon->wm_instance);
|
|
else
|
|
scr->balloon->text = wstrdup(aicon->wm_class);
|
|
} else {
|
|
wBalloonHide(scr);
|
|
return;
|
|
}
|
|
scr->balloon->h = aicon->icon->core->height - 2;
|
|
|
|
scr->balloon->objectWindow = aicon->icon->core->window;
|
|
if ((scr->balloon->prevType == object->parent_type || scr->balloon->prevType == WCLASS_MINIWINDOW)
|
|
&& scr->balloon->ignoreTimer) {
|
|
wm_backend->window_unmap((WNativeWindow)scr->balloon->window);
|
|
showBalloon(scr);
|
|
} else {
|
|
scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY, (WMCallback *) showBalloon, scr);
|
|
}
|
|
}
|
|
|
|
void wBalloonInitialize(WScreen *scr)
|
|
{
|
|
wm_backend->balloon_init(scr);
|
|
}
|
|
|
|
void wBalloonEnteredObject(WScreen *scr, WObjDescriptor *object)
|
|
{
|
|
WBalloon *balloon = scr->balloon;
|
|
|
|
if (balloon->timer) {
|
|
WMDeleteTimerHandler(balloon->timer);
|
|
balloon->timer = NULL;
|
|
balloon->ignoreTimer = 0;
|
|
}
|
|
|
|
if (scr->balloon->text)
|
|
wfree(scr->balloon->text);
|
|
scr->balloon->text = NULL;
|
|
|
|
scr->balloon->mini_preview = None;
|
|
|
|
if (!object) {
|
|
wBalloonHide(scr);
|
|
balloon->ignoreTimer = 0;
|
|
return;
|
|
}
|
|
|
|
switch (object->parent_type) {
|
|
case WCLASS_FRAME:
|
|
if (wPreferences.window_balloon)
|
|
frameBalloon(object);
|
|
break;
|
|
case WCLASS_DOCK_ICON:
|
|
if (wPreferences.appicon_balloon)
|
|
appiconBalloon(object);
|
|
break;
|
|
case WCLASS_MINIWINDOW:
|
|
if (wPreferences.miniwin_title_balloon || wPreferences.miniwin_preview_balloon)
|
|
miniwindowBalloon(object);
|
|
break;
|
|
case WCLASS_APPICON:
|
|
if (wPreferences.appicon_balloon)
|
|
appiconBalloon(object);
|
|
break;
|
|
default:
|
|
wBalloonHide(scr);
|
|
break;
|
|
}
|
|
scr->balloon->prevType = object->parent_type;
|
|
}
|
|
|
|
void wBalloonHide(WScreen *scr)
|
|
{
|
|
if (scr && scr->balloon) {
|
|
if (scr->balloon->mapped) {
|
|
wm_backend->window_unmap((WNativeWindow)scr->balloon->window);
|
|
scr->balloon->mapped = 0;
|
|
} else if (scr->balloon->timer) {
|
|
WMDeleteTimerHandler(scr->balloon->timer);
|
|
scr->balloon->timer = NULL;
|
|
}
|
|
scr->balloon->prevType = 0;
|
|
}
|
|
}
|
|
|
|
#endif
|