forked from vitrine/wmaker
- Also tested the backward compatibility ability of the WINGs proplist code which seems to work quite well. Starting with this moment, Window Maker no longer needs libPropList and is now using the better and much more robust proplist code from WINGs. Also the WINGs based proplist code is actively maintained while the old libPropList code is practically dead and flawed by the fact that it borrowed concepts from the UserDefaults which conflicted with the retain/release mechanism, making some problems that libPropList had, practically unsolvable without a complete redesign (which can be found in the more robust WINGs code).
951 lines
24 KiB
C
951 lines
24 KiB
C
/* appicon.c- icon for applications (not mini-window)
|
|
*
|
|
* Window Maker window manager
|
|
*
|
|
* Copyright (c) 1997, 1998 Alfredo K. Kojima
|
|
* Copyright (c) 1998 Dan Pascu
|
|
*
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
* USA.
|
|
*/
|
|
|
|
#include "wconfig.h"
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "WindowMaker.h"
|
|
#include "wcore.h"
|
|
#include "window.h"
|
|
#include "icon.h"
|
|
#include "appicon.h"
|
|
#include "actions.h"
|
|
#include "stacking.h"
|
|
#include "dock.h"
|
|
#include "funcs.h"
|
|
#include "defaults.h"
|
|
#include "workspace.h"
|
|
#include "superfluous.h"
|
|
#include "menu.h"
|
|
#include "framewin.h"
|
|
#include "dialog.h"
|
|
#include "client.h"
|
|
#ifdef XDND
|
|
#include "xdnd.h"
|
|
#endif
|
|
#include "wsound.h"
|
|
#include <WINGs/WINGsP.h>
|
|
|
|
|
|
/*
|
|
* icon_file for the dock is got from the preferences file by
|
|
* using the classname/instancename
|
|
*/
|
|
|
|
/**** Global variables ****/
|
|
extern Cursor wCursor[WCUR_LAST];
|
|
extern WPreferences wPreferences;
|
|
|
|
#define MOD_MASK wPreferences.modifier_mask
|
|
|
|
void appIconMouseDown(WObjDescriptor *desc, XEvent *event);
|
|
static void iconDblClick(WObjDescriptor *desc, XEvent *event);
|
|
static void iconExpose(WObjDescriptor *desc, XEvent *event);
|
|
|
|
|
|
|
|
WAppIcon*
|
|
wAppIconCreateForDock(WScreen *scr, char *command, char *wm_instance,
|
|
char *wm_class, int tile)
|
|
{
|
|
WAppIcon *dicon;
|
|
char *path;
|
|
|
|
dicon = wmalloc(sizeof(WAppIcon));
|
|
wretain(dicon);
|
|
memset(dicon, 0, sizeof(WAppIcon));
|
|
dicon->yindex = -1;
|
|
dicon->xindex = -1;
|
|
|
|
dicon->prev = NULL;
|
|
dicon->next = scr->app_icon_list;
|
|
if (scr->app_icon_list) {
|
|
scr->app_icon_list->prev = dicon;
|
|
}
|
|
scr->app_icon_list = dicon;
|
|
|
|
if (command) {
|
|
dicon->command = wstrdup(command);
|
|
}
|
|
if (wm_class)
|
|
dicon->wm_class = wstrdup(wm_class);
|
|
if (wm_instance)
|
|
dicon->wm_instance = wstrdup(wm_instance);
|
|
|
|
path = wDefaultGetIconFile(scr, wm_instance, wm_class, True);
|
|
if (!path && command) {
|
|
wApplicationExtractDirPackIcon(scr, command, wm_instance, wm_class);
|
|
|
|
path = wDefaultGetIconFile(scr, wm_instance, wm_class, False);
|
|
}
|
|
|
|
if (path)
|
|
path = FindImage(wPreferences.icon_path, path);
|
|
|
|
dicon->icon = wIconCreateWithIconFile(scr, path, tile);
|
|
if (path)
|
|
wfree(path);
|
|
#ifdef XDND
|
|
wXDNDMakeAwareness(dicon->icon->core->window);
|
|
#endif
|
|
|
|
#ifdef DEMATERIALIZE_ICON
|
|
{
|
|
XSetWindowAttributes attribs;
|
|
attribs.save_under = True;
|
|
XChangeWindowAttributes(dpy, dicon->icon->core->window,
|
|
CWSaveUnder, &attribs);
|
|
}
|
|
#endif
|
|
|
|
/* will be overriden by dock */
|
|
dicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
|
|
dicon->icon->core->descriptor.handle_expose = iconExpose;
|
|
dicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
|
|
dicon->icon->core->descriptor.parent = dicon;
|
|
AddToStackList(dicon->icon->core);
|
|
|
|
return dicon;
|
|
}
|
|
|
|
|
|
|
|
WAppIcon*
|
|
wAppIconCreate(WWindow *leader_win)
|
|
{
|
|
WAppIcon *aicon;
|
|
WScreen *scr = leader_win->screen_ptr;
|
|
|
|
aicon = wmalloc(sizeof(WAppIcon));
|
|
wretain(aicon);
|
|
memset(aicon, 0, sizeof(WAppIcon));
|
|
|
|
aicon->yindex = -1;
|
|
aicon->xindex = -1;
|
|
|
|
aicon->prev = NULL;
|
|
aicon->next = scr->app_icon_list;
|
|
if (scr->app_icon_list) {
|
|
scr->app_icon_list->prev = aicon;
|
|
}
|
|
scr->app_icon_list = aicon;
|
|
|
|
if (leader_win->wm_class)
|
|
aicon->wm_class = wstrdup(leader_win->wm_class);
|
|
if (leader_win->wm_instance)
|
|
aicon->wm_instance = wstrdup(leader_win->wm_instance);
|
|
|
|
aicon->icon = wIconCreate(leader_win);
|
|
#ifdef DEMATERIALIZE_ICON
|
|
{
|
|
XSetWindowAttributes attribs;
|
|
attribs.save_under = True;
|
|
XChangeWindowAttributes(dpy, aicon->icon->core->window,
|
|
CWSaveUnder, &attribs);
|
|
}
|
|
#endif
|
|
#ifdef XDND
|
|
wXDNDMakeAwareness(aicon->icon->core->window);
|
|
#endif
|
|
|
|
/* will be overriden if docked */
|
|
aicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
|
|
aicon->icon->core->descriptor.handle_expose = iconExpose;
|
|
aicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
|
|
aicon->icon->core->descriptor.parent = aicon;
|
|
AddToStackList(aicon->icon->core);
|
|
aicon->icon->show_title = 0;
|
|
wIconUpdate(aicon->icon);
|
|
|
|
return aicon;
|
|
}
|
|
|
|
|
|
void
|
|
wAppIconDestroy(WAppIcon *aicon)
|
|
{
|
|
WScreen *scr = aicon->icon->core->screen_ptr;
|
|
|
|
RemoveFromStackList(aicon->icon->core);
|
|
wIconDestroy(aicon->icon);
|
|
if (aicon->command)
|
|
wfree(aicon->command);
|
|
#ifdef OFFIX_DND
|
|
if (aicon->dnd_command)
|
|
wfree(aicon->dnd_command);
|
|
#endif
|
|
if (aicon->wm_instance)
|
|
wfree(aicon->wm_instance);
|
|
if (aicon->wm_class)
|
|
wfree(aicon->wm_class);
|
|
|
|
if (aicon == scr->app_icon_list) {
|
|
if (aicon->next)
|
|
aicon->next->prev = NULL;
|
|
scr->app_icon_list = aicon->next;
|
|
}
|
|
else {
|
|
if (aicon->next)
|
|
aicon->next->prev = aicon->prev;
|
|
if (aicon->prev)
|
|
aicon->prev->next = aicon->next;
|
|
}
|
|
|
|
aicon->destroyed = 1;
|
|
wrelease(aicon);
|
|
}
|
|
|
|
|
|
|
|
#ifdef NEWAPPICON
|
|
static void
|
|
drawCorner(WIcon *icon, WWindow *wwin, int active)
|
|
{
|
|
WScreen *scr = wwin->screen_ptr;
|
|
XPoint points[3];
|
|
GC gc;
|
|
|
|
points[0].x = 2;
|
|
points[0].y = 2;
|
|
points[1].x = 12;
|
|
points[1].y = 2;
|
|
points[2].x = 2;
|
|
points[2].y = 12;
|
|
if (active) {
|
|
gc=scr->focused_texture->any.gc;
|
|
} else {
|
|
gc=scr->unfocused_texture->any.gc;
|
|
}
|
|
XFillPolygon(dpy, icon->core->window, gc, points, 3,
|
|
Convex, CoordModeOrigin);
|
|
}
|
|
#endif /* NEWAPPICON */
|
|
|
|
|
|
static void
|
|
drawCorner(WIcon *icon)
|
|
{
|
|
WScreen *scr = icon->core->screen_ptr;
|
|
XPoint points[3];
|
|
|
|
points[0].x = 1;
|
|
points[0].y = 1;
|
|
points[1].x = 12;
|
|
points[1].y = 1;
|
|
points[2].x = 1;
|
|
points[2].y = 12;
|
|
XFillPolygon(dpy, icon->core->window, scr->icon_title_texture->normal_gc,
|
|
points, 3, Convex, CoordModeOrigin);
|
|
XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc,
|
|
0, 0, 0, 12);
|
|
XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc,
|
|
0, 0, 12, 0);
|
|
/* drawing the second line gives a weird concave look. -Dan */
|
|
#if 0
|
|
XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc,
|
|
1, 1, 1, 11);
|
|
XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc,
|
|
1, 1, 11, 1);
|
|
#endif
|
|
}
|
|
|
|
|
|
void
|
|
wAppIconMove(WAppIcon *aicon, int x, int y)
|
|
{
|
|
WApplication *app;
|
|
WAppIcon *tmp;
|
|
|
|
app = wApplicationOf(aicon->icon->owner->main_window);
|
|
|
|
if (!WFLAGP(app->main_window_desc, collapse_appicons)) {
|
|
XMoveWindow(dpy, aicon->icon->core->window, x, y);
|
|
aicon->x_pos = x;
|
|
aicon->y_pos = y;
|
|
} else {
|
|
tmp = aicon->icon->core->screen_ptr->app_icon_list;
|
|
|
|
/* move all icons of the same class/name to the same pos */
|
|
while (tmp) {
|
|
if (strcmp(tmp->wm_class, aicon->wm_class) == 0 &&
|
|
strcmp(tmp->wm_instance, aicon->wm_instance) == 0 &&
|
|
!tmp->docked) {
|
|
XMoveWindow(dpy, tmp->icon->core->window, x, y);
|
|
tmp->x_pos = x;
|
|
tmp->y_pos = y;
|
|
}
|
|
tmp = tmp->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef WS_INDICATOR
|
|
static void
|
|
updateDockNumbers(WScreen *scr)
|
|
{
|
|
int length;
|
|
char *ws_numbers;
|
|
GC numbers_gc;
|
|
XGCValues my_gc_values;
|
|
unsigned long my_v_mask = (GCForeground);
|
|
WAppIcon *dicon = scr->dock->icon_array[0];
|
|
|
|
my_gc_values.foreground = scr->white_pixel;
|
|
numbers_gc = XCreateGC(dpy, dicon->icon->core->window,
|
|
my_v_mask, &my_gc_values);
|
|
|
|
ws_numbers = wmalloc(20);
|
|
snprintf(ws_numbers, 20, "%i [ %i ]", scr->current_workspace+1,
|
|
((scr->current_workspace/10)+1));
|
|
length = strlen(ws_numbers);
|
|
|
|
XClearArea(dpy, dicon->icon->core->window, 2, 2, 50,
|
|
WMFontHeight(scr->icon_title_font)+1, False);
|
|
|
|
XSetForeground(dpy, numbers_gc, scr->black_pixel);
|
|
WMDrawString(scr->wmscreen, dicon->icon->core->window, numbers_gc,
|
|
scr->icon_title_font, 4, 3, ws_numbers, length);
|
|
|
|
XSetForeground(dpy, numbers_gc, scr->white_pixel);
|
|
WMDrawString(scr->wmscreen, dicon->icon->core->window, numbers_gc,
|
|
scr->icon_title_font, 3, 2, ws_numbers, length);
|
|
|
|
XFreeGC(dpy, numbers_gc);
|
|
wfree(ws_numbers);
|
|
}
|
|
#endif /* WS_INDICATOR */
|
|
|
|
|
|
|
|
WAppIcon*
|
|
wAppIconNextSibling(WAppIcon *icon)
|
|
{
|
|
WApplication *app;
|
|
WAppIcon *tmp;
|
|
|
|
app = wApplicationOf(icon->icon->owner->main_window);
|
|
|
|
if (!WFLAGP(app->main_window_desc, collapse_appicons)) {
|
|
return NULL;
|
|
}
|
|
|
|
tmp = icon->next;
|
|
while (tmp) {
|
|
if (strcmp(tmp->wm_class, icon->wm_class) == 0
|
|
&& strcmp(tmp->wm_instance, icon->wm_instance) == 0
|
|
&& !tmp->docked) {
|
|
return tmp;
|
|
}
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
tmp = icon->icon->core->screen_ptr->app_icon_list;
|
|
while (tmp && tmp != icon) {
|
|
if (strcmp(tmp->wm_class, icon->wm_class) == 0
|
|
&& strcmp(tmp->wm_instance, icon->wm_instance) == 0
|
|
&& !tmp->docked) {
|
|
return tmp;
|
|
}
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
Bool
|
|
wAppIconIsFirstInstance(WAppIcon *icon)
|
|
{
|
|
WAppIcon *list = icon->icon->core->screen_ptr->app_icon_list;
|
|
|
|
if (!WFLAGP(icon->icon->owner, collapse_appicons))
|
|
return True;
|
|
|
|
while (list) {
|
|
if (icon == list)
|
|
return True;
|
|
|
|
if (strcmp(icon->wm_instance,
|
|
list->wm_instance) == 0
|
|
&&
|
|
strcmp(icon->wm_class,
|
|
list->wm_class) == 0
|
|
&& !icon->docked)
|
|
return False;
|
|
|
|
list = list->next;
|
|
}
|
|
|
|
puts("OH SHIT!?!?!? HOW THE FUCK DID WE GET HERE!?!?!?!?!");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
wAppIconPaint(WAppIcon *aicon)
|
|
{
|
|
WApplication *wapp;
|
|
WScreen *scr = aicon->icon->core->screen_ptr;
|
|
int index;
|
|
|
|
if (aicon->icon->owner)
|
|
wapp = wApplicationOf(aicon->icon->owner->main_window);
|
|
else
|
|
wapp = NULL;
|
|
|
|
wIconPaint(aicon->icon);
|
|
|
|
|
|
# ifdef WS_INDICATOR
|
|
if (aicon->docked && scr->dock && scr->dock==aicon->dock &&
|
|
aicon->yindex==0)
|
|
updateDockNumbers(scr);
|
|
# endif
|
|
if (scr->dock_dots && aicon->docked && !aicon->running
|
|
&& aicon->command!=NULL) {
|
|
XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
|
|
XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
|
|
XCopyArea(dpy, scr->dock_dots->image, aicon->icon->core->window,
|
|
scr->copy_gc, 0, 0, scr->dock_dots->width,
|
|
scr->dock_dots->height, 0, 0);
|
|
}
|
|
|
|
#ifdef HIDDENDOT
|
|
if (wapp && wapp->flags.hidden) {
|
|
XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
|
|
XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
|
|
XCopyArea(dpy, scr->dock_dots->image,
|
|
aicon->icon->core->window,
|
|
scr->copy_gc, 0, 0, 7,
|
|
scr->dock_dots->height, 0, 0);
|
|
}
|
|
#endif /* HIDDENDOT */
|
|
|
|
if (wapp)
|
|
index = wApplicationIndexOfGroup(wapp);
|
|
else
|
|
index = 0;
|
|
|
|
if (index > 0) {
|
|
char buf[16];
|
|
|
|
snprintf(buf, sizeof(buf), "%i", index);
|
|
|
|
WMDrawString(scr->wmscreen, aicon->icon->core->window,
|
|
scr->clip_title_gc, scr->title_font,
|
|
3, 3, buf, strlen(buf));
|
|
}
|
|
|
|
|
|
if (aicon->omnipresent)
|
|
drawCorner(aicon->icon);
|
|
|
|
XSetClipMask(dpy, scr->copy_gc, None);
|
|
if (aicon->launching) {
|
|
XFillRectangle(dpy, aicon->icon->core->window, scr->stipple_gc,
|
|
0, 0, wPreferences.icon_size, wPreferences.icon_size);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#define canBeDocked(wwin) ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
|
|
|
|
|
|
|
|
static void
|
|
hideCallback(WMenu *menu, WMenuEntry *entry)
|
|
{
|
|
WApplication *wapp = (WApplication*)entry->clientdata;
|
|
|
|
if (wapp->flags.hidden) {
|
|
wWorkspaceChange(menu->menu->screen_ptr, wapp->last_workspace);
|
|
wUnhideApplication(wapp, False, False);
|
|
} else {
|
|
wHideApplication(wapp);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
unhideHereCallback(WMenu *menu, WMenuEntry *entry)
|
|
{
|
|
WApplication *wapp = (WApplication*)entry->clientdata;
|
|
|
|
wUnhideApplication(wapp, False, True);
|
|
}
|
|
|
|
|
|
static void
|
|
collapseCallback(WMenu *menu, WMenuEntry *entry)
|
|
{
|
|
WApplication *wapp = (WApplication*)entry->clientdata;
|
|
|
|
wApplicationSetCollapse(wapp,
|
|
!WFLAGP(wapp->main_window_desc, collapse_appicons));
|
|
}
|
|
|
|
|
|
static void
|
|
setIconCallback(WMenu *menu, WMenuEntry *entry)
|
|
{
|
|
WAppIcon *icon = ((WApplication*)entry->clientdata)->app_icon;
|
|
char *file=NULL;
|
|
WScreen *scr;
|
|
int result;
|
|
|
|
assert(icon!=NULL);
|
|
|
|
if (icon->editing)
|
|
return;
|
|
icon->editing = 1;
|
|
scr = icon->icon->core->screen_ptr;
|
|
|
|
wretain(icon);
|
|
|
|
result = wIconChooserDialog(scr, &file, icon->wm_instance, icon->wm_class);
|
|
|
|
if (result && !icon->destroyed) {
|
|
if (file[0]==0) {
|
|
wfree(file);
|
|
file = NULL;
|
|
}
|
|
if (!wIconChangeImageFile(icon->icon, file)) {
|
|
wMessageDialog(scr, _("Error"),
|
|
_("Could not open specified icon file"),
|
|
_("OK"), NULL, NULL);
|
|
} else {
|
|
wDefaultChangeIcon(scr, icon->wm_instance, icon->wm_class, file);
|
|
wAppIconPaint(icon);
|
|
}
|
|
if (file)
|
|
wfree(file);
|
|
}
|
|
icon->editing = 0;
|
|
wrelease(icon);
|
|
}
|
|
|
|
|
|
static void
|
|
killCallback(WMenu *menu, WMenuEntry *entry)
|
|
{
|
|
WApplication *wapp = (WApplication*)entry->clientdata;
|
|
char *buffer;
|
|
|
|
if (!WCHECK_STATE(WSTATE_NORMAL))
|
|
return;
|
|
|
|
WCHANGE_STATE(WSTATE_MODAL);
|
|
|
|
assert(entry->clientdata!=NULL);
|
|
|
|
buffer = wstrconcat(wapp->app_icon ? wapp->app_icon->wm_class : NULL,
|
|
_(" will be forcibly closed.\n"
|
|
"Any unsaved changes will be lost.\n"
|
|
"Please confirm."));
|
|
|
|
wretain(wapp->main_window_desc);
|
|
if (wPreferences.dont_confirm_kill
|
|
|| wMessageDialog(menu->frame->screen_ptr, _("Kill Application"),
|
|
buffer, _("Yes"), _("No"), NULL)==WAPRDefault) {
|
|
if (!wapp->main_window_desc->flags.destroyed)
|
|
wClientKill(wapp->main_window_desc);
|
|
}
|
|
wrelease(wapp->main_window_desc);
|
|
|
|
wfree(buffer);
|
|
|
|
WCHANGE_STATE(WSTATE_NORMAL);
|
|
}
|
|
|
|
|
|
static WMenu*
|
|
createApplicationMenu(WScreen *scr)
|
|
{
|
|
WMenu *menu;
|
|
|
|
menu = wMenuCreate(scr, NULL, False);
|
|
wMenuAddCallback(menu, _("Unhide Here"), unhideHereCallback, NULL);
|
|
wMenuAddCallback(menu, _("Hide"), hideCallback, NULL);
|
|
wMenuAddCallback(menu, _("Collapse"), collapseCallback, NULL);
|
|
wMenuAddCallback(menu, _("Set Icon..."), setIconCallback, NULL);
|
|
wMenuAddCallback(menu, _("Kill"), killCallback, NULL);
|
|
|
|
return menu;
|
|
}
|
|
|
|
|
|
static void
|
|
openApplicationMenu(WApplication *wapp, int x, int y)
|
|
{
|
|
WMenu *menu;
|
|
WScreen *scr = wapp->main_window_desc->screen_ptr;
|
|
int i;
|
|
|
|
if (!scr->icon_menu) {
|
|
scr->icon_menu = createApplicationMenu(scr);
|
|
wfree(scr->icon_menu->entries[1]->text);
|
|
}
|
|
|
|
menu = scr->icon_menu;
|
|
|
|
if (wapp->flags.hidden) {
|
|
menu->entries[1]->text = _("Unhide");
|
|
} else {
|
|
menu->entries[1]->text = _("Hide");
|
|
}
|
|
|
|
if (WFLAGP(wapp->main_window_desc, collapse_appicons)) {
|
|
menu->entries[2]->text = _("Uncollapse");
|
|
} else {
|
|
menu->entries[2]->text = _("Collapse");
|
|
}
|
|
|
|
menu->flags.realized = 0;
|
|
wMenuRealize(menu);
|
|
|
|
x -= menu->frame->core->width/2;
|
|
if (x + menu->frame->core->width > scr->scr_width)
|
|
x = scr->scr_width - menu->frame->core->width;
|
|
if (x < 0)
|
|
x = 0;
|
|
|
|
/* set client data */
|
|
for (i = 0; i < menu->entry_no; i++) {
|
|
menu->entries[i]->clientdata = wapp;
|
|
}
|
|
wMenuMapAt(menu, x, y, False);
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
|
|
static void
|
|
iconExpose(WObjDescriptor *desc, XEvent *event)
|
|
{
|
|
wAppIconPaint(desc->parent);
|
|
}
|
|
|
|
|
|
static void
|
|
iconDblClick(WObjDescriptor *desc, XEvent *event)
|
|
{
|
|
WAppIcon *aicon = desc->parent;
|
|
WApplication *wapp;
|
|
WScreen *scr = aicon->icon->core->screen_ptr;
|
|
int unhideHere;
|
|
|
|
assert(aicon->icon->owner!=NULL);
|
|
|
|
wapp = wApplicationOf(aicon->icon->owner->main_window);
|
|
#ifdef DEBUG0
|
|
if (!wapp) {
|
|
wwarning("could not find application descriptor for app icon!!");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
unhideHere = (event->xbutton.state & ShiftMask);
|
|
|
|
/* go to the last workspace that the user worked on the app */
|
|
if (!unhideHere && wapp->last_workspace != scr->current_workspace)
|
|
wWorkspaceChange(scr, wapp->last_workspace);
|
|
|
|
wUnhideApplication(wapp, event->xbutton.button==Button2, unhideHere);
|
|
|
|
if (event->xbutton.state & MOD_MASK) {
|
|
wHideOtherApplications(aicon->icon->owner);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
appIconMouseDown(WObjDescriptor *desc, XEvent *event)
|
|
{
|
|
WAppIcon *aicon = desc->parent;
|
|
WIcon *icon = aicon->icon;
|
|
XEvent ev;
|
|
int x=aicon->x_pos, y=aicon->y_pos;
|
|
int dx=event->xbutton.x, dy=event->xbutton.y;
|
|
int grabbed=0;
|
|
int done=0;
|
|
int superfluous = wPreferences.superfluous; /* we catch it to avoid problems */
|
|
WScreen *scr = icon->core->screen_ptr;
|
|
WWorkspace *workspace = scr->workspaces[scr->current_workspace];
|
|
int shad_x = 0, shad_y = 0, docking=0, dockable, collapsed = 0;
|
|
int ix, iy;
|
|
int clickButton = event->xbutton.button;
|
|
Pixmap ghost = None;
|
|
Window wins[2];
|
|
Bool movingSingle = False;
|
|
int oldX = x;
|
|
int oldY = y;
|
|
|
|
if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
|
|
return;
|
|
|
|
if (event->xbutton.button == Button1 && IsDoubleClick(scr, event)) {
|
|
iconDblClick(desc, event);
|
|
return;
|
|
}
|
|
|
|
if (event->xbutton.button == Button3) {
|
|
WObjDescriptor *desc;
|
|
WApplication *wapp = wApplicationOf(aicon->icon->owner->main_window);
|
|
|
|
if (!wapp)
|
|
return;
|
|
|
|
if (event->xbutton.send_event &&
|
|
XGrabPointer(dpy, aicon->icon->core->window, True, ButtonMotionMask
|
|
|ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
|
|
GrabModeAsync, None, None, CurrentTime) !=GrabSuccess) {
|
|
wwarning("pointer grab failed for appicon menu");
|
|
return;
|
|
}
|
|
|
|
openApplicationMenu(wapp, event->xbutton.x_root,
|
|
event->xbutton.y_root);
|
|
|
|
/* allow drag select of menu */
|
|
desc = &scr->icon_menu->menu->descriptor;
|
|
event->xbutton.send_event = True;
|
|
(*desc->handle_mousedown)(desc, event);
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
puts("Moving icon");
|
|
#endif
|
|
if (event->xbutton.state & MOD_MASK)
|
|
wLowerFrame(icon->core);
|
|
else
|
|
wRaiseFrame(icon->core);
|
|
|
|
|
|
if (clickButton == Button2) {
|
|
WAppIcon *next = wAppIconNextSibling(aicon);
|
|
|
|
if (next) {
|
|
wRaiseFrame(next->icon->core);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (XGrabPointer(dpy, icon->core->window, True, ButtonMotionMask
|
|
|ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
|
|
GrabModeAsync, None, None, CurrentTime) !=GrabSuccess) {
|
|
wwarning("pointer grab failed for appicon move");
|
|
}
|
|
|
|
if (wPreferences.flags.nodock && wPreferences.flags.noclip)
|
|
dockable = 0;
|
|
else
|
|
dockable = canBeDocked(icon->owner);
|
|
|
|
wins[0] = icon->core->window;
|
|
wins[1] = scr->dock_shadow;
|
|
XRestackWindows(dpy, wins, 2);
|
|
if (superfluous) {
|
|
if (icon->pixmap!=None)
|
|
ghost = MakeGhostIcon(scr, icon->pixmap);
|
|
else
|
|
ghost = MakeGhostIcon(scr, icon->core->window);
|
|
XSetWindowBackgroundPixmap(dpy, scr->dock_shadow,
|
|
ghost);
|
|
XClearWindow(dpy, scr->dock_shadow);
|
|
}
|
|
|
|
while (!done) {
|
|
WMMaskEvent(dpy, PointerMotionMask|ButtonReleaseMask|ButtonPressMask
|
|
|ButtonMotionMask|ExposureMask, &ev);
|
|
switch (ev.type) {
|
|
case Expose:
|
|
WMHandleEvent(&ev);
|
|
break;
|
|
|
|
case MotionNotify:
|
|
if (!grabbed) {
|
|
if (abs(dx-ev.xmotion.x)>=MOVE_THRESHOLD
|
|
|| abs(dy-ev.xmotion.y)>=MOVE_THRESHOLD) {
|
|
XChangeActivePointerGrab(dpy, ButtonMotionMask
|
|
|ButtonReleaseMask|ButtonPressMask,
|
|
wCursor[WCUR_MOVE], CurrentTime);
|
|
grabbed=1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
x = ev.xmotion.x_root - dx;
|
|
y = ev.xmotion.y_root - dy;
|
|
|
|
if (movingSingle) {
|
|
XMoveWindow(dpy, icon->core->window, x, y);
|
|
} else {
|
|
wAppIconMove(aicon, x, y);
|
|
}
|
|
|
|
if (dockable) {
|
|
if (scr->dock && wDockSnapIcon(scr->dock, aicon, x, y,
|
|
&ix, &iy, False)) {
|
|
shad_x = scr->dock->x_pos + ix*wPreferences.icon_size;
|
|
shad_y = scr->dock->y_pos + iy*wPreferences.icon_size;
|
|
|
|
if (scr->last_dock != scr->dock && collapsed) {
|
|
scr->last_dock->collapsed = 1;
|
|
wDockHideIcons(scr->last_dock);
|
|
collapsed = 0;
|
|
}
|
|
if (!collapsed && (collapsed = scr->dock->collapsed)) {
|
|
scr->dock->collapsed = 0;
|
|
wDockShowIcons(scr->dock);
|
|
}
|
|
|
|
if (scr->dock->auto_raise_lower)
|
|
wDockRaise(scr->dock);
|
|
|
|
scr->last_dock = scr->dock;
|
|
|
|
XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
|
|
if (!docking) {
|
|
XMapWindow(dpy, scr->dock_shadow);
|
|
}
|
|
docking = 1;
|
|
} else if (workspace->clip &&
|
|
wDockSnapIcon(workspace->clip, aicon, x, y,
|
|
&ix, &iy, False)) {
|
|
shad_x = workspace->clip->x_pos + ix*wPreferences.icon_size;
|
|
shad_y = workspace->clip->y_pos + iy*wPreferences.icon_size;
|
|
|
|
if (scr->last_dock != workspace->clip && collapsed) {
|
|
scr->last_dock->collapsed = 1;
|
|
wDockHideIcons(scr->last_dock);
|
|
collapsed = 0;
|
|
}
|
|
if (!collapsed && (collapsed = workspace->clip->collapsed)) {
|
|
workspace->clip->collapsed = 0;
|
|
wDockShowIcons(workspace->clip);
|
|
}
|
|
|
|
if (workspace->clip->auto_raise_lower)
|
|
wDockRaise(workspace->clip);
|
|
|
|
scr->last_dock = workspace->clip;
|
|
|
|
XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
|
|
if (!docking) {
|
|
XMapWindow(dpy, scr->dock_shadow);
|
|
}
|
|
docking = 1;
|
|
} else if (docking) {
|
|
XUnmapWindow(dpy, scr->dock_shadow);
|
|
docking = 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case ButtonPress:
|
|
break;
|
|
|
|
case ButtonRelease:
|
|
if (ev.xbutton.button != clickButton)
|
|
break;
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
|
|
if (docking) {
|
|
Bool docked;
|
|
|
|
/* icon is trying to be docked */
|
|
SlideWindow(icon->core->window, x, y, shad_x, shad_y);
|
|
XUnmapWindow(dpy, scr->dock_shadow);
|
|
docked = wDockAttachIcon(scr->last_dock, aicon, ix, iy);
|
|
if (scr->last_dock->auto_collapse) {
|
|
collapsed = 0;
|
|
}
|
|
if (workspace->clip &&
|
|
workspace->clip != scr->last_dock &&
|
|
workspace->clip->auto_raise_lower)
|
|
wDockLower(workspace->clip);
|
|
|
|
if (!docked) {
|
|
/* If icon could not be docked, slide it back to the old
|
|
* position */
|
|
SlideWindow(icon->core->window, x, y, oldX, oldY);
|
|
} else {
|
|
WAppIcon *nextIcon = wAppIconNextSibling(aicon);
|
|
|
|
if (nextIcon) {
|
|
/* move the next instance back to the old position */
|
|
SlideWindow(nextIcon->icon->core->window, x, y,
|
|
oldX, oldY);
|
|
wAppIconMove(nextIcon, oldX, oldY);
|
|
}
|
|
}
|
|
|
|
wSoundPlay(WSOUND_DOCK);
|
|
} else {
|
|
if (movingSingle) {
|
|
/* move back to its place */
|
|
SlideWindow(icon->core->window, x, y, oldX, oldY);
|
|
wAppIconMove(aicon, oldX, oldY);
|
|
} else {
|
|
XMoveWindow(dpy, icon->core->window, x, y);
|
|
aicon->x_pos = x;
|
|
aicon->y_pos = y;
|
|
}
|
|
if (workspace->clip && workspace->clip->auto_raise_lower)
|
|
wDockLower(workspace->clip);
|
|
}
|
|
if (collapsed) {
|
|
scr->last_dock->collapsed = 1;
|
|
wDockHideIcons(scr->last_dock);
|
|
collapsed = 0;
|
|
}
|
|
if (superfluous) {
|
|
if (ghost!=None)
|
|
XFreePixmap(dpy, ghost);
|
|
XSetWindowBackground(dpy, scr->dock_shadow, scr->white_pixel);
|
|
}
|
|
|
|
if (wPreferences.auto_arrange_icons)
|
|
wArrangeIcons(scr, True);
|
|
|
|
done = 1;
|
|
break;
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
puts("End icon move");
|
|
#endif
|
|
|
|
}
|