/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- client_list_menu.m for the Azalea window manager Copyright (c) 2006 Yen-Ju Chen client_list_menu.c for the Openbox window manager Copyright (c) 2003 Ben Jansens 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. See the COPYING file for a copy of the GNU General Public License. */ #import "AZScreen.h" #import "AZClient.h" #import "AZFocusManager.h" #import "AZMenuFrame.h" #import "AZMenuManager.h" #import "AZClientManager.h" #import "openbox.h" #import "AZMenu.h" #import "action.h" #import "config.h" #define MENU_NAME @"client-list-menu" static NSMutableArray *desktop_menus; static AZMenu *client_list_menu; @interface AZDesktopMenu: AZMenu { unsigned int data; } - (id) initWithName: (NSString *) name title: (NSString *) title desktop: (unsigned int) desktop; @end @implementation AZDesktopMenu - (id) initWithName: (NSString *) n title: (NSString *) t desktop: (unsigned int) d { self = [super initWithName: n title: t]; data = d; return self; } - (void) update: (AZMenuFrame *) frame { AZMenu *menu = [frame menu]; int i; int j, jcount; BOOL icons = NO; BOOL empty = YES; [menu clearEntries]; AZFocusManager *fManager = [AZFocusManager defaultManager]; jcount = [fManager numberOfFocusOrderInScreen: data]; for (j = 0, i = 0; j < jcount; j++, ++i) { AZClient *c = [fManager focusOrder: j inScreen: data]; if ([c normal] && (![c skip_taskbar] || [c iconic])) { NSMutableArray *acts = [[NSMutableArray alloc] init]; AZAction* act; AZNormalMenuEntry *e; AZClientIcon *icon; empty = NO; if (!icons && [c iconic]) { icons = YES; [menu addSeparatorMenuEntry: -1]; } act = [AZAction actionWithName: @"Activate" userAction: OB_USER_ACTION_MENU_SELECTION]; [act data_pointer]->activate.any.c = c; [acts addObject: act]; act = [AZAction actionWithName: @"Desktop" userAction: OB_USER_ACTION_MENU_SELECTION]; [act data_pointer]->desktop.desk = data; [acts addObject: act]; e = [menu addNormalMenuEntry: i label: ([c iconic] ? [c icon_title] : [c title]) actions: acts]; DESTROY(acts); if (config_menu_client_list_icons && (icon = [c iconWithWidth: 32 height: 32])) { [e set_icon_width: [icon width]]; [e set_icon_height: [icon height]]; [e set_icon_data: [icon data]]; } } } if (empty) { /* no entries */ AZAction* act; AZNormalMenuEntry *e; act = [AZAction actionWithName: @"Desktop" userAction: OB_USER_ACTION_MENU_SELECTION]; [act data_pointer]->desktop.desk = data; e = [menu addNormalMenuEntry: 0 label: @"Go there..." actions: [NSArray arrayWithObjects: act, nil]]; if (data == [[AZScreen defaultScreen] desktop]) [e set_enabled: NO]; } } /* executes it using the client in the actions, since we set that when we make the actions! */ - (BOOL) execute: (AZMenuEntry *) entry state: (unsigned int) state { AZAction *a; if ([entry isKindOfClass: [AZNormalMenuEntry class]] && [(AZNormalMenuEntry *)entry actions]) { AZNormalMenuEntry *e = (AZNormalMenuEntry *) entry; a = [[e actions] objectAtIndex: 0]; action_run([e actions], [a data].any.c, state); } return YES; } - (void) dealloc { [desktop_menus removeObject: self]; [super dealloc]; } @end @interface AZClientListMenu: AZMenu @end @implementation AZClientListMenu - (void) update: (AZMenuFrame *) frame { AZMenu *menu = [frame menu]; unsigned int i, j; AZScreen *screen = [AZScreen defaultScreen]; for (i = 0; i < [screen numberOfDesktops]; ++i) { if (i >= [desktop_menus count]) { AZDesktopMenu *submenu; NSString *n = [NSString stringWithFormat: @"%@-%u", MENU_NAME, i]; submenu = [[AZDesktopMenu alloc] initWithName: n title: [screen nameOfDesktopAtIndex: i] desktop: i]; [menu addSubmenuMenuEntry: i submenu: n]; [[AZMenuManager defaultManager] registerMenu: submenu]; RELEASE(submenu); [desktop_menus addObject: submenu]; } } for (j = [desktop_menus count]-1; j > i-1; j--) { [[AZMenuManager defaultManager] removeMenu: [desktop_menus objectAtIndex: j]]; [desktop_menus removeObjectAtIndex: j]; [menu removeEntryWithIdentifier: j]; } } - (void) clientDestroy: (NSNotification *) not { /* This concise function removes all references to a closed * client in the client_list_menu, so we don't have to check * in client.c */ int i, j; for (i = 0; i < [desktop_menus count]; i++) { AZMenu *mit = [desktop_menus objectAtIndex: i]; NSArray *mentries = [mit entries]; for (j = 0; j < [mentries count]; j++) { AZMenuEntry *meit = [mentries objectAtIndex: j]; if ([meit type] == OB_MENU_ENTRY_TYPE_NORMAL) { AZAction *a = [[(AZNormalMenuEntry *)meit actions] objectAtIndex: 0]; AZClient *c = [a data].any.c; if (c == [not object]) { [a data_pointer]->any.c = NULL; } } } } } @end void client_list_menu_startup(BOOL reconfig) { if (desktop_menus == nil) { desktop_menus = [[NSMutableArray alloc] init]; } else { [desktop_menus removeAllObjects]; } client_list_menu = [[AZClientListMenu alloc] initWithName: MENU_NAME title: @"Desktops"]; [[AZMenuManager defaultManager] registerMenu: client_list_menu]; // if (!reconfig) { [[NSNotificationCenter defaultCenter] addObserver: client_list_menu selector: @selector(clientDestroy:) name: AZClientDestroyNotification object: nil]; } } void client_list_menu_shutdown(BOOL reconfig) { // if (!reconfig) { [[NSNotificationCenter defaultCenter] removeObserver: client_list_menu]; } DESTROY(client_list_menu); }